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




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;
130 bool CWadCloseArchive(void *hCWAD)
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;
148 unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
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         }
164 unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
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;
176 void CWadListFilesInternal(void *hCWAD)
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         }
254 void * CWadOpenFile(void *hCWAD, const char *pszFileName)
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;
277 bool CWadCloseFile(void *hFile)
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;
296 unsigned long CWadGetFileSize(void *hFile)
298         if (!hFile)
299                 return -1;
301         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
302         return cOpenFile->f->dwFullSize;
305 unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
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         }
329 unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
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;
355 unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
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;
398 unsigned long CWadFindHeader(FILE *hFile)
400         return CWadFindHeaderAndSize(hFile, 0);
403 unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
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;
464 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
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         }