1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_file.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-09-30#$
14   $Rev: 11077 $
15   $Author: yosizaki $
16 
17  *---------------------------------------------------------------------------*/
18 
19 
20 #include <nitro/types.h>
21 #include <nitro/misc.h>
22 #include <nitro/mi.h>
23 #include <nitro/os.h>
24 #include <nitro/pxi.h>
25 #include <nitro/std/string.h>
26 #include <nitro/std/unicode.h>
27 #include <nitro/math/math.h>
28 
29 #include <nitro/fs.h>
30 
31 #include "../include/rom.h"
32 #include "../include/util.h"
33 #include "../include/command.h"
34 
35 
36 #define FS_DEBUG_TRACE(...) (void)0
37 //#define FS_DEBUG_TRACE  OS_TPrintf
38 
39 
40 /*---------------------------------------------------------------------------*/
41 /* Functions */
42 
43 #if defined(FS_IMPLEMENT)
44 
45 /*---------------------------------------------------------------------------*
46   Name:         FSi_IsValidTransferRegion
47 
48   Description:  Simple determination whether buffer used in read/write operations is in a dangerous range.
49 
50   Arguments:    buffer: Buffer targeted for transfer
51                 length: Transfer size
52 
53   Returns:      pos is either one returned character from the referenced position or -1.
54  *---------------------------------------------------------------------------*/
FSi_IsValidTransferRegion(const void * buffer,s32 length)55 static BOOL FSi_IsValidTransferRegion(const void *buffer, s32 length)
56 {
57     BOOL    retval = FALSE;
58     if (buffer == NULL)
59     {
60         OS_TWarning("specified transfer buffer is NULL.\n");
61     }
62     else if (((u32)buffer >= HW_IOREG) && ((u32)buffer < HW_IOREG_END))
63     {
64         OS_TWarning("specified transfer buffer is in I/O register %08X. (seems to be dangerous)\n", buffer);
65     }
66     else if (length < 0)
67     {
68         OS_TWarning("specified transfer size is minus. (%d)\n", length);
69     }
70     else
71     {
72 #if !defined(SDK_TWL)
73         s32     mainmem_size = HW_MAIN_MEM_EX_SIZE;
74 #else
75         s32     mainmem_size = OS_IsRunOnTwl() ? HW_TWL_MAIN_MEM_EX_SIZE : HW_MAIN_MEM_EX_SIZE;
76 #endif
77         if (length > mainmem_size)
78         {
79             OS_TWarning("specified transfer size is over mainmemory-size. (%d)\n", length);
80         }
81         else
82         {
83             retval = TRUE;
84         }
85     }
86     return retval;
87 }
88 
89 /*---------------------------------------------------------------------------*
90   Name:         FSi_DecrementSjisPosition
91 
92   Description:  Returns one character from the Shift_JIS string reference position.
93 
94   Arguments:    str: Pointer indicating the start of the Shift_JIS string
95                 pos: Current string reference position (in bytes)
96 
97   Returns:      pos is either one returned character from the referenced position or -1.
98  *---------------------------------------------------------------------------*/
FSi_DecrementSjisPosition(const char * str,int pos)99 int FSi_DecrementSjisPosition(const char *str, int pos)
100 {
101     // First, go back by just a one-byte amount
102     int     prev = --pos;
103     // The separation of characters in Shift_JIS is either by single bytes or successive bytes. Because the leading byte and subsequent byte share a portion of their mapping, the character type cannot be confirmed while that position appears to be the leading byte, so focus goes back farther
104     //
105     //
106     for (; (prev > 0) && STD_IsSjisLeadByte(str[prev - 1]); --prev)
107     {
108     }
109     // When there is a series of double-byte characters with unclear subsequent bytes, such as "===b," this goes back too far by a multiple of 2, so ignore it.
110     // (Take a multiplier of 2)
111     return pos - ((pos - prev) & 1);
112 }
113 
114 /*---------------------------------------------------------------------------*
115   Name:         FSi_IncrementSjisPositionToSlash
116 
117   Description:  Advances reference position of Shift_JIS string to either directory delimiter or end.
118 
119 
120   Arguments:    str: Pointer indicating the start of the Shift_JIS string
121                 pos: Current string reference position (in bytes)
122 
123   Returns:      Either first directory delimiter that appears after pos or the end position.
124  *---------------------------------------------------------------------------*/
FSi_IncrementSjisPositionToSlash(const char * str,int pos)125 int FSi_IncrementSjisPositionToSlash(const char *str, int pos)
126 {
127     while (str[pos] && !FSi_IsSlash((u8)str[pos]))
128     {
129         pos = FSi_IncrementSjisPosition(str, pos);
130     }
131     return pos;
132 }
133 
134 /*---------------------------------------------------------------------------*
135   Name:         FSi_DecrementSjisPositionToSlash
136 
137   Description:  Return reference position of Shift_JIS string to either directory separator character or beginning.
138 
139 
140   Arguments:    str: Pointer indicating the start of the Shift_JIS string
141                 pos: Current string reference position (in bytes)
142 
143   Returns:      Either first directory delimiter that appears before pos or -1.
144  *---------------------------------------------------------------------------*/
FSi_DecrementSjisPositionToSlash(const char * str,int pos)145 int FSi_DecrementSjisPositionToSlash(const char *str, int pos)
146 {
147     for (;;)
148     {
149         pos = FSi_DecrementSjisPosition(str, pos);
150         if ((pos < 0) || FSi_IsSlash((u8)str[pos]))
151         {
152             break;
153         }
154     }
155     return pos;
156 }
157 
158 /*---------------------------------------------------------------------------*
159   Name:         FSi_TrimSjisTrailingSlash
160 
161   Description:  Deletes if end of Shift_JIS string is a directory delimiter.
162 
163   Arguments:    str: Shift_JIS string
164 
165   Returns:      Length of string.
166  *---------------------------------------------------------------------------*/
FSi_TrimSjisTrailingSlash(char * str)167 int FSi_TrimSjisTrailingSlash(char *str)
168 {
169     int     length = STD_GetStringLength(str);
170     int     lastpos = FSi_DecrementSjisPosition(str, length);
171     if ((lastpos >= 0) && FSi_IsSlash((u8)str[lastpos]))
172     {
173         length = lastpos;
174         str[length] = '\0';
175     }
176     return length;
177 }
178 
179 /*---------------------------------------------------------------------------*
180   Name:         FSi_DecrementUnicodePosition
181 
182   Description:  Returns one character of the Unicode string reference position.
183 
184   Arguments:    str: Pointer indicating the start of the Unicode string
185                 pos: Current string reference position (in bytes)
186 
187   Returns:      pos is either one returned character from the referenced position or -1.
188  *---------------------------------------------------------------------------*/
FSi_DecrementUnicodePosition(const u16 * str,int pos)189 int FSi_DecrementUnicodePosition(const u16 *str, int pos)
190 {
191     // First, securely return the amount of 1 character
192     int     prev = --pos;
193     // Return one more character if valid surrogate pair
194     if ((pos > 0) &&
195         ((str[pos - 1] >= 0xD800) && (str[pos - 1] <= 0xDC00)) &&
196         ((str[pos - 0] >= 0xDC00) && (str[pos - 0] <= 0xE000)))
197     {
198         --pos;
199     }
200     return pos;
201 }
202 
203 /*---------------------------------------------------------------------------*
204   Name:         FSi_DecrementUnicodePositionToSlash
205 
206   Description:  Returns reference position of Unicode string to either directory delimiter or beginning.
207 
208 
209   Arguments:    str: Pointer indicating the start of the Unicode string
210                 pos: Current string reference position (in bytes)
211 
212   Returns:      Either first directory delimiter that appears before pos or -1.
213  *---------------------------------------------------------------------------*/
FSi_DecrementUnicodePositionToSlash(const u16 * str,int pos)214 int FSi_DecrementUnicodePositionToSlash(const u16 *str, int pos)
215 {
216     for (;;)
217     {
218         pos = FSi_DecrementUnicodePosition(str, pos);
219         if ((pos < 0) || FSi_IsUnicodeSlash(str[pos]))
220         {
221             break;
222         }
223     }
224     return pos;
225 }
226 
227 /*---------------------------------------------------------------------------*
228   Name:         FS_InitFile
229 
230   Description:  Initializes the FSFile structure.
231 
232   Arguments:    file: FSFile structure
233 
234   Returns:      None.
235  *---------------------------------------------------------------------------*/
FS_InitFile(FSFile * file)236 void FS_InitFile(FSFile *file)
237 {
238     SDK_NULL_ASSERT(file);
239     {
240         file->arc = NULL;
241         file->userdata = NULL;
242         file->next = NULL;
243         OS_InitThreadQueue(file->queue);
244         file->stat = 0;
245         file->stat |= (FS_COMMAND_INVALID << FS_FILE_STATUS_CMD_SHIFT);
246         file->argument = NULL;
247         file->error = FS_RESULT_SUCCESS;
248     }
249 }
250 
251 /*---------------------------------------------------------------------------*
252   Name:         FS_CancelFile
253 
254   Description:  Requests cancellation of an asynchronous command.
255 
256   Arguments:    file: File handle
257 
258   Returns:      None.
259  *---------------------------------------------------------------------------*/
FS_CancelFile(FSFile * file)260 void FS_CancelFile(FSFile *file)
261 {
262     SDK_NULL_ASSERT(file);
263     SDK_ASSERT(FS_IsAvailable());
264     {
265         OSIntrMode bak_psr = OS_DisableInterrupts();
266         if (FS_IsBusy(file))
267         {
268             file->stat |= FS_FILE_STATUS_CANCEL;
269             file->arc->flag |= FS_ARCHIVE_FLAG_CANCELING;
270         }
271         (void)OS_RestoreInterrupts(bak_psr);
272     }
273 }
274 
275 /*---------------------------------------------------------------------------*
276   Name:         FS_CreateFile
277 
278   Description:  Generates files.
279 
280   Arguments:    path: Path name
281                 mode: Access mode
282 
283   Returns:      TRUE if file is generated normally.
284  *---------------------------------------------------------------------------*/
FS_CreateFile(const char * path,u32 permit)285 BOOL FS_CreateFile(const char *path, u32 permit)
286 {
287     BOOL    retval = FALSE;
288     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
289     SDK_NULL_ASSERT(path);
290     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
291     {
292         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
293         u32         baseid = 0;
294         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
295         if (arc)
296         {
297             FSFile                  file[1];
298             FSArgumentForCreateFile arg[1];
299             FS_InitFile(file);
300             file->arc = arc;
301             file->argument = arg;
302             arg->baseid = baseid;
303             arg->relpath = relpath;
304             arg->permit = permit;
305             retval = FSi_SendCommand(file, FS_COMMAND_CREATEFILE, TRUE);
306         }
307     }
308     return retval;
309 }
310 
311 /*---------------------------------------------------------------------------*
312   Name:         FS_DeleteFile
313 
314   Description:  Deletes files.
315 
316   Arguments:    path: Path name
317 
318   Returns:      TRUE if file is deleted normally.
319  *---------------------------------------------------------------------------*/
FS_DeleteFile(const char * path)320 BOOL FS_DeleteFile(const char *path)
321 {
322     BOOL    retval = FALSE;
323     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
324     SDK_NULL_ASSERT(path);
325     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
326     {
327         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
328         u32         baseid = 0;
329         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
330         if (arc)
331         {
332             FSFile                  file[1];
333             FSArgumentForDeleteFile arg[1];
334             FS_InitFile(file);
335             file->arc = arc;
336             file->argument = arg;
337             arg->baseid = baseid;
338             arg->relpath = relpath;
339             retval = FSi_SendCommand(file, FS_COMMAND_DELETEFILE, TRUE);
340         }
341     }
342     return retval;
343 }
344 
345 /*---------------------------------------------------------------------------*
346   Name:         FS_RenameFile
347 
348   Description:  Changes the filename.
349 
350   Arguments:    src: Filename of the conversion source
351                 dst: Filename of the conversion target
352 
353   Returns:      TRUE if filename is changed normally.
354  *---------------------------------------------------------------------------*/
FS_RenameFile(const char * src,const char * dst)355 BOOL FS_RenameFile(const char *src, const char *dst)
356 {
357     BOOL    retval = FALSE;
358     FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
359     SDK_NULL_ASSERT(src);
360     SDK_NULL_ASSERT(dst);
361     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
362     {
363         char        relpath_src[FS_ARCHIVE_FULLPATH_MAX + 1];
364         char        relpath_dst[FS_ARCHIVE_FULLPATH_MAX + 1];
365         u32         baseid_src = 0;
366         u32         baseid_dst = 0;
367         FSArchive  *arc_src = FS_NormalizePath(src, &baseid_src, relpath_src);
368         FSArchive  *arc_dst = FS_NormalizePath(dst, &baseid_dst, relpath_dst);
369         if (arc_src != arc_dst)
370         {
371             OS_TWarning("cannot rename between defferent archives.\n");
372         }
373         else
374         {
375             FSFile                  file[1];
376             FSArgumentForRenameFile arg[1];
377             FS_InitFile(file);
378             file->arc = arc_src;
379             file->argument = arg;
380             arg->baseid_src = baseid_src;
381             arg->relpath_src = relpath_src;
382             arg->baseid_dst = baseid_dst;
383             arg->relpath_dst = relpath_dst;
384             retval = FSi_SendCommand(file, FS_COMMAND_RENAMEFILE, TRUE);
385         }
386     }
387     return retval;
388 }
389 
390 /*---------------------------------------------------------------------------*
391   Name:         FS_GetPathInfo
392 
393   Description:  Gets file or directory information.
394 
395   Arguments:    path: Path name
396                 info: Location to store the information
397 
398   Returns:      Processing result.
399  *---------------------------------------------------------------------------*/
FS_GetPathInfo(const char * path,FSPathInfo * info)400 BOOL FS_GetPathInfo(const char *path, FSPathInfo *info)
401 {
402     BOOL    retval = FALSE;
403     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
404     SDK_NULL_ASSERT(path);
405     SDK_NULL_ASSERT(info);
406     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
407     {
408         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
409         u32         baseid = 0;
410         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
411         if (arc)
412         {
413             FSFile                      file[1];
414             FSArgumentForGetPathInfo    arg[1];
415             FS_InitFile(file);
416             file->arc = arc;
417             file->argument = arg;
418             arg->baseid = baseid;
419             arg->relpath = relpath;
420             arg->info = info;
421             retval = FSi_SendCommand(file, FS_COMMAND_GETPATHINFO, TRUE);
422         }
423     }
424     return retval;
425 }
426 
427 /*---------------------------------------------------------------------------*
428   Name:         FS_SetPathInfo
429 
430   Description:  Sets file information.
431 
432   Arguments:    path: Path name
433                 info: Location to store the information
434 
435   Returns:      Processing result.
436  *---------------------------------------------------------------------------*/
FS_SetPathInfo(const char * path,const FSPathInfo * info)437 BOOL FS_SetPathInfo(const char *path, const FSPathInfo *info)
438 {
439     BOOL    retval = FALSE;
440     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
441     SDK_NULL_ASSERT(path);
442     SDK_NULL_ASSERT(info);
443     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
444     {
445         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
446         u32         baseid = 0;
447         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
448         if (arc)
449         {
450             FSFile                      file[1];
451             FSArgumentForSetPathInfo    arg[1];
452             FS_InitFile(file);
453             file->arc = arc;
454             file->argument = arg;
455             arg->baseid = baseid;
456             arg->relpath = relpath;
457             arg->info = (FSPathInfo*)info; // To clear FATFS_PROPERTY_CTRL_MASK in info->attributes
458             retval = FSi_SendCommand(file, FS_COMMAND_SETPATHINFO, TRUE);
459         }
460     }
461     return retval;
462 }
463 
464 /*---------------------------------------------------------------------------*
465   Name:         FS_CreateDirectory
466 
467   Description:  Generates a directory.
468 
469   Arguments:    path: Path name
470                 mode: Access mode
471 
472   Returns:      TRUE if directory is generated normally.
473  *---------------------------------------------------------------------------*/
FS_CreateDirectory(const char * path,u32 permit)474 BOOL FS_CreateDirectory(const char *path, u32 permit)
475 {
476     BOOL    retval = FALSE;
477     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
478     SDK_NULL_ASSERT(path);
479     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
480     {
481         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
482         u32         baseid = 0;
483         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
484         if (arc)
485         {
486             FSFile                          file[1];
487             FSArgumentForCreateDirectory    arg[1];
488             FS_InitFile(file);
489             file->arc = arc;
490             file->argument = arg;
491             arg->baseid = baseid;
492             arg->relpath = relpath;
493             arg->permit = permit;
494             retval = FSi_SendCommand(file, FS_COMMAND_CREATEDIRECTORY, TRUE);
495         }
496     }
497     return retval;
498 }
499 
500 /*---------------------------------------------------------------------------*
501   Name:         FS_DeleteDirectory
502 
503   Description:  Deletes the directory.
504 
505   Arguments:    path: Path name
506 
507   Returns:      TRUE if directory is deleted normally.
508  *---------------------------------------------------------------------------*/
FS_DeleteDirectory(const char * path)509 BOOL FS_DeleteDirectory(const char *path)
510 {
511     BOOL    retval = FALSE;
512     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
513     SDK_NULL_ASSERT(path);
514     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
515     {
516         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
517         u32         baseid = 0;
518         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
519         if (arc)
520         {
521             FSFile                          file[1];
522             FSArgumentForDeleteDirectory    arg[1];
523             FS_InitFile(file);
524             file->arc = arc;
525             file->argument = arg;
526             arg->baseid = baseid;
527             arg->relpath = relpath;
528             retval = FSi_SendCommand(file, FS_COMMAND_DELETEDIRECTORY, TRUE);
529         }
530     }
531     return retval;
532 }
533 
534 /*---------------------------------------------------------------------------*
535   Name:         FS_RenameDirectory
536 
537   Description:  Changes the directory name.
538 
539   Arguments:    src: Directory name of the conversion source
540                 dst: Directory name of the conversion destination
541 
542   Returns:      TRUE if directory name is changed normally.
543  *---------------------------------------------------------------------------*/
FS_RenameDirectory(const char * src,const char * dst)544 BOOL FS_RenameDirectory(const char *src, const char *dst)
545 {
546     BOOL    retval = FALSE;
547     FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
548     SDK_NULL_ASSERT(src);
549     SDK_NULL_ASSERT(dst);
550     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
551     {
552         char        relpath_src[FS_ARCHIVE_FULLPATH_MAX + 1];
553         char        relpath_dst[FS_ARCHIVE_FULLPATH_MAX + 1];
554         u32         baseid_src = 0;
555         u32         baseid_dst = 0;
556         FSArchive  *arc_src = FS_NormalizePath(src, &baseid_src, relpath_src);
557         FSArchive  *arc_dst = FS_NormalizePath(dst, &baseid_dst, relpath_dst);
558         if (arc_src != arc_dst)
559         {
560             OS_TWarning("cannot rename between defferent archives.\n");
561         }
562         else
563         {
564             FSFile                          file[1];
565             FSArgumentForRenameDirectory    arg[1];
566             FS_InitFile(file);
567             file->arc = arc_src;
568             file->argument = arg;
569             arg->baseid_src = baseid_src;
570             arg->relpath_src = relpath_src;
571             arg->baseid_dst = baseid_dst;
572             arg->relpath_dst = relpath_dst;
573             retval = FSi_SendCommand(file, FS_COMMAND_RENAMEDIRECTORY, TRUE);
574         }
575     }
576     return retval;
577 }
578 
579 /*---------------------------------------------------------------------------*
580   Name:         FSi_GetFullPath
581 
582   Description:  Converts specified path to full path.
583 
584   Arguments:    dst: Buffer that stores obtained full path
585                             Must be FS_ARCHIVE_FULLPATH_MAX+1 or higher
586                 path: Path name of file or directory
587 
588   Returns:      TRUE if full path was obtained normally.
589  *---------------------------------------------------------------------------*/
FSi_GetFullPath(char * dst,const char * path)590 static BOOL FSi_GetFullPath(char *dst, const char *path)
591 {
592     FSArchive  *arc = FS_NormalizePath(path, NULL, dst);
593     if (arc)
594     {
595         const char *arcname = FS_GetArchiveName(arc);
596         int     m = STD_GetStringLength(arcname);
597         int     n = STD_GetStringLength(dst);
598         (void)STD_MoveMemory(&dst[m + 2], &dst[0], (u32)n + 1);
599         (void)STD_MoveMemory(&dst[0], arcname, (u32)m);
600         dst[m + 0] = ':';
601         dst[m + 1] = '/';
602     }
603     return (arc != NULL);
604 }
605 
606 /*---------------------------------------------------------------------------*
607   Name:         FSi_ComplementDirectory
608 
609   Description:  Checks the existence of all parent directories up to the specified path; automatically generates and supplements nonexistent hierarchies.
610 
611 
612   Arguments:    path: Path name of file or directory
613                             Supplement a directory one level up from this
614                 autogen: Buffer that records the highest directory that was generated automatically
615                             Must be FS_ARCHIVE_FULLPATH_MAX+1 or higher
616                             Results are returned to autogen regardless of their success or failure; if there is a blank string, it indicates that all results exist.
617 
618 
619   Returns:      TRUE if directory is generated normally.
620  *---------------------------------------------------------------------------*/
FSi_ComplementDirectory(const char * path,char * autogen)621 static BOOL FSi_ComplementDirectory(const char *path, char *autogen)
622 {
623     BOOL    retval = FALSE;
624     int     root = 0;
625     // Normalize full path name for now. (Reuse autogen to conserve the stack)
626     char   *tmppath = autogen;
627     if (FSi_GetFullPath(tmppath, path))
628     {
629         int     length = STD_GetStringLength(tmppath);
630         if (length > 0)
631         {
632             int     pos = 0;
633             FS_DEBUG_TRACE("  trying to complete \"%s\"\n", tmppath);
634             // Delete the "/" at the end
635             length = FSi_TrimSjisTrailingSlash(tmppath);
636             // Ignore the lowest entry
637             length = FSi_DecrementSjisPositionToSlash(tmppath, length);
638             // Search the deepest hierarchy that exists
639             for (pos = length; pos >= 0;)
640             {
641                 FSPathInfo  info[1];
642                 BOOL        exists;
643                 tmppath[pos] = '\0';
644                 exists = FS_GetPathInfo(tmppath, info);
645                 FS_DEBUG_TRACE("    - \"%s\" is%s existent (result:%d)\n", tmppath, exists ? "" : " not",
646                                FS_GetArchiveResultCode(tmppath));
647                 tmppath[pos] = '/';
648                 // If an entry does not exist, go to a higher level in hierarchy
649                 if (!exists)
650                 {
651                     pos = FSi_DecrementSjisPositionToSlash(tmppath, pos);
652                 }
653                 // If something exists, stop the search for the time being
654                 else
655                 {
656                     // If the same filename exists, certain failure
657                     if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0)
658                     {
659                         pos = -1;
660                     }
661                     // If the same directory name exists, automatically generate below that level
662                     else
663                     {
664                         ++pos;
665                     }
666                     break;
667                 }
668             }
669             // If a base point is called for, repeatedly generate one after that hierarchy
670             if (pos >= 0)
671             {
672                 for (;;)
673                 {
674                     // If the end is reached, success
675                     if (pos >= length)
676                     {
677                         retval = TRUE;
678                         break;
679                     }
680                     else
681                     {
682                         pos = FSi_IncrementSjisPositionToSlash(tmppath, pos);
683                         tmppath[pos] = '\0';
684                         if (!FS_CreateDirectory(tmppath, FS_PERMIT_R | FS_PERMIT_W))
685                         {
686                             break;
687                         }
688                         else
689                         {
690                             // Store the highest hierarchy
691                             if (root == 0)
692                             {
693                                 FS_DEBUG_TRACE("    - we have created \"%s\" as root\n", tmppath);
694                                 root = pos;
695                             }
696                             tmppath[pos++] = '/';
697                         }
698                     }
699                 }
700             }
701         }
702     }
703     // Record the highest directory automatically generated
704     autogen[root] = '\0';
705     return retval;
706 }
707 
708 /*---------------------------------------------------------------------------*
709   Name:         FS_CreateFileAuto
710 
711   Description:  Generates files including the necessary intermediate directories.
712 
713   Arguments:    path: Path name
714                 permit: Access mode
715 
716   Returns:      TRUE if file is generated normally.
717  *---------------------------------------------------------------------------*/
FS_CreateFileAuto(const char * path,u32 permit)718 BOOL FS_CreateFileAuto(const char *path, u32 permit)
719 {
720     BOOL    result = FALSE;
721     char    autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
722     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
723     if (FSi_ComplementDirectory(path, autogen))
724     {
725         result = FS_CreateFile(path, permit);
726         if (!result)
727         {
728             (void)FS_DeleteDirectoryAuto(autogen);
729         }
730     }
731     return result;
732 }
733 
734 /*---------------------------------------------------------------------------*
735   Name:         FS_DeleteFileAuto
736 
737   Description:  Deletes files including the necessary intermediate directories.
738 
739   Arguments:    path: Path name
740 
741   Returns:      TRUE if file is deleted normally.
742  *---------------------------------------------------------------------------*/
FS_DeleteFileAuto(const char * path)743 BOOL FS_DeleteFileAuto(const char *path)
744 {
745     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
746     // Exists for consistency in command names, but actually the supplement process is unnecessary
747     return FS_DeleteFile(path);
748 }
749 
750 /*---------------------------------------------------------------------------*
751   Name:         FS_RenameFileAuto
752 
753   Description:  Changes filenames including the necessary intermediate directories.
754 
755   Arguments:    src: Filename of the conversion source
756                 dst: Filename of the conversion target
757 
758   Returns:      TRUE if filename is changed normally.
759  *---------------------------------------------------------------------------*/
FS_RenameFileAuto(const char * src,const char * dst)760 BOOL FS_RenameFileAuto(const char *src, const char *dst)
761 {
762     BOOL    result = FALSE;
763     char    autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
764     FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__);
765     if (FSi_ComplementDirectory(dst, autogen))
766     {
767         result = FS_RenameFile(src, dst);
768         if (!result)
769         {
770             (void)FS_DeleteDirectoryAuto(autogen);
771         }
772     }
773     return result;
774 }
775 
776 /*---------------------------------------------------------------------------*
777   Name:         FS_CreateDirectoryAuto
778 
779   Description:  Generates directories including the necessary intermediate directories.
780 
781   Arguments:    path: Directory name to generate
782                 permit: Access mode
783 
784   Returns:      TRUE if directory is generated normally.
785  *---------------------------------------------------------------------------*/
FS_CreateDirectoryAuto(const char * path,u32 permit)786 BOOL FS_CreateDirectoryAuto(const char *path, u32 permit)
787 {
788     BOOL    result = FALSE;
789     char    autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
790     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
791     if (FSi_ComplementDirectory(path, autogen))
792     {
793         result = FS_CreateDirectory(path, permit);
794         if (!result)
795         {
796             (void)FS_DeleteDirectoryAuto(autogen);
797         }
798     }
799     return result;
800 }
801 
802 /*---------------------------------------------------------------------------*
803   Name:         FS_DeleteDirectoryAuto
804 
805   Description:  Recursively deletes the directory.
806 
807   Arguments:    path: Path name
808 
809   Returns:      TRUE if directory is deleted normally.
810  *---------------------------------------------------------------------------*/
FS_DeleteDirectoryAuto(const char * path)811 BOOL FS_DeleteDirectoryAuto(const char *path)
812 {
813     BOOL    retval = FALSE;
814     FS_DEBUG_TRACE( "%s(%s)\n", __FUNCTION__, path);
815     if (path && *path)
816     {
817         char    tmppath[FS_ARCHIVE_FULLPATH_MAX + 1];
818         if (FSi_GetFullPath(tmppath, path))
819         {
820             int     pos;
821             BOOL    mayBeEmpty;
822             int     length = FSi_TrimSjisTrailingSlash(tmppath);
823             FS_DEBUG_TRACE("  trying to force-delete \"%s\"\n", tmppath);
824             mayBeEmpty = TRUE;
825             for (pos = 0; pos >= 0;)
826             {
827                 BOOL    failure = FALSE;
828                 // First, try to directly delete the directory and if successful, go to 1 level
829                 tmppath[length + pos] = '\0';
830                 if (mayBeEmpty && (FS_DeleteDirectory(tmppath) ||
831                     (FS_GetArchiveResultCode(tmppath) == FS_RESULT_ALREADY_DONE)))
832                 {
833                     FS_DEBUG_TRACE("  -> succeeded to delete \"%s\"\n", tmppath);
834                     pos = FSi_DecrementSjisPositionToSlash(&tmppath[length], pos);
835                 }
836                 else
837                 {
838                     // Enumerate all entries if the directory is to be opened
839                     FSFile  dir[1];
840                     FS_InitFile(dir);
841                     if (!FS_OpenDirectory(dir, tmppath, FS_FILEMODE_R))
842                     {
843                         FS_DEBUG_TRACE("  -> failed to delete & open \"%s\"\n", tmppath);
844                         failure = TRUE;
845                     }
846                     else
847                     {
848                         FSDirectoryEntryInfo    info[1];
849                         tmppath[length + pos] = '/';
850                         mayBeEmpty = TRUE;
851                         while (FS_ReadDirectory(dir, info))
852                         {
853                             (void)STD_CopyString(&tmppath[length + pos + 1], info->longname);
854                             // If the file exists, delete it
855                             if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0)
856                             {
857                                 if (!FS_DeleteFile(tmppath))
858                                 {
859                                     FS_DEBUG_TRACE("  -> failed to delete file \"%s\"\n", tmppath);
860                                     failure = TRUE;
861                                     break;
862                                 }
863                                 FS_DEBUG_TRACE("  -> succeeded to delete \"%s\"\n", tmppath);
864                             }
865                             // If "." or ".." ignore
866                             else if ((STD_CompareString(info->longname, ".") == 0) ||
867                                      (STD_CompareString(info->longname, "..") == 0))
868                             {
869                             }
870                             // If a directory that is empty exists, move to a lower level
871                             else if (!FS_DeleteDirectory(tmppath))
872                             {
873                                 pos += 1 + STD_GetStringLength(info->longname);
874                                 mayBeEmpty = FALSE;
875                                 break;
876                             }
877                         }
878                         (void)FS_CloseDirectory(dir);
879                     }
880                 }
881                 // Cancel processing when even operations that should succeed fail (such as ALREADY_DONE)
882                 if (failure)
883                 {
884                     break;
885                 }
886             }
887             retval = (pos < 0);
888         }
889     }
890     return retval;
891 }
892 
893 /*---------------------------------------------------------------------------*
894   Name:         FS_RenameDirectoryAuto
895 
896   Description:  Changes the directory name by automatically generating the necessary intermediate directories.
897 
898   Arguments:    src: Directory name of the conversion source
899                 dst: Directory name of the conversion destination
900 
901   Returns:      TRUE if directory name is changed normally.
902  *---------------------------------------------------------------------------*/
FS_RenameDirectoryAuto(const char * src,const char * dst)903 BOOL FS_RenameDirectoryAuto(const char *src, const char *dst)
904 {
905     BOOL    result = FALSE;
906     char    autogen[FS_ARCHIVE_FULLPATH_MAX + 1];
907     FS_DEBUG_TRACE( "%s(%s->%s)\n", __FUNCTION__, src, dst);
908     if (FSi_ComplementDirectory(dst, autogen))
909     {
910         result = FS_RenameDirectory(src, dst);
911         if (!result)
912         {
913             (void)FS_DeleteDirectoryAuto(autogen);
914         }
915     }
916     return result;
917 }
918 
919 /*---------------------------------------------------------------------------*
920   Name:         FS_GetArchiveResource
921 
922   Description:  Gets resource information of the specified archive.
923 
924   Arguments:    path: Path name that specifies the archive
925                 resource: Storage destination of obtained resource information
926 
927   Returns:      TRUE if resource information is obtained normally.
928  *---------------------------------------------------------------------------*/
FS_GetArchiveResource(const char * path,FSArchiveResource * resource)929 BOOL FS_GetArchiveResource(const char *path, FSArchiveResource *resource)
930 {
931     BOOL    retval = FALSE;
932     SDK_NULL_ASSERT(path);
933     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
934     {
935         FSArchive  *arc = FS_NormalizePath(path, NULL, NULL);
936         if (arc)
937         {
938             FSFile                          file[1];
939             FSArgumentForGetArchiveResource arg[1];
940             FS_InitFile(file);
941             file->arc = arc;
942             file->argument = arg;
943             arg->resource = resource;
944             retval = FSi_SendCommand(file, FS_COMMAND_GETARCHIVERESOURCE, TRUE);
945         }
946     }
947     return retval;
948 }
949 
950 /*---------------------------------------------------------------------------*
951   Name:         FSi_GetSpaceToCreateDirectoryEntries
952 
953   Description:  Estimates the volume of the directory entry generated at the same time as the file.
954                 (Assumes that the directory that exists in the path is newly generated.)
955 
956   Arguments:    path: Path name of generated file
957                 bytesPerCluster: Number of bytes per cluster on file system
958 
959   Returns:      Capacity.
960  *---------------------------------------------------------------------------*/
FSi_GetSpaceToCreateDirectoryEntries(const char * path,u32 bytesPerCluster)961 u32 FSi_GetSpaceToCreateDirectoryEntries(const char *path, u32 bytesPerCluster)
962 {
963     static const u32    bytesPerEntry = 32UL;
964     static const u32    longnamePerEntry = 13UL;
965     // Deletes the scheme if it is a full path and individually determines each entry
966     const char         *root = STD_SearchString(path, ":");
967     const char         *current = (root != NULL) ? (root + 1) : path;
968     u32                 totalBytes = 0;
969     u32                 restBytesInCluster = 0;
970     current += (*current == '/');
971     while (*current)
972     {
973         BOOL    isShortName = FALSE;
974         u32     entries = 0;
975         // Calculate entry name length
976         u32     len = (u32)FSi_IncrementSjisPositionToSlash(current, 0);
977         // Determine whether the entry name can be expressed in 8.3 format
978 #if 0
979         // (FAT drivers employed for TWL are always saved with long filenames, so it was not necessary to strictly determine up to here actually)
980         //
981         {
982             static const char  *alnum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
983             static const char  *special = "!#$%&'()*+-<>?@^_`{}~";
984             if ((len <= 8 + 1 + 3) && STD_SearchChar(alnum, current[0]))
985             {
986                 u32     namelen = 0;
987                 u32     extlen = 0;
988                 u32     scanned = 0;
989                 for (; namelen < len; ++namelen)
990                 {
991                     char    c = current[scanned + namelen];
992                     if (!STD_SearchChar(alnum, c) && !STD_SearchChar(special, c))
993                     {
994                         break;
995                     }
996                 }
997                 scanned += namelen;
998                 if ((scanned < len) && (current[scanned] == '.'))
999                 {
1000                     ++scanned;
1001                     for (; scanned + extlen < len; ++extlen)
1002                     {
1003                         char    c = current[scanned + extlen];
1004                         if (!STD_SearchChar(alnum, c) && !STD_SearchChar(special, c))
1005                         {
1006                             break;
1007                         }
1008                     }
1009                     scanned += extlen;
1010                 }
1011                 if ((scanned == len) && (namelen <= 8) && (extlen <= 3))
1012                 {
1013                     isShortName = TRUE;
1014                 }
1015             }
1016         }
1017 #endif
1018         // If it is not in 8.3 format, an added entry is needed for long filenames
1019         if (!isShortName)
1020         {
1021             entries += ((len + longnamePerEntry - 1UL) / longnamePerEntry);
1022         }
1023         // Anyway, 1 entry is always considered to be consumed
1024         entries += 1;
1025         current += len;
1026         // If the cluster margins of directories already created by yourself are inadequate, consume excess entries in cluster units
1027         //
1028         {
1029             int     over = (int)(entries * bytesPerEntry - restBytesInCluster);
1030             if (over > 0)
1031             {
1032                 totalBytes += MATH_ROUNDUP(over, bytesPerCluster);
1033             }
1034         }
1035         // If there is still a lower level, consume 1 cluster as a directory, and the size minus two entries of "." and ".." will be the margin
1036         //
1037         if (*current != '\0')
1038         {
1039             current += 1;
1040             totalBytes += bytesPerCluster;
1041             restBytesInCluster = bytesPerCluster - (2 * bytesPerEntry);
1042         }
1043     }
1044     return totalBytes;
1045 }
1046 
1047 /*---------------------------------------------------------------------------*
1048   Name:         FS_HasEnoughSpaceToCreateFile
1049 
1050   Description:  Determines whether it is currently possible to generate files having the specified path name and size
1051 
1052   Arguments:    resource: Archive information obtained by the FS_GetArchiveResource function in advance
1053                             If the function is successful, the sizes consumed by the files are reduced
1054                 path: Path name of generated file
1055                 size: Size of generated file
1056 
1057   Returns:      TRUE if it is currently possible to generate files having the specified path name and size.
1058  *---------------------------------------------------------------------------*/
FS_HasEnoughSpaceToCreateFile(FSArchiveResource * resource,const char * path,u32 size)1059 BOOL FS_HasEnoughSpaceToCreateFile(FSArchiveResource *resource, const char *path, u32 size)
1060 {
1061     BOOL    retval = FALSE;
1062     u32 bytesPerCluster = resource->bytesPerSector * resource->sectorsPerCluster;
1063     if (bytesPerCluster != 0)
1064     {
1065         u32     needbytes = (FSi_GetSpaceToCreateDirectoryEntries(path, bytesPerCluster) +
1066                              MATH_ROUNDUP(size, bytesPerCluster));
1067         u32     needclusters = needbytes / bytesPerCluster;
1068         if (needclusters <= resource->availableClusters)
1069         {
1070             resource->availableClusters -= needclusters;
1071             resource->availableSize -= needbytes;
1072             retval = TRUE;
1073         }
1074     }
1075     return retval;
1076 }
1077 
1078 /*---------------------------------------------------------------------------*
1079   Name:         FS_IsArchiveReady
1080 
1081   Description:  Determines whether it is currently possible to use the specified archive.
1082 
1083   Arguments:    path: Absolute path beginning with "archive name:"
1084 
1085   Returns:      TRUE if currently possible to use the specified archive name.
1086                 FALSE if an SD card archive that is not inserted in the slot or a save data archive not yet imported.
1087 
1088  *---------------------------------------------------------------------------*/
FS_IsArchiveReady(const char * path)1089 BOOL FS_IsArchiveReady(const char *path)
1090 {
1091     FSArchiveResource   resource[1];
1092     return FS_GetArchiveResource(path, resource);
1093 }
1094 
1095 /*---------------------------------------------------------------------------*
1096   Name:         FS_FlushFile
1097 
1098   Description:  Applies the file changes to the device.
1099 
1100   Arguments:    file: File handle
1101 
1102   Returns:      Processing result.
1103  *---------------------------------------------------------------------------*/
FS_FlushFile(FSFile * file)1104 FSResult FS_FlushFile(FSFile *file)
1105 {
1106     FSResult    retval = FS_RESULT_ERROR;
1107     SDK_NULL_ASSERT(file);
1108     SDK_ASSERT(FS_IsFile(file));
1109     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1110     {
1111         (void)FSi_SendCommand(file, FS_COMMAND_FLUSHFILE, TRUE);
1112         retval = FS_GetResultCode(file);
1113     }
1114     return retval;
1115 }
1116 
1117 /*---------------------------------------------------------------------------*
1118   Name:         FS_SetFileLength
1119 
1120   Description:  Changes the file size.
1121 
1122   Arguments:    file: File handle
1123                 length: Size after changes
1124 
1125   Returns:      Processing result.
1126  *---------------------------------------------------------------------------*/
FS_SetFileLength(FSFile * file,u32 length)1127 FSResult FS_SetFileLength(FSFile *file, u32 length)
1128 {
1129     FSResult    retval = FS_RESULT_ERROR;
1130     SDK_NULL_ASSERT(file);
1131     SDK_ASSERT(FS_IsFile(file));
1132     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1133     {
1134         FSArgumentForSetFileLength  arg[1];
1135         file->argument = arg;
1136         arg->length = length;
1137         (void)FSi_SendCommand(file, FS_COMMAND_SETFILELENGTH, TRUE);
1138         retval = FS_GetResultCode(file);
1139     }
1140     return retval;
1141 }
1142 
1143 /*---------------------------------------------------------------------------*
1144   Name:         FS_GetPathName
1145 
1146   Description:  Gets path name of the specified handle.
1147 
1148   Arguments:    file: File or directory
1149                 buffer: Path storage destination
1150                 length: Buffer size
1151 
1152   Returns:      TRUE if successful.
1153  *---------------------------------------------------------------------------*/
FS_GetPathName(FSFile * file,char * buffer,u32 length)1154 BOOL FS_GetPathName(FSFile *file, char *buffer, u32 length)
1155 {
1156     BOOL    retval = FALSE;
1157     SDK_ASSERT(FS_IsAvailable());
1158     SDK_ASSERT(FS_IsFile(file) || FS_IsDir(file));
1159     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1160     {
1161         FSArgumentForGetPath    arg[1];
1162         file->argument = arg;
1163         arg->is_directory = FS_IsDir(file);
1164         arg->buffer = buffer;
1165         arg->length = length;
1166         retval = FSi_SendCommand(file, FS_COMMAND_GETPATH, TRUE);
1167     }
1168     return retval;
1169 }
1170 
1171 /*---------------------------------------------------------------------------*
1172   Name:         FS_GetPathLength
1173 
1174   Description:  Gets length of full path name of the specified file or directory.
1175 
1176   Arguments:    file: File or directory handle
1177 
1178   Returns:      Length of the path name that included '\0' at the end if successful, and -1 if failed.
1179  *---------------------------------------------------------------------------*/
FS_GetPathLength(FSFile * file)1180 s32 FS_GetPathLength(FSFile *file)
1181 {
1182     s32     retval = -1;
1183     if (FS_GetPathName(file, NULL, 0))
1184     {
1185         retval = file->arg.getpath.total_len;
1186     }
1187     return retval;
1188 }
1189 
1190 /*---------------------------------------------------------------------------*
1191   Name:         FS_ConvertPathToFileID
1192 
1193   Description:  Gets file ID from the path name.
1194 
1195   Arguments:    p_fileid: FSFileID storage destination
1196                 path: Path name
1197 
1198   Returns:      TRUE if successful.
1199  *---------------------------------------------------------------------------*/
FS_ConvertPathToFileID(FSFileID * p_fileid,const char * path)1200 BOOL FS_ConvertPathToFileID(FSFileID *p_fileid, const char *path)
1201 {
1202     BOOL    retval = FALSE;
1203     SDK_NULL_ASSERT(p_fileid);
1204     SDK_NULL_ASSERT(path);
1205     SDK_ASSERT(FS_IsAvailable());
1206     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1207     {
1208         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1209         u32         baseid = 0;
1210         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
1211         if (arc)
1212         {
1213             FSFile      file[1];
1214             FSArgumentForFindPath   arg[1];
1215             FS_InitFile(file);
1216             file->arc = arc;
1217             file->argument = arg;
1218             arg->baseid = baseid;
1219             arg->relpath = relpath;
1220             arg->target_is_directory = FALSE;
1221             if (FSi_SendCommand(file, FS_COMMAND_FINDPATH, TRUE))
1222             {
1223                 p_fileid->arc = arc;
1224                 p_fileid->file_id = arg->target_id;
1225                 retval = TRUE;
1226             }
1227         }
1228     }
1229     return retval;
1230 }
1231 
1232 /*---------------------------------------------------------------------------*
1233   Name:         FS_OpenFileDirect
1234 
1235   Description:  Opens the file by directly specifying the region of the archive.
1236 
1237   Arguments:    file: FSFile that retains handle information
1238                 arc: Archive that is the map source
1239                 image_top: Offset for the file image start
1240                 image_bottom: Offset of the file image terminator
1241                 id: Arbitrarily specified file ID
1242 
1243   Returns:      TRUE if successful.
1244  *---------------------------------------------------------------------------*/
FS_OpenFileDirect(FSFile * file,FSArchive * arc,u32 image_top,u32 image_bottom,u32 id)1245 BOOL FS_OpenFileDirect(FSFile *file, FSArchive *arc,
1246                        u32 image_top, u32 image_bottom, u32 id)
1247 {
1248     BOOL    retval = FALSE;
1249     SDK_NULL_ASSERT(file);
1250     SDK_NULL_ASSERT(arc);
1251     SDK_ASSERT(FS_IsAvailable());
1252     SDK_ASSERT(!FS_IsFile(file));
1253     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1254     {
1255         FSArgumentForOpenFileDirect arg[1];
1256         file->arc = arc;
1257         file->argument = arg;
1258         arg->id = id;
1259         arg->top = image_top;
1260         arg->bottom = image_bottom;
1261         arg->mode = 0;
1262         retval = FSi_SendCommand(file, FS_COMMAND_OPENFILEDIRECT, TRUE);
1263     }
1264     return retval;
1265 }
1266 
1267 /*---------------------------------------------------------------------------*
1268   Name:         FS_OpenFileFast
1269 
1270   Description:  Opens the file by specifying the ID.
1271 
1272   Arguments:    file: FSFile that retains handle information
1273                 id: FSFileID that indicates the file to be opened
1274 
1275   Returns:      TRUE if successful.
1276  *---------------------------------------------------------------------------*/
FS_OpenFileFast(FSFile * file,FSFileID id)1277 BOOL FS_OpenFileFast(FSFile *file, FSFileID id)
1278 {
1279     BOOL    retval = FALSE;
1280     SDK_NULL_ASSERT(file);
1281     SDK_ASSERT(FS_IsAvailable());
1282     SDK_ASSERT(!FS_IsFile(file));
1283     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1284     if (id.arc)
1285     {
1286         FSArgumentForOpenFileFast   arg[1];
1287         file->arc = id.arc;
1288         file->argument = arg;
1289         arg->id = id.file_id;
1290         arg->mode = 0;
1291         retval = FSi_SendCommand(file, FS_COMMAND_OPENFILEFAST, TRUE);
1292     }
1293     return retval;
1294 }
1295 
1296 /*---------------------------------------------------------------------------*
1297   Name:         FS_OpenFileEx
1298 
1299   Description:  Opens the file by specifying the path name.
1300 
1301   Arguments:    file: FSFile structure
1302                 path: Path name
1303 
1304   Returns:      TRUE if successful.
1305  *---------------------------------------------------------------------------*/
FS_OpenFileEx(FSFile * file,const char * path,u32 mode)1306 BOOL FS_OpenFileEx(FSFile *file, const char *path, u32 mode)
1307 {
1308     BOOL    retval = FALSE;
1309     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1310     SDK_NULL_ASSERT(file);
1311     SDK_NULL_ASSERT(path);
1312     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1313 
1314     // Logic check relating to FS_FILEMODE_L
1315     // (It is meaningless if there is a size restriction when opening in creation mode)
1316     if (((mode & FS_FILEMODE_L) != 0) &&
1317         ((mode & FS_FILEMODE_RW) == FS_FILEMODE_W))
1318     {
1319         OS_TWarning("\"FS_FILEMODE_WL\" seems useless.\n"
1320                     "(this means creating empty file and prohibiting any modifications)");
1321     }
1322     {
1323         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1324         u32         baseid = 0;
1325         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
1326         if (arc)
1327         {
1328             FSArgumentForOpenFile   arg[1];
1329             FS_InitFile(file);
1330             file->arc = arc;
1331             file->argument = arg;
1332             arg->baseid = baseid;
1333             arg->relpath = relpath;
1334             arg->mode = mode;
1335             if (FSi_SendCommand(file, FS_COMMAND_OPENFILE, TRUE))
1336             {
1337                 retval = TRUE;
1338             }
1339             else
1340             {
1341                 file->arc = NULL;
1342             }
1343         }
1344     }
1345     return retval;
1346 }
1347 
1348 /*---------------------------------------------------------------------------*
1349   Name:         FS_CloseFile
1350 
1351   Description:  Closes the file.
1352 
1353   Arguments:    file: File handle
1354 
1355   Returns:      TRUE if successful.
1356  *---------------------------------------------------------------------------*/
FS_CloseFile(FSFile * file)1357 BOOL FS_CloseFile(FSFile *file)
1358 {
1359     BOOL    retval = FALSE;
1360     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1361     SDK_NULL_ASSERT(file);
1362     SDK_ASSERT(FS_IsAvailable());
1363     SDK_ASSERT(FS_IsFile(file));
1364     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1365     {
1366         retval = FSi_SendCommand(file, FS_COMMAND_CLOSEFILE, TRUE);
1367     }
1368     return retval;
1369 }
1370 
1371 /*---------------------------------------------------------------------------*
1372   Name:         FS_GetSeekCacheSize
1373 
1374   Description:  Finds the necessary buffer size for the full cache for high-speed reverse seek.
1375 
1376   Arguments:    path
1377 
1378   Returns:      Size if successful; 0 if failed.
1379  *---------------------------------------------------------------------------*/
FS_GetSeekCacheSize(const char * path)1380 u32 FS_GetSeekCacheSize(const char *path)
1381 {
1382     u32         retval = 0;
1383     // Gets the size if the file exists
1384     FSPathInfo  info;
1385     if (FS_GetPathInfo(path, &info) &&
1386         ((info.attributes & FS_ATTRIBUTE_IS_DIRECTORY) == 0))
1387     {
1388         // Get FAT information of the corresponding archive
1389         FSArchiveResource   resource;
1390         if (FS_GetArchiveResource(path, &resource))
1391         {
1392             // Calculate the cache size if the actual archive of the FAT base
1393             u32     bytesPerCluster = resource.sectorsPerCluster * resource.bytesPerSector;
1394             if (bytesPerCluster != 0)
1395             {
1396                 static const u32    fatBits = 32;
1397                 retval = (u32)((info.filesize + bytesPerCluster - 1) / bytesPerCluster) * ((fatBits + 4) / 8);
1398 				// Add margin to align the portions before and after the buffer to the cache lines
1399                 retval += (u32)(HW_CACHE_LINE_SIZE * 2);
1400             }
1401         }
1402     }
1403     return retval;
1404 }
1405 
1406 /*---------------------------------------------------------------------------*
1407   Name:         FS_SetSeekCache
1408 
1409   Description:  Assigns cache buffer for high-speed reverse seek.
1410 
1411   Arguments:    file: File handle
1412                 buf: Cache buffer
1413                 buf_size: Cache buffer size
1414 
1415   Returns:      TRUE if successful.
1416  *---------------------------------------------------------------------------*/
FS_SetSeekCache(FSFile * file,void * buf,u32 buf_size)1417 BOOL FS_SetSeekCache(FSFile *file, void* buf, u32 buf_size)
1418 {
1419     FSArgumentForSetSeekCache    arg[1];
1420     BOOL     retval = FALSE;
1421     SDK_ASSERT(FS_IsAvailable());
1422     SDK_ASSERT(FS_IsFile(file));
1423 
1424     file->argument = arg;
1425     arg->buf      = buf;
1426     arg->buf_size = buf_size;
1427     retval = FSi_SendCommand(file, FS_COMMAND_SETSEEKCACHE, TRUE);
1428 
1429     return retval;
1430 }
1431 
1432 /*---------------------------------------------------------------------------*
1433   Name:         FS_GetFileLength
1434 
1435   Description:  Gets file size.
1436 
1437   Arguments:    file: File handle
1438 
1439   Returns:      File size.
1440  *---------------------------------------------------------------------------*/
FS_GetFileLength(FSFile * file)1441 u32 FS_GetFileLength(FSFile *file)
1442 {
1443     u32     retval = 0;
1444     SDK_ASSERT(FS_IsAvailable());
1445     SDK_ASSERT(FS_IsFile(file));
1446     // Can reference directly in this case if it is an archive procedure
1447     if (!FSi_GetFileLengthIfProc(file, &retval))
1448     {
1449         FSArgumentForGetFileLength    arg[1];
1450         file->argument = arg;
1451         arg->length = 0;
1452         if (FSi_SendCommand(file, FS_COMMAND_GETFILELENGTH, TRUE))
1453         {
1454             retval = arg->length;
1455         }
1456     }
1457     return retval;
1458 }
1459 
1460 /*---------------------------------------------------------------------------*
1461   Name:         FS_GetFilePosition
1462 
1463   Description:  Gets the current position of the file pointer.
1464 
1465   Arguments:    file: File handle
1466 
1467   Returns:      Current position of the file pointer.
1468  *---------------------------------------------------------------------------*/
FS_GetFilePosition(FSFile * file)1469 u32 FS_GetFilePosition(FSFile *file)
1470 {
1471     u32     retval = 0;
1472     SDK_ASSERT(FS_IsAvailable());
1473     SDK_ASSERT(FS_IsFile(file));
1474     // Can reference directly in this case if it is an archive procedure
1475     if (!FSi_GetFilePositionIfProc(file, &retval))
1476     {
1477         FSArgumentForGetFilePosition    arg[1];
1478         file->argument = arg;
1479         arg->position = 0;
1480         if (FSi_SendCommand(file, FS_COMMAND_GETFILEPOSITION, TRUE))
1481         {
1482             retval = arg->position;
1483         }
1484     }
1485     return retval;
1486 }
1487 
1488 /*---------------------------------------------------------------------------*
1489   Name:         FS_SeekFile
1490 
1491   Description:  Moves the file pointer.
1492 
1493   Arguments:    file: File handle
1494                 offset: Movement amount
1495                 origin: Movement starting point
1496 
1497   Returns:      TRUE if successful.
1498  *---------------------------------------------------------------------------*/
FS_SeekFile(FSFile * file,s32 offset,FSSeekFileMode origin)1499 BOOL FS_SeekFile(FSFile *file, s32 offset, FSSeekFileMode origin)
1500 {
1501     BOOL    retval = FALSE;
1502     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1503     SDK_NULL_ASSERT(file);
1504     SDK_ASSERT(FS_IsAvailable());
1505     SDK_ASSERT(FS_IsFile(file));
1506     {
1507         FSArgumentForSeekFile   arg[1];
1508         file->argument = arg;
1509         arg->offset = (int)offset;
1510         arg->from = origin;
1511         retval = FSi_SendCommand(file, FS_COMMAND_SEEKFILE, TRUE);
1512     }
1513     return retval;
1514 }
1515 
1516 /*---------------------------------------------------------------------------*
1517   Name:         FS_ReadFile
1518 
1519   Description:  Read data from the file.
1520 
1521   Arguments:    file: File handle
1522                 buffer: Transfer destination buffer
1523                 length: Read size.
1524 
1525   Returns:      Actual read size if successful, -1 if failed.
1526  *---------------------------------------------------------------------------*/
FS_ReadFile(FSFile * file,void * buffer,s32 length)1527 s32 FS_ReadFile(FSFile *file, void *buffer, s32 length)
1528 {
1529     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1530     SDK_NULL_ASSERT(file);
1531     SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1532     SDK_ASSERT(FS_IsAvailable());
1533     SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1534     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1535     {
1536         FSArgumentForReadFile   arg[1];
1537         file->argument = arg;
1538         arg->buffer = buffer;
1539         arg->length = (u32)length;
1540         if (FSi_SendCommand(file, FS_COMMAND_READFILE, TRUE))
1541         {
1542             length = (s32)arg->length;
1543         }
1544         else
1545         {
1546             if( file->error == FS_RESULT_INVALID_PARAMETER) {
1547                 length = -1; //If not read at all
1548             }else{
1549                 length = (s32)arg->length; //If reading was tried, a value higher than -1 is entered
1550             }
1551         }
1552     }
1553     return length;
1554 }
1555 
1556 /*---------------------------------------------------------------------------*
1557   Name:         FS_ReadFileAsync
1558 
1559   Description:  Asynchronously reads data from the file.
1560 
1561   Arguments:    file: File handle
1562                 buffer: Transfer destination buffer
1563                 length: Read size
1564 
1565   Returns:      Simply the same value as the length if successful, and -1 if failed.
1566  *---------------------------------------------------------------------------*/
FS_ReadFileAsync(FSFile * file,void * buffer,s32 length)1567 s32 FS_ReadFileAsync(FSFile *file, void *buffer, s32 length)
1568 {
1569     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1570     SDK_NULL_ASSERT(file);
1571     SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1572     SDK_ASSERT(FS_IsAvailable());
1573     SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1574     // Correct size in this case if it is an archive procedure
1575     {
1576         u32     end, pos;
1577         if (FSi_GetFilePositionIfProc(file, &pos) &&
1578             FSi_GetFileLengthIfProc(file, &end) &&
1579             (pos + length > end))
1580         {
1581             length = (s32)(end - pos);
1582         }
1583     }
1584     {
1585         FSArgumentForReadFile  *arg = (FSArgumentForReadFile*)file->reserved2;
1586         file->argument = arg;
1587         arg->buffer = buffer;
1588         arg->length = (u32)length;
1589         (void)FSi_SendCommand(file, FS_COMMAND_READFILE, FALSE);
1590     }
1591     return length;
1592 }
1593 
1594 /*---------------------------------------------------------------------------*
1595   Name:         FS_WriteFile
1596 
1597   Description:  Writes data to the file.
1598 
1599   Arguments:    file: File handle
1600                 buffer: Transfer source buffer
1601                 length: Write size
1602 
1603   Returns:      Actual write size if successful, -1 if failed.
1604  *---------------------------------------------------------------------------*/
FS_WriteFile(FSFile * file,const void * buffer,s32 length)1605 s32 FS_WriteFile(FSFile *file, const void *buffer, s32 length)
1606 {
1607     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1608     SDK_NULL_ASSERT(file);
1609     SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1610     SDK_ASSERT(FS_IsAvailable());
1611     SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1612     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1613     {
1614         FSArgumentForWriteFile  arg[1];
1615         file->argument = arg;
1616         arg->buffer = buffer;
1617         arg->length = (u32)length;
1618         if (FSi_SendCommand(file, FS_COMMAND_WRITEFILE, TRUE))
1619         {
1620             length = (s32)arg->length;
1621         }
1622         else
1623         {
1624             if( file->error == FS_RESULT_INVALID_PARAMETER) {
1625                 length = -1; //If not written at all
1626             }else{
1627                 length = (s32)arg->length; //If writing was tried, a value higher than -1 is entered
1628             }
1629         }
1630     }
1631     return length;
1632 }
1633 
1634 /*---------------------------------------------------------------------------*
1635   Name:         FS_WriteFileAsync
1636 
1637   Description:  Asynchronously writes data to file.
1638 
1639   Arguments:    file: File handle
1640                 buffer: Transfer source buffer
1641                 length: Write size
1642 
1643   Returns:      Simply the same value as the length if successful, and -1 if failed.
1644  *---------------------------------------------------------------------------*/
FS_WriteFileAsync(FSFile * file,const void * buffer,s32 length)1645 s32 FS_WriteFileAsync(FSFile *file, const void *buffer, s32 length)
1646 {
1647     SDK_NULL_ASSERT(file);
1648     SDK_ASSERT(FSi_IsValidTransferRegion(buffer, length));
1649     SDK_ASSERT(FS_IsAvailable());
1650     SDK_ASSERT(FS_IsFile(file) && !FS_IsBusy(file));
1651     // Correct size in this case if it is an archive procedure
1652     {
1653         u32     end, pos;
1654         if (FSi_GetFilePositionIfProc(file, &pos) &&
1655             FSi_GetFileLengthIfProc(file, &end) &&
1656             (pos + length > end))
1657         {
1658             length = (s32)(end - pos);
1659         }
1660     }
1661     {
1662         FSArgumentForWriteFile *arg = (FSArgumentForWriteFile*)file->reserved2;
1663         file->argument = arg;
1664         arg->buffer = buffer;
1665         arg->length = (u32)length;
1666         (void)FSi_SendCommand(file, FS_COMMAND_WRITEFILE, FALSE);
1667     }
1668     return length;
1669 }
1670 
1671 /*---------------------------------------------------------------------------*
1672   Name:         FS_OpenDirectory
1673 
1674   Description:  Opens the directory handle.
1675 
1676   Arguments:    file: FSFile structure
1677                 path: Path name
1678                 mode: Access mode
1679 
1680   Returns:      TRUE if successful.
1681  *---------------------------------------------------------------------------*/
FS_OpenDirectory(FSFile * file,const char * path,u32 mode)1682 BOOL FS_OpenDirectory(FSFile *file, const char *path, u32 mode)
1683 {
1684     BOOL    retval = FALSE;
1685     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1686     SDK_NULL_ASSERT(path);
1687     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1688     {
1689         char        relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
1690         u32         baseid = 0;
1691         FSArchive  *arc = FS_NormalizePath(path, &baseid, relpath);
1692         if (arc)
1693         {
1694             FSArgumentForOpenDirectory  arg[1];
1695             FS_InitFile(file);
1696             file->arc = arc;
1697             file->argument = arg;
1698             arg->baseid = baseid;
1699             arg->relpath = relpath;
1700             arg->mode = mode;
1701             if (FSi_SendCommand(file, FS_COMMAND_OPENDIRECTORY, TRUE))
1702             {
1703                 retval = TRUE;
1704             }
1705             else
1706             {
1707                 file->arc = NULL;
1708             }
1709         }
1710     }
1711     return retval;
1712 }
1713 
1714 /*---------------------------------------------------------------------------*
1715   Name:         FS_CloseDirectory
1716 
1717   Description:  Closes the directory handle.
1718 
1719   Arguments:    file: FSFile structure
1720 
1721   Returns:      TRUE if successful.
1722  *---------------------------------------------------------------------------*/
FS_CloseDirectory(FSFile * file)1723 BOOL FS_CloseDirectory(FSFile *file)
1724 {
1725     BOOL    retval = FALSE;
1726     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
1727     SDK_NULL_ASSERT(file);
1728     SDK_ASSERT(FS_IsAvailable());
1729     SDK_ASSERT(FS_IsDir(file));
1730     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1731     {
1732         if (FSi_SendCommand(file, FS_COMMAND_CLOSEDIRECTORY, TRUE))
1733         {
1734             retval = TRUE;
1735         }
1736     }
1737     return retval;
1738 }
1739 
1740 /*---------------------------------------------------------------------------*
1741   Name:         FS_ReadDirectory
1742 
1743   Description:  Reads only one entry of the directory and advances.
1744 
1745   Arguments:    file: FSFile structure
1746                 info: FSDirectoryEntryInfo structure
1747 
1748   Returns:      TRUE if successful.
1749  *---------------------------------------------------------------------------*/
FS_ReadDirectory(FSFile * file,FSDirectoryEntryInfo * info)1750 BOOL FS_ReadDirectory(FSFile *file, FSDirectoryEntryInfo *info)
1751 {
1752     BOOL    retval = FALSE;
1753     SDK_NULL_ASSERT(file);
1754     SDK_NULL_ASSERT(info);
1755     SDK_ASSERT(FS_IsAvailable());
1756     SDK_ASSERT(FS_IsDir(file));
1757     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1758     {
1759         FSArgumentForReadDirectory  arg[1];
1760         file->argument = arg;
1761         arg->info = info;
1762         MI_CpuFill8(info, 0x00, sizeof(info));
1763         info->id = FS_INVALID_FILE_ID;
1764         if (FSi_SendCommand(file, FS_COMMAND_READDIR, TRUE))
1765         {
1766             retval = TRUE;
1767         }
1768     }
1769     return retval;
1770 }
1771 
1772 /*---------------------------------------------------------------------------*
1773   Name:         FS_SeekDir
1774 
1775   Description:  Opens by specifying the directory position.
1776 
1777   Arguments:    file: FSFile structure
1778                 pos: Directory position obtained by FS_ReadDir and FS_TellDir
1779 
1780   Returns:      TRUE if successful.
1781  *---------------------------------------------------------------------------*/
FS_SeekDir(FSFile * file,const FSDirPos * pos)1782 BOOL FS_SeekDir(FSFile *file, const FSDirPos *pos)
1783 {
1784     BOOL    retval = FALSE;
1785     SDK_NULL_ASSERT(file);
1786     SDK_NULL_ASSERT(pos);
1787     SDK_NULL_ASSERT(pos->arc);
1788     SDK_ASSERT(FS_IsAvailable());
1789     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1790     {
1791         FSArgumentForSeekDirectory  arg[1];
1792         arg->id = (u32)((pos->own_id << 0) | (pos->index << 16));
1793         arg->position = pos->pos;
1794         file->arc = pos->arc;
1795         file->argument = arg;
1796         if (FSi_SendCommand(file, FS_COMMAND_SEEKDIR, TRUE))
1797         {
1798             file->stat |= FS_FILE_STATUS_IS_DIR;
1799             retval = TRUE;
1800         }
1801     }
1802     return retval;
1803 }
1804 
1805 /*---------------------------------------------------------------------------*
1806   Name:         FS_TellDir
1807 
1808   Description:  Gets current directory position from directory handle.
1809 
1810   Arguments:    dir: Directory handle
1811                 pos: Storage destination of the directory position
1812 
1813   Returns:      TRUE if successful.
1814  *---------------------------------------------------------------------------*/
FS_TellDir(const FSFile * dir,FSDirPos * pos)1815 BOOL FS_TellDir(const FSFile *dir, FSDirPos *pos)
1816 {
1817     BOOL        retval = FALSE;
1818     SDK_NULL_ASSERT(dir);
1819     SDK_NULL_ASSERT(pos);
1820     SDK_ASSERT(FS_IsAvailable());
1821     SDK_ASSERT(FS_IsDir(dir));
1822     {
1823         *pos = dir->prop.dir.pos;
1824         retval = TRUE;
1825     }
1826     return retval;
1827 }
1828 
1829 /*---------------------------------------------------------------------------*
1830   Name:         FS_RewindDir
1831 
1832   Description:  Returns enumeration position of the directory handle to the top.
1833 
1834   Arguments:    dir: Directory handle
1835 
1836   Returns:      TRUE if successful.
1837  *---------------------------------------------------------------------------*/
FS_RewindDir(FSFile * dir)1838 BOOL FS_RewindDir(FSFile *dir)
1839 {
1840     BOOL        retval = FALSE;
1841     SDK_NULL_ASSERT(dir);
1842     SDK_ASSERT(FS_IsAvailable());
1843     SDK_ASSERT(FS_IsDir(dir));
1844     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
1845 
1846     {
1847         FSDirPos pos;
1848         pos.arc = dir->arc;
1849         pos.own_id = dir->prop.dir.pos.own_id;
1850         pos.pos = 0;
1851         pos.index = 0;
1852         retval = FS_SeekDir(dir, &pos);
1853     }
1854     return retval;
1855 }
1856 
1857 
1858 /*---------------------------------------------------------------------------*
1859  * Unicode support
1860  *---------------------------------------------------------------------------*/
1861 
1862 enum
1863 {
1864     FS_UNICODE_CONVSRC_ASCII,
1865     FS_UNICODE_CONVSRC_SHIFT_JIS,
1866     FS_UNICODE_CONVSRC_UNICODE
1867 };
1868 
1869 /*---------------------------------------------------------------------------*
1870   Name:         FSi_CopySafeUnicodeString
1871 
1872   Description:   Checks buffer size and copies string as Unicode.
1873 
1874   Arguments:    dst: Transfer destination buffer
1875                 dstlen: Transfer destination size
1876                 src: Transfer source buffer
1877                 srclen: Transfer character size
1878                 srctype: Character set of transfer source
1879                 stickyFailure: FALSE, if truncated at transfer origin
1880 
1881   Returns:      Actually stored character count.
1882  *---------------------------------------------------------------------------*/
FSi_CopySafeUnicodeString(u16 * dst,int dstlen,const void * srcptr,int srclen,int srctype,BOOL * stickyFailure)1883 static int FSi_CopySafeUnicodeString(u16 *dst, int dstlen,
1884                                      const void *srcptr, int srclen,
1885                                      int srctype, BOOL *stickyFailure)
1886 {
1887     int     srcpos = 0;
1888     int     dstpos = 0;
1889     if (srctype == FS_UNICODE_CONVSRC_ASCII)
1890     {
1891         const char *src = (const char *)srcptr;
1892         int     n = (dstlen - 1 < srclen) ? (dstlen - 1) : srclen;
1893         while ((dstpos < n) && src[srcpos])
1894         {
1895             dst[dstpos++] = (u8)src[srcpos++];
1896         }
1897         if ((srcpos < srclen) && src[srcpos])
1898         {
1899             *stickyFailure = TRUE;
1900         }
1901     }
1902     else if (srctype == FS_UNICODE_CONVSRC_UNICODE)
1903     {
1904         const u16 *src = (const u16 *)srcptr;
1905         int     n = (dstlen - 1 < srclen) ? (dstlen - 1) : srclen;
1906         while ((dstpos < n) && src[srcpos])
1907         {
1908             dst[dstpos++] = src[srcpos++];
1909         }
1910         if ((srcpos < srclen) && src[srcpos])
1911         {
1912             *stickyFailure = TRUE;
1913         }
1914     }
1915     else if (srctype == FS_UNICODE_CONVSRC_SHIFT_JIS)
1916     {
1917         const char *src = (const char *)srcptr;
1918         srcpos = srclen;
1919         dstpos = dstlen - 1;
1920         (void)FSi_ConvertStringSjisToUnicode(dst, &dstpos, src, &srcpos, NULL);
1921         if ((srcpos < srclen) && src[srcpos])
1922         {
1923             *stickyFailure = TRUE;
1924         }
1925     }
1926     dst[dstpos] = L'\0';
1927     return dstpos;
1928 }
1929 
1930 /*---------------------------------------------------------------------------*
1931   Name:         FSi_NormalizePathWtoW
1932 
1933   Description:  Converts Unicode path to Unicode full path that includes up to the archive name.
1934 
1935   Arguments:    path: Non-normalized path string
1936                 baseid: Standard directory ID storage destination or NULL
1937                 relpath: Path name storage destination after conversion or NULL
1938 
1939   Returns:      Archive pointer or NULL.
1940  *---------------------------------------------------------------------------*/
1941 FSArchive* FSi_NormalizePathWtoW(const u16 *path, u32*baseid, u16 *relpath);
FSi_NormalizePathWtoW(const u16 * path,u32 * baseid,u16 * relpath)1942 FSArchive* FSi_NormalizePathWtoW(const u16 *path, u32*baseid, u16 *relpath)
1943 {
1944     FSArchive  *arc = NULL;
1945     int         pathlen = 0;
1946     int         pathmax = FS_ARCHIVE_FULLPATH_MAX + 1;
1947     BOOL        stickyFailure = FALSE;
1948     // First, specify archive to be the command target
1949     // If specified Unicode path is absolute path, get archive
1950     BOOL        absolute = FALSE;
1951     int         arcnameLen;
1952     for (arcnameLen = 0; arcnameLen < FS_ARCHIVE_NAME_LONG_MAX + 1; ++arcnameLen)
1953     {
1954         if (path[arcnameLen] == L'\0')
1955         {
1956             break;
1957         }
1958         else if (FSi_IsUnicodeSlash(path[arcnameLen]))
1959         {
1960             break;
1961         }
1962         else if (path[arcnameLen] == L':')
1963         {
1964             char    arcname[FS_ARCHIVE_NAME_LONG_MAX + 1];
1965             int     j;
1966             for (j = 0; j < arcnameLen; ++j)
1967             {
1968                 arcname[j] = (char)path[j];
1969             }
1970             arcname[arcnameLen] = '\0';
1971             arc = FS_FindArchive(arcname, arcnameLen);
1972             break;
1973         }
1974     }
1975     if (arc)
1976     {
1977         absolute = TRUE;
1978         *baseid = 0;
1979     }
1980     else
1981     {
1982         arc = FS_NormalizePath("", baseid, NULL);
1983     }
1984     if (arc)
1985     {
1986         // If archive cannot support Unicode, fails here
1987         u32     caps = 0;
1988         (void)arc->vtbl->GetArchiveCaps(arc, &caps);
1989         if ((caps & FS_ARCHIVE_CAPS_UNICODE) == 0)
1990         {
1991             arc = NULL;
1992         }
1993         else
1994         {
1995             // Stores archive name at top
1996             pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
1997                                                  FS_GetArchiveName(arc), FS_ARCHIVE_NAME_LONG_MAX,
1998                                                  FS_UNICODE_CONVSRC_ASCII, &stickyFailure);
1999             pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2000                                                  L":", 1,
2001                                                  FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2002             // If absolute path, link the root and below as it is
2003             if (absolute)
2004             {
2005                 path += arcnameLen + 1 + FSi_IsUnicodeSlash(path[arcnameLen + 1]);
2006             }
2007             // If current root, directly link to the root and below
2008             else if (FSi_IsUnicodeSlash(*path))
2009             {
2010                 path += 1;
2011             }
2012             // If the current directory, convert Shift_JIS to Unicode and link
2013             else
2014             {
2015                 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2016                                                      L"/", 1,
2017                                                      FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2018                 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2019                                                      FS_GetCurrentDirectory(), FS_ENTRY_LONGNAME_MAX,
2020                                                      FS_UNICODE_CONVSRC_SHIFT_JIS, &stickyFailure);
2021             }
2022             // Link the remaining portion
2023             pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2024                                                  L"/", 1,
2025                                                  FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2026             {
2027                 // Be careful of special entry names and normalize relative path
2028                 int     curlen = 0;
2029                 while (!stickyFailure)
2030                 {
2031                     u16     c = path[curlen];
2032                     if ((c != L'\0') && !FSi_IsUnicodeSlash(c))
2033                     {
2034                         curlen += 1;
2035                     }
2036                     else
2037                     {
2038                         // Ignore empty directory
2039                         if (curlen == 0)
2040                         {
2041                         }
2042                         // Ignore "." (current directory)
2043                         else if ((curlen == 1) && (path[0] == L'.'))
2044                         {
2045                         }
2046                         // ".." (parent directory) raises the root one level as the upper limit
2047                         else if ((curlen == 2) && (path[0] == '.') && (path[1] == '.'))
2048                         {
2049                             if ((pathlen > 2) && (relpath[pathlen - 2] != L':'))
2050                             {
2051                                 --pathlen;
2052                                 pathlen = FSi_DecrementUnicodePositionToSlash(relpath, pathlen) + 1;
2053                             }
2054                         }
2055                         // Add entry for anything else
2056                         else
2057                         {
2058                             pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2059                                                                  path, curlen,
2060                                                                  FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2061                             if (c != L'\0')
2062                             {
2063                                 pathlen += FSi_CopySafeUnicodeString(&relpath[pathlen], pathmax - pathlen,
2064                                                                      L"/", 1,
2065                                                                      FS_UNICODE_CONVSRC_UNICODE, &stickyFailure);
2066                             }
2067                         }
2068                         if (c == L'\0')
2069                         {
2070                             break;
2071                         }
2072                         path += curlen + 1;
2073                         curlen = 0;
2074                     }
2075                 }
2076             }
2077             relpath[pathlen] = L'\0';
2078         }
2079     }
2080     return stickyFailure ? NULL : arc;
2081 }
2082 
2083 /*---------------------------------------------------------------------------*
2084   Name:         FS_OpenFileExW
2085 
2086   Description:  Opens the file by specifying the path name.
2087 
2088   Arguments:    file: FSFile structure
2089                 path: Path name
2090 
2091   Returns:      TRUE if successful.
2092  *---------------------------------------------------------------------------*/
FS_OpenFileExW(FSFile * file,const u16 * path,u32 mode)2093 BOOL FS_OpenFileExW(FSFile *file, const u16 *path, u32 mode)
2094 {
2095     BOOL    retval = FALSE;
2096     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
2097     SDK_NULL_ASSERT(file);
2098     SDK_NULL_ASSERT(path);
2099     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2100 
2101     // Logic check relating to FS_FILEMODE_L
2102     // (It is meaningless if there is a size restriction when opening in creation mode)
2103     if (((mode & FS_FILEMODE_L) != 0) &&
2104         ((mode & FS_FILEMODE_RW) == FS_FILEMODE_W))
2105     {
2106         OS_TWarning("\"FS_FILEMODE_WL\" seems useless.\n"
2107                     "(this means creating empty file and prohibiting any modifications)");
2108     }
2109     {
2110         u16         relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
2111         u32         baseid = 0;
2112         FSArchive  *arc = FSi_NormalizePathWtoW(path, &baseid, relpath);
2113         // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2114         //
2115         if (!arc)
2116         {
2117             file->error = FS_RESULT_UNSUPPORTED;
2118         }
2119         else
2120         {
2121             FSArgumentForOpenFile   arg[1];
2122             FS_InitFile(file);
2123             file->arc = arc;
2124             file->argument = arg;
2125             arg->baseid = baseid;
2126             arg->relpath = (char*)relpath;
2127             arg->mode = mode;
2128             file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2129             if (FSi_SendCommand(file, FS_COMMAND_OPENFILE, TRUE))
2130             {
2131                 retval = TRUE;
2132             }
2133             else
2134             {
2135                 file->arc = NULL;
2136             }
2137         }
2138     }
2139     return retval;
2140 }
2141 
2142 /*---------------------------------------------------------------------------*
2143   Name:         FS_OpenDirectoryW
2144 
2145   Description:  Opens the directory handle.
2146 
2147   Arguments:    file: FSFile structure
2148                 path: Path name
2149                 mode: Access mode
2150 
2151   Returns:      TRUE if successful.
2152  *---------------------------------------------------------------------------*/
FS_OpenDirectoryW(FSFile * file,const u16 * path,u32 mode)2153 BOOL FS_OpenDirectoryW(FSFile *file, const u16 *path, u32 mode)
2154 {
2155     BOOL    retval = FALSE;
2156     FS_DEBUG_TRACE( "%s\n", __FUNCTION__);
2157     SDK_NULL_ASSERT(path);
2158     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2159     {
2160         u16         relpath[FS_ARCHIVE_FULLPATH_MAX + 1];
2161         u32         baseid = 0;
2162         FSArchive  *arc = FSi_NormalizePathWtoW(path, &baseid, relpath);
2163         // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2164         //
2165         if (!arc)
2166         {
2167             file->error = FS_RESULT_UNSUPPORTED;
2168         }
2169         else
2170         {
2171             FSArgumentForOpenDirectory  arg[1];
2172             FS_InitFile(file);
2173             file->arc = arc;
2174             file->argument = arg;
2175             arg->baseid = baseid;
2176             arg->relpath = (char*)relpath;
2177             arg->mode = mode;
2178             file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2179             if (FSi_SendCommand(file, FS_COMMAND_OPENDIRECTORY, TRUE))
2180             {
2181                 retval = TRUE;
2182             }
2183             else
2184             {
2185                 file->arc = NULL;
2186             }
2187         }
2188     }
2189     return retval;
2190 }
2191 
2192 /*---------------------------------------------------------------------------*
2193   Name:         FS_ReadDirectoryW
2194 
2195   Description:  Reads only one entry of the directory and advances.
2196 
2197   Arguments:    file: FSFile structure
2198                 info: FSDirectoryEntryInfo structure
2199 
2200   Returns:      TRUE if successful.
2201  *---------------------------------------------------------------------------*/
FS_ReadDirectoryW(FSFile * file,FSDirectoryEntryInfoW * info)2202 BOOL FS_ReadDirectoryW(FSFile *file, FSDirectoryEntryInfoW *info)
2203 {
2204     BOOL    retval = FALSE;
2205     SDK_NULL_ASSERT(file);
2206     SDK_NULL_ASSERT(info);
2207     SDK_ASSERT(FS_IsAvailable());
2208     SDK_ASSERT(FS_IsDir(file));
2209     SDK_ASSERT(OS_GetProcMode() != OS_PROCMODE_IRQ);
2210     {
2211         FSArchive  *arc = file->arc;
2212         // Currently, to limit to the minimum changes where the Unicode can be used, return unsupported with archives that do not support Unicode such as ROM and the like
2213         //
2214         u32     caps = 0;
2215         (void)arc->vtbl->GetArchiveCaps(arc, &caps);
2216         if ((caps & FS_ARCHIVE_CAPS_UNICODE) == 0)
2217         {
2218             file->error = FS_RESULT_UNSUPPORTED;
2219         }
2220         else
2221         {
2222             FSArgumentForReadDirectory  arg[1];
2223             file->argument = arg;
2224             arg->info = (FSDirectoryEntryInfo*)info;
2225             MI_CpuFill8(info, 0x00, sizeof(info));
2226             info->id = FS_INVALID_FILE_ID;
2227             file->stat |= FS_FILE_STATUS_UNICODE_MODE;
2228             if (FSi_SendCommand(file, FS_COMMAND_READDIR, TRUE))
2229             {
2230                 retval = TRUE;
2231             }
2232         }
2233     }
2234     return retval;
2235 }
2236 
2237 
2238 /*---------------------------------------------------------------------------*
2239  * Deprecated Functions
2240  *---------------------------------------------------------------------------*/
2241 
2242 /*---------------------------------------------------------------------------*
2243   Name:         FSi_ConvertToDirEntry
2244 
2245   Description:  Converts from FSDirectoryEntryInfo structure to FSDirEntry structure.
2246 
2247   Arguments:    entry: FSDirEntry structure of the conversion destination
2248                 arc: Archive that obtained the conversion source information
2249                 info: FSDirectoryEntryInfo structure of the conversion source
2250 
2251   Returns:      TRUE if successful.
2252  *---------------------------------------------------------------------------*/
FSi_ConvertToDirEntry(FSDirEntry * entry,FSArchive * arc,const FSDirectoryEntryInfo * info)2253 static void FSi_ConvertToDirEntry(FSDirEntry *entry, FSArchive *arc, const FSDirectoryEntryInfo *info)
2254 {
2255     entry->name_len = info->longname_length;
2256     if (entry->name_len > sizeof(entry->name) - 1)
2257     {
2258         entry->name_len = sizeof(entry->name) - 1;
2259     }
2260     MI_CpuCopy8(info->longname, entry->name, entry->name_len);
2261     entry->name[entry->name_len] = '\0';
2262     if (info->id == FS_INVALID_FILE_ID)
2263     {
2264         entry->is_directory = FALSE;
2265         entry->file_id.file_id = FS_INVALID_FILE_ID;
2266         entry->file_id.arc = NULL;
2267     }
2268     else if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) != 0)
2269     {
2270         entry->is_directory = TRUE;
2271         entry->dir_id.arc = arc;
2272         entry->dir_id.own_id = (u16)(info->id >> 0);
2273         entry->dir_id.index = (u16)(info->id >> 16);
2274         entry->dir_id.pos = 0;
2275     }
2276     else
2277     {
2278         entry->is_directory = FALSE;
2279         entry->file_id.file_id = info->id;
2280         entry->file_id.arc = arc;
2281     }
2282 }
2283 
2284 /*---------------------------------------------------------------------------*
2285   Name:         FS_OpenFile
2286 
2287   Description:  Opens the file by specifying the path name.
2288 
2289   Arguments:    file: FSFile structure
2290                 path: Path name
2291 
2292   Returns:      TRUE if successful.
2293  *---------------------------------------------------------------------------*/
FS_OpenFile(FSFile * file,const char * path)2294 BOOL FS_OpenFile(FSFile *file, const char *path)
2295 {
2296     return FS_OpenFileEx(file, path, FS_FILEMODE_R);
2297 }
2298 
2299 /*---------------------------------------------------------------------------*
2300   Name:         FS_GetLength
2301 
2302   Description:  Gets file size.
2303 
2304   Arguments:    file: File handle
2305 
2306   Returns:      File size.
2307  *---------------------------------------------------------------------------*/
FS_GetLength(FSFile * file)2308 u32 FS_GetLength(FSFile *file)
2309 {
2310     return FS_GetFileLength(file);
2311 }
2312 
2313 /*---------------------------------------------------------------------------*
2314   Name:         FS_GetPosition
2315 
2316   Description:  Gets the current position of the file pointer.
2317 
2318   Arguments:    file: File handle
2319 
2320   Returns:      Current position of the file pointer.
2321  *---------------------------------------------------------------------------*/
FS_GetPosition(FSFile * file)2322 u32 FS_GetPosition(FSFile *file)
2323 {
2324     return FS_GetFilePosition(file);
2325 }
2326 
2327 /*---------------------------------------------------------------------------*
2328   Name:         FS_FindDir
2329 
2330   Description:  Opens the directory handle.
2331 
2332   Arguments:    dir: FSFile structure
2333                 path: Path name
2334 
2335   Returns:      TRUE if successful.
2336  *---------------------------------------------------------------------------*/
FS_FindDir(FSFile * dir,const char * path)2337 BOOL FS_FindDir(FSFile *dir, const char *path)
2338 {
2339     return FS_OpenDirectory(dir, path, FS_FILEMODE_R);
2340 }
2341 
2342 /*---------------------------------------------------------------------------*
2343   Name:         FS_ReadDir
2344 
2345   Description:  Reads only one entry of the directory and advances.
2346 
2347   Arguments:    file: FSFile structure
2348                 entry: FSDirEntry structure
2349 
2350   Returns:      TRUE if successful.
2351  *---------------------------------------------------------------------------*/
FS_ReadDir(FSFile * file,FSDirEntry * entry)2352 BOOL FS_ReadDir(FSFile *file, FSDirEntry *entry)
2353 {
2354     BOOL                    retval = FALSE;
2355     FSDirectoryEntryInfo    info[1];
2356     if (FS_ReadDirectory(file, info))
2357     {
2358         FSi_ConvertToDirEntry(entry, FS_GetAttachedArchive(file), info);
2359         retval = TRUE;
2360     }
2361     return retval;
2362 }
2363 
2364 /*---------------------------------------------------------------------------*
2365   Name:         FS_ChangeDir
2366 
2367   Description:  Changes the current directory.
2368 
2369   Arguments:    path: Path name
2370 
2371   Returns:      TRUE if successful.
2372  *---------------------------------------------------------------------------*/
FS_ChangeDir(const char * path)2373 BOOL    FS_ChangeDir(const char *path)
2374 {
2375     return FS_SetCurrentDirectory(path);
2376 }
2377 
2378 /*---------------------------------------------------------------------------*
2379   Name:         FS_GetFileInfo
2380 
2381   Description:  Gets the file information.
2382 
2383   Arguments:    path: Path name
2384                 info: Location to store the information
2385 
2386   Returns:      Processing result.
2387  *---------------------------------------------------------------------------*/
FS_GetFileInfo(const char * path,FSFileInfo * info)2388 FSResult FS_GetFileInfo(const char *path, FSFileInfo *info)
2389 {
2390     return FS_GetPathInfo(path, info) ? FS_RESULT_SUCCESS : FS_GetArchiveResultCode(path);
2391 }
2392 
2393 
2394 #endif /* FS_IMPLEMENT */
2395 
2396 // The following is also used outside the FS library, so it is not targeted by FS_IMPLEMENT
2397 // Support for Unicode on ARM7 is necessary only for TWL operations, so locate on extended memory
2398 #if defined(SDK_TWL) && defined(SDK_ARM7)
2399 #include <twl/ltdmain_begin.h>
2400 #endif
2401 
2402 static const int        FSiUnicodeBufferQueueMax = 4;
2403 static OSMessageQueue   FSiUnicodeBufferQueue[1];
2404 static OSMessage        FSiUnicodeBufferQueueArray[FSiUnicodeBufferQueueMax];
2405 static BOOL             FSiUnicodeBufferQueueInitialized = FALSE;
2406 static u16              FSiUnicodeBufferTable[FSiUnicodeBufferQueueMax][FS_ARCHIVE_FULLPATH_MAX + 1];
2407 
2408 /*---------------------------------------------------------------------------*
2409   Name:         FSi_GetUnicodeBuffer
2410 
2411   Description:  Gets temporary buffer for Unicode conversion.
2412                 The FS library is used for conversion of Shift_JIS.
2413 
2414   Arguments:    src: Shift_JIS string needed in Unicode conversion or NULL
2415 
2416   Returns:      String buffer converted to UTF16-LE if necessary.
2417  *---------------------------------------------------------------------------*/
FSi_GetUnicodeBuffer(const char * src)2418 u16* FSi_GetUnicodeBuffer(const char *src)
2419 {
2420     u16        *retval = NULL;
2421     // Added buffer to message queue when making the initial call
2422     OSIntrMode  bak = OS_DisableInterrupts();
2423     if (!FSiUnicodeBufferQueueInitialized)
2424     {
2425         int     i;
2426         FSiUnicodeBufferQueueInitialized = TRUE;
2427         OS_InitMessageQueue(FSiUnicodeBufferQueue, FSiUnicodeBufferQueueArray, 4);
2428         for (i = 0; i < FSiUnicodeBufferQueueMax; ++i)
2429         {
2430             (void)OS_SendMessage(FSiUnicodeBufferQueue, FSiUnicodeBufferTable[i], OS_MESSAGE_BLOCK);
2431         }
2432     }
2433     (void)OS_RestoreInterrupts(bak);
2434     // Allocate the buffer from the message queue (if not necessary, block here)
2435     (void)OS_ReceiveMessage(FSiUnicodeBufferQueue, (OSMessage*)&retval, OS_MESSAGE_BLOCK);
2436     if (src)
2437     {
2438         int     dstlen = FS_ARCHIVE_FULLPATH_MAX;
2439         (void)FSi_ConvertStringSjisToUnicode(retval, &dstlen, src, NULL, NULL);
2440         retval[dstlen] = L'\0';
2441     }
2442     return retval;
2443 }
2444 
2445 /*---------------------------------------------------------------------------*
2446   Name:         FSi_ReleaseUnicodeBuffer
2447 
2448   Description:  Deallocates the temporary buffer for Unicode conversion.
2449 
2450   Arguments:    buf: Buffer allocated by the FSi_GetUnicodeBuffer function
2451 
2452   Returns:      None.
2453  *---------------------------------------------------------------------------*/
FSi_ReleaseUnicodeBuffer(const void * buf)2454 void FSi_ReleaseUnicodeBuffer(const void *buf)
2455 {
2456     if (buf)
2457     {
2458         // Return used buffer to the message queue
2459         (void)OS_SendMessage(FSiUnicodeBufferQueue, (OSMessage)buf, OS_MESSAGE_BLOCK);
2460     }
2461 }
2462 
2463 /*---------------------------------------------------------------------------*
2464   Name:         FSi_ConvertStringSjisToUnicode
2465 
2466   Description:  Converts a Shift_JIS string into a Unicode string.
2467                 When the path name being handled is clearly only in ASCII code, and the mutual conversion of Unicode and ShiftJIS can be simplified, it is possible to prevent the standard processes of the STD library from linking by overwriting this function.
2468 
2469 
2470 
2471 
2472   Arguments:    dst: Conversion destination buffer
2473                                   The storage process is ignored if NULL is specified.
2474                 dst_len: Pointer which stores and passes the maximum number of characters for the conversion destination buffer, then receives the number of characters that were actually stored.
2475                                   Ignored when NULL is given.
2476 
2477                 src: Conversion source buffer
2478                 src_len: Pointer which stores and passes the maximum number of characters to be converted, then receives the number actually converted.
2479                                   The end-of-string position takes priority over this specification.
2480                                   When either a negative value is stored and passed, or NULL is given, the character count is revised to be the number of characters to the end of the string.
2481 
2482 
2483                 callback: Callback to be called if there are any characters that can't be converted.
2484                                   When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2485 
2486 
2487   Returns:      Result of the conversion process.
2488  *---------------------------------------------------------------------------*/
2489 SDK_WEAK_SYMBOL
FSi_ConvertStringSjisToUnicode(u16 * dst,int * dst_len,const char * src,int * src_len,STDConvertUnicodeCallback callback)2490 STDResult FSi_ConvertStringSjisToUnicode(u16 *dst, int *dst_len,
2491                                          const char *src, int *src_len,
2492                                          STDConvertUnicodeCallback callback)
2493  __attribute__((never_inline))
2494 {
2495     return STD_ConvertStringSjisToUnicode(dst, dst_len, src, src_len, callback);
2496 }
2497 
2498 /*---------------------------------------------------------------------------*
2499   Name:         FSi_ConvertStringUnicodeToSjis
2500 
2501   Description:  Converts a Unicode string into a Shift_JIS string.
2502                 When the path name being handled is clearly only in ASCII code, and the mutual conversion of Unicode and ShiftJIS can be simplified, it is possible to prevent the standard processes of the STD library from linking by overwriting this function.
2503 
2504 
2505 
2506 
2507   Arguments:    dst: Conversion destination buffer
2508                                   The storage process is ignored if NULL is specified.
2509                 dst_len: Pointer which stores and passes the maximum number of characters for the conversion destination buffer, then receives the number of characters that were actually stored.
2510                                   Ignored when NULL is given.
2511 
2512                 src: Conversion source buffer
2513                 src_len: Pointer which stores and passes the maximum number of characters to be converted, then receives the number actually converted.
2514                                   The end-of-string position takes priority over this specification.
2515                                   When either a negative value is stored and passed, or NULL is given, the character count is revised to be the number of characters to the end of the string.
2516 
2517 
2518                 callback: Callback to be called if there are any characters that can't be converted.
2519                                   When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2520 
2521 
2522   Returns:      Result of the conversion process.
2523  *---------------------------------------------------------------------------*/
2524 SDK_WEAK_SYMBOL
FSi_ConvertStringUnicodeToSjis(char * dst,int * dst_len,const u16 * src,int * src_len,STDConvertSjisCallback callback)2525 STDResult FSi_ConvertStringUnicodeToSjis(char *dst, int *dst_len,
2526                                          const u16 *src, int *src_len,
2527                                          STDConvertSjisCallback callback)
2528  __attribute__((never_inline))
2529 {
2530     return STD_ConvertStringUnicodeToSjis(dst, dst_len, src, src_len, callback);
2531 }
2532 
2533 #if defined(SDK_TWL) && defined(SDK_ARM7)
2534 #include <twl/ltdmain_end.h>
2535 #endif
2536