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
cfca19c6 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
11
12const UInt32 ID_CWAD = *(UInt32 *)"CWAD";
13const UInt32 ID_SEP = *(UInt32 *)"SEP\0";
14
15typedef struct _CWADFILEHEADER {
16 UInt32 dwPackedSize;
17 UInt32 dwNameLength;
18 UInt32 dwFullSize;
19 UInt32 dwFlags;
20// char szFileName[dwNameLength];
21// UInt8 byData[dwPackedSize];
22} CWADFILEHEADER;
23
24/* struct CWAD {
25 char IDTag[4] = "CWAD";
26 CWADFILEHEADER Files[];
27}; */
28
29typedef struct _CWADFILE CWADFILE;
30
31typedef 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;
44
45typedef 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;
55
56typedef struct _CWADFILEHANDLE {
57 CWADFILE *f;
58 UInt32 dwFilePointer;
59} CWADFILEHANDLE;
60
61void CWadListFilesInternal(void *hCWAD);
62unsigned long CWadFindHeaderAndSize(FILE *hFile, unsigned long *pnCwadEnd);
63void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength);
64
65void * CWadOpenArchive(const TCHAR *pszFileName)
66{
67 if (!pszFileName)
68 return 0;
69
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 }
92
93 free(cOpenArc);
94 }
95 }
96
97 fclose(pFile);
98 }
99
100 return 0;
101}
102
103bool CWadCloseArchive(void *hCWAD)
104{
105 if (!hCWAD)
106 return false;
107
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;
119}
120
121unsigned long CWadGetArchiveInfo(void *hCWAD, int nInfoType)
122{
123 if (!hCWAD)
124 return -1;
125
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 }
135}
136
137unsigned long CWadListFiles(void *hCWAD, char *pmszBuffer, unsigned long nBufferLength)
138{
139 if (!hCWAD)
140 return 0;
141
142 CWADARCHIVE *cOpenArc = (CWADARCHIVE *)hCWAD;
143 if (pmszBuffer && nBufferLength >= cOpenArc->nFileListSize)
144 memcpy(pmszBuffer, cOpenArc->pmszFileList, cOpenArc->nFileListSize);
145
146 return cOpenArc->nFileListSize;
147}
148
149void CWadListFilesInternal(void *hCWAD)
150{
151 if (!hCWAD)
152 return;
153
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 }
225}
226
227void * CWadOpenFile(void *hCWAD, const char *pszFileName)
228{
229 if (!hCWAD || !pszFileName)
230 return 0;
231
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 }
246
247 return 0;
248}
249
250bool CWadCloseFile(void *hFile)
251{
252 if (!hFile)
253 return false;
254
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);
265
266 return true;
267}
268
269unsigned long CWadGetFileSize(void *hFile)
270{
271 if (!hFile)
272 return -1;
273
274 CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile;
275 return cOpenFile->f->dwFullSize;
276}
277
278unsigned long CWadGetFileInfo(void *hFile, int nInfoType)
279{
280 if (!hFile)
281 return -1;
282
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 }
300}
301
302unsigned long CWadSetFilePointer(void *hFile, long nDistanceToMove, int nMoveMethod)
303{
304 if (!hFile)
305 return -1;
306
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 }
324
325 return cOpenFile->dwFilePointer;
326}
327
328unsigned long CWadReadFile(void *hFile, void *pBuffer, unsigned long nNumberOfBytesToRead)
329{
330 if (!hFile || !pBuffer || nNumberOfBytesToRead == 0)
331 return 0;
332
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 }
366
367 cOpenFile->dwFilePointer += nBytesRead;
368 return nBytesRead;
369}
370
371unsigned long CWadFindHeader(FILE *hFile)
372{
373 return CWadFindHeaderAndSize(hFile, 0);
374}
375
376unsigned long CWadFindHeaderAndSize(FILE *pFile, unsigned long *pnCwadEnd)
377{
378 if (!pFile) return -1;
379
380 if (fseek(pFile, 0, SEEK_END)) return -1;
381 long fsz = ftell(pFile);
382 UInt32 buffer[2];
383 long sep, i, offset;
384
385 if (pnCwadEnd) *pnCwadEnd = fsz;
386
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;
391
392 if (fsz < 12)
393 return -1;
394
395 if (pnCwadEnd) *pnCwadEnd = fsz - 8;
396
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 }
405
406 if (fsz < 132)
407 return -1;
408
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;
412
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;
417
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 }
429
430 break;
431 }
432 }
433
434 return -1;
435}
436
437void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength)
438{
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 }
447}