Mercurial > repos > RelicTools > SGAExtractor
view Class1.cs @ 0:85ff734c7605 default tip
Initial commit under GPLv3
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 06 Oct 2018 20:29:36 +0100 |
parents | |
children |
line wrap: on
line source
// This file is a part of the SGA Extractor command-line app and is copyright 2006-2018 IBBoard. // // The file and the library/program it is in are licensed under the GNU GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license. using System; using System.IO; using System.Collections; using System.Text.RegularExpressions; using IBBoard.Relic.RelicTools; namespace SgaExtractor { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { private const int DEFAULT_MODE = 2; private static readonly string nl = System.Environment.NewLine; private static string dest; private static SgaArchive archive; private static ArrayList paths; private static bool overwrite = false; private static bool recursive = false; private static string ext; private static short mode = DEFAULT_MODE; private static string logPath; private static StreamWriter sw; private static bool fullExtract = false; /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { if (args.Length<1 || args[0]=="/?") { ShowHelp(""); if (args.Length>1 && args[1].ToLower() == "usage") { Output(nl+"Click ENTER to see example usage..."); Console.ReadLine(); ShowUsage(); } return; } if (!Regex.IsMatch(args[0], "[a-zA-Z0-9]+.sga$")) { ShowHelp("Archive to extract must be specified as the first parameter"); return; } else { try { archive = new SgaArchive(args[0]); } catch (FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } } int i = 1; if (args.Length>1) { if (!args[i].StartsWith("-")) { //full-archive extraction with a destination fullExtract = true; dest = args[i]; i++; } else if (args[i]=="-paths") { fullExtract = false; i++; paths = new ArrayList(); while (i<args.Length && !args[i].StartsWith("-")) { paths.Add(args[i]); i++; } } else { fullExtract = true; } } else { fullExtract = true; } ArrayList arrFind = new ArrayList(); ArrayList arrReplace = new ArrayList(); while (i<args.Length) { if (!fullExtract && args[i]=="-d" && i<(args.Length-1) && !args[i+1].StartsWith("-")) { if (dest!="" && dest!=null) { ShowHelp("Please only specify one destination - either a single file or a folder"); } else { i++; dest = args[i]; i++; int lastSlash = dest.LastIndexOf('\\'); if (lastSlash<dest.LastIndexOf('.')) { //it looks like a file, so make sure they've not specified multiple files if (paths == null || paths.Count!=1) { ShowHelp("Multiple files were selected but a single destination file was specified"); return; } } } } else if (!fullExtract && args[i]=="-find" && i<(args.Length-3)) { i++; while (i<args.Length && !args[i].StartsWith("-")) { arrFind.Add(args[i]); i++; } } else if (!fullExtract && args[i]=="-replace" && i<(args.Length-1)) { i++; while (i<args.Length && !args[i].StartsWith("-")) { arrReplace.Add(args[i]); i++; } } else if (!fullExtract && (args[i]=="-extension" || args[i]=="-ext") && i<(args.Length-1)) { i++; ext = args[i]; i++; } else if (args[i]=="-mode" && i<args.Length-1) { i++; try { mode = short.Parse(args[i]); if (mode<1||mode>3) { mode = DEFAULT_MODE; Output("Warning: invalid mode used. Reverting to default"); } } catch { mode = DEFAULT_MODE; } i++; } else if (args[i]=="-log" && i<args.Length-1) { i++; logPath = args[i]; i++; } else if (args[i]=="--force") { i++; overwrite = true; } else if (!fullExtract && args[i]=="--recursive") { i++; recursive = true; } else { ShowHelp("Invalid parameter: "+args[i]); return; } } string [] find; string [] replace; if (arrReplace.Count!=arrFind.Count) { ShowHelp("Find and Replace lists must be the same length"); return; } else { find = new string[arrFind.Count]; replace = new string [arrReplace.Count]; for (int j = 0; j<arrFind.Count; j++) { find[j] = (string)arrFind[j]; } for (int j = 0; j<arrReplace.Count; j++) { replace[j] = (string)arrReplace[j]; } } if ((mode & 1) == 1) { archive.OnExtractFileFail += new SgaArchive.ExtractionNotification(OutputExtractionStatus); archive.OnExtractFolderFail += new SgaArchive.ExtractionNotification(OutputExtractionStatus); } if ((mode & 2) == 2) { archive.OnExtractFileSuccess += new SgaArchive.ExtractionNotification(OutputExtractionStatus); archive.OnExtractFolderSuccess += new SgaArchive.ExtractionNotification(OutputExtractionStatus); } if (logPath!=null && logPath!="") { sw = new StreamWriter(logPath,true); sw.AutoFlush = true; sw.WriteLine(DateTime.Now.ToString()+" - "+Environment.CommandLine.ToString()+nl); } if (paths==null || paths.Count==0) { //full archive extraction if (dest==null || dest == "") { //to default location try { Output("Extracting full archive "+archive.Name+" to default location"); archive.ExtractAll(overwrite); Output("Extraction Complete"); } catch (FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(Exception ex) { Output("Extraction failed: "+ex.Message); } } else { //to specified location try { Output("Extracting full archive "+archive.Name+" to "+dest); archive.ExtractAll(dest, overwrite); Output("Extraction Complete"); } catch (FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(Exception ex) { Output("Extraction failed: "+ex.Message); } } } else { string path = ""; for (int j = 0; j<paths.Count; j++) { path = (string)paths[j]; int lastindex = path.LastIndexOf('\\'); if (lastindex>=path.LastIndexOf('.')) { //the path to extract is a folder try { if (ext!=null) { Output("Attempting to extract files of type '"+ext+"' from folder: "+path); if (dest==null) { archive.ExtractType(ext, path, find, replace, recursive, overwrite); } else { archive.ExtractType(ext, path, dest, find, replace, recursive, overwrite); } } else { Output("Attempting to extract folder: "+path); if (dest==null && find.Length==0) { archive.ExtractFolder(path, recursive, overwrite); } else { archive.ExtractFolder(path, dest, find, replace, recursive, overwrite); } } Output("Extraction complete"); } catch(Exception ex) { Output("Extraction failed: "+ex.Message); } } else { Output("Attempting to extract file: "+path); try { if (dest==null) { archive.Extract(path, find, replace, overwrite); } else { archive.Extract(path, dest, find, replace, overwrite); } Output("Extraction complete"); } catch(Exception ex) { Output("Extraction failed: "+ex.Message); } } } } /* if (args.Length==1 && args[0]=="/?") { ShowHelp(""); } else if (args.Length==1 && args[0].EndsWith(".sga")) { try { archive = new SgaArchive(args[0]); Output("Extracting full archive "+args[0]); archive.ExtractAll(); Output("Extraction Complete"); } catch (RelicSga.Exceptions.FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } else if (args.Length ==2 && args[0]=="/?" && args[1]=="usage") { ShowHelp(""); Output(nl+"Click ENTER to see example usage..."); Console.ReadLine(); ShowUsage(); } else if (args.Length==2 && args[0].EndsWith(".sga")) { if (args[1]=="--force") { try { archive = new SgaArchive(args[0]); Output("Extracting full archive "+args[0]); archive.ExtractAll(true); Output("Extraction Complete"); } catch (RelicSga.Exceptions.FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } else if (!args[1].StartsWith("-")) { try { archive = new SgaArchive(args[0]); Output("Extracting full archive "+args[0]+" to "+args[1]); archive.ExtractAll(args[1]); Output("Extraction Complete"); } catch (RelicSga.Exceptions.FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } else { ShowHelp("Invalid parameter combination"); return; } } else if (args.Length<3) { ShowHelp(""); } else if (args.Length==3 && args[0].EndsWith(".sga") && !args[1].StartsWith("-") && args[2]=="--force") { try { archive = new SgaArchive(args[0]); Output("Extracting full archive "+args[0]+" to "+args[1]); archive.ExtractAll(args[1], true); Output("Extraction Complete"); } catch (RelicSga.Exceptions.FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } else { if (!Regex.IsMatch(args[0], "^[a-zA-Z0-9]+.sga$")) { ShowHelp("Archive to extract must be specified as the first parameter"); return; } else { try { archive = new SgaArchive(args[0]); } catch (RelicSga.Exceptions.FileNotFoundException) { ShowHelp("The archive specified was not found"); return; } } if (args[1]!="-paths") { ShowHelp("Must specifie a set of paths to extract"); return; } int i = 2; paths = new ArrayList(); while (i<args.Length && !args[i].StartsWith("-")) { paths.Add(args[i]); i++; } ArrayList arrFind = new ArrayList(); ArrayList arrReplace = new ArrayList(); if (i != args.Length) { while (i<args.Length) { if (args[i]=="-d" && i<(args.Length-1) && !args[i+1].StartsWith("-")) { i++; dest = args[i]; i++; int lastindex = dest.LastIndexOf('\\'); if (lastindex<=dest.LastIndexOf('.')) { //it looks like a file, so make sure they've not specified multiple files if (paths.Count!=1) { ShowHelp("Multiple files were selected but a single destination file was specified"); return; } } } else if (args[i]=="-find" && i<(args.Length-3)) { i++; while (i<args.Length && !args[i].StartsWith("-")) { arrFind.Add(args[i]); i++; } } else if (args[i]=="-replace" && i<(args.Length-1)) { i++; while (i<args.Length && !args[i].StartsWith("-")) { arrReplace.Add(args[i]); i++; } } else if ((args[i]=="-extension" || args[i]=="-ext") && i<(args.Length-1)) { i++; ext = args[i]; i++; } else if (args[i]=="-mode" && i<args.Length-1) { i++; try { mode = short.Parse(args[i]); } catch { mode = DEFAULT_MODE; } i++; } else if (args[i]=="-log" && i<args.Length-1) { i++; logPath = args[i]; i++; } else if (args[i]=="--force") { i++; overwrite = true; } else if (args[i]=="--recursive") { i++; recursive = true; } else { ShowHelp("Invalid parameter combination"); return; } } } string path = ""; string [] find; string [] replace; if (arrReplace.Count!=arrFind.Count) { ShowHelp("Find and Replace lists must be the same length"); return; } else { find = new string[arrFind.Count]; replace = new string [arrReplace.Count]; for (int j = 0; j<arrFind.Count; j++) { find[j] = (string)arrFind[j]; } for (int j = 0; j<arrReplace.Count; j++) { replace[j] = (string)arrReplace[j]; } } if ((mode & 1) == 1) { archive.OnExtractFileFail += new SgaArchive.ExtractionNotification(OutputExtractionStatus); archive.OnExtractFolderFail += new SgaArchive.ExtractionNotification(OutputExtractionStatus); } if ((mode & 2) == 2) { archive.OnExtractFileSuccess += new SgaArchive.ExtractionNotification(OutputExtractionStatus); archive.OnExtractFolderSuccess += new SgaArchive.ExtractionNotification(OutputExtractionStatus); } if (logPath!=null && logPath!="") { sw = new StreamWriter(logPath,false); sw.AutoFlush = true; } for (int j = 0; j<paths.Count; j++) { path = (string)paths[j]; int lastindex = path.LastIndexOf('\\'); if (lastindex>path.LastIndexOf('.')) { //it's a folder try { if (ext!=null) { Output("Attempting to extract files of type '"+ext+"' from folder: "+path); if (dest==null) { archive.ExtractType(ext, path, find, replace, recursive, overwrite); } else { archive.ExtractType(ext, path, dest, find, replace, recursive, overwrite); } } else { Output("Attempting to extract folder: "+path); if (dest==null && find.Length==0) { archive.ExtractFolder(path, recursive, overwrite); } else { archive.ExtractFolder(path, dest, find, replace, recursive, overwrite); } } Output("Extraction complete"); } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } else { Output("Attempting to extract file: "+path); try { if (dest==null) { archive.Extract(path, find, replace, overwrite); } else { archive.Extract(path, dest, find, replace, overwrite); } Output("Extraction complete"); } catch(RelicSga.Exceptions.Exception ex) { Output("Extraction failed: "+ex.Message); } } } } */ if (sw!=null) { sw.WriteLine(""); sw.Close(); } } private static void ShowHelp(string error) { if (error!="") { error = nl+"Error: "+error+nl; if (sw!=null) { //output just the error directly to the log if we errored in some important way and we're logging to a file sw.WriteLine(error); } } Output("Extracts files from an SGA archive file, with optional hex-editing"+nl+error+nl+ "SGAEXTRACTOR archive -paths path [path [...]] [-d destination]"+nl+ " [ -find find[ find ...] -replace repl[ repl] ] [-ext extension] "+nl+ " [-mode level] [-log logfile] [--force] [--recursive]"+nl+nl+ "SGAEXTRACTOR archive [destination] [-mode level] [-log logfile] [--force]"+nl+nl+ " archive\tSpecifies the SGA file to extract from"+nl+ " path\t\tSpecifies the file or folder path within the archive"+nl+ " \t\t to extract"+nl+ " destination\tLocation the files will be extracted to. Defaults to the"+nl+ " \t\t location of the archive"+nl+ " find\t\tThe text string that will be found to be replace"+nl+ " repl\t\tThe text string that will replace the found string"+nl+ " extension\tIf a folder is specified in 'path' ext specifies the extension"+nl+ " \t\tof file types to extract"+nl+ " level\tThe level of feedback required: 0 = minimal feedback, "+nl+ " \t\t 1 = failures, 2 = successes, 3 = both (default = 2)"+nl+ " log\t\tSpecifies the path of the log file to write to"+nl+ " --force\tForces an overwrite of the file or files if they exist"+nl+ " --recursive\tIf a folder is specified in 'path', extracts all sub folders", false); } private static void ShowUsage() { Output("Example Usage:"+nl+nl+ " Extract all of the Dawn of War texture archive to its default location:"+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\W40k\\W40KData-SharedTextures-Full.sga\""+nl+nl+ " Extract all of the Dawn of War texture archive to a new location:"+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\W40k\\W40KData-SharedTextures-Full.sga\" -d c:\\texture_temp"+nl+nl+ " Extract all of the Dawn of War RGDs to their default location, overwriting any that already exist:"+nl+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\W40k\\W40kData.sga\" -ext .rgd --force"+nl+nl+ "MORE...", false); Console.ReadLine(); Output(" Extract Chaplain texture from WXP texture archive to its default location:"+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\WXP\\WXPData-SharedTextures-Full.sga\" -paths data\\art\\ebps\\races\\space_marines\\texture_share\\sm_chaplain.rsh"+nl+nl+ " Extract Chaplain RSH and WTP from WXP texture archive to their default locations:"+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\WXP\\WXPData-SharedTextures-Full.sga\" -paths data\\art\\ebps\\races\\space_marines\\texture_share\\sm_chaplain.rsh data\\art\\ebps\\races\\space_marines\\texture_share\\sm_chaplain_default.wtp"+nl+nl+ " Extract Chaplain texture from WXP texture archive, save it to a different filename and hex-edit it for a new race:"+nl+ " SGAEXTRACTOR \"c:\\Program Files\\THQ\\Dawn of War\\WXP\\WXPData-SharedTextures-Full.sga\" -paths data\\art\\ebps\\races\\space_marines\\texture_share\\sm_chaplain.rsh -d \"c:\\program files\\thq\\dawn of war\\temp\\halved_chaplain.rsh\" -find races/space_marines -replace races/halvedmarines", false); } private static void OutputExtractionStatus(string type, string name, string message) { if (message=="") { Output(String.Format("Extraction of {0} \"{1}\" succeeded", type, name)); } else { Output(String.Format("Extraction of {0} \"{1}\" failed: {2}", type, name, message)); } } private static void Output(string str) { Output(str, true); } private static void Output(string str, bool log) { if (sw!=null && log) { sw.WriteLine(str); } Console.WriteLine(str); } } }