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