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
7b6f1c5a 92#ifndef _WIN32
93#define _T(x) x
94#define _tfopen fopen
95#define _tcsdup strdup
96#endif
97
cfca19c6 98void * CWadOpenArchive(const TCHAR *pszFileName)
99{
100 if (!pszFileName)
101 return 0;
102
103 unsigned long flen;
104 FILE *pFile;
105 pFile = _tfopen(pszFileName, _T("rb"));
106 if (pFile)
107 {
108 unsigned long nCwadStart = CWadFindHeaderAndSize(pFile, &flen);
109 if (nCwadStart != -1) {
110 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)malloc(sizeof(CWADARCHIVE));
111 if (cOpenArc) {
112 cOpenArc->pFile = pFile;
113 cOpenArc->nStart = nCwadStart;
114 cOpenArc->nEnd = flen;
115 cOpenArc->pmszFileList = 0;
116 cOpenArc->bHasFileNameBlank = false;
117 cOpenArc->pFiles = 0;
118 CWadListFilesInternal(cOpenArc);
119 if (cOpenArc->pmszFileList) {
120 cOpenArc->pszFileName = _tcsdup(pszFileName);
121 cOpenArc->nReferences = 0;
122 cOpenArc->bOpen = true;
123 return cOpenArc;
124 }
125
126 free(cOpenArc);
127 }
128 }
129
130 fclose(pFile);
131 }
132
133 return 0;
134}
135
136bool CWadCloseArchive(void *hCWAD)
137{
138 if (!hCWAD)
139 return false;
140
141 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
142 if (cOpenArc->nReferences > 0) {
143 cOpenArc->bOpen = false;
144 return false;
145 }
146 fclose(cOpenArc->pFile);
147 if (cOpenArc->pFiles) free(cOpenArc->pFiles);
148 if (cOpenArc->pmszFileList) free(cOpenArc->pmszFileList);
149 if (cOpenArc->pszFileName) free(cOpenArc->pszFileName);
150 free(cOpenArc);
151 return true;
152}
153
154unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
155{
156 if (!hCWAD)
157 return -1;
158
159 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
160 switch (nInfoType) {
161 case CWAD_INFO_NUM_FILES:
162 return cOpenArc->nFiles;
163 case CWAD_INFO_SIZE:
164 return cOpenArc->nEnd - cOpenArc->nStart;
165 default:
166 return -1;
167 }
168}
169
170unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
171{
172 if (!hCWAD)
173 return 0;
174
175 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
176 if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
177 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
178
179 return cOpenArc->nFileListSize;
180}
181
182void CWadListFilesInternal(void *hCWAD)
183{
184 if (!hCWAD)
185 return;
186
187 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
188 CWADFILEHEADER CwadFile;
189 unsigned long nReqSize = 0;
190 cOpenArc->nFiles = 0;
191 if (cOpenArc->bHasFileNameBlank && cOpenArc->pmszFileList) {
192 *cOpenArc->pmszFileList = 0;
193 nReqSize++;
194 }
195 fseek(cOpenArc->pFile, cOpenArc->nStart + 4, SEEK_SET);
196 for (long fpos = ftell(cOpenArc->pFile); fpos != -1 && fpos + sizeof(CWADFILEHEADER) <= cOpenArc->nEnd; fpos = ftell(cOpenArc->pFile)) {
197 if (fread(&CwadFile, sizeof(CWADFILEHEADER), 1, cOpenArc->pFile) == 1) {
198 if (cOpenArc->pmszFileList)
199 {
200 if (CwadFile.dwNameLength > 0) {
201 if (fread(cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength, 1, cOpenArc->pFile) == 1)
202 CWadDecryptData((UInt8 *)cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength);
203 cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList + nReqSize;
204 }
205 else
206 cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList;
207 cOpenArc->pFiles[cOpenArc->nFiles].pParentArc = cOpenArc;
208 cOpenArc->pFiles[cOpenArc->nFiles].dwPackedSize = CwadFile.dwPackedSize;
209 cOpenArc->pFiles[cOpenArc->nFiles].dwFullSize = CwadFile.dwFullSize;
210 cOpenArc->pFiles[cOpenArc->nFiles].dwFlags = CwadFile.dwFlags;
211 cOpenArc->pFiles[cOpenArc->nFiles].nOffset = fpos + sizeof(CWADFILEHEADER) + CwadFile.dwNameLength;
212 cOpenArc->pFiles[cOpenArc->nFiles].pBuffer = 0;
213 cOpenArc->pFiles[cOpenArc->nFiles].nReferences = 0;
214 }
215 else {
216 fseek(cOpenArc->pFile, CwadFile.dwNameLength, SEEK_CUR);
217 }
218 nReqSize += CwadFile.dwNameLength;
219 if (CwadFile.dwNameLength > 0) {
220 if (cOpenArc->pmszFileList)
221 cOpenArc->pmszFileList[nReqSize] = 0;
222 nReqSize++;
223 }
224 else if (!cOpenArc->bHasFileNameBlank) {
225 cOpenArc->bHasFileNameBlank = true;
226 nReqSize++;
227 }
228 fseek(cOpenArc->pFile, CwadFile.dwPackedSize, SEEK_CUR);
229 cOpenArc->nFiles++;
230 }
231 else break;
232 }
233 if (cOpenArc->pmszFileList)
234 cOpenArc->pmszFileList[nReqSize] = 0;
235 nReqSize++;
236 if (nReqSize == 1)
237 {
238 if (cOpenArc->pmszFileList)
239 cOpenArc->pmszFileList[nReqSize] = 0;
240 nReqSize++;
241 }
242 if (!cOpenArc->pmszFileList) {
243 cOpenArc->pmszFileList = (char *)malloc(nReqSize);
244 cOpenArc->nFileListSize = nReqSize;
245 if (cOpenArc->nFiles > 0)
246 cOpenArc->pFiles = (CWADFILE *)calloc(cOpenArc->nFiles, sizeof(CWADFILE));
247 if (cOpenArc->pmszFileList && (cOpenArc->pFiles || cOpenArc->nFiles == 0))
248 CWadListFilesInternal(hCWAD);
249 else {
250 if (cOpenArc->pmszFileList) {
251 free(cOpenArc->pmszFileList);
252 cOpenArc->pmszFileList = 0;
253 }
254 if (cOpenArc->pFiles)
255 free(cOpenArc->pFiles);
256 }
257 }
258}
259
260void * CWadOpenFile(void *hCWAD, const char *pszFileName)
261{
262 if (!hCWAD || !pszFileName)
263 return 0;
264
265 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
266 unsigned long nFile;
267 for (nFile = 0; nFile < cOpenArc->nFiles; nFile++) {
268 if (strcmp(pszFileName, cOpenArc->pFiles[nFile].pszFileName) == 0) {
269 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)malloc(sizeof(CWADFILEHANDLE));
270 if (cOpenFile) {
271 cOpenFile->f = &cOpenArc->pFiles[nFile];
272 cOpenFile->dwFilePointer = 0;
273 cOpenFile->f->nReferences++;
274 cOpenArc->nReferences++;
275 return cOpenFile;
276 }
277 }
278 }
279
280 return 0;
281}
282
283bool CWadCloseFile(void *hFile)
284{
285 if (!hFile)
286 return false;
287
288 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
289 cOpenFile->f->nReferences--;
290 cOpenFile->f->pParentArc->nReferences--;
291 if (cOpenFile->f->nReferences < 1 && cOpenFile->f->pBuffer) {
292 free(cOpenFile->f->pBuffer);
293 cOpenFile->f->pBuffer = 0;
294 }
295 if (cOpenFile->f->pParentArc->nReferences < 1 && !cOpenFile->f->pParentArc->bOpen)
296 CWadCloseArchive(cOpenFile->f->pParentArc);
297 free(cOpenFile);
298
299 return true;
300}
301
302unsigned long CWadGetFileSize(void *hFile)
303{
304 if (!hFile)
305 return -1;
306
307 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
308 return cOpenFile->f->dwFullSize;
309}
310
311unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
312{
313 if (!hFile)
314 return -1;
315
316 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
317 switch (nInfoType) {
318 case CWAD_INFO_NUM_FILES:
319 return cOpenFile->f->pParentArc->nFiles;
320 case CWAD_INFO_SIZE:
321 return cOpenFile->f->dwFullSize;
322 case CWAD_INFO_COMPRESSED_SIZE:
323 return cOpenFile->f->dwPackedSize;
324 case CWAD_INFO_FLAGS:
325 return cOpenFile->f->dwFlags;
326 case CWAD_INFO_PARENT:
327 return (unsigned long)cOpenFile->f->pParentArc;
328 case CWAD_INFO_POSITION:
329 return cOpenFile->dwFilePointer;
330 default:
331 return -1;
332 }
333}
334
335unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
336{
337 if (!hFile)
338 return -1;
339
340 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
341 long fsz = cOpenFile->f->dwFullSize;
342 long cpos = cOpenFile->dwFilePointer;
343 switch (nMoveMethod) {
344 case CWAD_FILE_CURRENT:
345 if (cpos + nDistanceToMove < 0 || cpos + nDistanceToMove > fsz) return -1;
346 cOpenFile->dwFilePointer += nDistanceToMove;
347 break;
348 case CWAD_FILE_END:
349 if (fsz + nDistanceToMove < 0 || nDistanceToMove > 0) return -1;
350 cOpenFile->dwFilePointer = fsz + nDistanceToMove;
351 break;
352 case CWAD_FILE_BEGIN:
353 default:
354 if (nDistanceToMove < 0 || nDistanceToMove > fsz) return -1;
355 cOpenFile->dwFilePointer = nDistanceToMove;
356 }
357
358 return cOpenFile->dwFilePointer;
359}
360
361unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
362{
363 if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
364 return 0;
365
366 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
367 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)cOpenFile->f->pParentArc;
368 if (cOpenFile->dwFilePointer >= cOpenFile->f->dwFullSize)
369 return 0;
370 if (cOpenFile->dwFilePointer + nNumberOfBytesToRead > cOpenFile->f->dwFullSize)
371 nNumberOfBytesToRead = cOpenFile->f->dwFullSize - cOpenFile->dwFilePointer;
372 unsigned long nBytesRead = nNumberOfBytesToRead;
373 if (cOpenFile->f->dwFlags & 1) {
374 if (!cOpenFile->f->pBuffer) {
375 cOpenFile->f->pBuffer = (UInt8 *)malloc(cOpenFile->f->dwFullSize);
376 UInt8 *compbuffer = (UInt8 *)malloc(cOpenFile->f->dwPackedSize);
377 bool bReadOK = false;
378 if (cOpenFile->f->pBuffer && compbuffer) {
379 fseek(cOpenArc->pFile, cOpenFile->f->nOffset, SEEK_SET);
380 if (fread(compbuffer, 1, cOpenFile->f->dwPackedSize, cOpenArc->pFile) == cOpenFile->f->dwPackedSize)
381 if (uncompress(cOpenFile->f->pBuffer, &nBytesRead, compbuffer, cOpenFile->f->dwPackedSize) == Z_OK)
382 bReadOK = true;
383 }
384 if (!bReadOK && cOpenFile->f->pBuffer) {
385 free(cOpenFile->f->pBuffer);
386 cOpenFile->f->pBuffer = 0;
387 nBytesRead = 0;
388 }
389 if (compbuffer)
390 free(compbuffer);
391 }
392 if (cOpenFile->f->pBuffer)
393 memcpy(pBuffer, cOpenFile->f->pBuffer + cOpenFile->dwFilePointer, nNumberOfBytesToRead);
394 }
395 else {
396 fseek(cOpenArc->pFile, cOpenFile->f->nOffset + cOpenFile->dwFilePointer, SEEK_SET);
397 nBytesRead = fread(pBuffer, 1, nNumberOfBytesToRead, cOpenArc->pFile);
398 }
399
400 cOpenFile->dwFilePointer += nBytesRead;
401 return nBytesRead;
402}
403
404unsigned long CWadFindHeader(FILE *hFile)
405{
406 return CWadFindHeaderAndSize(hFile, 0);
407}
408
409unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
410{
411 if (!pFile) return -1;
412
413 if (fseek(pFile, 0, SEEK_END)) return -1;
414 long fsz = ftell(pFile);
415 UInt32 buffer[2];
416 long sep, i, offset;
417
418 if (pnCwadEnd) *pnCwadEnd = fsz;
419
420 fseek(pFile, 0, SEEK_SET);
421 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
422 if (buffer[0] == ID_CWAD)
423 return 0;
424
425 if (fsz < 12)
426 return -1;
427
428 if (pnCwadEnd) *pnCwadEnd = fsz - 8;
429
430 fseek(pFile, -8, SEEK_END);
431 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
432 if (buffer[0] == ID_CWAD) {
433 fseek(pFile, buffer[1], SEEK_SET);
434 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
435 if (buffer[0] == ID_CWAD)
436 return buffer[1];
437 }
438
439 if (fsz < 132)
440 return -1;
441
442 for (sep = fsz - 12; sep >= fsz - 132; sep -= 8) {
443 fseek(pFile, sep, SEEK_SET);
444 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
445
446 if (buffer[0] == ID_SEP) {
447 for (i = sep + 4; i < fsz; i += 8) {
448 fseek(pFile, i, SEEK_SET);
449 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
450
451 offset = buffer[0];
452 if (pnCwadEnd) *pnCwadEnd = offset + buffer[1] - 8;
453 fseek(pFile, offset + buffer[1] - 8, SEEK_SET);
454 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
455 if (buffer[0] == ID_CWAD) {
456 fseek(pFile, offset + buffer[1], SEEK_SET);
457 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
458 if (buffer[0] == ID_CWAD)
459 return offset + buffer[1];
460 }
461 }
462
463 break;
464 }
465 }
466
467 return -1;
468}
469
470void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
471{
472 if (!pBuffer || nBufferLength == 0) return;
473 pBuffer += nBufferLength - 1;
474 UInt8 byCWadKey;
475 byCWadKey = (UInt8)(66 - (nBufferLength << 1));
476 for (unsigned long i = 0; i < nBufferLength; i++) {
477 pBuffer[0] ^= (UInt8)(byCWadKey + (i << 1));
478 pBuffer--;
479 }
480}