-
Notifications
You must be signed in to change notification settings - Fork 6
/
CRC_32.cpp
343 lines (301 loc) · 11.9 KB
/
CRC_32.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/****************************************************************************
CRC_32.cpp : implementation file for the CRC_32 class
written by PJ Arends
pja@telus.net
based on the CRC-32 code found at
http://www.createwindow.com/programming/crc32/crcfile.htm
For updates check http://www3.telus.net/pja/crc32.htm
-----------------------------------------------------------------------------
This code is provided as is, with no warranty as to it's suitability or usefulness
in any application in which it may be used. This code has not been tested for
UNICODE builds, nor has it been tested on a network ( with UNC paths ).
This code may be used in any way you desire. This file may be redistributed by any
means as long as it is not sold for profit, and providing that this notice and the
authors name are included.
If any bugs are found and fixed, a note to the author explaining the problem and
fix would be nice.
-----------------------------------------------------------------------------
created : October 2001
Revision History:
October 11, 2001 - changed SendMessage to PostMessage in CRC32ThreadProc
****************************************************************************/
#include "CRC_32.h"
#include <io.h> // _close(), _read()
#include <fcntl.h> // _O_* flags
#include <share.h> // _SH_DENYWR
#include <tchar.h> // UNICODE compatibility
#include <commctrl.h> // PBM_* progress bar messages
// use a 100 KB buffer (a larger buffer does not seem to run
// significantly faster, but takes more RAM)
#define BUFFERSIZE 102400
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32::CRC32ThreadProc (static private member function)
// Calculates the CRC-32 value for a file or data buffer.
//
// Parameters :
// lpVoid [in] : A pointer to a CRCStruct structure, type casted as a void pointer
//
// Returns :
// The CRC-32 value of the supplied buffer or file
//
// Note :
// If this function is started as a thread, it will send PBM_* messages to the supplied
// progress bar control. When the thread is finished, this function will send a
// WM_CRC_THREAD_DONE message to the parent window of the progress bar. the WPARAM parameter
// will contain the HANDLE of the thread, and the LPARAM will contain the CRC-32 value
// of the supplied buffer or file.
//
/////////////////////////////////////////////////////////////////////////////
DWORD WINAPI CRC_32::CRC32ThreadProc(LPVOID lpVoid)
{
LPCRCStruct pCRCSt = (LPCRCStruct)lpVoid;
ULONG CRC = 0xFFFFFFFF;
HWND Progress = NULL;
if (::IsWindow(pCRCSt->hWnd))
{ // setup the progress bar
Progress = pCRCSt->hWnd;
::PostMessage(Progress, PBM_SETPOS, 0, 0);
::PostMessage(Progress, PBM_SETRANGE32, 0, 100);
}
if (pCRCSt->pByte)
{ // calculate CRC for a buffer
for (UINT offset = 0; offset < pCRCSt->size; offset += BUFFERSIZE)
{
pCRCSt->pCRC_32->Calculate(pCRCSt->pByte + offset,
(pCRCSt->size - offset > BUFFERSIZE) ? BUFFERSIZE : (pCRCSt->size - offset),
CRC);
if(::IsWindow(Progress))
{
int percent = offset > pCRCSt->size ? 100 : (int)(((double)offset / (double)pCRCSt->size) * 100);
::PostMessage(Progress, PBM_SETPOS, percent, 0);
}
}
}
else if (pCRCSt->FileName)
{ // calculate CRC for a file
LONGLONG done = 0;
UINT size = BUFFERSIZE;
BYTE buffer[BUFFERSIZE];
// Open the file
int theFile = _tsopen(pCRCSt->FileName, _O_RDONLY | _O_SEQUENTIAL | _O_BINARY, _SH_DENYWR);
if (theFile != -1)
{ // Get the file size
_lseeki64(theFile, 0L, SEEK_SET);
LONGLONG length = _lseeki64(theFile, 0L, SEEK_END);
_lseeki64(theFile, 0L, SEEK_SET);
// process the file
while (size == BUFFERSIZE)
{
size = _read(theFile, buffer, BUFFERSIZE);
if (size)
{
pCRCSt->pCRC_32->Calculate(buffer, size, CRC);
if (::IsWindow(Progress))
{ // update the progress bar
done += size;
int percent = (int)(((long double)done / (long double)length) * 100);
::PostMessage(Progress, PBM_SETPOS, percent, 0);
}
}
}
_close(theFile);
}
}
CRC ^= 0xFFFFFFFF;
if(IsWindow(Progress))
// notify dialog that we are done
::PostMessage(::GetParent(Progress), WM_CRC_THREAD_DONE, (WPARAM)pCRCSt->Thread, CRC);
// clean up
// Known Problem : If the thread is prematurely terminated,
// this cleanup code is never run, resulting in a memory leak.
delete pCRCSt->pByte;
delete pCRCSt;
// return our CRC-32 value
return CRC;
}
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32 constructor (public member function)
// Sets up the CRC-32 reference table
//
// Parameters :
// None
//
// Returns :
// Nothing
//
/////////////////////////////////////////////////////////////////////////////
CRC_32::CRC_32()
{
// This is the official polynomial used by CRC-32
// in PKZip, WinZip and Ethernet.
ULONG ulPolynomial = 0x04C11DB7;
// 256 values representing ASCII character codes.
for (int i = 0; i <= 0xFF; i++)
{
Table[i] = Reflect(i, 8) << 24;
for (int j = 0; j < 8; j++)
Table[i] = (Table[i] << 1) ^ (Table[i] & (1 << 31) ? ulPolynomial : 0);
Table[i] = Reflect(Table[i], 32);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32::Reflect (private member function)
// used by the constructor to help set up the CRC-32 reference table
//
// Parameters :
// ref [in] : the value to be reflected
// ch [in] : the number of bits to move
//
// Returns :
// the new value
//
/////////////////////////////////////////////////////////////////////////////
ULONG CRC_32::Reflect(ULONG ref, char ch)
{
ULONG value = 0;
// Swap bit 0 for bit 7
// bit 1 for bit 6, etc.
for(int i = 1; i < (ch + 1); i++)
{
if (ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32::Calculate (private member function)
// Calculates the CRC-32 value for the given buffer
//
// Parameters :
// buffer [in] : pointer to the data bytes
// size [in] : the size of the buffer
// CRC [in] : the initial CRC-32 value
// [out] : the new CRC-32 value
//
// Returns :
// Nothing
//
/////////////////////////////////////////////////////////////////////////////
void CRC_32::Calculate(const LPBYTE buffer, UINT size, ULONG &CRC)
{ // calculate the CRC
LPBYTE pbyte = buffer;
while (size--)
CRC = (CRC >> 8) ^ Table[(CRC & 0xFF) ^ *pbyte++];
}
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32::CalcCRC (public member function)
// calculates the CRC-32 value for the given buffer
//
// Parameters :
// buffer [in] : a pointer to the data bytes
// size [in] : the size of the buffer
// ProgressWnd [in] : the HWND of the progress bar
//
// Returns :
// if ProgressWnd is not a window returns the CRC-32 value of the buffer
// if ProgressWnd is a window, returns the HANDLE of the created thread
// returns NULL if an error occurs
//
// Note :
// ProgressWnd is passed through the IsWindow() API function. If IsWindow()
// returns zero, CalcCRC() will calculate the CRC-32 value directly. if IsWindow()
// returns nonzero, CalcCRC() will start a seperate thread. The thread will send
// PBM_* progress bar messages to the ProgressWnd. When the thread is finished,
// the thread will send a WM_CRC_THREAD_DONE message to the parent window of the
// ProgressWnd. the WPARAM parameter will contain the HANDLE of the thread, and
// the LPARAM will contain the CRC-32 value of the buffer.
//
/////////////////////////////////////////////////////////////////////////////
DWORD CRC_32::CalcCRC(LPVOID buffer, UINT size, HWND ProgressWnd/*= NULL*/)
{ // check the validity of the data
if (!buffer || !size)
return 0;
if (!IsWindow(ProgressWnd))
{ // calculate CRC directly
DWORD CRC = 0xFFFFFFFF;
Calculate ((LPBYTE)buffer, size, CRC);
return CRC ^ 0xFFFFFFFF;
}
// start the thread
LPCRCStruct pCRCSt = new CRCStruct();
DWORD ThreadID;
HANDLE Handle = ::CreateThread(NULL, 0, CRC32ThreadProc, (LPVOID)pCRCSt, CREATE_SUSPENDED, &ThreadID);
if (Handle)
{ // thread successfully created
pCRCSt->pCRC_32 = this;
pCRCSt->FileName[0] = 0;
pCRCSt->pByte = new BYTE[size];
memcpy(pCRCSt->pByte, buffer, size);
pCRCSt->size = size;
pCRCSt->hWnd = ProgressWnd;
pCRCSt->Thread = Handle;
::ResumeThread(Handle);
}
else // thread creation failed, clean up
delete pCRCSt;
return (DWORD)Handle;
}
/////////////////////////////////////////////////////////////////////////////
//
// CRC_32::CalcCRC (public member function)
// calculates the CRC-32 value for the given buffer
//
// Parameters :
// FileName [in] : the complete path to the file
// ProgressWnd [in] : the HWND of the progress bar
//
// Returns :
// if ProgressWnd is not a window returns the CRC-32 value of the file
// if ProgressWnd is a window, returns the HANDLE of the created thread
// returns NULL if an error occurs
//
// Note :
// ProgressWnd is passed through the IsWindow() API function. If IsWindow()
// returns zero, CalcCRC() will calculate the CRC-32 value directly. if IsWindow()
// returns nonzero, CalcCRC() will start a seperate thread. The thread will send
// PBM_* progress bar messages to the ProgressWnd. When the thread is finished,
// the thread will send a WM_CRC_THREAD_DONE message to the parent window of the
// ProgressWnd. the WPARAM parameter will contain the HANDLE of the thread, and
// the LPARAM will contain the CRC-32 value of the file.
//
/////////////////////////////////////////////////////////////////////////////
DWORD CRC_32::CalcCRC(LPCTSTR FileName, HWND ProgressWnd/*= NULL*/)
{ // make sure the file exists and is not a directory
DWORD attrib = ::GetFileAttributes(FileName);
if (attrib == 0xFFFFFFFF || attrib & FILE_ATTRIBUTE_DIRECTORY)
return 0;
// setup the CRCStruct
LPCRCStruct pCRCSt = new CRCStruct();
pCRCSt->pCRC_32 = this;
_tcsncpy(pCRCSt->FileName, FileName, _MAX_PATH);
pCRCSt->pByte = NULL;
pCRCSt->size = 0;
pCRCSt->hWnd = ProgressWnd;
pCRCSt->Thread = NULL;
if (!IsWindow(ProgressWnd))
{ // calculate CRC directly
return CRC32ThreadProc((LPVOID)pCRCSt);
}
// start the thread
DWORD ThreadID;
HANDLE Handle = ::CreateThread(NULL, 0, CRC32ThreadProc, (LPVOID)pCRCSt, CREATE_SUSPENDED, &ThreadID);
if (Handle)
{ // thread successfully created
pCRCSt->Thread = Handle;
::ResumeThread(Handle);
}
else // thread creation failed, clean up
delete pCRCSt;
return (DWORD)Handle;
}
/////////////////////////////////////////////////////////////////////////////
//
// End of CRC_32.cpp
//
/////////////////////////////////////////////////////////////////////////////