1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_romfat_default.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-12-08#$
14   $Rev: 9544 $
15   $Author: yosizaki $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro/fs.h>
21 
22 #include <nitro/mi/memory.h>
23 #include <nitro/math/math.h>
24 #include <nitro/std.h>
25 
26 
27 #include "../include/util.h"
28 #include "../include/command.h"
29 #include "../include/rom.h"
30 
31 
32 #if defined(FS_IMPLEMENT)
33 
34 
35 /*---------------------------------------------------------------------------*/
36 /* Declarations */
37 
38 // Synchronous system command blocking read structure
39 typedef struct FSiSyncReadParam
40 {
41     FSArchive  *arc;
42     u32         pos;
43 }
44 FSiSyncReadParam;
45 
46 // Bit and alignment macros
47 #define	BIT_MASK(n)	((1 << (n)) - 1)
48 
49 
50 /*---------------------------------------------------------------------------*/
51 /* functions */
52 
53 /*---------------------------------------------------------------------------*
54   Name:         FSi_SeekAndReadSRL
55 
56   Description:  SRL access callback called from the ROM hash context
57 
58   Arguments:    userdata         Any user-defined data
59                 buffer            Transfer destination buffer
60                 offset            Transfer source ROM offset
61                 length           Transfer size
62 
63   Returns:      Size of the transmission
64  *---------------------------------------------------------------------------*/
FSi_SeekAndReadSRL(void * userdata,void * buffer,u32 offset,u32 length)65 static int FSi_SeekAndReadSRL(void *userdata, void *buffer, u32 offset, u32 length)
66 {
67     FSFile     *file = (FSFile*)userdata;
68     if (file)
69     {
70         (void)FS_SeekFile(file, (int)offset, FS_SEEK_SET);
71         (void)FS_ReadFile(file, buffer, (int)length);
72     }
73     return (int)length;
74 }
75 
76 /*---------------------------------------------------------------------------*
77   Name:         FSi_GetTemporaryFileContext
78 
79   Description:  Gets dummy FSFile structure temporarily used by commands that do not directly operate files or directories
80 
81 
82   Arguments:    arc              Associated archive
83 
84   Returns:      Pointer of the FSFile structure.
85  *---------------------------------------------------------------------------*/
FSi_GetTemporaryFileContext(FSArchive * arc)86 static FSFile* FSi_GetTemporaryFileContext(FSArchive *arc)
87 {
88     static FSFile   tmp[1];
89     FS_InitFile(tmp);
90     tmp->arc = arc;
91     return tmp;
92 }
93 
94 /*---------------------------------------------------------------------------*
95   Name:         FSi_TranslateCommand
96 
97   Description:  Calls a user procedure or the default process and returns the result.
98                 If a synchronous command returns an asynchronous response, wait for completion internally.
99                 If an asynchronous command returns an asynchronous response, return it as is.
100 
101   Arguments:    p_file           FSFile structure in which the command argument is stored
102                 Command: Command ID
103                 block		TRUE if blocking
104 
105   Returns:      Command processing result.
106  *---------------------------------------------------------------------------*/
107 static FSResult FSi_TranslateCommand(FSFile *p_file, FSCommandType command, BOOL block);
108 
109 /*---------------------------------------------------------------------------*
110   Name:         FSi_ReadTable
111 
112   Description:  Execute synchronous Read inside synchronous-type command
113 
114   Arguments:    p                Synchronous read structure
115                 dst              Read data storage destination buffer
116                 len              Number of bytes to read
117 
118   Returns:      Result of synchronous read
119  *---------------------------------------------------------------------------*/
FSi_ReadTable(FSiSyncReadParam * p,void * dst,u32 len)120 static FSResult FSi_ReadTable(FSiSyncReadParam * p, void *dst, u32 len)
121 {
122     FSResult                result;
123     FSArchive       * const arc = p->arc;
124     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
125 
126 
127     if (context->load_mem)
128     {
129         MI_CpuCopy8((const void *)p->pos, dst, len);
130         result = FS_RESULT_SUCCESS;
131     }
132     else
133     {
134         result = (*context->read_func) (arc, dst, p->pos, len);
135         result = FSi_WaitForArchiveCompletion(arc->list, result);
136     }
137     p->pos += len;
138     return result;
139 }
140 
141 /*---------------------------------------------------------------------------*
142   Name:         FSi_SeekDirDirect
143 
144   Description:  Directly moves to beginning of specified directory
145 
146   Arguments:    file            Pointer that stores directory list
147                 id               Directory ID
148 
149   Returns:      None.
150  *---------------------------------------------------------------------------*/
FSi_SeekDirDirect(FSFile * file,u32 id)151 static void FSi_SeekDirDirect(FSFile *file, u32 id)
152 {
153     file->arg.seekdir.pos.arc = file->arc;
154     file->arg.seekdir.pos.own_id = (u16)id;
155     file->arg.seekdir.pos.index = 0;
156     file->arg.seekdir.pos.pos = 0;
157     (void)FSi_TranslateCommand(file, FS_COMMAND_SEEKDIR, TRUE);
158 }
159 
160 /*---------------------------------------------------------------------------*
161   Name:         FSi_SeekDirDefault
162 
163   Description:  Default implementation of SEEKDIR command
164 
165   Arguments:    file           Handle to process command
166 
167   Returns:      Command result value
168  *---------------------------------------------------------------------------*/
FSi_SeekDirDefault(FSFile * file)169 static FSResult FSi_SeekDirDefault(FSFile *file)
170 {
171     FSResult                result;
172     FSArchive       * const arc = file->arc;
173     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
174 
175     const FSDirPos  * const arg = &file->arg.seekdir.pos;
176     FSArchiveFNT            fnt;
177     FSiSyncReadParam        param;
178     param.arc = arc;
179     param.pos = context->fnt + arg->own_id * sizeof(fnt);
180     result = FSi_ReadTable(&param, &fnt, sizeof(fnt));
181     if (result == FS_RESULT_SUCCESS)
182     {
183         file->prop.dir.pos = *arg;
184         if ((arg->index == 0) && (arg->pos == 0))
185         {
186             file->prop.dir.pos.index = fnt.index;
187             file->prop.dir.pos.pos = context->fnt + fnt.start;
188         }
189         file->prop.dir.parent = (u32)(fnt.parent & BIT_MASK(12));
190     }
191     return result;
192 }
193 
194 /*---------------------------------------------------------------------------*
195   Name:         FSi_ReadDirDefault
196 
197   Description:  Default implementation of READDIR command
198 
199   Arguments:    file           Handle to process command
200 
201   Returns:      Command result value
202  *---------------------------------------------------------------------------*/
FSi_ReadDirDefault(FSFile * file)203 static FSResult FSi_ReadDirDefault(FSFile *file)
204 {
205     FSResult                result;
206     FSDirEntry             *entry = file->arg.readdir.p_entry;
207     u8                      len;
208 
209     FSiSyncReadParam        param;
210     param.arc = file->arc;
211     param.pos = file->prop.dir.pos.pos;
212 
213     result = FSi_ReadTable(&param, &len, sizeof(len));
214 
215     if (result == FS_RESULT_SUCCESS)
216     {
217         entry->name_len = (u32)(len & BIT_MASK(7));
218         entry->is_directory = (u32)((len >> 7) & 1);
219         if (entry->name_len == 0)
220         {
221             result = FS_RESULT_FAILURE;
222         }
223         else
224         {
225             if (!file->arg.readdir.skip_string)
226             {
227                 result = FSi_ReadTable(&param, entry->name, entry->name_len);
228                 if (result != FS_RESULT_SUCCESS)
229                 {
230                     return result;
231                 }
232                 entry->name[entry->name_len] = '\0';
233             }
234             else
235             {
236                 param.pos += entry->name_len;
237             }
238             if (!entry->is_directory)
239             {
240                 entry->file_id.arc = file->arc;
241                 entry->file_id.file_id = file->prop.dir.pos.index;
242                 ++file->prop.dir.pos.index;
243             }
244             else
245             {
246                 u16     id;
247                 result = FSi_ReadTable(&param, &id, sizeof(id));
248                 if (result == FS_RESULT_SUCCESS)
249                 {
250                     entry->dir_id.arc = file->arc;
251                     entry->dir_id.own_id = (u16)(id & BIT_MASK(12));
252                     entry->dir_id.index = 0;
253                     entry->dir_id.pos = 0;
254                 }
255             }
256             if (result == FS_RESULT_SUCCESS)
257             {
258                 file->prop.dir.pos.pos = param.pos;
259             }
260         }
261     }
262 
263     return result;
264 }
265 
266 /*---------------------------------------------------------------------------*
267   Name:         FSi_FindPathDefault
268 
269   Description:  Default implementation of FINDPATH command
270                 (Uses SEEKDIR, READDIR  commands)
271 
272   Arguments:    p_dir           Handle to process command
273 
274   Returns:      Command result value
275  *---------------------------------------------------------------------------*/
FSi_FindPathDefault(FSFile * p_dir)276 static FSResult FSi_FindPathDefault(FSFile *p_dir)
277 {
278     const char *path = p_dir->arg.findpath.path;
279     const BOOL  is_dir = p_dir->arg.findpath.find_directory;
280 
281     // Path name search based on specified directory
282     p_dir->arg.seekdir.pos = p_dir->arg.findpath.pos;
283     (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR, TRUE);
284     for (; *path; path += (*path ? 1 : 0))
285     {
286         // Extract the entry name targeted for the search
287         int     name_len = FSi_IncrementSjisPositionToSlash(path, 0);
288         u32     is_directory = ((path[name_len] != '\0') || is_dir);
289         // If an illegal directory such as "//" is detected, failure
290         if (name_len == 0)
291         {
292             return FS_RESULT_INVALID_PARAMETER;
293         }
294         // Special directory specification
295         else if (*path == '.')
296         {
297             // "." is the current directory
298             if (name_len == 1)
299             {
300                 path += 1;
301                 continue;
302             }
303             // ".." is the parent directory
304             else if ((name_len == 2) & (path[1] == '.'))
305             {
306                 if (p_dir->prop.dir.pos.own_id != 0)
307                 {
308                     FSi_SeekDirDirect(p_dir, p_dir->prop.dir.parent);
309                 }
310                 path += 2;
311                 continue;
312             }
313         }
314         else if (*path == '*')
315         {
316             // "*" specifies a wildcard (Ignore this with the archive procedure)
317             break;
318         }
319         // If an entry name that is too long is detected, failure
320         if (name_len > FS_FILE_NAME_MAX)
321         {
322             return FS_RESULT_NO_ENTRY;
323         }
324         // Enumerate entries and sequentially compare
325         else
326         {
327             FSDirEntry etr;
328             p_dir->arg.readdir.p_entry = &etr;
329             p_dir->arg.readdir.skip_string = FALSE;
330             for (;;)
331             {
332                 // If corresponding entry did not exist even when the end is reached, failure
333                 if (FSi_TranslateCommand(p_dir, FS_COMMAND_READDIR, TRUE) != FS_RESULT_SUCCESS)
334                 {
335                     return FS_RESULT_NO_ENTRY;
336                 }
337                 // If there is no match, ingore
338                 if ((is_directory == etr.is_directory) &&
339                     (name_len == etr.name_len) && (FSi_StrNICmp(path, etr.name, (u32)name_len) == 0))
340                 {
341                     // If directory, move to the top again
342                     if (is_directory)
343                     {
344                         path += name_len;
345                         p_dir->arg.seekdir.pos = etr.dir_id;
346                         (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR, TRUE);
347                         break;
348                     }
349                     // If it is a file and expecting a directory, failure
350                     else if (is_dir)
351                     {
352                         return FS_RESULT_NO_ENTRY;
353                     }
354                     // Discover the file
355                     else
356                     {
357                         *p_dir->arg.findpath.result.file = etr.file_id;
358                         return FS_RESULT_SUCCESS;
359                     }
360                 }
361             }
362         }
363     }
364     // If file cannot be found, failure
365     if (!is_dir)
366     {
367         return FS_RESULT_NO_ENTRY;
368     }
369     else
370     {
371         *p_dir->arg.findpath.result.dir = p_dir->prop.dir.pos;
372         return FS_RESULT_SUCCESS;
373     }
374 }
375 
376 /*---------------------------------------------------------------------------*
377   Name:         FSi_GetPathDefault
378 
379   Description:  Default implementation of GETPATH command
380                 (Uses SEEKDIR, READDIR  commands)
381 
382   Arguments:    file           Handle to process command
383 
384   Returns:      Command result value
385  *---------------------------------------------------------------------------*/
FSi_GetPathDefault(FSFile * file)386 static FSResult FSi_GetPathDefault(FSFile *file)
387 {
388     FSResult            result;
389     FSArchive   * const arc = file->arc;
390     FSFile             *tmp = FSi_GetTemporaryFileContext(arc);
391     FSGetPathInfo      *p_info = &file->arg.getpath;
392     FSDirEntry          entry;
393     u32                 dir_id;
394     u32                 file_id;
395 
396     enum
397     { INVALID_ID = 0x10000 };
398 
399     if (FS_IsDir(file))
400     {
401         dir_id = file->prop.dir.pos.own_id;
402         file_id = INVALID_ID;
403     }
404     else
405     {
406         file_id = file->prop.file.own_id;
407         {
408             // Search for all directories from root
409             u32     pos = 0;
410             u32     num_dir = 0;
411             dir_id = INVALID_ID;
412             do
413             {
414                 FSi_SeekDirDirect(tmp, pos);
415                 // Get total directory count first time
416                 if (!pos)
417                 {
418                     num_dir = tmp->prop.dir.parent;
419                 }
420                 tmp->arg.readdir.p_entry = &entry;
421                 tmp->arg.readdir.skip_string = TRUE;
422                 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
423                 {
424                     if (!entry.is_directory && (entry.file_id.file_id == file_id))
425                     {
426                         dir_id = tmp->prop.dir.pos.own_id;
427                         break;
428                     }
429                 }
430             }
431             while ((dir_id == INVALID_ID) && (++pos < num_dir));
432         }
433     }
434 
435     // FALSE if the corresponding directory cannot be found
436     if (dir_id == INVALID_ID)
437     {
438         p_info->total_len = 0;
439         result = FS_RESULT_NO_ENTRY;
440     }
441     else
442     {
443         // If path length not calculated, measure once this time
444         {
445             u32         id = dir_id;
446             // First, add "archive name:/"
447             const char *arcname = FS_GetArchiveName(arc);
448             u32         len = (u32)STD_GetStringLength(arcname);
449             len += 2;
450             // Move to standard directory
451             FSi_SeekDirDirect(tmp, id);
452             // If necessary, add file name. (Already obtained)
453             if (file_id != INVALID_ID)
454             {
455                 len += entry.name_len;
456             }
457             // Trace back in order and add own name
458             if (id != 0)
459             {
460                 do
461                 {
462                     // Move to parent and search self
463                     FSi_SeekDirDirect(tmp, tmp->prop.dir.parent);
464                     tmp->arg.readdir.p_entry = &entry;
465                     tmp->arg.readdir.skip_string = TRUE;
466                     while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
467                     {
468                         if (entry.is_directory && (entry.dir_id.own_id == id))
469                         {
470                             len += entry.name_len + 1;
471                             break;
472                         }
473                     }
474                     id = tmp->prop.dir.pos.own_id;
475                 }
476                 while (id != 0);
477             }
478             // Save the currently calculated data
479             p_info->total_len = (u16)(len + 1);
480             p_info->dir_id = (u16)dir_id;
481         }
482 
483         // Success if measuring path length is the objective
484         if (!p_info->buf)
485         {
486             result = FS_RESULT_SUCCESS;
487         }
488         // Failure if buffer length is insufficient
489         else if (p_info->buf_len < p_info->total_len)
490         {
491             result = FS_RESULT_NO_MORE_RESOURCE;
492         }
493         // Store the character string from the end
494         else
495         {
496             u8         *dst = p_info->buf;
497             u32         total = p_info->total_len;
498             u32         pos = 0;
499             u32         id = dir_id;
500             // First, add "archive name:/"
501             const char *arcname = FS_GetArchiveName(arc);
502             u32         len = (u32)STD_GetStringLength(arcname);
503             MI_CpuCopy8(arcname, dst + pos, len);
504             pos += len;
505             MI_CpuCopy8(":/", dst + pos, 2);
506             pos += 2;
507             // Move to standard directory
508             FSi_SeekDirDirect(tmp, id);
509             // If necessary, add file name.
510             if (file_id != INVALID_ID)
511             {
512                 tmp->arg.readdir.p_entry = &entry;
513                 tmp->arg.readdir.skip_string = FALSE;
514                 while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
515                 {
516                     if (!entry.is_directory && (entry.file_id.file_id == file_id))
517                     {
518                         break;
519                     }
520                 }
521                 len = entry.name_len + 1;
522                 MI_CpuCopy8(entry.name, dst + total - len, len);
523                 total -= len;
524             }
525             else
526             {
527                 // If directory, append only the end
528                 dst[total - 1] = '\0';
529                 total -= 1;
530             }
531             // Trace back in order and add own name
532             if (id != 0)
533             {
534                 do
535                 {
536                     // Move to parent and search self
537                     FSi_SeekDirDirect(tmp, tmp->prop.dir.parent);
538                     tmp->arg.readdir.p_entry = &entry;
539                     tmp->arg.readdir.skip_string = FALSE;
540                     // Add "/"
541                     dst[total - 1] = '/';
542                     total -= 1;
543                     // Search parent's children (previous self)
544                     while (FSi_TranslateCommand(tmp, FS_COMMAND_READDIR, TRUE) == FS_RESULT_SUCCESS)
545                     {
546                         if (entry.is_directory && (entry.dir_id.own_id == id))
547                         {
548                             u32     len = entry.name_len;
549                             MI_CpuCopy8(entry.name, dst + total - len, len);
550                             total -= len;
551                             break;
552                         }
553                     }
554                     id = tmp->prop.dir.pos.own_id;
555                 }
556                 while (id != 0);
557             }
558             SDK_ASSERT(pos == total);
559         }
560         result = FS_RESULT_SUCCESS;
561     }
562     return result;
563 }
564 
565 /*---------------------------------------------------------------------------*
566   Name:         FSi_OpenFileFastDefault
567 
568   Description:  Default implementation of OPENFILEFAST command
569                 (Uses OPENFILEDIRECT command)
570 
571   Arguments:    p_file           Handle to process command
572 
573   Returns:      Command result value
574  *---------------------------------------------------------------------------*/
FSi_OpenFileFastDefault(FSFile * p_file)575 static FSResult FSi_OpenFileFastDefault(FSFile *p_file)
576 {
577     FSResult                result;
578     FSArchive       * const p_arc = p_file->arc;
579     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(p_arc);
580     const FSFileID         *p_id = &p_file->arg.openfilefast.id;
581     const u32               index = p_id->file_id;
582 
583     {
584         // Determine propriety of FAT accessing region
585         u32     pos = (u32)(index * sizeof(FSArchiveFAT));
586         if (pos >= context->fat_size)
587         {
588             result = FS_RESULT_NO_ENTRY;
589         }
590         else
591         {
592             // Obtain the image area of the specified file from FAT
593             FSArchiveFAT fat;
594             FSiSyncReadParam param;
595             param.arc = p_arc;
596             param.pos = context->fat + pos;
597             result = FSi_ReadTable(&param, &fat, sizeof(fat));
598             if (result == FS_RESULT_SUCCESS)
599             {
600                 // Directly open
601                 p_file->arg.openfiledirect.top = fat.top;
602                 p_file->arg.openfiledirect.bottom = fat.bottom;
603                 p_file->arg.openfiledirect.index = index;
604                 result = FSi_TranslateCommand(p_file, FS_COMMAND_OPENFILEDIRECT, TRUE);
605             }
606         }
607     }
608     return result;
609 }
610 
611 /*---------------------------------------------------------------------------*
612   Name:         FSi_OpenFileDirectDefault
613 
614   Description:  Default implementation of OPENFILEDIRECT command
615 
616   Arguments:    p_file           Handle to process command
617 
618   Returns:      Command result value
619  *---------------------------------------------------------------------------*/
FSi_OpenFileDirectDefault(FSFile * p_file)620 static FSResult FSi_OpenFileDirectDefault(FSFile *p_file)
621 {
622     p_file->prop.file.top = p_file->arg.openfiledirect.top;
623     p_file->prop.file.pos = p_file->arg.openfiledirect.top;
624     p_file->prop.file.bottom = p_file->arg.openfiledirect.bottom;
625     p_file->prop.file.own_id = p_file->arg.openfiledirect.index;
626     return FS_RESULT_SUCCESS;
627 }
628 
629 /*---------------------------------------------------------------------------*
630   Name:         FSi_ReadFileDefault
631 
632   Description:  Default implementation of READFILE command
633 
634   Arguments:    file           Handle to process command
635 
636   Returns:      Command result value
637  *---------------------------------------------------------------------------*/
FSi_ReadFileDefault(FSFile * file)638 static FSResult FSi_ReadFileDefault(FSFile *file)
639 {
640     FSArchive       * const arc = file->arc;
641     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
642     const u32               pos = file->prop.file.pos;
643     const u32               len = file->arg.readfile.len;
644     void            * const dst = file->arg.readfile.dst;
645     file->prop.file.pos += len;
646     return (*context->read_func) (arc, dst, pos, len);
647 }
648 
649 /*---------------------------------------------------------------------------*
650   Name:         FSi_WriteFileDefault
651 
652   Description:  Default implementation of WRITEFILE command
653 
654   Arguments:    file           Handle to process command
655 
656   Returns:      Command result value
657  *---------------------------------------------------------------------------*/
FSi_WriteFileDefault(FSFile * file)658 static FSResult FSi_WriteFileDefault(FSFile *file)
659 {
660     FSArchive       * const arc = file->arc;
661     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
662     const u32               pos = file->prop.file.pos;
663     const u32               len = file->arg.writefile.len;
664     const void      * const src = file->arg.writefile.src;
665     file->prop.file.pos += len;
666     return (*context->write_func) (arc, src, pos, len);
667 }
668 
669 /*---------------------------------------------------------------------------*
670   Name:         FSi_IgnoredCommand
671 
672   Description:  Implements commands that do nothing by default
673 
674   Arguments:    file           Handle to process command
675 
676   Returns:      Command result value
677  *---------------------------------------------------------------------------*/
FSi_IgnoredCommand(FSFile * file)678 static FSResult FSi_IgnoredCommand(FSFile *file)
679 {
680     (void)file;
681     return FS_RESULT_SUCCESS;
682 }
683 
684 /*---------------------------------------------------------------------------*
685   Name:         FSi_TranslateCommand
686 
687   Description:  Calls user procedure or default process
688                 If a synchronous command returns an asynchronous response, wait for completion internally.
689                 If an asynchronous command returns an asynchronous response, return it as is.
690 
691   Arguments:    file             FSFile structure that stores the argument
692                 Command: Command ID
693                 block            TRUE if blocking is necessary
694 
695   Returns:      The processing result for the command.
696  *---------------------------------------------------------------------------*/
FSi_TranslateCommand(FSFile * file,FSCommandType command,BOOL block)697 FSResult FSi_TranslateCommand(FSFile *file, FSCommandType command, BOOL block)
698 {
699     FSResult                result = FS_RESULT_PROC_DEFAULT;
700     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(file->arc);
701     // Execute if it is a command that supports the procedure
702     if ((context->proc_flag & (1 << command)) != 0)
703     {
704         result = (*context->proc) (file, command);
705         switch (result)
706         {
707         case FS_RESULT_SUCCESS:
708         case FS_RESULT_FAILURE:
709         case FS_RESULT_UNSUPPORTED:
710             break;
711         case FS_RESULT_PROC_ASYNC:
712             // Control asynchronous process handling in detail later.
713             break;
714         case FS_RESULT_PROC_UNKNOWN:
715             // Unknown command, so switch to the default process from this time onward.
716             result = FS_RESULT_PROC_DEFAULT;
717             context->proc_flag &= ~(1 << command);
718             break;
719         }
720     }
721     // If not processed in the procedure, call default process
722     if (result == FS_RESULT_PROC_DEFAULT)
723     {
724         static FSResult (*const (default_table[])) (FSFile *) =
725         {
726             FSi_ReadFileDefault,
727             FSi_WriteFileDefault,
728             FSi_SeekDirDefault,
729             FSi_ReadDirDefault,
730             FSi_FindPathDefault,
731             FSi_GetPathDefault,
732             FSi_OpenFileFastDefault,
733             FSi_OpenFileDirectDefault,
734             FSi_IgnoredCommand,
735             FSi_IgnoredCommand,
736             FSi_IgnoredCommand,
737             FSi_IgnoredCommand,
738             FSi_IgnoredCommand,
739         };
740         if (command < sizeof(default_table) / sizeof(*default_table))
741         {
742             result = (*default_table[command])(file);
743         }
744         else
745         {
746             result = FS_RESULT_UNSUPPORTED;
747         }
748     }
749     // If necessary, block here
750     if (block)
751     {
752         result = FSi_WaitForArchiveCompletion(file, result);
753     }
754     return result;
755 }
756 
757 /*---------------------------------------------------------------------------*
758   Name:         FSi_ROMFAT_ReadFile
759 
760   Description:  The FS_COMMAND_READFILE command.
761 
762   Arguments:    arc: The calling archive
763                 file: The target file
764                 buffer: The memory to transfer to
765                 length           Transfer size
766 
767   Returns:      The processing result for the command.
768  *---------------------------------------------------------------------------*/
FSi_ROMFAT_ReadFile(FSArchive * arc,FSFile * file,void * buffer,u32 * length)769 static FSResult FSi_ROMFAT_ReadFile(FSArchive *arc, FSFile *file, void *buffer, u32 *length)
770 {
771     FSROMFATProperty   *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
772     const u32 pos = prop->file.pos;
773     const u32 rest = (u32)(prop->file.bottom - pos);
774     const u32 org = *length;
775     if (*length > rest)
776     {
777         *length = rest;
778     }
779     file->arg.readfile.dst = buffer;
780     file->arg.readfile.len_org = org;
781     file->arg.readfile.len = *length;
782     (void)arc;
783     return FSi_TranslateCommand(file, FS_COMMAND_READFILE, FALSE);
784 }
785 
786 /*---------------------------------------------------------------------------*
787   Name:         FSi_ROMFAT_WriteFile
788 
789   Description:  The FS_COMMAND_WRITEFILE command.
790 
791   Arguments:    arc: The calling archive
792                 file: The target file
793                 buffer: The memory to transfer from
794                 length           Transfer size
795 
796   Returns:      The processing result for the command.
797  *---------------------------------------------------------------------------*/
FSi_ROMFAT_WriteFile(FSArchive * arc,FSFile * file,const void * buffer,u32 * length)798 static FSResult FSi_ROMFAT_WriteFile(FSArchive *arc, FSFile *file, const void *buffer, u32 *length)
799 {
800     FSROMFATProperty   *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
801     const u32 pos = prop->file.pos;
802     const u32 rest = (u32)(prop->file.bottom - pos);
803     const u32 org = *length;
804     if (*length > rest)
805     {
806         *length = rest;
807     }
808     file->arg.writefile.src = buffer;
809     file->arg.writefile.len_org = org;
810     file->arg.writefile.len = *length;
811     (void)arc;
812     return FSi_TranslateCommand(file, FS_COMMAND_WRITEFILE, FALSE);
813 }
814 
815 /*---------------------------------------------------------------------------*
816   Name:         FSi_ROMFAT_SeekDirectory
817 
818   Description:  FS_COMMAND_SEEKDIR command
819 
820   Arguments:    arc: The calling archive
821                 file: The target file
822                 id               Unique directory ID
823                 position         Indicate enumeration state
824 
825   Returns:      The processing result for the command.
826  *---------------------------------------------------------------------------*/
FSi_ROMFAT_SeekDirectory(FSArchive * arc,FSFile * file,u32 id,u32 position)827 static FSResult FSi_ROMFAT_SeekDirectory(FSArchive *arc, FSFile *file, u32 id, u32 position)
828 {
829     FSResult                result;
830     FSROMFATCommandInfo    *arg = &file->arg;
831     file->arc = arc;
832     arg->seekdir.pos.arc = arc;
833     arg->seekdir.pos.own_id = (u16)(id >> 0);
834     arg->seekdir.pos.index = (u16)(id >> 16);
835     arg->seekdir.pos.pos = position;
836     result = FSi_TranslateCommand(file, FS_COMMAND_SEEKDIR, TRUE);
837     if (result == FS_RESULT_SUCCESS)
838     {
839         FS_SetDirectoryHandle(file, arc, &file->prop);
840     }
841     return result;
842 }
843 
844 /*---------------------------------------------------------------------------*
845   Name:         FSi_ROMFAT_ReadDirectory
846 
847   Description:  The FS_COMMAND_READDIR command.
848 
849   Arguments:    arc: The calling archive
850                 file: The target file
851                 info: Location to save information
852 
853   Returns:      The processing result for the command.
854  *---------------------------------------------------------------------------*/
FSi_ROMFAT_ReadDirectory(FSArchive * arc,FSFile * file,FSDirectoryEntryInfo * info)855 static FSResult FSi_ROMFAT_ReadDirectory(FSArchive *arc, FSFile *file, FSDirectoryEntryInfo *info)
856 {
857     FSResult                result;
858     FSDirEntry              entry[1];
859     FSROMFATCommandInfo    *arg = &file->arg;
860     arg->readdir.p_entry = entry;
861     arg->readdir.skip_string = FALSE;
862     result = FSi_TranslateCommand(file, FS_COMMAND_READDIR, TRUE);
863     if (result == FS_RESULT_SUCCESS)
864     {
865         info->shortname_length = 0;
866         info->longname_length = entry->name_len;
867         MI_CpuCopy8(entry->name, info->longname, info->longname_length);
868         info->longname[info->longname_length] = '\0';
869         if (entry->is_directory)
870         {
871             info->attributes = FS_ATTRIBUTE_IS_DIRECTORY;
872             info->id = (u32)((entry->dir_id.own_id << 0) | (entry->dir_id.index << 16));
873             info->filesize = 0;
874         }
875         else
876         {
877             info->attributes = 0;
878             info->id = entry->file_id.file_id;
879             info->filesize = 0;
880             // If a valid file ID, get file size information from FAT
881             {
882                 FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
883                 u32                     pos = (u32)(info->id * sizeof(FSArchiveFAT));
884                 if (pos < context->fat_size)
885                 {
886                     FSArchiveFAT        fat;
887                     FSiSyncReadParam    param;
888                     param.arc = arc;
889                     param.pos = context->fat + pos;
890                     if (FSi_ReadTable(&param, &fat, sizeof(fat)) == FS_RESULT_SUCCESS)
891                     {
892                         info->filesize = (u32)(fat.bottom - fat.top);
893                         // If running in NTR mode, record with a flag that the TWL dedicated region is not read
894                         if (FSi_IsUnreadableRomOffset(arc, fat.top))
895                         {
896                             info->attributes |= FS_ATTRIBUTE_IS_OFFLINE;
897                         }
898                     }
899                 }
900             }
901         }
902         info->mtime.year = 0;
903         info->mtime.month = 0;
904         info->mtime.day = 0;
905         info->mtime.hour = 0;
906         info->mtime.minute = 0;
907         info->mtime.second = 0;
908     }
909     (void)arc;
910     return result;
911 }
912 
913 /*---------------------------------------------------------------------------*
914   Name:         FSi_ROMFAT_FindPath
915 
916   Description:  FS_COMMAND_FINDPATH command
917 
918   Arguments:    arc: The calling archive
919                 base_dir_id  The base directory ID (0 for the root)
920                 path                Search path
921                 target_id           ID storage destination
922                 target_is_directory  Storage destination of whether this is a directory
923 
924   Returns:      The processing result for the command.
925  *---------------------------------------------------------------------------*/
FSi_ROMFAT_FindPath(FSArchive * arc,u32 base_dir_id,const char * path,u32 * target_id,BOOL target_is_directory)926 static FSResult FSi_ROMFAT_FindPath(FSArchive *arc, u32 base_dir_id, const char *path, u32 *target_id, BOOL target_is_directory)
927 {
928     FSResult        result;
929     union
930     {
931         FSFileID    file;
932         FSDirPos    dir;
933     }
934     id;
935     FSFile         *tmp = FSi_GetTemporaryFileContext(arc);
936     tmp->arg.findpath.pos.arc = arc;
937     tmp->arg.findpath.pos.own_id = (u16)(base_dir_id >> 0);
938     tmp->arg.findpath.pos.index = 0;
939     tmp->arg.findpath.pos.pos = 0;
940     tmp->arg.findpath.path = path;
941     tmp->arg.findpath.find_directory = target_is_directory;
942     if (target_is_directory)
943     {
944         tmp->arg.findpath.result.dir = &id.dir;
945     }
946     else
947     {
948         tmp->arg.findpath.result.file = &id.file;
949     }
950     result = FSi_TranslateCommand(tmp, FS_COMMAND_FINDPATH, TRUE);
951     if (result == FS_RESULT_SUCCESS)
952     {
953         if (target_is_directory)
954         {
955             *target_id = id.dir.own_id;
956         }
957         else
958         {
959             *target_id = id.file.file_id;
960         }
961     }
962     return result;
963 }
964 
965 /*---------------------------------------------------------------------------*
966   Name:         FSi_ROMFAT_GetPath
967 
968   Description:  FS_COMMAND_GETPATH command.
969 
970   Arguments:    arc: The calling archive
971                 file: The target file
972                 is_directory        False, if file is a file, TRUE if it is a directory
973                 buffer      Path storage destination
974                 length            Buffer size
975 
976   Returns:      The processing result for the command.
977  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetPath(FSArchive * arc,FSFile * file,BOOL is_directory,char * buffer,u32 * length)978 static FSResult FSi_ROMFAT_GetPath(FSArchive *arc, FSFile *file, BOOL is_directory, char *buffer, u32 *length)
979 {
980     FSResult                result;
981     FSROMFATCommandInfo    *arg = &file->arg;
982     arg->getpath.total_len = 0;
983     arg->getpath.dir_id = 0;
984     arg->getpath.buf = (u8 *)buffer;
985     arg->getpath.buf_len = *length;
986     result = FSi_TranslateCommand(file, FS_COMMAND_GETPATH, TRUE);
987     if (result == FS_RESULT_SUCCESS)
988     {
989         *length = arg->getpath.buf_len;
990     }
991     (void)arc;
992     (void)is_directory;
993     return result;
994 }
995 
996 /*---------------------------------------------------------------------------*
997   Name:         FSi_ROMFAT_OpenFileFast
998 
999   Description:  The FS_COMMAND_OPENFILEFAST command
1000 
1001   Arguments:    arc: The calling archive
1002                 file: The target file
1003                 id                  File ID
1004                 mode: The access mode
1005 
1006   Returns:      The processing result for the command.
1007  *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFileFast(FSArchive * arc,FSFile * file,u32 id,u32 mode)1008 static FSResult FSi_ROMFAT_OpenFileFast(FSArchive *arc, FSFile *file, u32 id, u32 mode)
1009 {
1010     FSResult                result;
1011     FSROMFATCommandInfo    *arg = &file->arg;
1012     arg->openfilefast.id.arc = arc;
1013     arg->openfilefast.id.file_id = id;
1014     result = FSi_TranslateCommand(file, FS_COMMAND_OPENFILEFAST, TRUE);
1015     if (result == FS_RESULT_SUCCESS)
1016     {
1017         FS_SetFileHandle(file, arc, &file->prop);
1018     }
1019     (void)mode;
1020     return result;
1021 }
1022 
1023 /*---------------------------------------------------------------------------*
1024   Name:         FSi_ROMFAT_OpenFileDirect
1025 
1026   Description:  The FS_COMMAND_OPENFILEDIRECT command.
1027 
1028   Arguments:    arc: The calling archive
1029                 file: The target file
1030                 top                 File top offset
1031                 bottom              File bottom offset
1032                 id                  Storage destination for required file ID and results
1033 
1034   Returns:      The processing result for the command.
1035  *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFileDirect(FSArchive * arc,FSFile * file,u32 top,u32 bottom,u32 * id)1036 static FSResult FSi_ROMFAT_OpenFileDirect(FSArchive *arc, FSFile *file, u32 top, u32 bottom, u32 *id)
1037 {
1038     FSResult                result;
1039     FSROMFATCommandInfo    *arg = &file->arg;
1040     arg->openfiledirect.top = top;
1041     arg->openfiledirect.bottom = bottom;
1042     arg->openfiledirect.index = *id;
1043     result = FSi_TranslateCommand(file, FS_COMMAND_OPENFILEDIRECT, TRUE);
1044     if (result == FS_RESULT_SUCCESS)
1045     {
1046         FS_SetFileHandle(file, arc, &file->prop);
1047     }
1048     return result;
1049 }
1050 
1051 /*---------------------------------------------------------------------------*
1052   Name:         FSi_ROMFAT_CloseFile
1053 
1054   Description:  The FS_COMMAND_CLOSEFILE command.
1055 
1056   Arguments:    arc: The calling archive
1057                 file: The target file
1058 
1059   Returns:      The processing result for the command.
1060  *---------------------------------------------------------------------------*/
FSi_ROMFAT_CloseFile(FSArchive * arc,FSFile * file)1061 static FSResult FSi_ROMFAT_CloseFile(FSArchive *arc, FSFile *file)
1062 {
1063     FSResult            result;
1064     result = FSi_TranslateCommand(file, FS_COMMAND_CLOSEFILE, TRUE);
1065     FS_DetachHandle(file);
1066     (void)arc;
1067     return result;
1068 }
1069 
1070 /*---------------------------------------------------------------------------*
1071   Name:         FSi_ROMFAT_Activate
1072 
1073   Description:  The FS_COMMAND_ACTIVATE command.
1074 
1075   Arguments:    arc: The calling archive
1076 
1077   Returns:      None.
1078  *---------------------------------------------------------------------------*/
FSi_ROMFAT_Activate(FSArchive * arc)1079 static void FSi_ROMFAT_Activate(FSArchive* arc)
1080 {
1081     (void)FSi_TranslateCommand(FSi_GetTemporaryFileContext(arc), FS_COMMAND_ACTIVATE, FALSE);
1082 }
1083 
1084 /*---------------------------------------------------------------------------*
1085   Name:         FSi_ROMFAT_Idle
1086 
1087   Description:  The FS_COMMAND_ACTIVATE command.
1088 
1089   Arguments:    arc: The calling archive
1090 
1091   Returns:      None.
1092  *---------------------------------------------------------------------------*/
FSi_ROMFAT_Idle(FSArchive * arc)1093 static void FSi_ROMFAT_Idle(FSArchive* arc)
1094 {
1095     (void)FSi_TranslateCommand(FSi_GetTemporaryFileContext(arc), FS_COMMAND_IDLE, FALSE);
1096 }
1097 
1098 /*---------------------------------------------------------------------------*
1099   Name:         FSi_ROMFAT_Suspend
1100 
1101   Description:  The FS_COMMAND_SUSPEND command.
1102 
1103   Arguments:    arc: The calling archive
1104 
1105   Returns:      None.
1106  *---------------------------------------------------------------------------*/
FSi_ROMFAT_Suspend(FSArchive * arc)1107 static void FSi_ROMFAT_Suspend(FSArchive* arc)
1108 {
1109     (void)FSi_TranslateCommand(FSi_GetTemporaryFileContext(arc), FS_COMMAND_SUSPEND, FALSE);
1110 }
1111 
1112 /*---------------------------------------------------------------------------*
1113   Name:         FSi_ROMFAT_Resume
1114 
1115   Description:  The FS_COMMAND_RESUME command.
1116 
1117   Arguments:    arc: The calling archive
1118 
1119   Returns:      None.
1120  *---------------------------------------------------------------------------*/
FSi_ROMFAT_Resume(FSArchive * arc)1121 static void FSi_ROMFAT_Resume(FSArchive* arc)
1122 {
1123     (void)FSi_TranslateCommand(FSi_GetTemporaryFileContext(arc), FS_COMMAND_RESUME, FALSE);
1124 }
1125 
1126 /*---------------------------------------------------------------------------*
1127   Name:         FSi_ROMFAT_OpenFile
1128 
1129   Description:  The FS_COMMAND_OPENFILE command.
1130 
1131   Arguments:    arc: The calling archive
1132                 file: The target file
1133                 baseid: The base directory (0 for the root)
1134                 path :   File path
1135                 mode: The access mode
1136 
1137   Returns:      The processing result for the command.
1138  *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenFile(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)1139 static FSResult FSi_ROMFAT_OpenFile(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
1140 {
1141     FSResult    result;
1142     u32         fileid;
1143     result = FSi_ROMFAT_FindPath(arc, baseid, path, &fileid, FALSE);
1144     if (result == FS_RESULT_SUCCESS)
1145     {
1146         result = FSi_ROMFAT_OpenFileFast(arc, file, fileid, mode);
1147     }
1148     return result;
1149 }
1150 
1151 /*---------------------------------------------------------------------------*
1152   Name:         FSi_ROMFAT_SeekFile
1153 
1154   Description:  The FS_COMMAND_SEEKFILE command.
1155 
1156   Arguments:    arc: The calling archive
1157                 file: The target file
1158                 offset: The displacement and moved position
1159                 from: The starting point to seek from
1160 
1161   Returns:      The processing result for the command.
1162  *---------------------------------------------------------------------------*/
FSi_ROMFAT_SeekFile(FSArchive * arc,FSFile * file,int * offset,FSSeekFileMode from)1163 static FSResult FSi_ROMFAT_SeekFile(FSArchive *arc, FSFile *file, int *offset, FSSeekFileMode from)
1164 {
1165     FSROMFATProperty   *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1166     int pos = *offset;
1167     switch (from)
1168     {
1169     case FS_SEEK_SET:
1170         pos += prop->file.top;
1171         break;
1172     case FS_SEEK_CUR:
1173     default:
1174         pos += prop->file.pos;
1175         break;
1176     case FS_SEEK_END:
1177         pos += prop->file.bottom;
1178         break;
1179     }
1180     // Considered seek processing outside of range to have failed
1181     if ((pos < (int)prop->file.top) || (pos > (int)prop->file.bottom))
1182     {
1183         return FS_RESULT_INVALID_PARAMETER;
1184     }
1185     else
1186     {
1187         prop->file.pos = (u32)pos;
1188         *offset = pos;
1189         (void)arc;
1190         return FS_RESULT_SUCCESS;
1191     }
1192 }
1193 
1194 /*---------------------------------------------------------------------------*
1195   Name:         FSi_ROMFAT_GetFileLength
1196 
1197   Description:  The FS_COMMAND_GETFILELENGTH command.
1198 
1199   Arguments:    arc: The calling archive
1200                 file: The target file
1201                 length: Location to save the obtained size
1202 
1203   Returns:      The processing result for the command.
1204  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetFileLength(FSArchive * arc,FSFile * file,u32 * length)1205 static FSResult FSi_ROMFAT_GetFileLength(FSArchive *arc, FSFile *file, u32 *length)
1206 {
1207     FSROMFATProperty   *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1208     *length = prop->file.bottom - prop->file.top;
1209     (void)arc;
1210     return FS_RESULT_SUCCESS;
1211 }
1212 
1213 /*---------------------------------------------------------------------------*
1214   Name:         FSi_ROMFAT_GetFilePosition
1215 
1216   Description:  The FS_COMMAND_GETFILEPOSITION command.
1217 
1218   Arguments:    arc: The calling archive
1219                 file: The target file
1220                 length	 Storage destination of gotten position
1221 
1222   Returns:      The processing result for the command.
1223  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetFilePosition(FSArchive * arc,FSFile * file,u32 * position)1224 static FSResult FSi_ROMFAT_GetFilePosition(FSArchive *arc, FSFile *file, u32 *position)
1225 {
1226     FSROMFATProperty   *prop = (FSROMFATProperty*)FS_GetFileUserData(file);
1227     *position = prop->file.pos - prop->file.top;
1228     (void)arc;
1229     return FS_RESULT_SUCCESS;
1230 }
1231 
1232 /*---------------------------------------------------------------------------*
1233   Name:         FSi_ROMFAT_Unmount
1234 
1235   Description:  The FS_COMMAND_UNMOUNT command
1236 
1237   Arguments:    arc: The calling archive
1238 
1239   Returns:      None.
1240  *---------------------------------------------------------------------------*/
FSi_ROMFAT_Unmount(FSArchive * arc)1241 static void FSi_ROMFAT_Unmount(FSArchive *arc)
1242 {
1243     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1244     if (FS_IsArchiveTableLoaded(arc))
1245     {
1246         OS_TWarning("memory may leak. preloaded-table of archive \"%s\" (0x%08X)",
1247                     FS_GetArchiveName(arc), context->load_mem);
1248     }
1249     context->base = 0;
1250     context->fat = 0;
1251     context->fat_size = 0;
1252     context->fnt = 0;
1253     context->fnt_size = 0;
1254     context->fat_bak = 0;
1255     context->fnt_bak = 0;
1256 }
1257 
1258 /*---------------------------------------------------------------------------*
1259   Name:         FSi_ROMFAT_GetArchiveCaps
1260 
1261   Description:  The FS_COMMAND_GETARCHIVECAPS command.
1262 
1263   Arguments:    arc: The calling archive
1264                 caps: Location to save the device capability flag
1265 
1266   Returns:      The processing result for the command.
1267  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetArchiveCaps(FSArchive * arc,u32 * caps)1268 static FSResult FSi_ROMFAT_GetArchiveCaps(FSArchive *arc, u32 *caps)
1269 {
1270     (void)arc;
1271     *caps = 0;
1272     return FS_RESULT_SUCCESS;
1273 }
1274 
1275 /*---------------------------------------------------------------------------*
1276   Name:         FSi_ROMFAT_OpenDirectory
1277 
1278   Description:  The FS_COMMAND_OPENDIRECTORY command.
1279 
1280   Arguments:    arc: The calling archive
1281                 file: The target file
1282                 baseid: The base directory ID (0 for the root)
1283                 path: The path
1284                 mode: The access mode
1285 
1286   Returns:      The processing result for the command.
1287  *---------------------------------------------------------------------------*/
FSi_ROMFAT_OpenDirectory(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)1288 static FSResult FSi_ROMFAT_OpenDirectory(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
1289 {
1290     FSResult    result = FS_RESULT_ERROR;
1291     u32         id = 0;
1292     result = FSi_ROMFAT_FindPath(arc, baseid, path, &id, TRUE);
1293     if (result == FS_RESULT_SUCCESS)
1294     {
1295         result = FSi_ROMFAT_SeekDirectory(arc, file, id, 0);
1296     }
1297     (void)mode;
1298     return result;
1299 }
1300 
1301 /*---------------------------------------------------------------------------*
1302   Name:         FSi_ROMFAT_CloseDirectory
1303 
1304   Description:  The FS_COMMAND_CLOSEDIRECTORY command.
1305 
1306   Arguments:    arc: The calling archive
1307                 file: The target file
1308 
1309   Returns:      The processing result for the command.
1310  *---------------------------------------------------------------------------*/
FSi_ROMFAT_CloseDirectory(FSArchive * arc,FSFile * file)1311 static FSResult FSi_ROMFAT_CloseDirectory(FSArchive *arc, FSFile *file)
1312 {
1313     FS_DetachHandle(file);
1314     (void)arc;
1315     return FS_RESULT_SUCCESS;
1316 }
1317 
1318 /*---------------------------------------------------------------------------*
1319   Name:         FSi_ROMFAT_GetPathInfo
1320 
1321   Description:  The FS_COMMAND_GETPATHINFO command.
1322 
1323   Arguments:    arc: The calling archive
1324                 baseid: The base directory ID (0 for the root)
1325                 path: The path
1326                 info: Location to save file information
1327 
1328   Returns:      The processing result for the command.
1329  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetPathInfo(FSArchive * arc,u32 baseid,const char * path,FSPathInfo * info)1330 static FSResult FSi_ROMFAT_GetPathInfo(FSArchive *arc, u32 baseid, const char *path, FSPathInfo *info)
1331 {
1332     FSResult    result = FS_RESULT_ERROR;
1333     u32         id = 0;
1334     MI_CpuFill8(info, 0x00, sizeof(*info));
1335     // The ratio is quite poor, so it is better to call the function separately
1336     if (FSi_ROMFAT_FindPath(arc, baseid, path, &id, TRUE) == FS_RESULT_SUCCESS)
1337     {
1338         info->attributes = FS_ATTRIBUTE_IS_DIRECTORY;
1339         info->id = id;
1340         result = FS_RESULT_SUCCESS;
1341     }
1342     else if (FSi_ROMFAT_FindPath(arc, baseid, path, &id, FALSE) == FS_RESULT_SUCCESS)
1343     {
1344         info->attributes = 0;
1345         info->id = id;
1346         info->filesize = 0;
1347         // If a valid file ID, get file size information from FAT
1348         {
1349             FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1350             u32                     pos = (u32)(id * sizeof(FSArchiveFAT));
1351             if (pos < context->fat_size)
1352             {
1353                 FSArchiveFAT        fat;
1354                 FSiSyncReadParam    param;
1355                 param.arc = arc;
1356                 param.pos = context->fat + pos;
1357                 if (FSi_ReadTable(&param, &fat, sizeof(fat)) == FS_RESULT_SUCCESS)
1358                 {
1359                     info->filesize = (u32)(fat.bottom - fat.top);
1360                     // If running in NTR mode, record with a flag that the TWL dedicated region is not read
1361                     if (FSi_IsUnreadableRomOffset(arc, fat.top))
1362                     {
1363                         info->attributes |= FS_ATTRIBUTE_IS_OFFLINE;
1364                     }
1365                 }
1366             }
1367         }
1368         result = FS_RESULT_SUCCESS;
1369     }
1370     // The NitroROM format archive prohibits writing by default
1371     info->attributes |= FS_ATTRIBUTE_IS_PROTECTED;
1372     return result;
1373 }
1374 
1375 /*---------------------------------------------------------------------------*
1376   Name:         FSi_ROMFAT_GetPathInfo
1377 
1378   Description:  The FATFS_COMMAND_GETARCHIVERESOURCE command.
1379 
1380   Arguments:    arc: The calling archive
1381                 resource            Storage destination of resource information
1382 
1383   Returns:      The processing result for the command.
1384  *---------------------------------------------------------------------------*/
FSi_ROMFAT_GetArchiveResource(FSArchive * arc,FSArchiveResource * resource)1385 static FSResult FSi_ROMFAT_GetArchiveResource(FSArchive *arc, FSArchiveResource *resource)
1386 {
1387     const CARDRomHeader    *header = (const CARDRomHeader *)CARD_GetRomHeader();
1388     resource->bytesPerSector = 0;
1389     resource->sectorsPerCluster = 0;
1390     resource->totalClusters = 0;
1391     resource->availableClusters = 0;
1392     resource->totalSize = header->rom_size;
1393     resource->availableSize = 0;
1394     resource->maxFileHandles = 0x7FFFFFFF;
1395     resource->currentFileHandles = 0;
1396     resource->maxDirectoryHandles = 0x7FFFFFFF;
1397     resource->currentDirectoryHandles = 0;
1398     (void)arc;
1399     return FS_RESULT_SUCCESS;
1400 }
1401 
1402 /*---------------------------------------------------------------------------*
1403   Name:         FSi_ReadSRLCallback
1404 
1405   Description:  SRL file read callback
1406 
1407   Arguments:    p_arc            FSArchive structure
1408                 dst        Transfer destination
1409                 src        Transfer source
1410                 len        Transfer size
1411 
1412   Returns:      Read process results
1413  *---------------------------------------------------------------------------*/
FSi_ReadSRLCallback(FSArchive * arc,void * buffer,u32 offset,u32 length)1414 static FSResult FSi_ReadSRLCallback(FSArchive *arc, void *buffer, u32 offset, u32 length)
1415 {
1416     CARDRomHashContext *hash = (CARDRomHashContext*)FS_GetArchiveBase(arc);
1417     CARD_ReadRomHashImage(hash, buffer, offset, length);
1418     return FS_RESULT_SUCCESS;
1419 }
1420 
1421 /*---------------------------------------------------------------------------*
1422   Name:         FSi_SRLArchiveProc
1423 
1424   Description:  SRL file archive procedure
1425 
1426   Arguments:    file           FSFile structure that stores command information
1427                 cmd:              Command type.
1428 
1429   Returns:      Command processing result
1430  *---------------------------------------------------------------------------*/
FSi_SRLArchiveProc(FSFile * file,FSCommandType cmd)1431 static FSResult FSi_SRLArchiveProc(FSFile *file, FSCommandType cmd)
1432 {
1433     (void)file;
1434     switch (cmd)
1435     {
1436     case FS_COMMAND_WRITEFILE:
1437         return FS_RESULT_UNSUPPORTED;
1438     default:
1439         return FS_RESULT_PROC_UNKNOWN;
1440     }
1441 }
1442 
1443 /*---------------------------------------------------------------------------*
1444   Name:         FSi_MountSRLFile
1445 
1446   Description:  Mount the ROM file system that is included in the SRL file
1447 
1448   Arguments:    arc              FSArchive structure used in mounting
1449                                  Names must have been registered
1450                 file             File targeted for mounting and that is already open
1451                                  Do not destroy this structure while mounting
1452                 hash             Hash context structure
1453 
1454   Returns:      TRUE if the process is successful
1455  *---------------------------------------------------------------------------*/
FSi_MountSRLFile(FSArchive * arc,FSFile * file,CARDRomHashContext * hash)1456 BOOL FSi_MountSRLFile(FSArchive *arc, FSFile *file, CARDRomHashContext *hash)
1457 {
1458     BOOL                    retval = FALSE;
1459     static CARDRomHeaderTWL header[1] ATTRIBUTE_ALIGN(32);
1460     if (file &&
1461         (FS_SeekFileToBegin(file) &&
1462         (FS_ReadFile(file, header, sizeof(header)) == sizeof(header))))
1463     {
1464         // For security, NAND applications require a hash table
1465         // When a ROM called NITRO compatible mode but will use the file system appears in the future, study usage policy at that time
1466         //
1467         if ((((const u8 *)header)[0x1C] & 0x01) != 0)
1468         {
1469             FSResult (*proc)(FSFile*, FSCommandType) = FSi_SRLArchiveProc;
1470             FSResult (*read)(FSArchive*, void*, u32, u32) = FSi_ReadSRLCallback;
1471             FSResult (*write)(FSArchive*, const void*, u32, u32) = NULL;
1472             FS_SetArchiveProc(arc, proc, FS_ARCHIVE_PROC_WRITEFILE);
1473             // Access change is created in the order of arc -> hash -> files
1474             if (FS_LoadArchive(arc, (u32)hash,
1475                                header->ntr.fat.offset, header->ntr.fat.length,
1476                                header->ntr.fnt.offset, header->ntr.fnt.length,
1477                                read, write))
1478             {
1479                 // If it was content that differed from the ROM header of the system work region, the buffer allocated in advance by the CARDi_InitRom function is wasted
1480                 //
1481                 extern u8  *CARDiHashBufferAddress;
1482                 extern u32  CARDiHashBufferLength;
1483                 u32         len = CARD_CalcRomHashBufferLength(header);
1484                 if (len > CARDiHashBufferLength)
1485                 {
1486                     u8     *lo = (u8 *)MATH_ROUNDUP((u32)OS_GetMainArenaLo(), 32);
1487                     u8     *hi = (u8 *)MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 32);
1488                     if (&lo[len] > hi)
1489                     {
1490                         OS_TPanic("cannot allocate memory for ROM-hash from ARENA");
1491                     }
1492                     else
1493                     {
1494                         OS_SetMainArenaLo(&lo[len]);
1495                         CARDiHashBufferAddress = lo;
1496                         CARDiHashBufferLength = len;
1497                     }
1498                 }
1499                 CARD_InitRomHashContext(hash, header,
1500                                         CARDiHashBufferAddress, CARDiHashBufferLength,
1501                                         FSi_SeekAndReadSRL, NULL, file);
1502                 // Destroy the pointer so that there is no competition for use of the same buffer
1503                 CARDiHashBufferAddress = NULL;
1504                 CARDiHashBufferLength = 0;
1505                 retval = TRUE;
1506             }
1507         }
1508     }
1509     return retval;
1510 }
1511 
1512 /*---------------------------------------------------------------------------*
1513   Name:         FSi_ReadMemCallback
1514 
1515   Description:  Default memory read callback
1516 
1517   Arguments:    p_arc:          Archive on which to operate
1518                 dst:              Storage destination of the memory to read
1519                 pos             Read position
1520                 size             Size to read
1521 
1522   Returns:      Always FS_RESULT_SUCCESS
1523  *---------------------------------------------------------------------------*/
FSi_ReadMemCallback(FSArchive * p_arc,void * dst,u32 pos,u32 size)1524 static FSResult FSi_ReadMemCallback(FSArchive *p_arc, void *dst, u32 pos, u32 size)
1525 {
1526     MI_CpuCopy8((const void *)FS_GetArchiveOffset(p_arc, pos), dst, size);
1527     return FS_RESULT_SUCCESS;
1528 }
1529 
1530 /*---------------------------------------------------------------------------*
1531   Name:         FSi_WriteMemCallback
1532 
1533   Description:  Default memory write callback
1534 
1535   Arguments:    p_arc:          Archive on which to operate
1536                 dst:              Reference destination of the memory to write
1537                 pos:              Write location
1538                 size             Size to write
1539 
1540   Returns:      Always FS_RESULT_SUCCESS
1541  *---------------------------------------------------------------------------*/
FSi_WriteMemCallback(FSArchive * p_arc,const void * src,u32 pos,u32 size)1542 static FSResult FSi_WriteMemCallback(FSArchive *p_arc, const void *src, u32 pos, u32 size)
1543 {
1544     MI_CpuCopy8(src, (void *)FS_GetArchiveOffset(p_arc, pos), size);
1545     return FS_RESULT_SUCCESS;
1546 }
1547 
1548 static const FSArchiveInterface FSiArchiveProcInterface =
1549 {
1550     // Commands that are compatible with old specifications
1551     FSi_ROMFAT_ReadFile,
1552     FSi_ROMFAT_WriteFile,
1553     FSi_ROMFAT_SeekDirectory,
1554     FSi_ROMFAT_ReadDirectory,
1555     FSi_ROMFAT_FindPath,
1556     FSi_ROMFAT_GetPath,
1557     FSi_ROMFAT_OpenFileFast,
1558     FSi_ROMFAT_OpenFileDirect,
1559     FSi_ROMFAT_CloseFile,
1560     FSi_ROMFAT_Activate,
1561     FSi_ROMFAT_Idle,
1562     FSi_ROMFAT_Suspend,
1563     FSi_ROMFAT_Resume,
1564     // Items that are compatible with old specifications but were not commands
1565     FSi_ROMFAT_OpenFile,
1566     FSi_ROMFAT_SeekFile,
1567     FSi_ROMFAT_GetFileLength,
1568     FSi_ROMFAT_GetFilePosition,
1569     // Command extended by the new specifications (UNSUPPORTED if NULL)
1570     NULL,               // Mount
1571     FSi_ROMFAT_Unmount,
1572     FSi_ROMFAT_GetArchiveCaps,
1573     NULL,               // CreateFile
1574     NULL,               // DeleteFile
1575     NULL,               // RenameFile
1576     FSi_ROMFAT_GetPathInfo,
1577     NULL,               // SetFileInfo
1578     NULL,               // CreateDirectory
1579     NULL,               // DeleteDirectory
1580     NULL,               // RenameDirectory
1581     FSi_ROMFAT_GetArchiveResource,
1582     NULL,               // 29UL
1583     NULL,               // FlushFile
1584     NULL,               // SetFileLength
1585     FSi_ROMFAT_OpenDirectory,
1586     FSi_ROMFAT_CloseDirectory,
1587 };
1588 
1589 /*---------------------------------------------------------------------------*
1590   Name:         FS_LoadArchive
1591 
1592   Description:  Loads the archive into the file system.
1593                 Its name must already be registered on the archive list.
1594 
1595   Arguments:    arc            Archive to load
1596                 base             Any u32 value that can be uniquely used.
1597                 fat              Starting offset of the FAT table
1598                 fat_size         Size of FAT table
1599                 fat              Starting offset of the FNT table
1600                 fat_size         Size of FNT table
1601                 read_func        Read access callback.
1602                 write_func       Write access callback
1603 
1604   Returns:      TRUE if archive is loaded correctly
1605  *---------------------------------------------------------------------------*/
FS_LoadArchive(FSArchive * arc,u32 base,u32 fat,u32 fat_size,u32 fnt,u32 fnt_size,FS_ARCHIVE_READ_FUNC read_func,FS_ARCHIVE_WRITE_FUNC write_func)1606 BOOL FS_LoadArchive(FSArchive *arc, u32 base,
1607                     u32 fat, u32 fat_size,
1608                     u32 fnt, u32 fnt_size,
1609                     FS_ARCHIVE_READ_FUNC read_func, FS_ARCHIVE_WRITE_FUNC write_func)
1610 {
1611     BOOL    retval = FALSE;
1612     SDK_ASSERT(FS_IsAvailable());
1613     SDK_NULL_ASSERT(arc);
1614     SDK_ASSERT(!FS_IsArchiveLoaded(arc));
1615 
1616     // Initialize information for archive
1617     {
1618         FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)arc->reserved2;
1619         context->base = base;
1620         context->fat_size = fat_size;
1621         context->fat = fat;
1622         context->fat_bak = fat;
1623         context->fnt_size = fnt_size;
1624         context->fnt = fnt;
1625         context->fnt_bak = fnt;
1626         context->read_func = read_func ? read_func : FSi_ReadMemCallback;
1627         context->write_func = write_func ? write_func : FSi_WriteMemCallback;
1628         context->load_mem = NULL;
1629         return FS_MountArchive(arc, context, &FSiArchiveProcInterface, 0);
1630     }
1631     return retval;
1632 }
1633 
1634 /*---------------------------------------------------------------------------*
1635   Name:         FS_UnloadArchive
1636 
1637   Description:  Unload the archive from the file system.
1638                 Block until all currently running tasks are completed.
1639 
1640   Arguments:    arc            Archive to unload
1641 
1642   Returns:      TRUE if archive is unloaded correctly.
1643  *---------------------------------------------------------------------------*/
FS_UnloadArchive(FSArchive * arc)1644 BOOL FS_UnloadArchive(FSArchive *arc)
1645 {
1646     return FS_UnmountArchive(arc);
1647 }
1648 
1649 /*---------------------------------------------------------------------------*
1650   Name:         FSi_GetFileLengthIfProc
1651 
1652   Description:  If the specified file is an archive procedure, gets the size.
1653 
1654   Arguments:    file        File handle
1655                 length			Storage destination of the size
1656 
1657   Returns:      If the specified file is an archive procedure, returns its size
1658  *---------------------------------------------------------------------------*/
FSi_GetFileLengthIfProc(FSFile * file,u32 * length)1659 BOOL FSi_GetFileLengthIfProc(FSFile *file, u32 *length)
1660 {
1661     return (file->arc->vtbl == &FSiArchiveProcInterface) &&
1662            (FSi_ROMFAT_GetFileLength(file->arc, file, length) == FS_RESULT_SUCCESS);
1663 }
1664 
1665 /*---------------------------------------------------------------------------*
1666   Name:         FSi_GetFilePositionIfProc
1667 
1668   Description:  If the specified file is an archive procedure, gets the current position
1669 
1670   Arguments:    file        File handle
1671                 length			Storage destination of the size
1672 
1673   Returns:      If the specified file is an archive procedure, returns its current position
1674  *---------------------------------------------------------------------------*/
FSi_GetFilePositionIfProc(FSFile * file,u32 * length)1675 BOOL FSi_GetFilePositionIfProc(FSFile *file, u32 *length)
1676 {
1677     return (file->arc->vtbl == &FSiArchiveProcInterface) &&
1678            (FSi_ROMFAT_GetFilePosition(file->arc, file, length) == FS_RESULT_SUCCESS);
1679 }
1680 
1681 /*---------------------------------------------------------------------------*
1682   Name:         FS_SetArchiveProc
1683 
1684   Description:  Sets the archive's user procedure.
1685                 If proc == NULL or flags = 0,
1686                 Merely invalidates the user procedure.
1687 
1688   Arguments:    arc     Archive for which to set the user procedure.
1689                 proc             User procedure.
1690                 flags            Bit collection of commands that hook to procedures.
1691 
1692   Returns:      Always returns the total table size.
1693  *---------------------------------------------------------------------------*/
FS_SetArchiveProc(FSArchive * arc,FS_ARCHIVE_PROC_FUNC proc,u32 flags)1694 void FS_SetArchiveProc(FSArchive *arc, FS_ARCHIVE_PROC_FUNC proc, u32 flags)
1695 {
1696     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)arc->reserved2;
1697     if (!flags)
1698     {
1699         proc = NULL;
1700     }
1701     else if (!proc)
1702     {
1703         flags = 0;
1704     }
1705     context->proc = proc;
1706     context->proc_flag = flags;
1707 }
1708 
1709 /*---------------------------------------------------------------------------*
1710   Name:         FS_LoadArchiveTables
1711 
1712   Description:  Preloads archive FAT + FNT in memory.
1713                 Only if within specified size, execute the load and return the required size.
1714 
1715   Arguments:    p_arc            Archive that will preload table.
1716                 p_mem            Storage destination buffer for table data
1717                 max_size         p_mem size
1718 
1719   Returns:      Always returns the total table size.
1720  *---------------------------------------------------------------------------*/
FS_LoadArchiveTables(FSArchive * p_arc,void * p_mem,u32 max_size)1721 u32 FS_LoadArchiveTables(FSArchive *p_arc, void *p_mem, u32 max_size)
1722 {
1723     SDK_ASSERT(FS_IsAvailable());
1724     SDK_NULL_ASSERT(p_arc);
1725 
1726     // If this is a table that has already been loaded, unload it
1727     if ((p_mem != NULL) && FS_IsArchiveTableLoaded(p_arc))
1728     {
1729         (void)FS_UnloadArchiveTables(p_arc);
1730     }
1731 
1732     {
1733         FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(p_arc);
1734         // The preload size is 32-byte aligned.
1735         u32     total_size = (u32)((context->fat_size + context->fnt_size + 32 + 31) & ~31);
1736         if (total_size <= max_size)
1737         {
1738             // If the size is sufficient, load into memory.
1739             u8     *p_cache = (u8 *)(((u32)p_mem + 31) & ~31);
1740             FSFile  tmp;
1741             FS_InitFile(&tmp);
1742             // Sometimes the table cannot be read.
1743             // * In that case, nothing is done because the table could not be accessed originally.
1744             if (FS_OpenFileDirect(&tmp, p_arc, context->fat, context->fat + context->fat_size, (u32)~0))
1745             {
1746                 if (FS_ReadFile(&tmp, p_cache, (s32)context->fat_size) < 0)
1747                 {
1748                     MI_CpuFill8(p_cache, 0x00, context->fat_size);
1749                 }
1750                 (void)FS_CloseFile(&tmp);
1751             }
1752             context->fat = (u32)p_cache;
1753             p_cache += context->fat_size;
1754             if (FS_OpenFileDirect(&tmp, p_arc, context->fnt, context->fnt + context->fnt_size, (u32)~0))
1755             {
1756                 if (FS_ReadFile(&tmp, p_cache, (s32)context->fnt_size) < 0)
1757                 {
1758                     MI_CpuFill8(p_cache, 0x00, context->fnt_size);
1759                 }
1760                 (void)FS_CloseFile(&tmp);
1761             }
1762             context->fnt = (u32)p_cache;
1763             // Thereafter, preload memory will be used with table reads.
1764             context->load_mem = p_mem;
1765             p_arc->flag |= FS_ARCHIVE_FLAG_TABLE_LOAD;
1766         }
1767         return total_size;
1768     }
1769 }
1770 
1771 /*---------------------------------------------------------------------------*
1772   Name:         FS_UnloadArchiveTables
1773 
1774   Description:  Deallocates the archive's preloaded memory.
1775 
1776   Arguments:    arc            Archive with preloaded memory to release.
1777 
1778   Returns:      Buffer given by the user as preloaded memory.
1779  *---------------------------------------------------------------------------*/
FS_UnloadArchiveTables(FSArchive * arc)1780 void   *FS_UnloadArchiveTables(FSArchive *arc)
1781 {
1782     void   *retval = NULL;
1783 
1784     SDK_ASSERT(FS_IsAvailable());
1785     SDK_NULL_ASSERT(arc);
1786 
1787     if (FS_IsArchiveLoaded(arc))
1788     {
1789         FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1790         BOOL    bak_stat = FS_SuspendArchive(arc);
1791         if (FS_IsArchiveTableLoaded(arc))
1792         {
1793             arc->flag &= ~FS_ARCHIVE_FLAG_TABLE_LOAD;
1794             retval = context->load_mem;
1795             context->fat = context->fat_bak;
1796             context->fnt = context->fnt_bak;
1797             context->load_mem = NULL;
1798         }
1799         if (bak_stat)
1800         {
1801             (void)FS_ResumeArchive(arc);
1802         }
1803     }
1804     return retval;
1805 }
1806 
1807 /*---------------------------------------------------------------------------*
1808   Name:         FS_GetArchiveBase
1809 
1810   Description:  Gets ROMFAT-type archive base offset
1811 
1812   Arguments:    arc              ROMFAT-type archive
1813 
1814   Returns:      ROMFAT-type archive base offset
1815  *---------------------------------------------------------------------------*/
FS_GetArchiveBase(const struct FSArchive * arc)1816 u32 FS_GetArchiveBase(const struct FSArchive *arc)
1817 {
1818     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1819     return context->base;
1820 }
1821 
1822 /*---------------------------------------------------------------------------*
1823   Name:         FS_GetArchiveFAT
1824 
1825   Description:  Gets ROMFAT-type archive FAT offset
1826 
1827   Arguments:    arc              ROMFAT-type archive
1828 
1829   Returns:      ROMFAT-type archive FAT offset
1830  *---------------------------------------------------------------------------*/
FS_GetArchiveFAT(const struct FSArchive * arc)1831 u32 FS_GetArchiveFAT(const struct FSArchive *arc)
1832 {
1833     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1834     return context->fat;
1835 }
1836 
1837 /*---------------------------------------------------------------------------*
1838   Name:         FS_GetArchiveFNT
1839 
1840   Description:  Gets ROMFAT-type archive FNT offset
1841 
1842   Arguments:    arc              ROMFAT-type archive
1843 
1844   Returns:      ROMFAT-type archive FNT offset
1845  *---------------------------------------------------------------------------*/
FS_GetArchiveFNT(const struct FSArchive * arc)1846 u32 FS_GetArchiveFNT(const struct FSArchive *arc)
1847 {
1848     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1849     return context->fnt;
1850 }
1851 
1852 /* Obtain specified position offset from the archive's base */
1853 /*---------------------------------------------------------------------------*
1854   Name:         FS_GetArchiveOffset
1855 
1856   Description:  Gets specified position offset from the ROMFAT-type archive's base
1857 
1858   Arguments:    arc              ROMFAT-type archive
1859 
1860   Returns:      Specified position offset with the archive base added
1861  *---------------------------------------------------------------------------*/
FS_GetArchiveOffset(const struct FSArchive * arc,u32 pos)1862 u32 FS_GetArchiveOffset(const struct FSArchive *arc, u32 pos)
1863 {
1864     FSROMFATArchiveContext *context = (FSROMFATArchiveContext*)FS_GetArchiveUserData(arc);
1865     return context->base + pos;
1866 }
1867 
1868 /*---------------------------------------------------------------------------*
1869   Name:         FS_IsArchiveTableLoaded
1870 
1871   Description:  Determines whether the ROMFAT-type archive has finished preloading the table.
1872 
1873   Arguments:    arc              ROMFAT-type archive
1874 
1875   Returns:      TRUE if the table has been preloaded
1876  *---------------------------------------------------------------------------*/
FS_IsArchiveTableLoaded(volatile const struct FSArchive * arc)1877 BOOL FS_IsArchiveTableLoaded(volatile const struct FSArchive *arc)
1878 {
1879     return ((arc->flag & FS_ARCHIVE_FLAG_TABLE_LOAD) != 0);
1880 }
1881 
1882 /*---------------------------------------------------------------------------*
1883   Name:         FS_GetFileImageTop
1884 
1885   Description:  Gets the top offset of the file opened from the ROMFAT-type archive
1886 
1887 
1888   Arguments:    file        File handle
1889 
1890   Returns:      File top offset on the archive
1891  *---------------------------------------------------------------------------*/
FS_GetFileImageTop(const struct FSFile * file)1892 u32 FS_GetFileImageTop(const struct FSFile *file)
1893 {
1894     return file->prop.file.top;
1895 }
1896 
1897 /*---------------------------------------------------------------------------*
1898   Name:         FS_GetFileImageBottom
1899 
1900   Description:  Gets the bottom offset of the file opened from the ROMFAT-type archive
1901 
1902 
1903   Arguments:    file        File handle
1904 
1905   Returns:      File bottom offset on the archive
1906  *---------------------------------------------------------------------------*/
FS_GetFileImageBottom(const struct FSFile * file)1907 u32 FS_GetFileImageBottom(const struct FSFile *file)
1908 {
1909     return file->prop.file.bottom;
1910 }
1911 
1912 
1913 #endif /* FS_IMPLEMENT */
1914