diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Class1.cs	Sat Oct 06 20:29:36 2018 +0100
@@ -0,0 +1,776 @@
+// 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);
+		}
+	}
+}