1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     lyt_Arc.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: 31311 $
16  *---------------------------------------------------------------------------*/
17 
18 #include "precompiled.h"
19 
20 #include <nw/lyt/lyt_Arc.h>
21 #include <ctype.h>          // for tolower
22 
23 namespace nw
24 {
25 namespace lyt
26 {
27 
28 typedef struct FSTEntry FSTEntry;
29 
30 struct FSTEntry
31 {
32     unsigned int    isDirAndStringOff;    // the first byte is for isDir
33                                           // the next 3bytes: name offset
34     unsigned int    parentOrPosition;     // parent entry (dir entry)
35                                           // position (file entry)
36     unsigned int    nextEntryOrLength;    // next entry (dir entry)
37                                           // length (file entry)
38 };
39 
40 #define entryIsDir(fstStart, i)     \
41     ( ( ( fstStart[i].isDirAndStringOff & 0xff000000 ) == 0 )? false:true )
42 #define stringOff(fstStart, i)      \
43         ( fstStart[i].isDirAndStringOff & 0x00ffffff )
44 #define parentDir(fstStart, i)       \
45         ( fstStart[i].parentOrPosition )
46 #define nextDir(fstStart, i)        \
47         ( fstStart[i].nextEntryOrLength )
48 #define filePosition(fstStart, i)       \
49         ( fstStart[i].parentOrPosition )
50 #define fileLength(fstStart, i)         \
51         ( fstStart[i].nextEntryOrLength )
52 
53 namespace
54 {
55 
56 inline
57 wchar_t*
GetStringPtr(wchar_t * str,size_t offset)58 GetStringPtr(
59     wchar_t*    str,
60     size_t      offset
61 )
62 {
63     return
64         reinterpret_cast<wchar_t*>(
65             reinterpret_cast<u8*>(str) + offset
66         );
67 }
68 
69 inline
70 const wchar_t*
GetStringPtr(const wchar_t * str,size_t offset)71 GetStringPtr(
72     const wchar_t*  str,
73     size_t          offset
74 )
75 {
76     return
77         reinterpret_cast<const wchar_t*>(
78             reinterpret_cast<const u8*>(str) + offset
79         );
80 }
81 
82 #if defined(_MSC_VER) && _MSC_VER >= 1500
83     #pragma warning(push)
84     #pragma warning(disable: 4996)
85 #endif
86 
87 inline
88 size_t
WcsToMbs(char * mbstr,const wchar_t * wcstr,size_t count)89 WcsToMbs(
90    char*            mbstr,
91    const wchar_t*   wcstr,
92    size_t           count
93 )
94 {
95     return std::wcstombs(mbstr, wcstr, count);
96 }
97 
98 #if defined(_MSC_VER) && _MSC_VER >= 1500
99     #pragma warning(pop)
100 #endif
101 
102 }   // namespace
103 
ARCInitHandle(void * arcStart,ARCHandle * handle)104 bool ARCInitHandle(void* arcStart, ARCHandle* handle)
105 {
106     FSTEntry*           FSTEntries;
107     ARCHeader*          arcHeader;
108 
109     arcHeader = (ARCHeader*)arcStart;
110 
111     NN_ASSERTMSG(arcHeader->signature == DARCH_SIGNATURE,       "ARCInitHandle: bad archive format");
112     NN_ASSERTMSG(arcHeader->byteOrder == DARCH_BYTE_ORDER_MARK, "ARCInitHandle: bad archive format");
113     NN_ASSERTMSG(arcHeader->version   == DARCH_VERSION,         "ARCInitHandle: bad archive format");
114 
115     handle->archiveStartAddr = arcStart;
116     handle->FSTStart = FSTEntries = reinterpret_cast<FSTEntry*>((u32)arcStart + arcHeader->fstStart);
117     handle->fileStart = (void*)((u32)arcStart + arcHeader->fileStart);
118 
119     NN_ASSERTMSG(FSTEntries != NULL, "ARCInitHandle: bad archive format");
120 
121     handle->entryNum = nextDir(FSTEntries, 0);
122     handle->FSTStringStart = reinterpret_cast<wchar_t*>(&(FSTEntries[handle->entryNum]));
123     handle->FSTLength = (u32)arcHeader->fstSize;
124     handle->currDir = 0;
125 
126     return true;
127 }
128 
ARCOpen(ARCHandle * handle,const wchar_t * fileName,ARCFileInfo * af)129 bool ARCOpen(ARCHandle* handle, const wchar_t* fileName, ARCFileInfo* af)
130 {
131     s32         entry;
132     FSTEntry*   FSTEntries;
133 
134     NN_ASSERTMSG( handle, "ARCOpen(): NULL pointer is specified to ARCHandle structure" );
135     NN_ASSERTMSG( fileName, "ARCOpen(): NULL pointer is specified to fileName" );
136     NN_ASSERTMSG( af, "ARCOpen(): NULL pointer is specified to ARCFileInfo structure" );
137 
138     FSTEntries = (FSTEntry*)handle->FSTStart;
139 
140     entry = ARCConvertPathToEntrynum(handle, fileName);
141 
142 #if defined(NW_DEBUG)
143     if (0 > entry)
144     {
145         const size_t BufMax = 127;
146         wchar_t     currentDir[BufMax + 1];
147         char chBuf[BufMax + 1];
148         WcsToMbs(chBuf, fileName, BufMax);
149         chBuf[BufMax] = '\0';
150         NN_LOG("Warning: ARCOpen(): file '%s' was not found", chBuf);
151         ARCGetCurrentDir(handle, currentDir, BufMax + 1);
152         WcsToMbs(chBuf, currentDir, BufMax);
153         chBuf[BufMax] = '\0';
154         NN_LOG(" under %s in the archive.\n", chBuf);
155         NN_ASSERT(false);
156     }
157 #endif
158 
159     NN_ASSERTMSG( !entryIsDir(FSTEntries, entry), "ARCOpen(): %s is a directory", fileName );
160 
161     if ( (entry < 0) || entryIsDir(FSTEntries, entry) )
162     {
163         return false;
164     }
165 
166     af->handle      = handle;
167     af->startOffset = filePosition(FSTEntries, entry);
168     af->length      = fileLength(FSTEntries, entry);
169 
170     return true;
171 }
172 
ARCFastOpen(ARCHandle * handle,s32 entrynum,ARCFileInfo * af)173 bool ARCFastOpen(ARCHandle* handle, s32 entrynum, ARCFileInfo* af)
174 {
175     FSTEntry*           FSTEntries;
176 
177     NN_ASSERTMSG(handle, "ARCFastOpen(): null pointer is specified to ARCHandle address  ");
178     NN_ASSERTMSG(af,
179               "ARCFastOpen(): null pointer is specified to ARCFileInfo address  ");
180     NN_ASSERTMSG((0 <= entrynum) && (entrynum < static_cast<s32>(handle->entryNum)),
181                "ARCFastOpen(): specified entry number '%d' is out of range  ",
182                entrynum);
183 
184     FSTEntries = (FSTEntry*)handle->FSTStart;
185 
186     NN_ASSERTMSG(!entryIsDir(FSTEntries, entrynum),
187                "ARCFastOpen(): entry number '%d' is assigned to a directory  ",
188                entrynum);
189 
190     if ( (entrynum < 0) || (entrynum >= static_cast<s32>(handle->entryNum)) ||
191          entryIsDir(FSTEntries, entrynum) )
192     {
193         return false;
194     }
195 
196     af->handle      = handle;
197     af->startOffset = filePosition(FSTEntries, entrynum);
198     af->length      = fileLength(FSTEntries, entrynum);
199 
200     return true;
201 }
202 
203  /*---------------------------------------------------------------------------*
204     Description:        compare two strings up to the first string hits '/' or
205                         '\0'
206 
207     Arguments:          path     path name
208                         string   directory or file name
209 
210     Returns:            true if same, false if not
211  *---------------------------------------------------------------------------*/
isSame(const wchar_t * path,const wchar_t * string)212 static bool isSame(const wchar_t* path, const wchar_t* string)
213 {
214     while(*string != '\0')
215     {
216         // compare in case-insensitive
217         if (tolower(*path++) != tolower(*string++))
218         {
219             return false;
220         }
221     }
222 
223     if ( (*path == '/') || (*path == '\0') )
224     {
225         return true;
226     }
227 
228     return false;
229 }
230 
231 
ARCConvertPathToEntrynum(ARCHandle * handle,const wchar_t * pathPtr)232 s32 ARCConvertPathToEntrynum(ARCHandle* handle, const wchar_t* pathPtr)
233 {
234     const wchar_t* ptr;
235     wchar_t*     stringPtr;
236     bool         isDir;
237     s32          length; // must be signed
238     u32          dirLookAt;
239     u32          i;
240     const wchar_t*  origPathPtr = pathPtr;
241     FSTEntry*    FSTEntries;
242 
243 
244     NN_ASSERTMSG(handle, "ARCConvertPathToEntrynum(): null pointer is specified to ARCHandle structure");
245     NN_ASSERTMSG(pathPtr, "ARCConvertPathToEntrynum(): null pointer is specified to file name");
246 
247 
248     dirLookAt = handle->currDir;
249     FSTEntries = (FSTEntry*)handle->FSTStart;
250 
251     while (1)
252     {
253 
254         // check /, ./, ../
255         if (*pathPtr == '\0')
256         {
257             return (s32)dirLookAt;
258         } else if (*pathPtr == '/')
259         {
260             dirLookAt = 0;
261             pathPtr++;
262             continue;
263         }
264         else if (*pathPtr == '.')
265         {
266             if (*(pathPtr + 1) == '.')
267             {
268                 if (*(pathPtr + 2) == '/')
269                 {
270                     dirLookAt = parentDir(FSTEntries, dirLookAt);
271                     pathPtr += 3;
272                     continue;
273                 }
274                 else if (*(pathPtr + 2) == '\0')
275                 {
276                     return (s32)parentDir(FSTEntries, dirLookAt);
277                 }
278             }
279             else if (*(pathPtr + 1) == '/')
280             {
281                 pathPtr += 2;
282                 continue;
283             }
284             else if (*(pathPtr + 1) == '\0')
285             {
286                 return (s32)dirLookAt;
287             }
288         }
289 
290         // directory or file? Can be checked by the endmark
291         for(ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++)
292             ;
293 
294         // it's true that one ends with '/' should be a directory name,
295         // but one ends with '\0' is not always a file name.
296         isDir = (*ptr == '\0')? false : true;
297         length = (s32)(ptr - pathPtr);
298 
299         ptr = pathPtr;
300 
301         for(i = dirLookAt + 1; i < nextDir(FSTEntries, dirLookAt);
302             i = entryIsDir(FSTEntries, i)? nextDir(FSTEntries, i): (i+1) )
303         {
304 dot:
305             // isDir == false doesn't mean it's a file.
306             // so it's legal to compare it to a directory
307             if ( ( entryIsDir(FSTEntries, i) == false ) &&
308                  (isDir == true) )
309             {
310                 continue;
311             }
312 
313             stringPtr = GetStringPtr(handle->FSTStringStart, stringOff(FSTEntries, i));
314 
315             // check "."
316             // support archive files created by "darch[D] -c ."
317             if (*stringPtr == '.' && *(stringPtr + 1) == '\0') {
318                 i++;
319                 goto dot;
320             }
321 
322             if ( isSame(ptr, stringPtr) == true )
323             {
324                 goto next_hier;
325             }
326 
327         } // for()
328 
329         return -1;
330 
331       next_hier:
332         if (! isDir)
333         {
334             return (s32)i;
335         }
336 
337         dirLookAt = i;
338         pathPtr += length + 1;
339 
340     } // while (1)
341 
342     // NOT REACHED
343 }
344 
ARCEntrynumIsDir(const ARCHandle * handle,s32 entrynum)345 bool  ARCEntrynumIsDir( const ARCHandle * handle, s32 entrynum )
346 {
347     FSTEntry*           FSTEntries;
348 
349     NN_ASSERTMSG(handle, "ARCEntrynumIsDir(): null pointer is specified to ARCHandle structure");
350     NN_ASSERTMSG((entrynum >= 0) , "ARCEntrynumIsDir(): no file/directory is specified to entrynum");
351     FSTEntries = (FSTEntry*)handle->FSTStart;
352 
353     return entryIsDir( FSTEntries, entrynum );
354 }
355 
356 /*---------------------------------------------------------------------------*
357   Name:         myStrncpy
358 
359   Description:  copy a string. Difference from standard strncpy is:
360                     1. do not pad dest with null characters
361                     2. do not terminate dest with a null
362                     3. return the number of chars copied
363 
364   Arguments:    dest        destination
365                 src         source
366                 maxlen      maximum length of copy
367 
368   Returns:      Num of chars copied
369  *---------------------------------------------------------------------------*/
myStrncpy(wchar_t * dest,wchar_t * src,u32 maxlen)370 static u32 myStrncpy(wchar_t* dest, wchar_t* src, u32 maxlen)
371 {
372     u32         i = maxlen;
373 
374     while( (i > 0) && (*src != 0) )
375     {
376         *dest++ = *src++;
377         i--;
378     }
379 
380     return (maxlen - i);
381 }
382 
383 /*---------------------------------------------------------------------------*
384   Name:         entryToPath
385 
386   Description:  Convert from fst entry to path. The result is not null
387                 terminated.
388 
389   Arguments:    entry       FST entry
390                 path        pointer to store the result
391                 maxlen      size of the buffer start from path
392 
393   Returns:      Num of chars copied
394  *---------------------------------------------------------------------------*/
entryToPath(ARCHandle * handle,u32 entry,wchar_t * path,u32 maxlen)395 static u32 entryToPath(ARCHandle* handle, u32 entry, wchar_t* path, u32 maxlen)
396 {
397     wchar_t*    name;
398     u32         loc;
399     FSTEntry*    FSTEntries;
400 
401     FSTEntries = (FSTEntry*)handle->FSTStart;
402 
403     if (entry == 0)
404     {
405         return 0;
406     }
407 
408     name = GetStringPtr(handle->FSTStringStart, stringOff(FSTEntries, entry));
409 
410     loc = entryToPath(handle, parentDir(FSTEntries, entry), path, maxlen);
411 
412     if (loc == maxlen)
413     {
414         return loc;
415     }
416 
417     *(path + loc++) = '/';
418 
419     loc += myStrncpy(path + loc, name, maxlen - loc);
420 
421     return loc;
422 }
423 
424 
425 /*---------------------------------------------------------------------------*
426   Name:         ARCConvertEntrynumToPath
427 
428   Description:  Convert from fst entry to path.
429 
430   Arguments:    entrynum    FST entry
431                 path        pointer to store the result
432                 maxlen      size of the buffer start from path
433 
434   Returns:      true if all the path fits in maxlen. false if not (in this
435                 case, it's truncated to fit maxlen).
436  *---------------------------------------------------------------------------*/
ARCConvertEntrynumToPath(ARCHandle * handle,s32 entrynum,wchar_t * path,u32 maxlen)437 static bool ARCConvertEntrynumToPath(ARCHandle* handle, s32 entrynum, wchar_t* path, u32 maxlen)
438 {
439     u32         loc;
440     FSTEntry*    FSTEntries;
441 
442 
443     FSTEntries = (FSTEntry*)handle->FSTStart;
444     NN_ASSERTMSG((0 <= entrynum) && (entrynum < static_cast<s32>(handle->entryNum)),
445                "ARCConvertEntrynumToPath: specified entrynum(%d) is out of range  ",
446                 entrynum );
447     NN_ASSERTMSG(1 < maxlen, "ARCConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)",
448                maxlen );
449     // currently only directories can be converted to path
450     // finding the directory where a file is located is not so easy
451     // while finding the parent directory of a directory is a piece of cake.
452     NN_ASSERTMSG(entryIsDir(FSTEntries, entrynum),
453               "ARCConvertEntrynumToPath: cannot convert an entry num for a file to path  ");
454 
455     loc = entryToPath(handle, (u32)entrynum, path, maxlen);
456 
457     if (loc == maxlen)
458     {
459         // Overwrite the last char with NULL
460         path[maxlen - 1] = '\0';
461         return false;
462     }
463 
464     // For directories, put '/' at the last
465     if (entryIsDir(FSTEntries, entrynum))
466     {
467         if (loc == maxlen - 1)
468         {
469             // There's no room to put the last '/', so just put '\0' and return false
470             path[loc] = '\0';
471             return false;
472         }
473 
474         path[loc++] = '/';
475     }
476 
477     path[loc] = '\0';
478     return true;
479 }
480 
481 /*---------------------------------------------------------------------------*
482   Name:         ARCGetCurrentDir
483 
484   Description:  Get current directory
485 
486   Arguments:    path        pointer to store the result
487                 maxlen      size of the buffer start from path
488 
489   Returns:      true if all the path fits in maxlen. false if not (in this
490                 case, it's truncated to fit maxlen).
491  *---------------------------------------------------------------------------*/
ARCGetCurrentDir(ARCHandle * handle,wchar_t * path,u32 maxlen)492 bool ARCGetCurrentDir(ARCHandle* handle, wchar_t* path, u32 maxlen)
493 {
494     NN_ASSERTMSG( 1 < maxlen, "ARCGetCurrentDir: maxlen should be more than 1 (%d is specified)",
495                 maxlen );
496 
497     return ARCConvertEntrynumToPath(handle, (s32)handle->currDir, path, maxlen);
498 }
499 
ARCGetStartAddrInMem(ARCFileInfo * af)500 void* ARCGetStartAddrInMem(ARCFileInfo* af)
501 {
502     ARCHandle* handle;
503 
504     handle = af->handle;
505 
506     NN_ASSERTMSG(handle, "ARCGetFileAddr(): af->handle is null pointer. Maybe it's not initialized properly");
507     NN_ASSERTMSG(af, "ARCGetFileAddr(): null pointer is specified to ARCFileInfo structure");
508 
509     return (void*)( (u32)handle->archiveStartAddr + af->startOffset );
510 }
511 
ARCGetStartOffset(ARCFileInfo * af)512 u32 ARCGetStartOffset(ARCFileInfo* af)
513 {
514     return af->startOffset;
515 }
516 
ARCGetLength(ARCFileInfo * af)517 u32 ARCGetLength(ARCFileInfo* af)
518 {
519     return af->length;
520 }
521 
522 
ARCClose(ARCFileInfo * af)523 bool ARCClose(ARCFileInfo* af)
524 {
525     NN_UNUSED_VAR(af);
526 
527     return true;
528 }
529 
ARCChangeDir(ARCHandle * handle,const wchar_t * dirName)530 bool ARCChangeDir(ARCHandle* handle, const wchar_t* dirName)
531 {
532     s32         entry;
533     FSTEntry*   FSTEntries;
534 
535     NN_ASSERTMSG(handle, "ARCChangeDir(): null pointer is specified to ARCHandle");
536     NN_ASSERTMSG(dirName, "ARCChangeDir(): null pointer is specified to dirname");
537 
538     entry = ARCConvertPathToEntrynum(handle, dirName);
539     FSTEntries = (FSTEntry*)handle->FSTStart;
540 
541 #if defined(NW_DEBUG)
542     if (0 > entry)
543     {
544         const size_t BufMax = 127;
545         wchar_t currentDir[BufMax + 1];
546         char chBuf[BufMax + 1];
547         WcsToMbs(chBuf, dirName, BufMax);
548         chBuf[BufMax] = '\0';
549         NN_LOG("ARCOpendir(): directory '%s' is not found", chBuf);
550         ARCGetCurrentDir(handle, currentDir, BufMax + 1);
551         WcsToMbs(chBuf, currentDir, BufMax);
552         chBuf[BufMax] = '\0';
553         NN_LOG(" under %s  ", chBuf);
554         NN_ASSERT(false);
555     }
556 #endif
557     NN_ASSERTMSG(entryIsDir(FSTEntries, entry), "ARCChangeDir(): %s is not a directory", dirName );
558 
559     if ( (entry < 0) || (entryIsDir(FSTEntries, entry) == false) )
560     {
561         return false;
562     }
563 
564     handle->currDir = (u32)entry;
565 
566     return true;
567 }
568 
ARCChangeDir(ARCHandle * handle,s32 entrynum)569 bool ARCChangeDir(ARCHandle* handle, s32 entrynum)
570 {
571     NN_ASSERTMSG(
572         handle != NULL,
573         "ARCChangeDir(): null pointer is specified to ARCHandle address");
574 
575     NN_ASSERTMSG(
576         (0 <= entrynum) && (entrynum < static_cast<s32>(handle->entryNum)),
577         "ARCChangeDir(): specified entry number '%d' is out of range",
578         entrynum);
579 
580     FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart;
581 
582     NN_ASSERTMSG(
583         entryIsDir(FSTEntries, entrynum),
584         "ARCChangeDir(): %s entry[%d] a regular file", entrynum);
585 
586     if (handle == NULL)
587     {
588         return false;
589     }
590 
591     if (entrynum < 0 || static_cast<s32>(handle->entryNum) <= entrynum)
592     {
593         return false;
594     }
595 
596     if (!entryIsDir(FSTEntries, entrynum))
597     {
598         return false;
599     }
600 
601     handle->currDir = (u32)entrynum;
602 
603     return true;
604 }
605 
ARCOpenDir(ARCHandle * handle,const wchar_t * dirName,ARCDir * dir)606 bool ARCOpenDir(ARCHandle* handle, const wchar_t* dirName, ARCDir* dir)
607 {
608     s32         entry;
609     FSTEntry*   FSTEntries;
610 
611     NN_ASSERTMSG(handle, "ARCOpenDir(): null pointer is specified to ARCHandle");
612     NN_ASSERTMSG(dirName, "ARCOpenDir(): null pointer is specified to ARCDir");
613 
614     entry = ARCConvertPathToEntrynum(handle, dirName);
615     FSTEntries = (FSTEntry*)handle->FSTStart;
616 
617 #if defined(NW_DEBUG)
618     if (entry < 0)
619     {
620         const size_t BufMax = 127;
621         wchar_t currentDir[BufMax + 1];
622         char chBuf[BufMax + 1];
623         WcsToMbs(chBuf, dirName, BufMax);
624         chBuf[BufMax] = '\0';
625         NN_LOG("ARCOpenDir(): directory '%s' is not found", chBuf);
626         ARCGetCurrentDir(handle, currentDir, BufMax + 1);
627         WcsToMbs(chBuf, currentDir, BufMax);
628         chBuf[BufMax] = '\0';
629         NN_LOG(" under %s  ", chBuf);
630         NN_ASSERT(false);
631     }
632 #endif
633 
634     NN_ASSERTMSG( entryIsDir(FSTEntries, entry), "ARCOpenDir(): %s is a regular file", dirName );
635 
636     if ( (entry < 0) || (entryIsDir(FSTEntries, entry) == false) )
637         return false;
638 
639     dir->handle = handle;
640     dir->entryNum = (u32)entry;
641     dir->location = (u32)entry + 1;
642     dir->next = nextDir(FSTEntries, entry);
643 
644     return true;
645 }
646 
ARCOpenDir(ARCHandle * handle,s32 entrynum,ARCDir * dir)647 bool ARCOpenDir(ARCHandle* handle, s32 entrynum, ARCDir* dir)
648 {
649     NN_ASSERTMSG(
650         handle != NULL,
651         "ARCOpenDir(): null pointer is specified to ARCHandle address");
652 
653     NN_ASSERTMSG(
654         (0 <= entrynum) && (entrynum < static_cast<s32>(handle->entryNum)),
655         "ARCOpenDir(): specified entry number '%d' is out of range",
656         entrynum);
657 
658     FSTEntry* FSTEntries = (FSTEntry*)handle->FSTStart;
659 
660     NN_ASSERTMSG(
661         entryIsDir(FSTEntries, entrynum),
662         "ARCOpenDir(): %s entry[%d] a regular file", entrynum);
663 
664     if (handle == NULL)
665     {
666         return false;
667     }
668 
669     if (entrynum < 0 || static_cast<s32>(handle->entryNum) <= entrynum)
670     {
671         return false;
672     }
673 
674     if (!entryIsDir(FSTEntries, entrynum))
675     {
676         return false;
677     }
678 
679     dir->handle = handle;
680     dir->entryNum = (u32)entrynum;
681     dir->location = (u32)entrynum + 1;
682     dir->next = nextDir(FSTEntries, entrynum);
683 
684     return true;
685 }
686 
ARCReadDir(ARCDir * dir,ARCDirEntry * dirent)687 bool ARCReadDir(ARCDir* dir, ARCDirEntry* dirent)
688 {
689     u32         loc;
690     FSTEntry*   FSTEntries;
691     ARCHandle*  handle;
692 
693     handle = dir->handle;
694 
695     NN_ASSERTMSG(handle, "ARCReadDir: dir->handle is null pointer. Maybe it's not initialized properly");
696 
697     FSTEntries = (FSTEntry*)handle->FSTStart;
698 
699     // Check the next location. loc == dir->next means it reached the
700     // end of the directory. Other check is for illegal setting by ARCSeekDir.
701     loc = dir->location;
702 retry:
703     if ( (loc <= dir->entryNum) || (dir->next <= loc) )
704         return false;
705 
706     dirent->handle = handle;
707     dirent->entryNum = loc;
708     dirent->isDir = entryIsDir(FSTEntries, loc);
709     dirent->name = GetStringPtr(handle->FSTStringStart, stringOff(FSTEntries, loc));
710 
711     // check "."
712     // support archive files created by "darch[D] -c ."
713     if (dirent->name[0] == '.' && dirent->name[1] == '\0') {
714         loc++;
715         goto retry;
716     }
717 
718     dir->location = entryIsDir(FSTEntries, loc)? nextDir(FSTEntries, loc) : (loc+1);
719 
720     return true;
721 }
722 
ARCCloseDir(ARCDir * dir)723 bool ARCCloseDir(ARCDir* dir)
724 {
725     NN_UNUSED_VAR(dir);
726 
727     return true;
728 }
729 
730 } // namespace lyt
731 } // namespace nw
732