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