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 #include "CwadLib.h"
2 #include "SFTypes.h"
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #ifndef __SYS_ZLIB
7 #include "zlib/zlib.h"
8 #else
9 #include <zlib.h>
10 #endif
12 const UInt32 ID_CWAD = *(UInt32 *)"CWAD";
13 const UInt32 ID_SEP = *(UInt32 *)"SEP\0";
15 typedef struct _CWADFILEHEADER {
16         UInt32 dwPackedSize;
17         UInt32 dwNameLength;
18         UInt32 dwFullSize;
19         UInt32 dwFlags;
20 //      char   szFileName[dwNameLength];
21 //      UInt8  byData[dwPackedSize];
22 } CWADFILEHEADER;
24 /* struct CWAD {
25         char     IDTag[4] = "CWAD";
26         CWADFILEHEADER Files[];
27 }; */
29 typedef struct _CWADFILE CWADFILE;
31 typedef struct _CWADARCHIVE {
32         TCHAR *pszFileName;
33         FILE *pFile;
34         unsigned long nStart;
35         unsigned long nEnd;
36         unsigned long nFiles;
37         CWADFILE *pFiles;
38         char *pmszFileList;
39         unsigned long nFileListSize;
40         bool bHasFileNameBlank;
41         long nReferences;
42         bool bOpen;
43 } CWADARCHIVE;
45 typedef struct _CWADFILE {
46         char *pszFileName;
47         CWADARCHIVE *pParentArc;
48         UInt32 dwPackedSize;
49         UInt32 dwFullSize;
50         UInt32 dwFlags;
51         unsigned long nOffset;
52         UInt8 *pBuffer;
53         long nReferences;
54 } CWADFILE;
56 typedef struct _CWADFILEHANDLE {
57         CWADFILE *f;
58         UInt32 dwFilePointer;
59 } CWADFILEHANDLE;
61 void CWadListFilesInternal(void *hCWAD);
62 unsigned long CWadFindHeaderAndSize(FILE *hFile, unsigned long *pnCwadEnd);
63 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength);
65 void * CWadOpenArchive(const TCHAR *pszFileName)
66 {
67         if (!pszFileName)
68                 return 0;
70         unsigned long flen;
71         FILE *pFile;
72         pFile = _tfopen(pszFileName, _T("rb"));
73         if (pFile)
74         {
75                 unsigned long nCwadStart = CWadFindHeaderAndSize(pFile, &flen);
76                 if (nCwadStart != -1) {
77                         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)malloc(sizeof(CWADARCHIVE));
78                         if (cOpenArc) {
79                                 cOpenArc->pFile = pFile;
80                                 cOpenArc->nStart = nCwadStart;
81                                 cOpenArc->nEnd = flen;
82                                 cOpenArc->pmszFileList = 0;
83                                 cOpenArc->bHasFileNameBlank = false;
84                                 cOpenArc->pFiles = 0;
85                                 CWadListFilesInternal(cOpenArc);
86                                 if (cOpenArc->pmszFileList) {
87                                         cOpenArc->pszFileName = _tcsdup(pszFileName);
88                                         cOpenArc->nReferences = 0;
89                                         cOpenArc->bOpen = true;
90                                         return cOpenArc;
91                                 }
93                                 free(cOpenArc);
94                         }
95                 }
97                 fclose(pFile);
98         }
100         return 0;
103 bool CWadCloseArchive(void *hCWAD)
105         if (!hCWAD)
106                 return false;
108         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
109         if (cOpenArc->nReferences > 0) {
110                 cOpenArc->bOpen = false;
111                 return false;
112         }
113         fclose(cOpenArc->pFile);
114         if (cOpenArc->pFiles) free(cOpenArc->pFiles);
115         if (cOpenArc->pmszFileList) free(cOpenArc->pmszFileList);
116         if (cOpenArc->pszFileName) free(cOpenArc->pszFileName);
117         free(cOpenArc);
118         return true;
121 unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
123         if (!hCWAD)
124                 return -1;
126         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
127         switch (nInfoType) {
128         case CWAD_INFO_NUM_FILES:
129                 return cOpenArc->nFiles;
130         case CWAD_INFO_SIZE:
131                 return cOpenArc->nEnd - cOpenArc->nStart;
132         default:
133                 return -1;
134         }
137 unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
139         if (!hCWAD)
140                 return 0;
142         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
143         if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
144                 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
146         return cOpenArc->nFileListSize;
149 void CWadListFilesInternal(void *hCWAD)
151         if (!hCWAD)
152                 return;
154         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
155         CWADFILEHEADER CwadFile;
156         unsigned long nReqSize = 0;
157         cOpenArc->nFiles = 0;
158         if (cOpenArc->bHasFileNameBlank && cOpenArc->pmszFileList) {
159                 *cOpenArc->pmszFileList = 0;
160                 nReqSize++;
161         }
162         fseek(cOpenArc->pFile, cOpenArc->nStart + 4, SEEK_SET);
163         for (long fpos = ftell(cOpenArc->pFile); fpos != -1 && fpos + sizeof(CWADFILEHEADER) <= cOpenArc->nEnd; fpos = ftell(cOpenArc->pFile)) {
164                 if (fread(&CwadFile, sizeof(CWADFILEHEADER), 1, cOpenArc->pFile) == 1) {
165                         if (cOpenArc->pmszFileList)
166                         {
167                                 if (CwadFile.dwNameLength > 0) {
168                                         if (fread(cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength, 1, cOpenArc->pFile) == 1)
169                                                 CWadDecryptData((UInt8 *)cOpenArc->pmszFileList + nReqSize, CwadFile.dwNameLength);
170                                         cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList + nReqSize;
171                                 }
172                                 else
173                                         cOpenArc->pFiles[cOpenArc->nFiles].pszFileName = cOpenArc->pmszFileList;
174                                 cOpenArc->pFiles[cOpenArc->nFiles].pParentArc = cOpenArc;
175                                 cOpenArc->pFiles[cOpenArc->nFiles].dwPackedSize = CwadFile.dwPackedSize;
176                                 cOpenArc->pFiles[cOpenArc->nFiles].dwFullSize = CwadFile.dwFullSize;
177                                 cOpenArc->pFiles[cOpenArc->nFiles].dwFlags = CwadFile.dwFlags;
178                                 cOpenArc->pFiles[cOpenArc->nFiles].nOffset = fpos + sizeof(CWADFILEHEADER) + CwadFile.dwNameLength;
179                                 cOpenArc->pFiles[cOpenArc->nFiles].pBuffer = 0;
180                                 cOpenArc->pFiles[cOpenArc->nFiles].nReferences = 0;
181                         }
182                         else {
183                                 fseek(cOpenArc->pFile, CwadFile.dwNameLength, SEEK_CUR);
184                         }
185                         nReqSize += CwadFile.dwNameLength;
186                         if (CwadFile.dwNameLength > 0) {
187                                 if (cOpenArc->pmszFileList)
188                                         cOpenArc->pmszFileList[nReqSize] = 0;
189                                 nReqSize++;
190                         }
191                         else if (!cOpenArc->bHasFileNameBlank) {
192                                 cOpenArc->bHasFileNameBlank = true;
193                                 nReqSize++;
194                         }
195                         fseek(cOpenArc->pFile, CwadFile.dwPackedSize, SEEK_CUR);
196                         cOpenArc->nFiles++;
197                 }
198                 else break;
199         }
200         if (cOpenArc->pmszFileList)
201                 cOpenArc->pmszFileList[nReqSize] = 0;
202         nReqSize++;
203         if (nReqSize == 1)
204         {
205                 if (cOpenArc->pmszFileList)
206                         cOpenArc->pmszFileList[nReqSize] = 0;
207                 nReqSize++;
208         }
209         if (!cOpenArc->pmszFileList) {
210                 cOpenArc->pmszFileList = (char *)malloc(nReqSize);
211                 cOpenArc->nFileListSize = nReqSize;
212                 if (cOpenArc->nFiles > 0)
213                         cOpenArc->pFiles = (CWADFILE *)calloc(cOpenArc->nFiles, sizeof(CWADFILE));
214                 if (cOpenArc->pmszFileList && (cOpenArc->pFiles || cOpenArc->nFiles == 0))
215                         CWadListFilesInternal(hCWAD);
216                 else {
217                         if (cOpenArc->pmszFileList) {
218                                 free(cOpenArc->pmszFileList);
219                                 cOpenArc->pmszFileList = 0;
220                         }
221                         if (cOpenArc->pFiles)
222                                 free(cOpenArc->pFiles);
223                 }
224         }
227 void * CWadOpenFile(void *hCWAD, const char *pszFileName)
229         if (!hCWAD || !pszFileName)
230                 return 0;
232         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
233         unsigned long nFile;
234         for (nFile = 0; nFile < cOpenArc->nFiles; nFile++) {
235                 if (strcmp(pszFileName, cOpenArc->pFiles[nFile].pszFileName) == 0) {
236                         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)malloc(sizeof(CWADFILEHANDLE));
237                         if (cOpenFile) {
238                                 cOpenFile->f = &cOpenArc->pFiles[nFile];
239                                 cOpenFile->dwFilePointer = 0;
240                                 cOpenFile->f->nReferences++;
241                                 cOpenArc->nReferences++;
242                                 return cOpenFile;
243                         }
244                 }
245         }
247         return 0;
250 bool CWadCloseFile(void *hFile)
252         if (!hFile)
253                 return false;
255         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
256         cOpenFile->f->nReferences--;
257         cOpenFile->f->pParentArc->nReferences--;
258         if (cOpenFile->f->nReferences < 1 && cOpenFile->f->pBuffer) {
259                 free(cOpenFile->f->pBuffer);
260                 cOpenFile->f->pBuffer = 0;
261         }
262         if (cOpenFile->f->pParentArc->nReferences < 1 && !cOpenFile->f->pParentArc->bOpen)
263                 CWadCloseArchive(cOpenFile->f->pParentArc);
264         free(cOpenFile);
266         return true;
269 unsigned long CWadGetFileSize(void *hFile)
271         if (!hFile)
272                 return -1;
274         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
275         return cOpenFile->f->dwFullSize;
278 unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
280         if (!hFile)
281                 return -1;
283         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
284         switch (nInfoType) {
285         case CWAD_INFO_NUM_FILES:
286                 return cOpenFile->f->pParentArc->nFiles;
287         case CWAD_INFO_SIZE:
288                 return cOpenFile->f->dwFullSize;
289         case CWAD_INFO_COMPRESSED_SIZE:
290                 return cOpenFile->f->dwPackedSize;
291         case CWAD_INFO_FLAGS:
292                 return cOpenFile->f->dwFlags;
293         case CWAD_INFO_PARENT:
294                 return (unsigned long)cOpenFile->f->pParentArc;
295         case CWAD_INFO_POSITION:
296                 return cOpenFile->dwFilePointer;
297         default:
298                 return -1;
299         }
302 unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
304         if (!hFile)
305                 return -1;
307         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
308         long fsz = cOpenFile->f->dwFullSize;
309         long cpos = cOpenFile->dwFilePointer;
310         switch (nMoveMethod) {
311         case CWAD_FILE_CURRENT:
312                 if (cpos + nDistanceToMove < 0 || cpos + nDistanceToMove > fsz) return -1;
313                 cOpenFile->dwFilePointer += nDistanceToMove;
314                 break;
315         case CWAD_FILE_END:
316                 if (fsz + nDistanceToMove < 0 || nDistanceToMove > 0) return -1;
317                 cOpenFile->dwFilePointer = fsz + nDistanceToMove;
318                 break;
319         case CWAD_FILE_BEGIN:
320         default:
321                 if (nDistanceToMove < 0 || nDistanceToMove > fsz) return -1;
322                 cOpenFile->dwFilePointer = nDistanceToMove;
323         }
325         return cOpenFile->dwFilePointer;
328 unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
330         if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
331                 return 0;
333         CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
334         CWADARCHIVE *cOpenArc = (CWADARCHIVE *)cOpenFile->f->pParentArc;
335         if (cOpenFile->dwFilePointer >= cOpenFile->f->dwFullSize)
336                 return 0;
337         if (cOpenFile->dwFilePointer + nNumberOfBytesToRead > cOpenFile->f->dwFullSize)
338                 nNumberOfBytesToRead = cOpenFile->f->dwFullSize - cOpenFile->dwFilePointer;
339         unsigned long nBytesRead = nNumberOfBytesToRead;
340         if (cOpenFile->f->dwFlags & 1) {
341                 if (!cOpenFile->f->pBuffer) {
342                         cOpenFile->f->pBuffer = (UInt8 *)malloc(cOpenFile->f->dwFullSize);
343                         UInt8 *compbuffer = (UInt8 *)malloc(cOpenFile->f->dwPackedSize);
344                         bool bReadOK = false;
345                         if (cOpenFile->f->pBuffer && compbuffer) {
346                                 fseek(cOpenArc->pFile, cOpenFile->f->nOffset, SEEK_SET);
347                                 if (fread(compbuffer, 1, cOpenFile->f->dwPackedSize, cOpenArc->pFile) == cOpenFile->f->dwPackedSize)
348                                         if (uncompress(cOpenFile->f->pBuffer, &nBytesRead, compbuffer, cOpenFile->f->dwPackedSize) == Z_OK)
349                                                 bReadOK = true;
350                         }
351                         if (!bReadOK && cOpenFile->f->pBuffer) {
352                                 free(cOpenFile->f->pBuffer);
353                                 cOpenFile->f->pBuffer = 0;
354                                 nBytesRead = 0;
355                         }
356                         if (compbuffer)
357                                 free(compbuffer);
358                 }
359                 if (cOpenFile->f->pBuffer)
360                         memcpy(pBuffer, cOpenFile->f->pBuffer + cOpenFile->dwFilePointer, nNumberOfBytesToRead);
361         }
362         else {
363                 fseek(cOpenArc->pFile, cOpenFile->f->nOffset + cOpenFile->dwFilePointer, SEEK_SET);
364                 nBytesRead = fread(pBuffer, 1, nNumberOfBytesToRead, cOpenArc->pFile);
365         }
367         cOpenFile->dwFilePointer += nBytesRead;
368         return nBytesRead;
371 unsigned long CWadFindHeader(FILE *hFile)
373         return CWadFindHeaderAndSize(hFile, 0);
376 unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
378         if (!pFile) return -1;
380         if (fseek(pFile, 0, SEEK_END)) return -1;
381         long fsz = ftell(pFile);
382         UInt32 buffer[2];
383         long sep, i, offset;
385         if (pnCwadEnd) *pnCwadEnd = fsz;
387         fseek(pFile, 0, SEEK_SET);
388         if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
389         if (buffer[0] == ID_CWAD)
390                 return 0;
392         if (fsz < 12)
393                 return -1;
395         if (pnCwadEnd) *pnCwadEnd = fsz - 8;
397         fseek(pFile, -8, SEEK_END);
398         if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
399         if (buffer[0] == ID_CWAD) {
400                 fseek(pFile, buffer[1], SEEK_SET);
401                 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
402                 if (buffer[0] == ID_CWAD)
403                         return buffer[1];
404         }
406         if (fsz < 132)
407                 return -1;
409         for (sep = fsz - 12; sep >= fsz - 132; sep -= 8) {
410                 fseek(pFile, sep, SEEK_SET);
411                 if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
413                 if (buffer[0] == ID_SEP) {
414                         for (i = sep + 4; i < fsz; i += 8) {
415                                 fseek(pFile, i, SEEK_SET);
416                                 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
418                                 offset = buffer[0];
419                                 if (pnCwadEnd) *pnCwadEnd = offset + buffer[1] - 8;
420                                 fseek(pFile, offset + buffer[1] - 8, SEEK_SET);
421                                 if (fread(buffer, sizeof(UInt32), 2, pFile) < 2) return -1;
422                                 if (buffer[0] == ID_CWAD) {
423                                         fseek(pFile, offset + buffer[1], SEEK_SET);
424                                         if (fread(buffer, sizeof(UInt32), 1, pFile) < 1) return -1;
425                                         if (buffer[0] == ID_CWAD)
426                                                 return offset + buffer[1];
427                                 }
428                         }
430                         break;
431                 }
432         }
434         return -1;
437 void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
439         if (!pBuffer || nBufferLength == 0) return;
440         pBuffer += nBufferLength - 1;
441         UInt8 byCWadKey;
442         byCWadKey = (UInt8)(66 - (nBufferLength << 1));
443         for (unsigned long i = 0; i < nBufferLength; i++) {
444                 pBuffer[0] ^= (UInt8)(byCWadKey + (i << 1));
445                 pBuffer--;
446         }