1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_file.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-02-05#$
14   $Rev: 9971 $
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 (Byte Units)
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, securely return a one-byte amount
102     int     prev = --pos;
103     // The separation for characters in Shift_JIS is either single bytes or sucessive bytes
104     // Because the leading byte and subsequent byte share a portion of the mapping, the character type is not confirmed when the leading byte is seen, so it returns again.
105     //
106     for (; (prev > 0) && STD_IsSjisLeadByte(str[prev - 1]); --prev)
107     {
108     }
109     // When double-byte characters having unclear subsequent bytes such as  "===b"
110     // Ignore this because an excess of only a multiple of 2 is returned (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 (Byte Units)
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 character 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 (Byte Units)
142 
143   Returns:      Either first directory delimiter that appears less of the position 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 character 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 (Byte Units)
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 surrrogate 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 character 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 (Byte Units)
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: The 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 source
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 save information
397 
398   Returns:      Process 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 save information
434 
435   Returns:      Process 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; //In order to drop FATFS_PROPERTY_CTRL_MASK of 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: The 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:  Change 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 gotten 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 non-existent 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 intemediate 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 gotten resource information
926 
927   Returns:      TRUE if resource information is gotten 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:      Process 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:      Process 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:      If successful, TRUE.
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:      If successful, TRUE.
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 for the file image end
1241                 id           Arbitrarily specified file ID
1242 
1243   Returns:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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 a blank to let the cache line adjust the buffer front and back.
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:      If successful, TRUE.
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:      If successful, TRUE.
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 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: The access mode
1679 
1680   Returns:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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:      If successful, TRUE.
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: The access mode
2150 
2151   Returns:      If successful, TRUE.
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:      If successful, TRUE.
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  * obsolete functions
2240  *---------------------------------------------------------------------------*/
2241 
2242 /*---------------------------------------------------------------------------*
2243   Name:         FSi_ConvertToDirEntry
2244 
2245   Description:  Convert from FSDirectoryEntryInfo structure to FSDirEntry structure
2246 
2247   Arguments:    entry       FSDirEntry structure of the conversion destination
2248                 info        FSDirectoryEntryInfo structure of the conversion source
2249 
2250   Returns:      If successful, TRUE.
2251  *---------------------------------------------------------------------------*/
FSi_ConvertToDirEntry(FSDirEntry * entry,const FSDirectoryEntryInfo * info)2252 static void FSi_ConvertToDirEntry(FSDirEntry *entry, const FSDirectoryEntryInfo *info)
2253 {
2254     entry->name_len = info->longname_length;
2255     if (entry->name_len > sizeof(entry->name) - 1)
2256     {
2257         entry->name_len = sizeof(entry->name) - 1;
2258     }
2259     MI_CpuCopy8(info->longname, entry->name, entry->name_len);
2260     entry->name[entry->name_len] = '\0';
2261     if (info->id == FS_INVALID_FILE_ID)
2262     {
2263         entry->is_directory = FALSE;
2264         entry->file_id.file_id = FS_INVALID_FILE_ID;
2265     }
2266     else if ((info->attributes & FS_ATTRIBUTE_IS_DIRECTORY) != 0)
2267     {
2268         entry->is_directory = TRUE;
2269         entry->dir_id.own_id = (u16)(info->id >> 0);
2270         entry->dir_id.index = (u16)(info->id >> 16);
2271         entry->dir_id.pos = 0;
2272     }
2273     else
2274     {
2275         entry->is_directory = FALSE;
2276         entry->file_id.file_id = info->id;
2277     }
2278 }
2279 
2280 /*---------------------------------------------------------------------------*
2281   Name:         FS_OpenFile
2282 
2283   Description:  Opens the file by specifying the path name
2284 
2285   Arguments:    file             FSFile structure
2286                 path        Path name
2287 
2288   Returns:      If successful, TRUE.
2289  *---------------------------------------------------------------------------*/
FS_OpenFile(FSFile * file,const char * path)2290 BOOL FS_OpenFile(FSFile *file, const char *path)
2291 {
2292     return FS_OpenFileEx(file, path, FS_FILEMODE_R);
2293 }
2294 
2295 /*---------------------------------------------------------------------------*
2296   Name:         FS_GetLength
2297 
2298   Description:  Gets file size
2299 
2300   Arguments:    file        File handle
2301 
2302   Returns:      File size
2303  *---------------------------------------------------------------------------*/
FS_GetLength(FSFile * file)2304 u32 FS_GetLength(FSFile *file)
2305 {
2306     return FS_GetFileLength(file);
2307 }
2308 
2309 /*---------------------------------------------------------------------------*
2310   Name:         FS_GetPosition
2311 
2312   Description:  Gets the current position of the file pointer
2313 
2314   Arguments:    file        File handle
2315 
2316   Returns:      Current position of the file pointer
2317  *---------------------------------------------------------------------------*/
FS_GetPosition(FSFile * file)2318 u32 FS_GetPosition(FSFile *file)
2319 {
2320     return FS_GetFilePosition(file);
2321 }
2322 
2323 /*---------------------------------------------------------------------------*
2324   Name:         FS_FindDir
2325 
2326   Description:  Opens the directory handle
2327 
2328   Arguments:    dir         FSFile structure
2329                 path        Path name
2330 
2331   Returns:      If successful, TRUE.
2332  *---------------------------------------------------------------------------*/
FS_FindDir(FSFile * dir,const char * path)2333 BOOL FS_FindDir(FSFile *dir, const char *path)
2334 {
2335     return FS_OpenDirectory(dir, path, FS_FILEMODE_R);
2336 }
2337 
2338 /*---------------------------------------------------------------------------*
2339   Name:         FS_ReadDir
2340 
2341   Description:  Reads only one entry of the directory and advances
2342 
2343   Arguments:    file             FSFile structure
2344                 entry       FSDirEntry structure
2345 
2346   Returns:      If successful, TRUE.
2347  *---------------------------------------------------------------------------*/
FS_ReadDir(FSFile * file,FSDirEntry * entry)2348 BOOL FS_ReadDir(FSFile *file, FSDirEntry *entry)
2349 {
2350     BOOL                    retval = FALSE;
2351     FSDirectoryEntryInfo    info[1];
2352     if (FS_ReadDirectory(file, info))
2353     {
2354         FSi_ConvertToDirEntry(entry, info);
2355         retval = TRUE;
2356     }
2357     return retval;
2358 }
2359 
2360 /*---------------------------------------------------------------------------*
2361   Name:         FS_ChangeDir
2362 
2363   Description:  Changes the current directory
2364 
2365   Arguments:    path        Path name
2366 
2367   Returns:      If successful, TRUE.
2368  *---------------------------------------------------------------------------*/
FS_ChangeDir(const char * path)2369 BOOL    FS_ChangeDir(const char *path)
2370 {
2371     return FS_SetCurrentDirectory(path);
2372 }
2373 
2374 /*---------------------------------------------------------------------------*
2375   Name:         FS_GetFileInfo
2376 
2377   Description:  Gets the file information
2378 
2379   Arguments:    path        Path name
2380                 info: Location to save information
2381 
2382   Returns:      Process result
2383  *---------------------------------------------------------------------------*/
FS_GetFileInfo(const char * path,FSFileInfo * info)2384 FSResult FS_GetFileInfo(const char *path, FSFileInfo *info)
2385 {
2386     return FS_GetPathInfo(path, info) ? FS_RESULT_SUCCESS : FS_GetArchiveResultCode(path);
2387 }
2388 
2389 
2390 #endif /* FS_IMPLEMENT */
2391 
2392 // The following is also used outside of the FS library, so it is not targeted by FS_IMPLEMENT
2393 // Support for Unicode on ARM7 is necessary only for TWL operations, so locate on extended memory
2394 #if defined(SDK_TWL) && defined(SDK_ARM7)
2395 #include <twl/ltdmain_begin.h>
2396 #endif
2397 
2398 static const int        FSiUnicodeBufferQueueMax = 4;
2399 static OSMessageQueue   FSiUnicodeBufferQueue[1];
2400 static OSMessage        FSiUnicodeBufferQueueArray[FSiUnicodeBufferQueueMax];
2401 static BOOL             FSiUnicodeBufferQueueInitialized = FALSE;
2402 static u16              FSiUnicodeBufferTable[FSiUnicodeBufferQueueMax][FS_ARCHIVE_FULLPATH_MAX + 1];
2403 
2404 /*---------------------------------------------------------------------------*
2405   Name:         FSi_GetUnicodeBuffer
2406 
2407   Description:  Gets temporary buffer for Unicode conversion.
2408                 The FS library is used for conversion of Shift_JIS.
2409 
2410   Arguments:    src: Shift_JIS string needed in Unicode conversion or NULL
2411 
2412   Returns:      String buffer converted to UTF16-LE if necessary
2413  *---------------------------------------------------------------------------*/
FSi_GetUnicodeBuffer(const char * src)2414 u16* FSi_GetUnicodeBuffer(const char *src)
2415 {
2416     u16        *retval = NULL;
2417     // Added buffer to message queue when making the initial call
2418     OSIntrMode  bak = OS_DisableInterrupts();
2419     if (!FSiUnicodeBufferQueueInitialized)
2420     {
2421         int     i;
2422         FSiUnicodeBufferQueueInitialized = TRUE;
2423         OS_InitMessageQueue(FSiUnicodeBufferQueue, FSiUnicodeBufferQueueArray, 4);
2424         for (i = 0; i < FSiUnicodeBufferQueueMax; ++i)
2425         {
2426             (void)OS_SendMessage(FSiUnicodeBufferQueue, FSiUnicodeBufferTable[i], OS_MESSAGE_BLOCK);
2427         }
2428     }
2429     (void)OS_RestoreInterrupts(bak);
2430     // Allocate the buffer from the message queue (If not necessary block here)
2431     (void)OS_ReceiveMessage(FSiUnicodeBufferQueue, (OSMessage*)&retval, OS_MESSAGE_BLOCK);
2432     if (src)
2433     {
2434         int     dstlen = FS_ARCHIVE_FULLPATH_MAX;
2435         (void)FSi_ConvertStringSjisToUnicode(retval, &dstlen, src, NULL, NULL);
2436         retval[dstlen] = L'\0';
2437     }
2438     return retval;
2439 }
2440 
2441 /*---------------------------------------------------------------------------*
2442   Name:         FSi_ReleaseUnicodeBuffer
2443 
2444   Description:  Deallocates the temporary buffer for Unicode conversion
2445 
2446   Arguments:    buf: Buffer allocated by the FSi_GetUnicodeBuffer function
2447 
2448   Returns:      None.
2449  *---------------------------------------------------------------------------*/
FSi_ReleaseUnicodeBuffer(const void * buf)2450 void FSi_ReleaseUnicodeBuffer(const void *buf)
2451 {
2452     if (buf)
2453     {
2454         // Return used buffer to the message queue
2455         (void)OS_SendMessage(FSiUnicodeBufferQueue, (OSMessage)buf, OS_MESSAGE_BLOCK);
2456     }
2457 }
2458 
2459 /*---------------------------------------------------------------------------*
2460   Name:         FSi_ConvertStringSjisToUnicode
2461 
2462   Description:  Converts a ShiftJIS character string to a Unicode character string.
2463                 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.
2464 
2465 
2466 
2467 
2468   Arguments:    dst:               Conversion destination buffer
2469                                   The storage process is ignored if NULL is specified.
2470                 dst_len           Pointer that stores and passes the maximum character count for the conversion destination buffer,
2471                                   and receives the number of characters actually stored.
2472                                   Ignored when NULL is given.
2473                 src:               Conversion source buffer
2474                 src_len           Pointer that stores and passes the maximum character count that should be converted,
2475                                   Pointer that receives the number of characters actually converted
2476                                   The end-of-string position takes priority over this specification.
2477                                   When a negative value is stored and passed or NULL is given,
2478                                   the character count is revised to be the number of characters to the end of the string.
2479                 callback:          The callback to be called if there are any characters that can't be converted.
2480                                   When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2481                                   at the position of the character that cannot be converted.
2482 
2483   Returns:      Result of the conversion process.
2484  *---------------------------------------------------------------------------*/
2485 SDK_WEAK_SYMBOL
FSi_ConvertStringSjisToUnicode(u16 * dst,int * dst_len,const char * src,int * src_len,STDConvertUnicodeCallback callback)2486 STDResult FSi_ConvertStringSjisToUnicode(u16 *dst, int *dst_len,
2487                                          const char *src, int *src_len,
2488                                          STDConvertUnicodeCallback callback)
2489  __attribute__((never_inline))
2490 {
2491     return STD_ConvertStringSjisToUnicode(dst, dst_len, src, src_len, callback);
2492 }
2493 
2494 /*---------------------------------------------------------------------------*
2495   Name:         FSi_ConvertStringUnicodeToSjis
2496 
2497   Description:  Converts a Unicode character string into a ShiftJIS character string.
2498                 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.
2499 
2500 
2501 
2502 
2503   Arguments:    dst:               Conversion destination buffer
2504                                   The storage process is ignored if NULL is specified.
2505                 dst_len           Pointer that stores and passes the maximum character count for the conversion destination buffer,
2506                                   and receives the number of characters actually stored.
2507                                   Ignored when NULL is given.
2508                 src:               Conversion source buffer
2509                 src_len           Pointer that stores and passes the maximum character count that should be converted,
2510                                   Pointer that receives the number of characters actually converted
2511                                   The end-of-string position takes priority over this specification.
2512                                   When a negative value is stored and passed or NULL is given,
2513                                   the character count is revised to be the number of characters to the end of the string.
2514                 callback:          The callback to be called if there are any characters that can't be converted.
2515                                   When NULL is specified, the conversion process ends at the position of the character that cannot be converted.
2516                                   at the position of the character that cannot be converted.
2517 
2518   Returns:      Result of the conversion process.
2519  *---------------------------------------------------------------------------*/
2520 SDK_WEAK_SYMBOL
FSi_ConvertStringUnicodeToSjis(char * dst,int * dst_len,const u16 * src,int * src_len,STDConvertSjisCallback callback)2521 STDResult FSi_ConvertStringUnicodeToSjis(char *dst, int *dst_len,
2522                                          const u16 *src, int *src_len,
2523                                          STDConvertSjisCallback callback)
2524  __attribute__((never_inline))
2525 {
2526     return STD_ConvertStringUnicodeToSjis(dst, dst_len, src, src_len, callback);
2527 }
2528 
2529 #if defined(SDK_TWL) && defined(SDK_ARM7)
2530 #include <twl/ltdmain_end.h>
2531 #endif
2532