1 /*---------------------------------------------------------------------------*
2
3 Copyright (C) 2009-2013 Nintendo. All rights reserved.
4
5 These coded instructions, statements, and computer programs contain
6 proprietary information of Nintendo of America Inc. and/or Nintendo
7 Company Ltd., and are protected by Federal copyright law. They may
8 not be disclosed to third parties or copied or duplicated in any form,
9 in whole or in part, without the prior written consent of Nintendo.
10
11 *---------------------------------------------------------------------------*/
12 #include <stdlib.h>
13 #include <cafe/szfile.h>
14 #include "7z.h"
15 #include "7zCrc.h"
16
17 static int sgCrcInit = 0;
18
19 /* --------------------------------------------------------------------------------- */
20
21 struct _MemStream
22 {
23 ILookInStream iFace; /* must be first thing in structure */
24
25 UINT8 const * mpSrcData;
26 UINT32 mSrcDataBytes;
27
28 UINT32 mCurPos;
29 };
30 typedef struct _MemStream MemStream;
31
memStreamLook(void * p,const void ** buf,size_t * size)32 static SRes memStreamLook(void *p, const void **buf, size_t *size)
33 {
34 UINT32 left;
35 SRes ret;
36
37 if ((!(*size)) || (!buf))
38 return SZ_ERROR_PARAM;
39
40 left = ((MemStream *)p)->mSrcDataBytes - ((MemStream *)p)->mCurPos;
41
42 if (left < (*size))
43 {
44 ret = SZ_ERROR_INPUT_EOF;
45 *size = left;
46 }
47 else
48 ret = 0;
49
50 *buf = ((MemStream *)p)->mpSrcData + ((MemStream *)p)->mCurPos;
51
52 return ret;
53 }
54
memStreamSkip(void * p,size_t offset)55 static SRes memStreamSkip(void *p, size_t offset)
56 {
57 UINT32 left;
58 SRes ret;
59
60 if (!offset)
61 return SZ_ERROR_PARAM;
62 left = ((MemStream *)p)->mSrcDataBytes - ((MemStream *)p)->mCurPos;
63 if (!left)
64 return SZ_ERROR_INPUT_EOF;
65 if (left < offset)
66 {
67 offset = left;
68 ret = SZ_ERROR_INPUT_EOF;
69 }
70 else
71 ret = 0;
72 ((MemStream *)p)->mCurPos += offset;
73 return ret;
74 }
75
memStreamRead(void * p,void * buf,size_t * size)76 static SRes memStreamRead(void *p, void *buf, size_t *size)
77 {
78 UINT32 left;
79 UINT32 act;
80 SRes ret;
81
82 act = *size;
83 if (!act)
84 return SZ_ERROR_PARAM;
85 left = ((MemStream *)p)->mSrcDataBytes - ((MemStream *)p)->mCurPos;
86 if (!left)
87 return SZ_ERROR_INPUT_EOF;
88 if (left < act)
89 {
90 act = left;
91 ret = SZ_ERROR_INPUT_EOF;
92 *size = left;
93 }
94 else
95 ret = 0;
96 memcpy(buf, ((MemStream *)p)->mpSrcData + ((MemStream *)p)->mCurPos, act);
97 ((MemStream *)p)->mCurPos += act;
98 return ret;
99 }
100
memStreamSeek(void * p,Int64 * pos,ESzSeek origin)101 static SRes memStreamSeek(void *p, Int64 *pos, ESzSeek origin)
102 {
103 UINT32 pos32;
104
105 if (origin != SZ_SEEK_CUR)
106 {
107 /* trying to move file pointer */
108 if (origin == SZ_SEEK_END)
109 ((MemStream *)p)->mCurPos = ((MemStream *)p)->mSrcDataBytes;
110 else if (origin == SZ_SEEK_SET)
111 {
112 if ((*pos)&0xFFFFFFFF80000000ull)
113 return SZ_ERROR_PARAM;
114 pos32 = (UINT32)((*pos)&0x7FFFFFFF);
115 if (pos32 > ((MemStream *)p)->mSrcDataBytes)
116 return SZ_ERROR_PARAM;
117 ((MemStream *)p)->mCurPos = pos32;
118 }
119 else
120 return SZ_ERROR_PARAM;
121 }
122 *pos = (Int64)((MemStream *)p)->mCurPos;
123 return 0;
124 }
125
Init_MemStream(MemStream * apStream,UINT8 const * apData,UINT32 aDataBytes)126 static void Init_MemStream(MemStream *apStream, UINT8 const *apData, UINT32 aDataBytes)
127 {
128 apStream->iFace.Look = memStreamLook;
129 apStream->iFace.Read = memStreamRead;
130 apStream->iFace.Seek = memStreamSeek;
131 apStream->iFace.Skip = memStreamSkip;
132 apStream->mpSrcData = apData;
133 apStream->mSrcDataBytes = aDataBytes;
134 apStream->mCurPos = 0;
135 }
136
137 /* --------------------------------------------------------------------------------- */
138
139 #ifdef WIN32
140 #define STRNICMP _strnicmp
141 #endif
142 #ifdef EPPC
143 #define STRNICMP _mystrnicmp
144
145 /* cafe doesn't have this function so it is provided here */
_mystrnicmp(char const * apStr1,char const * apStr2,size_t len)146 static int _mystrnicmp(char const *apStr1, char const *apStr2, size_t len)
147 {
148 int c1;
149 int c2;
150
151 if (!len)
152 return 0;
153 do {
154 c1 = (int)*apStr1; if ((c1 >='a') && (c1 <='z')) c1 -= ('a'-'A');
155 c2 = (int)*apStr2; if ((c2 >='a') && (c2 <='z')) c2 -= ('a'-'A');
156 if ((!c1) && (!c2))
157 return 0;
158 if (!c1)
159 return -1;
160 if (!c2)
161 return 1;
162 c1 -= c2;
163 if (c1)
164 return c1;
165 apStr1++;
166 apStr2++;
167 } while (--len);
168 return 0;
169 }
170 #endif
171
sCompStrLens(char const * pStr1,UINT32 strLen1,char const * pStr2,UINT32 strLen2)172 static int sCompStrLens(char const *pStr1, UINT32 strLen1, char const *pStr2, UINT32 strLen2)
173 {
174 int c,v;
175
176 c = ((int)strLen2) - ((int)strLen1);
177 if (c > 0)
178 {
179 /* str2 longer than str1 */
180 c = STRNICMP(pStr1, pStr2, strLen1);
181 if (!c)
182 return -1;
183 return c;
184 }
185 v = STRNICMP(pStr1, pStr2, strLen2);
186 if (c < 0)
187 {
188 /* str2 shorter than str1 name */
189 if (!v)
190 return 1;
191 }
192 return v;
193 }
194
sComparePaths(char const * pPath1,UINT32 path1Len,char const * pPath2,UINT32 path2Len)195 static int sComparePaths(char const *pPath1, UINT32 path1Len, char const *pPath2, UINT32 path2Len)
196 {
197 char const *pSlash1;
198 char const *pSlash2;
199 UINT32 left;
200 int c;
201
202 pSlash1 = pPath1;
203 left = path1Len;
204 do {
205 if (*pSlash1 == '/')
206 break;
207 pSlash1++;
208 } while (--left);
209 if (!left)
210 pSlash1 = NULL;
211
212 pSlash2 = pPath2;
213 left = path2Len;
214 do {
215 if (*pSlash2 == '/')
216 break;
217 pSlash2++;
218 } while (--left);
219 if (!left)
220 pSlash2 = NULL;
221
222 if ((!pSlash1) && (!pSlash2))
223 return sCompStrLens(pPath1,path1Len,pPath2,path2Len);
224
225 if (pSlash1 && (!pSlash2))
226 return 1;
227 if ((!pSlash1) && (pSlash2))
228 return -1;
229
230 /* both have slashes */
231 c = sCompStrLens(pPath1, (UINT32)(pSlash1-pPath1), pPath2, (UINT32)(pSlash2-pPath2));
232 if (c)
233 return c;
234
235 /* both have slashes and are the same up to the first slash */
236 left = (UINT32)(pSlash1 - pPath1);
237
238 /* both have slashes and start with the same stuff */
239 return sComparePaths(pPath1+left+1, path1Len - (left+1), pPath2+left+1, path2Len - (left+1));
240 }
241
sCompare(void const * p1,void const * p2)242 static int sCompare(void const *p1, void const *p2)
243 {
244 SZFILE_ENTRY const * pFile1;
245 SZFILE_ENTRY const * pFile2;
246
247 pFile1 = (SZFILE_ENTRY const *)p1;
248 pFile2 = (SZFILE_ENTRY const *)p2;
249
250 if ((!pFile1->mUncompBytes) && (pFile2->mUncompBytes))
251 return -1;
252 if ((pFile1->mUncompBytes) && (!pFile2->mUncompBytes))
253 return 1;
254 return sComparePaths(pFile1->mpNameOnly, pFile1->mNameOnlyLen, pFile2->mpNameOnly, pFile2->mNameOnlyLen);
255 }
256
257 /* --------------------------------------------------------------------------------- */
258
259 struct _SZFILE_IMP
260 {
261 ISzAlloc mAllocator;
262 MemStream mMemStream;
263 SZFILE_ARC * mpArc;
264 CSzArEx mDB;
265 char * mpNames;
266 SZFILE_ENTRY * mpFiles;
267 };
268 typedef struct _SZFILE_IMP SZFILE_IMP;
269
sAlloc(void * p,size_t bytes)270 static void * sAlloc(void *p, size_t bytes)
271 {
272 if (!bytes)
273 return NULL;
274 return ((SZFILE_IMP *)p)->mpArc->mfAlloc(bytes);
275 }
276
sFree(void * p,void * address)277 static void sFree(void *p, void *address)
278 {
279 if (!address)
280 return;
281 ((SZFILE_IMP *)p)->mpArc->mfFree(address);
282 }
283
284 /* --------------------------------------------------------------------------------- */
285
sCountDirsNeeded(SZFILE_ENTRY * apFiles,UINT32 aNumFiles)286 static UINT32 sCountDirsNeeded(SZFILE_ENTRY *apFiles, UINT32 aNumFiles)
287 {
288 char const * pLook;
289 char const * pComp;
290 UINT32 left;
291 SZFILE_ENTRY * pRest;
292 UINT32 ret;
293 UINT32 subLen;
294 UINT32 numSub;
295
296 /* don't need dir for files without a slash at beginning of sorted list */
297 do {
298 pLook = apFiles->mpNameOnly;
299 left = apFiles->mNameOnlyLen;
300 do {
301 if (*pLook=='/')
302 break;
303 pLook++;
304 } while (--left);
305 if (left)
306 break;
307 apFiles++;
308 } while (--aNumFiles);
309 if (!aNumFiles)
310 return 0; /* no subdirs at this point */
311
312 pLook++;
313 subLen = (UINT32)(pLook-apFiles->mpNameOnly);
314 if (aNumFiles==1)
315 {
316 apFiles->mpNameOnly += subLen;
317 apFiles->mNameOnlyLen -= subLen;
318 return 1 + sCountDirsNeeded(apFiles, 1);
319 }
320
321 ret = 1;
322 pComp = apFiles->mpNameOnly;
323 apFiles->mpNameOnly += subLen;
324 apFiles->mNameOnlyLen -= subLen;
325 pRest = apFiles+1;
326 aNumFiles--;
327 numSub = 1;
328 do {
329 if ((pRest->mNameOnlyLen < subLen) || (STRNICMP(pRest->mpNameOnly, pComp, subLen)))
330 break;
331 pRest->mpNameOnly += subLen;
332 pRest->mNameOnlyLen -= subLen;
333 numSub++;
334 pRest++;
335 } while (--aNumFiles);
336
337 ret += sCountDirsNeeded(apFiles, numSub);
338
339 if (aNumFiles)
340 ret += sCountDirsNeeded(pRest, aNumFiles);
341
342 return ret;
343 }
344
sDirify(SZFILE_DIR * pThisDir,SZFILE_ENTRY * apFiles,UINT32 aNumFiles,SZFILE_DIR ** ppFreeDir)345 static void sDirify(SZFILE_DIR *pThisDir, SZFILE_ENTRY *apFiles, UINT32 aNumFiles, SZFILE_DIR **ppFreeDir)
346 {
347 char const * pLook;
348 char const * pComp;
349 UINT32 left;
350 SZFILE_ENTRY * pRest;
351 UINT32 subLen;
352 UINT32 numSub;
353 SZFILE_DIR * pNewDir;
354 SZFILE_DIR * pPrev;
355
356 /* don't need dir for files without a slash at beginning of sorted list */
357 pRest = apFiles;
358 subLen = 0;
359 numSub = aNumFiles;
360 do {
361 pLook = pRest->mpNameOnly;
362 left = pRest->mNameOnlyLen;
363 do {
364 if (*pLook=='/')
365 break;
366 pLook++;
367 } while (--left);
368 if (left)
369 break;
370 subLen++;
371 pRest->mpParentDir = pThisDir;
372 pRest++;
373 } while (--numSub);
374
375 if (subLen)
376 {
377 pThisDir->mpFilesArray = apFiles;
378 pThisDir->mNumFiles = subLen;
379 apFiles = pRest;
380 aNumFiles -= subLen;
381 if (!numSub)
382 return;
383 }
384 else
385 {
386 pThisDir->mpFilesArray = NULL;
387 pThisDir->mNumFiles = 0;
388 }
389
390 /* subdirs found */
391
392 pNewDir = *ppFreeDir;
393 (*ppFreeDir)++;
394
395 subLen = (UINT32)(pLook-apFiles->mpNameOnly);
396
397 pNewDir->mpArc = pThisDir->mpArc;
398 pNewDir->mpParentDir = pThisDir;
399 pNewDir->mpNameOnly = apFiles->mpNameOnly;
400 pNewDir->mNameOnlyLen = subLen;
401 pNewDir->mpNextSib = NULL;
402 if (!pThisDir->mpSubDirList)
403 pThisDir->mpSubDirList = pNewDir;
404 else
405 {
406 pPrev = pThisDir->mpSubDirList;
407 while (pPrev->mpNextSib)
408 pPrev = pPrev->mpNextSib;
409 pPrev->mpNextSib = pNewDir;
410 }
411
412 pLook++;
413 subLen++;
414
415 if (aNumFiles==1)
416 {
417 apFiles->mpNameOnly += subLen;
418 apFiles->mNameOnlyLen -= subLen;
419 sDirify(pNewDir, apFiles, 1, ppFreeDir);
420 return;
421 }
422
423 pComp = apFiles->mpNameOnly;
424 apFiles->mpNameOnly += subLen;
425 apFiles->mNameOnlyLen -= subLen;
426 pRest = apFiles+1;
427 aNumFiles--;
428 numSub = 1;
429 do {
430 if ((pRest->mNameOnlyLen < subLen) || (STRNICMP(pRest->mpNameOnly, pComp, subLen)))
431 break;
432 pRest->mpNameOnly += subLen;
433 pRest->mNameOnlyLen -= subLen;
434 numSub++;
435 pRest++;
436 } while (--aNumFiles);
437
438 sDirify(pNewDir, apFiles, numSub, ppFreeDir);
439
440 if (aNumFiles)
441 sDirify(pThisDir, pRest, aNumFiles, ppFreeDir);
442 }
443
444
SZFILE_CreateArc(SZFILE_ARC * apArc,UINT8 const * apFileData,UINT32 aFileBytes,SZFILE_pf_Alloc afAlloc,SZFILE_pf_Free afFree)445 int SZFILE_CreateArc(SZFILE_ARC *apArc, UINT8 const *apFileData, UINT32 aFileBytes, SZFILE_pf_Alloc afAlloc, SZFILE_pf_Free afFree)
446 {
447 SRes res;
448 SZFILE_IMP * pImp;
449 UINT32 fileNameSpace;
450 UINT16 const * pUnic;
451 char * pAscii;
452 SZFILE_ENTRY * pEntry;
453 UINT32 ix, ixe;
454 UINT32 jx;
455 UINT32 nzFileCount;
456 SZFILE_ENTRY * pnzFiles;
457 SZFILE_DIR * pDirs;
458 UINT32 ixFolder;
459 UINT64 folderTotalUnpackSize;
460 UINT32 folderUnpackedOffset;
461
462 if ((!apArc) || (!apFileData) || (!aFileBytes) || (!afAlloc) || (!afFree))
463 return ERRCODE_SZFILE_BADARG; // bad argument
464
465 pImp = (SZFILE_IMP *)afAlloc(sizeof(SZFILE_IMP));
466 if (!pImp)
467 return ERRCODE_SZFILE_OUTOFMEMORY; // out of memory
468
469 memset(pImp, 0, sizeof(SZFILE_IMP));
470
471 pImp->mpArc = apArc;
472 apArc->mpImp = pImp;
473 apArc->mfAlloc = afAlloc;
474 apArc->mfFree = afFree;
475 apArc->mpSrcFile = apFileData;
476 apArc->mSrcFileBytes = aFileBytes;
477
478 if (!sgCrcInit)
479 {
480 CrcGenerateTable();
481 sgCrcInit = 1;
482 }
483
484 SzArEx_Init(&pImp->mDB);
485 pImp->mAllocator.Alloc = sAlloc;
486 pImp->mAllocator.Free = sFree;
487
488 Init_MemStream(&pImp->mMemStream, apFileData, aFileBytes);
489
490 res = SzArEx_Open(&pImp->mDB, &pImp->mMemStream.iFace, &pImp->mAllocator, &pImp->mAllocator);
491 if (res != SZ_OK)
492 {
493 afFree(pImp);
494 return res;
495 }
496
497 apArc->mNumStreams = pImp->mDB.db.NumPackStreams;
498 apArc->mppUnpackedStreams = (UINT8 **)afAlloc(sizeof(UINT8 *)*apArc->mNumStreams);
499 if (!apArc->mppUnpackedStreams)
500 {
501 SZFILE_PurgeArc(apArc);
502 return ERRCODE_SZFILE_OUTOFMEMORY; // out of memory
503 }
504 memset(apArc->mppUnpackedStreams, 0, sizeof(UINT8 *) * apArc->mNumStreams);
505
506 pUnic = ((UINT16 const*)pImp->mDB.FileNames.data) + pImp->mDB.FileNameOffsets[pImp->mDB.db.NumFiles-1];
507 while (*pUnic)
508 pUnic++;
509 pUnic++;
510 fileNameSpace = (UINT32)(pUnic - (UINT16 const *)pImp->mDB.FileNames.data);
511
512 pImp->mpNames = (char *)afAlloc(fileNameSpace);
513 if (!pImp->mpNames)
514 {
515 SZFILE_PurgeArc(apArc);
516 return ERRCODE_SZFILE_OUTOFMEMORY; // out of memory
517 }
518 pAscii = pImp->mpNames;
519 pUnic = (UINT16 const *)pImp->mDB.FileNames.data;
520 do {
521 #ifdef WIN32
522 *pAscii = (UINT8)(*pUnic);
523 #endif
524 #ifdef EPPC
525 *pAscii = (UINT8)((*pUnic)>>8);
526 #endif
527 pAscii++;
528 pUnic++;
529 } while (--fileNameSpace);
530
531 pImp->mpFiles = (SZFILE_ENTRY *)afAlloc(sizeof(SZFILE_ENTRY) * pImp->mDB.db.NumFiles);
532 if (!pImp->mpFiles)
533 {
534 SZFILE_PurgeArc(apArc);
535 return ERRCODE_SZFILE_OUTOFMEMORY; // out of memory
536 }
537 memset(pImp->mpFiles, 0, sizeof(SZFILE_ENTRY) * pImp->mDB.db.NumFiles);
538
539 pEntry = pImp->mpFiles;
540 ixFolder = 0;
541 ix = pImp->mDB.FolderStartFileIndex[ixFolder];
542 if (ixFolder==pImp->mDB.db.NumFolders-1)
543 ixe = pImp->mDB.db.NumFiles;
544 else
545 ixe = pImp->mDB.FolderStartFileIndex[ixFolder+1];
546 do {
547 folderUnpackedOffset = 0;
548 folderTotalUnpackSize = 0;
549 for(jx=0;jx<pImp->mDB.db.Folders[ixFolder].NumPackStreams;jx++)
550 folderTotalUnpackSize += pImp->mDB.db.Folders[ixFolder].UnpackSizes[jx];
551 while (ix < ixe)
552 {
553 pEntry->mArcIndex = ix;
554 pEntry->mpNameOnly = pImp->mpNames + pImp->mDB.FileNameOffsets[ix];
555 pEntry->mNameOnlyLen = strlen(pEntry->mpNameOnly);
556 pEntry->mStreamIx = ixFolder;
557 pEntry->mStreamUnpackedOffset = folderUnpackedOffset;
558 pEntry->mUncompBytes = (UINT32)pImp->mDB.db.Files[ix].Size;
559 folderUnpackedOffset += pEntry->mUncompBytes;
560 pEntry++;
561 ix++;
562 }
563 if (folderUnpackedOffset != folderTotalUnpackSize)
564 {
565 SZFILE_PurgeArc(apArc);
566 return ERRCODE_SZFILE_CORRUPT;
567 }
568 ixFolder++;
569 if (ixFolder == pImp->mDB.db.NumFolders)
570 break;
571 ixe = pImp->mDB.FolderStartFileIndex[ixFolder+1];
572 } while (1);
573
574 qsort(pImp->mpFiles, pImp->mDB.db.NumFiles, sizeof(SZFILE_ENTRY), sCompare);
575
576 /* ignore empty files at the start of the sorted list */
577 nzFileCount = pImp->mDB.db.NumFiles;
578 pnzFiles = pImp->mpFiles;
579 while (!pnzFiles->mUncompBytes)
580 {
581 nzFileCount--;
582 pnzFiles++;
583 if (!nzFileCount)
584 break;
585 }
586 if (!nzFileCount)
587 {
588 SZFILE_PurgeArc(apArc);
589 return ERRCODE_SZFILE_EMPTY; // empty archive
590 }
591
592 jx = 1 + sCountDirsNeeded(pnzFiles,nzFileCount);
593
594 /* must reset name pointers and sizes so dir construction can follow same as what counting did */
595 pEntry = pnzFiles;
596 for(ix=0;ix<nzFileCount;ix++)
597 {
598 pEntry->mpNameOnly = pImp->mpNames + pImp->mDB.FileNameOffsets[pEntry->mArcIndex];
599 pEntry->mNameOnlyLen = strlen(pEntry->mpNameOnly);
600 pEntry++;
601 }
602
603 apArc->mpRootDir = (SZFILE_DIR *)afAlloc(sizeof(SZFILE_DIR) * jx);
604 if (!apArc->mpRootDir)
605 {
606 SZFILE_PurgeArc(apArc); // out of memory
607 return ERRCODE_SZFILE_OUTOFMEMORY;
608 }
609 memset(apArc->mpRootDir, 0, sizeof(SZFILE_DIR) * jx);
610 pDirs = apArc->mpRootDir;
611 pDirs->mNameOnlyLen = 0;
612 pDirs->mpArc = apArc;
613 pDirs->mpNameOnly = "";
614 pDirs++;
615 sDirify(apArc->mpRootDir, pnzFiles, nzFileCount, &pDirs);
616
617 if (pDirs != (apArc->mpRootDir+jx))
618 {
619 SZFILE_PurgeArc(apArc);
620 return ERRCODE_SZFILE_INTERNAL; // internal error
621 }
622
623 return 0;
624 }
625
sFindInDir(SZFILE_DIR * apDir,char const * apPath,SZFILE_ENTRY ** apRetEntryPtr)626 static int sFindInDir(SZFILE_DIR *apDir, char const *apPath, SZFILE_ENTRY **apRetEntryPtr)
627 {
628 char const * pSlash;
629 char c;
630 int partLen;
631 int err;
632 UINT32 ix;
633 SZFILE_ENTRY * pEntry;
634 SZFILE_DIR * pSubDir;
635
636 *apRetEntryPtr = NULL;
637
638 if (!(*apPath))
639 return ERRCODE_SZFILE_BADARG; // argument error
640
641 pSlash = apPath;
642 do {
643 c = *pSlash;
644 if ((!c) || (c=='/'))
645 break;
646 pSlash++;
647 } while (1);
648 partLen = (int)(pSlash - apPath);
649 if (!c)
650 {
651 pEntry = apDir->mpFilesArray;
652 for(ix=0;ix<apDir->mNumFiles;ix++)
653 {
654 if (pEntry->mNameOnlyLen == partLen)
655 {
656 if (!STRNICMP(apPath, apDir->mpFilesArray[ix].mpNameOnly, partLen))
657 break;
658 }
659 pEntry++;
660 }
661 if (ix != apDir->mNumFiles)
662 {
663 *apRetEntryPtr = pEntry;
664 return 0;
665 }
666 return ERRCODE_SZFILE_FILENOTFOUND; // file not found
667 }
668
669 /* there is a slash, so this part is a subdirectory */
670 pSubDir = apDir->mpSubDirList;
671 if (pSubDir)
672 {
673 do {
674 err = sFindInDir(pSubDir, apPath + partLen + 1, apRetEntryPtr);
675 if (!err)
676 return 0;
677 pSubDir = pSubDir->mpNextSib;
678 } while (pSubDir);
679 }
680
681 return ERRCODE_SZFILE_PATHNOTFOUND; /* path not found */
682 }
SZFILE_FindInArc(SZFILE_ARC * apArc,char const * apFileName,SZFILE_ENTRY ** apRetEntryPtr)683 int SZFILE_FindInArc(SZFILE_ARC *apArc, char const *apFileName, SZFILE_ENTRY **apRetEntryPtr)
684 {
685 if ((!apArc) || (!apFileName) || (!apRetEntryPtr))
686 return ERRCODE_SZFILE_BADARG;
687 while (*apFileName=='/')
688 apFileName++;
689 return sFindInDir(apArc->mpRootDir, apFileName, apRetEntryPtr);
690 }
691
SZFILE_UnpackStream(SZFILE_ARC * apArc,UINT32 aStreamIx)692 int SZFILE_UnpackStream(SZFILE_ARC *apArc, UINT32 aStreamIx)
693 {
694 SRes res;
695 SZFILE_IMP * pImp;
696 UINT32 decBytes;
697
698 if ((!apArc) || (aStreamIx >= apArc->mNumStreams))
699 return ERRCODE_SZFILE_BADARG;
700 if (apArc->mppUnpackedStreams[aStreamIx])
701 return 0;
702
703 pImp = (SZFILE_IMP *)apArc->mpImp;
704
705 decBytes = 0;
706 res = SzArEx_ExtractFolder(&pImp->mDB, &pImp->mMemStream.iFace, aStreamIx, &apArc->mppUnpackedStreams[aStreamIx], &decBytes, &pImp->mAllocator, &pImp->mAllocator);
707 if (res != SZ_OK)
708 return res;
709
710 return 0;
711 }
712
SZFILE_GetUnpackedFile(SZFILE_ENTRY * apEntry,UINT8 ** apRetDataPtr,UINT32 * apRetDataBytes)713 int SZFILE_GetUnpackedFile(SZFILE_ENTRY *apEntry, UINT8 **apRetDataPtr, UINT32 *apRetDataBytes)
714 {
715 SZFILE_ARC *pArc;
716 int err;
717
718 if (apRetDataPtr)
719 *apRetDataPtr = NULL;
720 if (apRetDataBytes)
721 *apRetDataBytes = 0;
722 if ((!apEntry) || (!apRetDataPtr) || (!apRetDataBytes))
723 return ERRCODE_SZFILE_BADARG;
724
725 pArc = apEntry->mpParentDir->mpArc;
726 if (!pArc->mppUnpackedStreams[apEntry->mStreamIx])
727 {
728 err = SZFILE_UnpackStream(pArc,apEntry->mStreamIx);
729 if (err)
730 return err;
731 }
732
733 *apRetDataPtr = pArc->mppUnpackedStreams[apEntry->mStreamIx] + apEntry->mStreamUnpackedOffset;
734 *apRetDataBytes = apEntry->mUncompBytes;
735
736 return 0;
737 }
738
SZFILE_Get(SZFILE_ARC * apArc,char const * apFileName,UINT32 * apRetFileBytes)739 UINT8 * SZFILE_Get(SZFILE_ARC *apArc, char const *apFileName, UINT32 *apRetFileBytes)
740 {
741 UINT8 * pRet;
742 SZFILE_ENTRY * pEntry;
743 int err;
744
745 if ((!apArc) || (!apFileName) || (!apRetFileBytes))
746 return NULL;
747 err = SZFILE_FindInArc(apArc, apFileName, &pEntry);
748 if (err)
749 return NULL;
750 err = SZFILE_GetUnpackedFile(pEntry, &pRet, apRetFileBytes);
751 if (err)
752 return NULL;
753 return pRet;
754 }
755
SZFILE_PurgeArc(SZFILE_ARC * apArc)756 void SZFILE_PurgeArc(SZFILE_ARC *apArc)
757 {
758 SZFILE_IMP * pImp;
759 UINT32 ix;
760
761 if (!apArc)
762 return;
763 pImp = (SZFILE_IMP *)apArc->mpImp;
764
765 if (pImp)
766 {
767 if (apArc->mpRootDir)
768 {
769 apArc->mfFree(apArc->mpRootDir);
770 apArc->mpRootDir = NULL;
771 }
772
773 if (pImp->mpFiles)
774 {
775 apArc->mfFree(pImp->mpFiles);
776 pImp->mpFiles = NULL;
777 }
778
779 if (pImp->mpNames)
780 {
781 apArc->mfFree(pImp->mpNames);
782 pImp->mpNames = NULL;
783 }
784
785 if (apArc->mppUnpackedStreams)
786 {
787 for(ix=0;ix<apArc->mNumStreams;ix++)
788 {
789 if (apArc->mppUnpackedStreams[ix])
790 pImp->mAllocator.Free(pImp, apArc->mppUnpackedStreams[ix]);
791 }
792 apArc->mfFree(apArc->mppUnpackedStreams);
793 apArc->mppUnpackedStreams = NULL;
794 }
795
796 SzArEx_Free(&pImp->mDB, &pImp->mAllocator);
797
798 apArc->mfFree(pImp);
799 apArc->mpImp = NULL;
800 }
801
802 apArc->mfAlloc = NULL;
803 apArc->mfFree = NULL;
804 apArc->mNumStreams = 0;
805 apArc->mpSrcFile = NULL;
806 apArc->mSrcFileBytes = 0;
807 }
808
809