Commit | Line | Data |
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 | |
12 | const UInt32 ID_CWAD = *(UInt32 *)"CWAD"; |
13 | const UInt32 ID_SEP = *(UInt32 *)"SEP\0"; |
14 | |
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; |
23 | |
24 | /* struct CWAD { |
25 | char IDTag[4] = "CWAD"; |
26 | CWADFILEHEADER Files[]; |
27 | }; */ |
28 | |
29 | typedef struct _CWADFILE CWADFILE; |
30 | |
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; |
44 | |
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; |
55 | |
56 | typedef struct _CWADFILEHANDLE { |
57 | CWADFILE *f; |
58 | UInt32 dwFilePointer; |
59 | } CWADFILEHANDLE; |
60 | |
61 | void CWadListFilesInternal(void *hCWAD); |
62 | unsigned long CWadFindHeaderAndSize(FILE *hFile, unsigned long *pnCwadEnd); |
63 | void CWadDecryptData(UInt8 *pBuffer, unsigned long nBufferLength); |
64 | |
65 | void * 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 | |
103 | bool 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 | |
121 | unsigned 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 | |
137 | unsigned 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 | |
149 | void 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 | |
227 | void * 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 | |
250 | bool 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 | |
269 | unsigned long CWadGetFileSize(void *hFile) |
270 | { |
271 | if (!hFile) |
272 | return -1; |
273 | |
274 | CWADFILEHANDLE *cOpenFile = (CWADFILEHANDLE *)hFile; |
275 | return cOpenFile->f->dwFullSize; |
276 | } |
277 | |
278 | unsigned 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 | |
302 | unsigned 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 | |
328 | unsigned 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 | |
371 | unsigned long CWadFindHeader(FILE *hFile) |
372 | { |
373 | return CWadFindHeaderAndSize(hFile, 0); |
374 | } |
375 | |
376 | unsigned 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 | |
437 | void 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 | } |