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




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 #ifndef _WIN32
93 #define _T(x) x
94 #define _tfopen fopen
95 #define _tcsdup strdup
96 #endif
98 void * CWadOpenArchive(const TCHAR *pszFileName)
99 {
100         if (!pszFileName)
101                 return 0;
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                                 }
126                                 free(cOpenArc);
127                         }
128                 }
130                 fclose(pFile);
131         }
133         return 0;
136 bool CWadCloseArchive(void *hCWAD)
138         if (!hCWAD)
139                 return false;
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;
154 unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
156         if (!hCWAD)
157                 return -1;
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         }
170 unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
172         if (!hCWAD)
173                 return 0;
175         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
176         if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
177                 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
179         return cOpenArc->nFileListSize;
182 void CWadListFilesInternal(void *hCWAD)
184         if (!hCWAD)
185                 return;
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         }
260 void * CWadOpenFile(void *hCWAD, const char *pszFileName)
262         if (!hCWAD || !pszFileName)
263                 return 0;
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         }
280         return 0;
283 bool CWadCloseFile(void *hFile)
285         if (!hFile)
286                 return false;
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);
299         return true;
302 unsigned long CWadGetFileSize(void *hFile)
304         if (!hFile)
305                 return -1;
307         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
308         return cOpenFile->f->dwFullSize;
311 unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
313         if (!hFile)
314                 return -1;
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         }
335 unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
337         if (!hFile)
338                 return -1;
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         }
358         return cOpenFile->dwFilePointer;
361 unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
363         if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
364                 return 0;
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         }
400         cOpenFile->dwFilePointer += nBytesRead;
401         return nBytesRead;
404 unsigned long CWadFindHeader(FILE *hFile)
406         return CWadFindHeaderAndSize(hFile, 0);
409 unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
411         if (!pFile) return -1;
413         if (fseek(pFile, 0, SEEK_END)) return -1;
414         long fsz = ftell(pFile);
415         UInt32 buffer[2];
416         long sep, i, offset;
418         if (pnCwadEnd) *pnCwadEnd = fsz;
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;
425         if (fsz < 12)
426                 return -1;
428         if (pnCwadEnd) *pnCwadEnd = fsz - 8;
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         }
439         if (fsz < 132)
440                 return -1;
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;
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;
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                         }
463                         break;
464                 }
465         }
467         return -1;
470 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
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         }