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