Current News Archived News Search News Discussion Forum Old Forum Install Programs More Downloads... Troubleshooting Source Code Format Specs. Misc. Information Non-SF Stuff Links Small banner for links to this site: |
a62bc601ddda432770b5d111b11961219a23822b
1 /*
2 Copyright (c) 2002-2013, ShadowFlare <blakflare@hotmail.com>
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
15 THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 SUCH DAMAGE.
26 */
28 #include "CwadLib.h"
29 #include "SFTypes.h"
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #ifndef __SYS_ZLIB
34 #include "zlib/zlib.h"
35 #else
36 #include <zlib.h>
37 #endif
39 const UInt32 ID_CWAD = *(UInt32 *)"CWAD";
40 const UInt32 ID_SEP = *(UInt32 *)"SEP\0";
42 typedef struct _CWADFILEHEADER {
43 UInt32 dwPackedSize;
44 UInt32 dwNameLength;
45 UInt32 dwFullSize;
46 UInt32 dwFlags;
47 // char szFileName[dwNameLength];
48 // UInt8 byData[dwPackedSize];
49 } CWADFILEHEADER;
51 /* struct CWAD {
52 char IDTag[4] = "CWAD";
53 CWADFILEHEADER Files[];
54 }; */
56 typedef struct _CWADFILE CWADFILE;
58 typedef struct _CWADARCHIVE {
59 TCHAR *pszFileName;
60 FILE *pFile;
61 unsigned long nStart;
62 unsigned long nEnd;
63 unsigned long nFiles;
64 CWADFILE *pFiles;
65 char *pmszFileList;
66 unsigned long nFileListSize;
67 bool bHasFileNameBlank;
68 long nReferences;
69 bool bOpen;
70 } CWADARCHIVE;
72 typedef struct _CWADFILE {
73 char *pszFileName;
74 CWADARCHIVE *pParentArc;
75 UInt32 dwPackedSize;
76 UInt32 dwFullSize;
77 UInt32 dwFlags;
78 unsigned long nOffset;
79 UInt8 *pBuffer;
80 long nReferences;
81 } CWADFILE;
83 typedef struct _CWADFILEHANDLE {
84 CWADFILE *f;
85 UInt32 dwFilePointer;
86 } CWADFILEHANDLE;
88 void CWadListFilesInternal(void *hCWAD);
89 unsigned long CWadFindHeaderAndSize(FILE *hFile, unsigned long *pnCwadEnd);
90 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength);
92 void * CWadOpenArchive(const TCHAR *pszFileName)
93 {
94 if (!pszFileName)
95 return 0;
97 unsigned long flen;
98 FILE *pFile;
99 pFile = _tfopen(pszFileName, _T("rb"));
100 if (pFile)
101 {
102 unsigned long nCwadStart = CWadFindHeaderAndSize(pFile, &flen);
103 if (nCwadStart != -1) {
104 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)malloc(sizeof(CWADARCHIVE));
105 if (cOpenArc) {
106 cOpenArc->pFile = pFile;
107 cOpenArc->nStart = nCwadStart;
108 cOpenArc->nEnd = flen;
109 cOpenArc->pmszFileList = 0;
110 cOpenArc->bHasFileNameBlank = false;
111 cOpenArc->pFiles = 0;
112 CWadListFilesInternal(cOpenArc);
113 if (cOpenArc->pmszFileList) {
114 cOpenArc->pszFileName = _tcsdup(pszFileName);
115 cOpenArc->nReferences = 0;
116 cOpenArc->bOpen = true;
117 return cOpenArc;
118 }
120 free(cOpenArc);
121 }
122 }
124 fclose(pFile);
125 }
127 return 0;
128 }
130 bool CWadCloseArchive(void *hCWAD)
131 {
132 if (!hCWAD)
133 return false;
135 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
136 if (cOpenArc->nReferences > 0) {
137 cOpenArc->bOpen = false;
138 return false;
139 }
140 fclose(cOpenArc->pFile);
141 if (cOpenArc->pFiles) free(cOpenArc->pFiles);
142 if (cOpenArc->pmszFileList) free(cOpenArc->pmszFileList);
143 if (cOpenArc->pszFileName) free(cOpenArc->pszFileName);
144 free(cOpenArc);
145 return true;
146 }
148 unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
149 {
150 if (!hCWAD)
151 return -1;
153 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
154 switch (nInfoType) {
155 case CWAD_INFO_NUM_FILES:
156 return cOpenArc->nFiles;
157 case CWAD_INFO_SIZE:
158 return cOpenArc->nEnd - cOpenArc->nStart;
159 default:
160 return -1;
161 }
162 }
164 unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
165 {
166 if (!hCWAD)
167 return 0;
169 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
170 if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
171 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
173 return cOpenArc->nFileListSize;
174 }
176 void CWadListFilesInternal(void *hCWAD)
177 {
178 if (!hCWAD)
179 return;
181 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
182 CWADFILEHEADER CwadFile;
183 unsigned long nReqSize = 0;
184 cOpenArc->nFiles = 0;
185 if (cOpenArc->bHasFileNameBlank && cOpenArc->pmszFileList) {
186 *cOpenArc->pmszFileList = 0;
187 nReqSize++;
188 }
189 fseek(cOpenArc->pFile, cOpenArc->nStart + 4, SEEK_SET);
190 for (long fpos = ftell(cOpenArc->pFile); fpos != -1 && fpos + sizeof(CWADFILEHEADER) <= cOpenArc->nEnd; fpos = ftell(cOpenArc->pFile)) {
191 if (fread(&CwadFile, sizeof(CWADFILEHEADER), 1, cOpenArc->pFile) == 1) {
192 if (cOpenArc->pmszFileList)
193 {
194 if (CwadFile.dwNameLength > 0) {
195 if (fread(cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength, 1, cOpenArc->pFile) == 1)
196 CWadDecryptData((UInt8 *)cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength);
197 cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList + nReqSize;
198 }
199 else
200 cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList;
201 cOpenArc->pFiles[cOpenArc->nFiles].pParentArc = cOpenArc;
202 cOpenArc->pFiles[cOpenArc->nFiles].dwPackedSize = CwadFile.dwPackedSize;
203 cOpenArc->pFiles[cOpenArc->nFiles].dwFullSize = CwadFile.dwFullSize;
204 cOpenArc->pFiles[cOpenArc->nFiles].dwFlags = CwadFile.dwFlags;
205 cOpenArc->pFiles[cOpenArc->nFiles].nOffset = fpos + sizeof(CWADFILEHEADER) + CwadFile.dwNameLength;
206 cOpenArc->pFiles[cOpenArc->nFiles].pBuffer = 0;
207 cOpenArc->pFiles[cOpenArc->nFiles].nReferences = 0;
208 }
209 else {
210 fseek(cOpenArc->pFile, CwadFile.dwNameLength, SEEK_CUR);
211 }
212 nReqSize += CwadFile.dwNameLength;
213 if (CwadFile.dwNameLength > 0) {
214 if (cOpenArc->pmszFileList)
215 cOpenArc->pmszFileList[nReqSize] = 0;
216 nReqSize++;
217 }
218 else if (!cOpenArc->bHasFileNameBlank) {
219 cOpenArc->bHasFileNameBlank = true;
220 nReqSize++;
221 }
222 fseek(cOpenArc->pFile, CwadFile.dwPackedSize, SEEK_CUR);
223 cOpenArc->nFiles++;
224 }
225 else break;
226 }
227 if (cOpenArc->pmszFileList)
228 cOpenArc->pmszFileList[nReqSize] = 0;
229 nReqSize++;
230 if (nReqSize == 1)
231 {
232 if (cOpenArc->pmszFileList)
233 cOpenArc->pmszFileList[nReqSize] = 0;
234 nReqSize++;
235 }
236 if (!cOpenArc->pmszFileList) {
237 cOpenArc->pmszFileList = (char *)malloc(nReqSize);
238 cOpenArc->nFileListSize = nReqSize;
239 if (cOpenArc->nFiles > 0)
240 cOpenArc->pFiles = (CWADFILE *)calloc(cOpenArc->nFiles, sizeof(CWADFILE));
241 if (cOpenArc->pmszFileList && (cOpenArc->pFiles || cOpenArc->nFiles == 0))
242 CWadListFilesInternal(hCWAD);
243 else {
244 if (cOpenArc->pmszFileList) {
245 free(cOpenArc->pmszFileList);
246 cOpenArc->pmszFileList = 0;
247 }
248 if (cOpenArc->pFiles)
249 free(cOpenArc->pFiles);
250 }
251 }
252 }
254 void * CWadOpenFile(void *hCWAD, const char *pszFileName)
255 {
256 if (!hCWAD || !pszFileName)
257 return 0;
259 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
260 unsigned long nFile;
261 for (nFile = 0; nFile < cOpenArc->nFiles; nFile++) {
262 if (strcmp(pszFileName, cOpenArc->pFiles[nFile].pszFileName) == 0) {
263 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)malloc(sizeof(CWADFILEHANDLE));
264 if (cOpenFile) {
265 cOpenFile->f = &cOpenArc->pFiles[nFile];
266 cOpenFile->dwFilePointer = 0;
267 cOpenFile->f->nReferences++;
268 cOpenArc->nReferences++;
269 return cOpenFile;
270 }
271 }
272 }
274 return 0;
275 }
277 bool CWadCloseFile(void *hFile)
278 {
279 if (!hFile)
280 return false;
282 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
283 cOpenFile->f->nReferences--;
284 cOpenFile->f->pParentArc->nReferences--;
285 if (cOpenFile->f->nReferences < 1 && cOpenFile->f->pBuffer) {
286 free(cOpenFile->f->pBuffer);
287 cOpenFile->f->pBuffer = 0;
288 }
289 if (cOpenFile->f->pParentArc->nReferences < 1 && !cOpenFile->f->pParentArc->bOpen)
290 CWadCloseArchive(cOpenFile->f->pParentArc);
291 free(cOpenFile);
293 return true;
294 }
296 unsigned long CWadGetFileSize(void *hFile)
297 {
298 if (!hFile)
299 return -1;
301 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
302 return cOpenFile->f->dwFullSize;
303 }
305 unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
306 {
307 if (!hFile)
308 return -1;
310 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
311 switch (nInfoType) {
312 case CWAD_INFO_NUM_FILES:
313 return cOpenFile->f->pParentArc->nFiles;
314 case CWAD_INFO_SIZE:
315 return cOpenFile->f->dwFullSize;
316 case CWAD_INFO_COMPRESSED_SIZE:
317 return cOpenFile->f->dwPackedSize;
318 case CWAD_INFO_FLAGS:
319 return cOpenFile->f->dwFlags;
320 case CWAD_INFO_PARENT:
321 return (unsigned long)cOpenFile->f->pParentArc;
322 case CWAD_INFO_POSITION:
323 return cOpenFile->dwFilePointer;
324 default:
325 return -1;
326 }
327 }
329 unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
330 {
331 if (!hFile)
332 return -1;
334 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
335 long fsz = cOpenFile->f->dwFullSize;
336 long cpos = cOpenFile->dwFilePointer;
337 switch (nMoveMethod) {
338 case CWAD_FILE_CURRENT:
339 if (cpos + nDistanceToMove < 0 || cpos + nDistanceToMove > fsz) return -1;
340 cOpenFile->dwFilePointer += nDistanceToMove;
341 break;
342 case CWAD_FILE_END:
343 if (fsz + nDistanceToMove < 0 || nDistanceToMove > 0) return -1;
344 cOpenFile->dwFilePointer = fsz + nDistanceToMove;
345 break;
346 case CWAD_FILE_BEGIN:
347 default:
348 if (nDistanceToMove < 0 || nDistanceToMove > fsz) return -1;
349 cOpenFile->dwFilePointer = nDistanceToMove;
350 }
352 return cOpenFile->dwFilePointer;
353 }
355 unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
356 {
357 if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
358 return 0;
360 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
361 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)cOpenFile->f->pParentArc;
362 if (cOpenFile->dwFilePointer >= cOpenFile->f->dwFullSize)
363 return 0;
364 if (cOpenFile->dwFilePointer + nNumberOfBytesToRead > cOpenFile->f->dwFullSize)
365 nNumberOfBytesToRead = cOpenFile->f->dwFullSize - cOpenFile->dwFilePointer;
366 unsigned long nBytesRead = nNumberOfBytesToRead;
367 if (cOpenFile->f->dwFlags & 1) {
368 if (!cOpenFile->f->pBuffer) {
369 cOpenFile->f->pBuffer = (UInt8 *)malloc(cOpenFile->f->dwFullSize);
370 UInt8 *compbuffer = (UInt8 *)malloc(cOpenFile->f->dwPackedSize);
371 bool bReadOK = false;
372 if (cOpenFile->f->pBuffer && compbuffer) {
373 fseek(cOpenArc->pFile, cOpenFile->f->nOffset, SEEK_SET);
374 if (fread(compbuffer, 1, cOpenFile->f->dwPackedSize, cOpenArc->pFile) == cOpenFile->f->dwPackedSize)
375 if (uncompress(cOpenFile->f->pBuffer, &nBytesRead, compbuffer, cOpenFile->f->dwPackedSize) == Z_OK)
376 bReadOK = true;
377 }
378 if (!bReadOK && cOpenFile->f->pBuffer) {
379 free(cOpenFile->f->pBuffer);
380 cOpenFile->f->pBuffer = 0;
381 nBytesRead = 0;
382 }
383 if (compbuffer)
384 free(compbuffer);
385 }
386 if (cOpenFile->f->pBuffer)
387 memcpy(pBuffer, cOpenFile->f->pBuffer + cOpenFile->dwFilePointer, nNumberOfBytesToRead);
388 }
389 else {
390 fseek(cOpenArc->pFile, cOpenFile->f->nOffset + cOpenFile->dwFilePointer, SEEK_SET);
391 nBytesRead = fread(pBuffer, 1, nNumberOfBytesToRead, cOpenArc->pFile);
392 }
394 cOpenFile->dwFilePointer += nBytesRead;
395 return nBytesRead;
396 }
398 unsigned long CWadFindHeader(FILE *hFile)
399 {
400 return CWadFindHeaderAndSize(hFile, 0);
401 }
403 unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
404 {
405 if (!pFile) return -1;
407 if (fseek(pFile, 0, SEEK_END)) return -1;
408 long fsz = ftell(pFile);
409 UInt32 buffer[2];
410 long sep, i, offset;
412 if (pnCwadEnd) *pnCwadEnd = fsz;
414 fseek(pFile, 0, SEEK_SET);
415 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
416 if (buffer[0] == ID_CWAD)
417 return 0;
419 if (fsz < 12)
420 return -1;
422 if (pnCwadEnd) *pnCwadEnd = fsz - 8;
424 fseek(pFile, -8, SEEK_END);
425 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
426 if (buffer[0] == ID_CWAD) {
427 fseek(pFile, buffer[1], SEEK_SET);
428 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
429 if (buffer[0] == ID_CWAD)
430 return buffer[1];
431 }
433 if (fsz < 132)
434 return -1;
436 for (sep = fsz - 12; sep >= fsz - 132; sep -= 8) {
437 fseek(pFile, sep, SEEK_SET);
438 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
440 if (buffer[0] == ID_SEP) {
441 for (i = sep + 4; i < fsz; i += 8) {
442 fseek(pFile, i, SEEK_SET);
443 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
445 offset = buffer[0];
446 if (pnCwadEnd) *pnCwadEnd = offset + buffer[1] - 8;
447 fseek(pFile, offset + buffer[1] - 8, SEEK_SET);
448 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
449 if (buffer[0] == ID_CWAD) {
450 fseek(pFile, offset + buffer[1], SEEK_SET);
451 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
452 if (buffer[0] == ID_CWAD)
453 return offset + buffer[1];
454 }
455 }
457 break;
458 }
459 }
461 return -1;
462 }
464 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
465 {
466 if (!pBuffer || nBufferLength == 0) return;
467 pBuffer += nBufferLength - 1;
468 UInt8 byCWadKey;
469 byCWadKey = (UInt8)(66 - (nBufferLength << 1));
470 for (unsigned long i = 0; i < nBufferLength; i++) {
471 pBuffer[0] ^= (UInt8)(byCWadKey + (i << 1));
472 pBuffer--;
473 }
474 }
|