1 /*---------------------------------------------------------------------------*
2 
3   Copyright (C) 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