Mercurial > hg > AutoCRCheck
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8ac8eb805b6c |
---|---|
1 using System; | |
2 using System.Diagnostics; | |
3 using System.Globalization; | |
4 using System.IO; | |
5 using System.Windows.Forms; | |
6 | |
7 namespace AutoCRCheck { | |
8 static class Program { | |
9 static Boolean DeleteBad = false; | |
10 static String RenameBadSuffix = null; | |
11 static Boolean WaitOnCompletion = false; | |
12 static Boolean PrintMissing = false; | |
13 static Boolean PrintMismatch = false; | |
14 static UInt32 DirectoriesChecked = 0; | |
15 static UInt32 ListsChecked = 0; | |
16 static UInt32 FilesMissing = 0; | |
17 static UInt32 FilesBad = 0; | |
18 static UInt32 FilesGood = 0; | |
19 [STAThread] | |
20 static int Main(String[] args) { | |
21 String rootdirectory = null; | |
22 Console.Error.WriteLine("UCIS AutoCRCheck (c) 2014 Ivo Smits <Ivo@UCIS.nl>"); | |
23 Console.Error.WriteLine("See http://wiki.ucis.nl/AutoCRCheck for more information"); | |
24 for (int i = 0; i < args.Length; i++) { | |
25 if (args[i].StartsWith("-")) { | |
26 switch (args[i].Substring(1)) { | |
27 case "d": | |
28 case "delete": | |
29 DeleteBad = true; | |
30 break; | |
31 case "r": | |
32 case "rename": | |
33 RenameBadSuffix = args[++i]; | |
34 break; | |
35 case "w": | |
36 case "wait": | |
37 WaitOnCompletion = true; | |
38 break; | |
39 case "printmissing": | |
40 PrintMissing = true; | |
41 break; | |
42 case "p": | |
43 case "printmismatch": | |
44 PrintMismatch = true; | |
45 break; | |
46 case "help": | |
47 case "h": | |
48 PrintCommandlineHelp(Console.Out); | |
49 return -1; | |
50 default: | |
51 Console.Error.WriteLine("Error: unknown command line argument: " + args[i]); | |
52 PrintCommandlineHelp(Console.Error); | |
53 return -1; | |
54 } | |
55 } else { | |
56 if (rootdirectory != null) { | |
57 Console.Error.WriteLine("Error: duplicate root directory specified."); | |
58 return -1; | |
59 } | |
60 rootdirectory = args[i]; | |
61 } | |
62 } | |
63 if (rootdirectory == null) { | |
64 Console.Error.WriteLine("Root directory not set, waiting for GUI input..."); | |
65 try { | |
66 using (new Control()) ; | |
67 } catch { | |
68 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."); | |
69 PrintCommandlineHelp(Console.Error); | |
70 return -1; | |
71 } | |
72 using (frmOptions options = new frmOptions()) { | |
73 DialogResult result = options.ShowDialog(); | |
74 if (result != DialogResult.OK) return -2; | |
75 rootdirectory = options.RootDirectory; | |
76 DeleteBad = options.MismatchDelete; | |
77 RenameBadSuffix = options.MismatchRenameSuffix; | |
78 WaitOnCompletion = true; | |
79 } | |
80 | |
81 } | |
82 if (!Directory.Exists(rootdirectory)) { | |
83 Console.Error.WriteLine("Error: root directory not found."); | |
84 return -1; | |
85 } | |
86 rootdirectory = Path.GetFullPath(rootdirectory); | |
87 ScanDirectory(rootdirectory); | |
88 String report = String.Format( | |
89 "{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", | |
90 DirectoriesChecked, ListsChecked, FilesMissing, FilesBad, FilesGood); | |
91 Console.Error.WriteLine(report); | |
92 Console.Error.WriteLine("Done."); | |
93 if (WaitOnCompletion) { | |
94 MessageBox.Show("All files have been checked." + Environment.NewLine + report, "UCIS AutoCRCheck", MessageBoxButtons.OK, MessageBoxIcon.Information); | |
95 } | |
96 return 0; | |
97 } | |
98 static void PrintCommandlineHelp(TextWriter w) { | |
99 w.WriteLine("UCIS AutoCRCheck recursively checks directories for .SFV files and handles mismatching checksums as instructed."); | |
100 w.WriteLine("Usage: AutoCRCheck.exe [options] [root directory]"); | |
101 w.WriteLine("Possible options:"); | |
102 w.WriteLine(" -delete Delete mismatching files"); | |
103 w.WriteLine(" -rename [suffix] Rename mismatching files, append [suffix] to filename"); | |
104 w.WriteLine(" -printmissing Print full path of missing files"); | |
105 w.WriteLine(" -printmismatch Print full path of mismatched files"); | |
106 w.WriteLine(" -wait Wait for user input when done"); | |
107 w.WriteLine(" -help Display this message"); | |
108 w.WriteLine(); | |
109 w.WriteLine("Examples:"); | |
110 w.WriteLine(" AutoCRCheck.exe . -rename .badcrc"); | |
111 w.WriteLine(" AutoCRCheck.exe . -printmismatch > badfiles.txt"); | |
112 } | |
113 static void ScanDirectory(String dir) { | |
114 DirectoriesChecked++; | |
115 Console.Error.WriteLine("Directory: {0}", dir); | |
116 foreach (String sfv in Directory.GetFiles(dir, "*.sfv")) { | |
117 ListsChecked++; | |
118 Console.Error.WriteLine("Checksum file: {0}", Path.GetFileName(sfv)); | |
119 using (TextReader reader = File.OpenText(Path.Combine(dir, sfv))) { | |
120 while (true) { | |
121 String line = reader.ReadLine(); | |
122 if (line == null) break; | |
123 if (line.Length == 0 || line[0] == ';') continue; | |
124 int lastspace = line.LastIndexOf(' '); | |
125 if (lastspace == -1) continue; | |
126 String file = line.Substring(0, lastspace).TrimEnd(' '); | |
127 String cksumstr = line.Substring(lastspace); | |
128 UInt32 goodcksum; | |
129 if (!UInt32.TryParse(cksumstr, NumberStyles.HexNumber, null, out goodcksum)) { | |
130 Console.Error.WriteLine("Failed to decode checksum string: {0}", cksumstr); | |
131 continue; | |
132 } | |
133 String filepath = Path.Combine(dir, file); | |
134 if (!File.Exists(filepath)) { | |
135 FilesMissing++; | |
136 Console.Error.WriteLine("File not found: {0}", file); | |
137 if (PrintMissing) Console.Out.WriteLine(filepath); | |
138 continue; | |
139 } | |
140 UInt32 realcksum; | |
141 Console.Error.Write("Checking file: {0}... ", file); | |
142 using (Stream input = File.OpenRead(filepath)) realcksum = CRCCalculate(input); | |
143 if (goodcksum != realcksum) { | |
144 FilesBad++; | |
145 Console.Error.WriteLine("Mismatch."); | |
146 if (PrintMismatch) Console.Out.WriteLine(filepath); | |
147 if (RenameBadSuffix != null) { | |
148 File.Move(filepath, filepath + RenameBadSuffix); | |
149 } else if (DeleteBad) { | |
150 File.Delete(filepath); | |
151 } | |
152 } else { | |
153 FilesGood++; | |
154 Console.Error.WriteLine("Good."); | |
155 } | |
156 } | |
157 } | |
158 } | |
159 foreach (String subdir in Directory.GetDirectories(dir)) { | |
160 ScanDirectory(Path.Combine(dir, subdir)); | |
161 } | |
162 } | |
163 static readonly UInt32[] CRCTable = CRCGenerateTable(); | |
164 static UInt32[] CRCGenerateTable() { | |
165 UInt32[] table = new UInt32[256]; | |
166 for (UInt32 v = 0; v < 256; v++) { | |
167 UInt32 e = CRCReflect(v, 8) << 24; | |
168 for (int i = 0; i < 8; i++) { | |
169 if ((e & 0x80000000L) == 0) e <<= 1; | |
170 else e = (e << 1) ^ 0x04C11DB7; | |
171 } | |
172 table[v] = CRCReflect(e, 32); | |
173 } | |
174 return table; | |
175 } | |
176 static UInt32 CRCReflect(UInt32 r, int v) { | |
177 UInt32 ret = 0; | |
178 for (int i = 1; i < v + 1; i++, r >>= 1) if ((r & 1) != 0) ret |= 1u << (v - i); | |
179 return ret; | |
180 } | |
181 static uint CRCCalculate(Stream input) { | |
182 uint c = 0xffffffff; | |
183 Byte[] buffer = new Byte[Math.Min(1024, input.Length)]; | |
184 while (true) { | |
185 int n = input.Read(buffer, 0, buffer.Length); | |
186 if (n <= 0) break; | |
187 for (int i = 0; i < n; i++) c = CRCTable[(c ^ buffer[i]) & 0xFF] ^ (c >> 8); | |
188 } | |
189 return c ^ 0xffffffff; | |
190 } | |
191 } | |
192 } |