1 /*
2 crc.c
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Sunday, March 5, 1995 6:21:30 PM
22
23 CRC Checksum generation for a file.
24
25 Aug 15, 2000 (Loren Petrich):
26 Using object-oriented file handler
27
28 Nov 6, 2000 (Loren Petrich);
29 Suppressed commented-out FileSpecifier function
30 */
31
32 #include <stdlib.h>
33
34 #include "cseries.h"
35 #include "FileHandler.h"
36 #include "crc.h"
37
38 /* ---------- constants */
39 #define TABLE_SIZE (256)
40 #define CRC32_POLYNOMIAL 0xEDB88320L
41 #define BUFFER_SIZE 1024
42
43 /* ---------- local data */
44 static uint32 *crc_table= NULL;
45
46 /* ---------- local prototypes ------- */
47 static uint32 calculate_file_crc(unsigned char *buffer,
48 short buffer_size, OpenedFile& OFile);
49 static uint32 calculate_buffer_crc(int32 count, uint32 crc, void *buffer);
50 static bool build_crc_table(void);
51 static void free_crc_table(void);
52
53 /* -------------- Entry Point ----------- */
calculate_crc_for_file(FileSpecifier & File)54 uint32 calculate_crc_for_file(FileSpecifier& File)
55 {
56 uint32 crc = 0;
57
58 OpenedFile OFile;
59 if (File.Open(OFile))
60 {
61 crc= calculate_crc_for_opened_file(OFile);
62 OFile.Close();
63 }
64
65 return crc;
66 }
67
calculate_crc_for_opened_file(OpenedFile & OFile)68 uint32 calculate_crc_for_opened_file(OpenedFile& OFile)
69 {
70 uint32 crc = 0;
71 unsigned char *buffer;
72
73 /* Build the crc table */
74 if(build_crc_table())
75 {
76 buffer = new byte[BUFFER_SIZE];
77 if(buffer)
78 {
79 crc= calculate_file_crc(buffer, BUFFER_SIZE, OFile);
80 delete []buffer;
81 }
82
83 /* free the crc table! */
84 free_crc_table();
85 }
86
87 return crc;
88 }
89
90 /* Calculate the crc for a file using the given buffer.. */
calculate_data_crc(unsigned char * buffer,int32 length)91 uint32 calculate_data_crc(
92 unsigned char *buffer,
93 int32 length)
94 {
95 uint32 crc = 0;
96
97 assert(buffer);
98
99 /* Build the crc table */
100 if(build_crc_table())
101 {
102 /* The odd permutions ensure that we get the same crc as for a file */
103 crc = 0xFFFFFFFFL;
104 crc = calculate_buffer_crc(length, crc, buffer);
105 crc ^= 0xFFFFFFFFL;
106
107 /* free the crc table! */
108 free_crc_table();
109 }
110
111 return crc;
112 }
113
114 /* ---------------- Private Code --------------- */
build_crc_table(void)115 static bool build_crc_table(
116 void)
117 {
118 bool success= false;
119
120 assert(!crc_table);
121 crc_table= new uint32[TABLE_SIZE];
122 if(crc_table)
123 {
124 /* Build the table */
125 short index, j;
126 uint32 crc;
127
128 for(index= 0; index<TABLE_SIZE; ++index)
129 {
130 crc= index;
131 for(j=0; j<8; j++)
132 {
133 if(crc & 1) crc=(crc>>1) ^ CRC32_POLYNOMIAL;
134 else crc>>=1;
135 }
136 crc_table[index] = crc;
137 }
138
139 success= true;
140 }
141
142 return success;
143 }
144
free_crc_table(void)145 static void free_crc_table(
146 void)
147 {
148 assert(crc_table);
149 delete []crc_table;
150 crc_table= NULL;
151 }
152
153 /* Calculate for a block of data incrementally */
calculate_buffer_crc(int32 count,uint32 crc,void * buffer)154 static uint32 calculate_buffer_crc(
155 int32 count,
156 uint32 crc,
157 void *buffer)
158 {
159 unsigned char *p;
160 uint32 a;
161 uint32 b;
162
163 p= (unsigned char *) buffer;
164 while (count--)
165 {
166 a= (crc >> 8) & 0x00FFFFFFL;
167 b= crc_table[((int) crc ^ *p++) & 0xff];
168 crc= a^b;
169 }
170 return crc;
171 }
172
173 /* Calculate the crc for a file using the given buffer.. */
calculate_file_crc(unsigned char * buffer,short buffer_size,OpenedFile & OFile)174 static uint32 calculate_file_crc(
175 unsigned char *buffer,
176 short buffer_size,
177 OpenedFile& OFile)
178 {
179 uint32 crc;
180 int32 count;
181 int32 file_length, initial_position;
182
183 /* Save and restore the initial file position */
184 if (!OFile.GetPosition(initial_position))
185 return 0;
186
187 /* Get the file_length */
188 if (!OFile.GetLength(file_length))
189 return 0;
190
191 /* Set to the start of the file */
192 if (!OFile.SetPosition(0))
193 return 0;
194
195 crc = 0xFFFFFFFFL;
196 while(file_length)
197 {
198 if(file_length>buffer_size)
199 {
200 count= buffer_size;
201 } else {
202 count= file_length;
203 }
204
205 if (!OFile.Read(count, buffer))
206 return 0;
207
208 crc = calculate_buffer_crc(count, crc, buffer);
209 file_length -= count;
210 }
211
212 /* Restore the file position */
213 OFile.SetPosition(initial_position);
214
215 return (crc ^= 0xFFFFFFFFL);
216 }
217
218 /* crcccitt.c - a demonstration of look up table based CRC
219 * computation using the non-reversed CCITT_CRC
220 * polynomial 0x1021 (truncated)
221 *
222 * Copyright (C) 2000 Jack Klein
223 * Macmillan Computer Publishing
224 * Adapted for Aleph One, 2006, by Gregory Smith
225 * License: GPL 2 or newer (as above)
226 *
227 * Jack Klein may be contacted by email at:
228 * The_C_Guru@yahoo.com
229 *
230 * ghs: this is from http://home.att.net/~jackklein/C_Unleashed/crcccitt.c
231 */
232
233 static uint16 crc_ccitt_table [256] =
234 {
235 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
236 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
237 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
238 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
239 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
240 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
241 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
242 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
243 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
244 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
245 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
246 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
247 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
248 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
249 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
250 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
251 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
252 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
253 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
254 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
255 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
256 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
257 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
258 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
259 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
260 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
261 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
262 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
263 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
264 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
265 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
266 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
267 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
268 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
269 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
270 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
271 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
272 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
273 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
274 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
275 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
276 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
277 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
278 };
279
calculate_data_crc_ccitt(unsigned char * data,int32 length)280 uint16 calculate_data_crc_ccitt(unsigned char *data, int32 length)
281 {
282 int32 count;
283 uint32 crc = 0xffff;
284 uint32 temp;
285
286 for (count = 0; count < length; ++count)
287 {
288 temp = (*data++ ^ (crc >> 8)) & 0xff;
289 crc = crc_ccitt_table[temp] ^ (crc << 8);
290 }
291 return (uint16)(crc ^ 0);
292 }
293