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




CommitLineData
c3242ac4 1/*
2 Copyright (c) 2002-2013, ShadowFlare <blakflare@hotmail.com>
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
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.
14
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*/
27
cfca19c6 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
38
39const UInt32 ID_CWAD = *(UInt32 *)"CWAD";
40const UInt32 ID_SEP = *(UInt32 *)"SEP\0";
41
42typedef struct _CWADFILEHEADER {
43 UInt32 dwPackedSize;
44 UInt32 dwNameLength;
45 UInt32 dwFullSize;
46 UInt32 dwFlags;
47// char szFileName[dwNameLength];
48// UInt8 byData[dwPackedSize];
49} CWADFILEHEADER;
50
51/* struct CWAD {
52 char IDTag[4] = "CWAD";
53 CWADFILEHEADER Files[];
54}; */
55
56typedef struct _CWADFILE CWADFILE;
57
58typedef 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;
71
72typedef 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;
82
83typedef struct _CWADFILEHANDLE {
84 CWADFILE *f;
85 UInt32 dwFilePointer;
86} CWADFILEHANDLE;
87
88void CWadListFilesInternal(void *hCWAD);
89unsigned long CWadFindHeaderAndSize(FILE *hFile, unsigned long *pnCwadEnd);
90void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength);
91
92void * CWadOpenArchive(const TCHAR *pszFileName)
93{
94 if (!pszFileName)
95 return 0;
96
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 }
119
120 free(cOpenArc);
121 }
122 }
123
124 fclose(pFile);
125 }
126
127 return 0;
128}
129
130bool CWadCloseArchive(void *hCWAD)
131{
132 if (!hCWAD)
133 return false;
134
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}
147
148unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
149{
150 if (!hCWAD)
151 return -1;
152
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}
163
164unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
165{
166 if (!hCWAD)
167 return 0;
168
169 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
170 if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
171 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
172
173 return cOpenArc->nFileListSize;
174}
175
176void CWadListFilesInternal(void *hCWAD)
177{
178 if (!hCWAD)
179 return;
180
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}
253
254void * CWadOpenFile(void *hCWAD, const char *pszFileName)
255{
256 if (!hCWAD || !pszFileName)
257 return 0;
258
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 }
273
274 return 0;
275}
276
277bool CWadCloseFile(void *hFile)
278{
279 if (!hFile)
280 return false;
281
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);
292
293 return true;
294}
295
296unsigned long CWadGetFileSize(void *hFile)
297{
298 if (!hFile)
299 return -1;
300
301 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
302 return cOpenFile->f->dwFullSize;
303}
304
305unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
306{
307 if (!hFile)
308 return -1;
309
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}
328
329unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
330{
331 if (!hFile)
332 return -1;
333
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 }
351
352 return cOpenFile->dwFilePointer;
353}
354
355unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
356{
357 if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
358 return 0;
359
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 }
393
394 cOpenFile->dwFilePointer += nBytesRead;
395 return nBytesRead;
396}
397
398unsigned long CWadFindHeader(FILE *hFile)
399{
400 return CWadFindHeaderAndSize(hFile, 0);
401}
402
403unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
404{
405 if (!pFile) return -1;
406
407 if (fseek(pFile, 0, SEEK_END)) return -1;
408 long fsz = ftell(pFile);
409 UInt32 buffer[2];
410 long sep, i, offset;
411
412 if (pnCwadEnd) *pnCwadEnd = fsz;
413
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;
418
419 if (fsz < 12)
420 return -1;
421
422 if (pnCwadEnd) *pnCwadEnd = fsz - 8;
423
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 }
432
433 if (fsz < 132)
434 return -1;
435
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;
439
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;
444
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 }
456
457 break;
458 }
459 }
460
461 return -1;
462}
463
464void 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}