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