Mercurial > hg > AutoCRCheck
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; + } + } +}