view 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 source

???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;
		}
	}
}