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