diff Program.cs @ 0:8ac8eb805b6c default tip

Initial commit
author Ivo Smits <Ivo@UCIS.nl>
date Fri, 07 Feb 2014 23:23:08 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Program.cs	Fri Feb 07 23:23:08 2014 +0100
@@ -0,0 +1,192 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Windows.Forms;
+
+namespace AutoCRCheck {
+	static class Program {
+		static Boolean DeleteBad = false;
+		static String RenameBadSuffix = null;
+		static Boolean WaitOnCompletion = false;
+		static Boolean PrintMissing = false;
+		static Boolean PrintMismatch = false;
+		static UInt32 DirectoriesChecked = 0;
+		static UInt32 ListsChecked = 0;
+		static UInt32 FilesMissing = 0;
+		static UInt32 FilesBad = 0;
+		static UInt32 FilesGood = 0;
+		[STAThread]
+		static int Main(String[] args) {
+			String rootdirectory = null;
+			Console.Error.WriteLine("UCIS AutoCRCheck (c) 2014 Ivo Smits <Ivo@UCIS.nl>");
+			Console.Error.WriteLine("See http://wiki.ucis.nl/AutoCRCheck for more information");
+			for (int i = 0; i < args.Length; i++) {
+				if (args[i].StartsWith("-")) {
+					switch (args[i].Substring(1)) {
+						case "d":
+						case "delete":
+							DeleteBad = true;
+							break;
+						case "r":
+						case "rename":
+							RenameBadSuffix = args[++i];
+							break;
+						case "w":
+						case "wait":
+							WaitOnCompletion = true;
+							break;
+						case "printmissing":
+							PrintMissing = true;
+							break;
+						case "p":
+						case "printmismatch":
+							PrintMismatch = true;
+							break;
+						case "help":
+						case "h":
+							PrintCommandlineHelp(Console.Out);
+							return -1;
+						default:
+							Console.Error.WriteLine("Error: unknown command line argument: " + args[i]);
+							PrintCommandlineHelp(Console.Error);
+							return -1;
+					}
+				} else {
+					if (rootdirectory != null) {
+						Console.Error.WriteLine("Error: duplicate root directory specified.");
+						return -1;
+					}
+					rootdirectory = args[i];
+				}
+			}
+			if (rootdirectory == null) {
+				Console.Error.WriteLine("Root directory not set, waiting for GUI input...");
+				try {
+					using (new Control()) ;
+				} catch {
+					Console.Error.WriteLine("It looks like you're trying to run this application in a non-GUI session. Luckily we're handling this nearly fatal error for you.");
+					PrintCommandlineHelp(Console.Error);
+					return -1;
+				}
+				using (frmOptions options = new frmOptions()) {
+					DialogResult result = options.ShowDialog();
+					if (result != DialogResult.OK) return -2;
+					rootdirectory = options.RootDirectory;
+					DeleteBad = options.MismatchDelete;
+					RenameBadSuffix = options.MismatchRenameSuffix;
+					WaitOnCompletion = true;
+				}
+
+			}
+			if (!Directory.Exists(rootdirectory)) {
+				Console.Error.WriteLine("Error: root directory not found.");
+				return -1;
+			}
+			rootdirectory = Path.GetFullPath(rootdirectory);
+			ScanDirectory(rootdirectory);
+			String report = String.Format(
+				"{0} directories scanned.\n{1} .SFV files processed\n{2} files were missing\n{3} files had a mismatching checksum, they have been dealt with.\n{4} files are good",
+				DirectoriesChecked, ListsChecked, FilesMissing, FilesBad, FilesGood);
+			Console.Error.WriteLine(report);
+			Console.Error.WriteLine("Done.");
+			if (WaitOnCompletion) {
+				MessageBox.Show("All files have been checked." + Environment.NewLine + report, "UCIS AutoCRCheck", MessageBoxButtons.OK, MessageBoxIcon.Information);
+			}
+			return 0;
+		}
+		static void PrintCommandlineHelp(TextWriter w) {
+			w.WriteLine("UCIS AutoCRCheck recursively checks directories for .SFV files and handles mismatching checksums as instructed.");
+			w.WriteLine("Usage: AutoCRCheck.exe [options] [root directory]");
+			w.WriteLine("Possible options:");
+			w.WriteLine("    -delete            Delete mismatching files");
+			w.WriteLine("    -rename [suffix]   Rename mismatching files, append [suffix] to filename");
+			w.WriteLine("    -printmissing      Print full path of missing files");
+			w.WriteLine("    -printmismatch     Print full path of mismatched files");
+			w.WriteLine("    -wait              Wait for user input when done");
+			w.WriteLine("    -help              Display this message");
+			w.WriteLine();
+			w.WriteLine("Examples:");
+			w.WriteLine("    AutoCRCheck.exe . -rename .badcrc");
+			w.WriteLine("    AutoCRCheck.exe . -printmismatch > badfiles.txt");
+		}
+		static void ScanDirectory(String dir) {
+			DirectoriesChecked++;
+			Console.Error.WriteLine("Directory: {0}", dir);
+			foreach (String sfv in Directory.GetFiles(dir, "*.sfv")) {
+				ListsChecked++;
+				Console.Error.WriteLine("Checksum file: {0}", Path.GetFileName(sfv));
+				using (TextReader reader = File.OpenText(Path.Combine(dir, sfv))) {
+					while (true) {
+						String line = reader.ReadLine();
+						if (line == null) break;
+						if (line.Length == 0 || line[0] == ';') continue;
+						int lastspace = line.LastIndexOf(' ');
+						if (lastspace == -1) continue;
+						String file = line.Substring(0, lastspace).TrimEnd(' ');
+						String cksumstr = line.Substring(lastspace);
+						UInt32 goodcksum;
+						if (!UInt32.TryParse(cksumstr, NumberStyles.HexNumber, null, out goodcksum)) {
+							Console.Error.WriteLine("Failed to decode checksum string: {0}", cksumstr);
+							continue;
+						}
+						String filepath = Path.Combine(dir, file);
+						if (!File.Exists(filepath)) {
+							FilesMissing++;
+							Console.Error.WriteLine("File not found: {0}", file);
+							if (PrintMissing) Console.Out.WriteLine(filepath);
+							continue;
+						}
+						UInt32 realcksum;
+						Console.Error.Write("Checking file: {0}... ", file);
+						using (Stream input = File.OpenRead(filepath)) realcksum = CRCCalculate(input);
+						if (goodcksum != realcksum) {
+							FilesBad++;
+							Console.Error.WriteLine("Mismatch.");
+							if (PrintMismatch) Console.Out.WriteLine(filepath);
+							if (RenameBadSuffix != null) {
+								File.Move(filepath, filepath + RenameBadSuffix);
+							} else if (DeleteBad) {
+								File.Delete(filepath);
+							}
+						} else {
+							FilesGood++;
+							Console.Error.WriteLine("Good.");
+						}
+					}
+				}
+			}
+			foreach (String subdir in Directory.GetDirectories(dir)) {
+				ScanDirectory(Path.Combine(dir, subdir));
+			}
+		}
+		static readonly UInt32[] CRCTable = CRCGenerateTable();
+		static UInt32[] CRCGenerateTable() {
+			UInt32[] table = new UInt32[256];
+			for (UInt32 v = 0; v < 256; v++) {
+				UInt32 e = CRCReflect(v, 8) << 24;
+				for (int i = 0; i < 8; i++) {
+					if ((e & 0x80000000L) == 0) e <<= 1;
+					else e = (e << 1) ^ 0x04C11DB7;
+				}
+				table[v] = CRCReflect(e, 32);
+			}
+			return table;
+		}
+		static UInt32 CRCReflect(UInt32 r, int v) {
+			UInt32 ret = 0;
+			for (int i = 1; i < v + 1; i++, r >>= 1) if ((r & 1) != 0) ret |= 1u << (v - i);
+			return ret;
+		}
+		static uint CRCCalculate(Stream input) {
+			uint c = 0xffffffff;
+			Byte[] buffer = new Byte[Math.Min(1024, input.Length)];
+			while (true) {
+				int n = input.Read(buffer, 0, buffer.Length);
+				if (n <= 0) break;
+				for (int i = 0; i < n; i++) c = CRCTable[(c ^ buffer[i]) & 0xFF] ^ (c >> 8);
+			}
+			return c ^ 0xffffffff;
+		}
+	}
+}