1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - demos - arc-2
3   File:     main.c
4 
5   Copyright 2003-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:: 2008-09-17 #$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 
19 #include <nitro.h>
20 
21 
22 struct FixedDirectoryList;
23 
24 // File image structure for a custom archive
25 typedef struct FixedFile
26 {
27     char    buffer[256];
28 }
29 FixedFile;
30 
31 // Directory structure for a custom archive
32 typedef struct FixedDirectory
33 {
34     const char *name;
35     union
36     {
37         void   *common_ptr;
38         struct FixedDirectoryList *dir;
39         FixedFile *file;
40     }
41     obj;
42 }
43 FixedDirectory;
44 
45 // Directory list structure for a custom archive (equivalent to FNT)
46 typedef struct FixedDirectoryList
47 {
48     int     parent;
49     FixedDirectory *own;
50 }
51 FixedDirectoryList;
52 
53 
54 // Define the directory structure of a custom archive
55 extern FixedFile file_list[];
56 extern FixedDirectoryList dir_list[];
57 extern const int file_max;
58 extern const int dir_max;
59 
60 static FixedFile file_list[] = {
61     {
62      "hello, world!\n" "fixed file of root.\n"},
63     {
64      "fixed file 1.\n"},
65     {
66      "fixed file 2.\n"},
67     {
68      "fixed file 3.\n"},
69 };
70 static FixedDirectory sub_dir1[] = {
71     {"file1.txt", file_list + 1,},
72     {"file2.txt", file_list + 2,},
73     {"file3.txt", file_list + 3,},
74     {NULL,},
75 };
76 static FixedDirectory sub_dir2[] = {
77     {"test1.txt", file_list + 1,},
78     {"test2.txt", file_list + 2,},
79     {"test3.txt", file_list + 3,},
80     {NULL,},
81 };
82 static FixedDirectory root_dir[] = {
83     {"root.txt", file_list + 0,},
84     {"sub1", dir_list + 1,},
85     {"sub2", dir_list + 2,},
86     {NULL,},
87 };
88 FixedDirectoryList dir_list[] = {
89     {-1, root_dir,},
90     {0, sub_dir1,},
91     {0, sub_dir2,},
92 };
93 const int dir_max = sizeof(dir_list) / sizeof(*dir_list);
94 const int file_max = sizeof(file_list) / sizeof(*file_list);
95 
96 
97 // Access callback from the FS library to an archive.
98 // This simply reads from and writes to memory.
CustomRom_ReadCallback(FSArchive * arc,void * dst,u32 pos,u32 size)99 static FSResult CustomRom_ReadCallback(FSArchive *arc, void *dst, u32 pos, u32 size)
100 {
101     (void)arc;
102     MI_CpuCopy8((const void *)pos, dst, size);
103     return FS_RESULT_SUCCESS;
104 }
CustomRom_WriteCallback(FSArchive * arc,const void * src,u32 pos,u32 size)105 static FSResult CustomRom_WriteCallback(FSArchive *arc, const void *src, u32 pos, u32 size)
106 {
107     (void)arc;
108     MI_CpuCopy8(src, (void *)pos, size);
109     return FS_RESULT_SUCCESS;
110 }
111 
112 // User procedure for a custom archive
CustomRom_ArchiveProc(FSFile * file,FSCommandType cmd)113 static FSResult CustomRom_ArchiveProc(FSFile *file, FSCommandType cmd)
114 {
115     FSArchive *const p_rom = FS_GetAttachedArchive(file);
116 
117     switch (cmd)
118     {
119 
120         // Customize only low-level commands according to FS library specifications
121 
122     case FS_COMMAND_SEEKDIR:
123         {
124             const FSDirPos *const arg = &file->arg.seekdir.pos;
125             const int dir_id = arg->own_id;
126             file->prop.dir.pos = *arg;
127             // Seek to the start of the directory when index and pos are both 0
128             if ((arg->index == 0) && (arg->pos == 0))
129             {
130                 file->prop.dir.pos.index = 0; /* Not used */
131                 file->prop.dir.pos.pos = (u32)dir_list[dir_id].own;
132             }
133             // At the root directory, parent-ID shows the total number of directories
134             file->prop.dir.parent = (u16)((dir_id != 0) ? dir_list[dir_id].parent : dir_max);
135             return FS_RESULT_SUCCESS;
136         }
137 
138     case FS_COMMAND_READDIR:
139         {
140             FSDirEntry *const p_entry = file->arg.readdir.p_entry;
141             const FixedDirectory *const cur = (const FixedDirectory *)file->prop.dir.pos.pos;
142             // FS_RESULT_FAILURE is returned at the end of the directory
143             if (!cur->name)
144             {
145                 return FS_RESULT_FAILURE;
146             }
147             p_entry->name_len = (u32)STD_GetStringLength(cur->name);
148             // The entry name is also returned if skip_string has not been specified
149             if (!file->arg.readdir.skip_string)
150             {
151                 MI_CpuCopy8(cur->name, p_entry->name, p_entry->name_len + 1);
152             }
153             // If the entry indicates a directory, information will be returned as an FSDirPos value
154             if ((cur->obj.dir >= dir_list) && (cur->obj.dir < dir_list + dir_max))
155             {
156                 p_entry->is_directory = 1;
157                 p_entry->dir_id.arc = file->arc;
158                 p_entry->dir_id.own_id = (u16)(cur->obj.dir - dir_list);
159                 p_entry->dir_id.index = 0;
160                 p_entry->dir_id.pos = 0;
161             }
162             // If the entry indicates a file, information will be returned as an FSFileID value
163             else
164             {
165                 p_entry->is_directory = 0;
166                 p_entry->file_id.arc = file->arc;
167                 p_entry->file_id.file_id = (u32)(cur->obj.file - file_list);
168             }
169             // Advance the position by 1 if the entry could be read normally
170             file->prop.dir.pos.pos = (u32)(cur + 1);
171             return FS_RESULT_SUCCESS;
172         }
173 
174     case FS_COMMAND_OPENFILEFAST:
175         {
176             const int id = (int)file->arg.openfilefast.id.file_id;
177             // FS_RESULT_FAILURE is returned if an invalid file ID has been specified
178             if ((id < 0) || (id >= file_max))
179             {
180                 return FS_RESULT_FAILURE;
181             }
182             else
183             {
184                 // Specify the appropriate top and bottom if the file is a linear image
185                 const char *text = file_list[id].buffer;
186                 file->arg.openfiledirect.top = (u32)text;
187                 file->arg.openfiledirect.bottom = (u32)(text + STD_GetStringLength(text));
188                 file->arg.openfiledirect.index = (u32)id;
189             }
190             // Continue to FS_COMMAND_OPENFILEDIRECT processing
191         }
192 
193     case FS_COMMAND_OPENFILEDIRECT:
194         {
195             // Configure the parameters as specified by the caller
196             file->prop.file.top = file->arg.openfiledirect.top;
197             file->prop.file.pos = file->arg.openfiledirect.top;
198             file->prop.file.bottom = file->arg.openfiledirect.bottom;
199             file->prop.file.own_id = file->arg.openfiledirect.index;
200             return FS_RESULT_SUCCESS;
201         }
202 
203         // If FS_RESULT_PROC_UNKNOWN is returned to a high-level command and default behavior is used, the low-level commands customized here will be called as necessary
204         //
205 
206     default:
207     case FS_COMMAND_FINDPATH:
208     case FS_COMMAND_GETPATH:
209     case FS_COMMAND_CLOSEFILE:
210     case FS_COMMAND_READFILE:
211     case FS_COMMAND_WRITEFILE:
212     case FS_COMMAND_ACTIVATE:
213     case FS_COMMAND_IDLE:
214         return FS_RESULT_PROC_UNKNOWN;
215 
216     }
217 
218 }
219 
220 // Initialize a custom archive
CreateCustomArchive(FSArchive * arc,const char * name)221 static void CreateCustomArchive(FSArchive *arc, const char *name)
222 {
223     FS_InitArchive(arc);
224     if (!FS_RegisterArchiveName(arc, name, (u32)STD_GetStringLength(name)))
225     {
226         OS_TPanic("error! FS_RegisterArchiveName(%s) failed.\n", name);
227     }
228     FS_SetArchiveProc(arc, CustomRom_ArchiveProc, (u32)FS_ARCHIVE_PROC_ALL);
229     // All commands that require FAT and FNT by default are customized, so you do not need to specify anything in particular here
230     //
231     if (!FS_LoadArchive(arc, 0, NULL, 0, NULL, 0, CustomRom_ReadCallback, CustomRom_WriteCallback))
232     {
233         OS_TPanic("error! FS_LoadArchive() failed.\n");
234     }
235 }
236 
237 // List the directories in a ROM archive
DumpRomDirectorySub(int tab,FSDirEntry * pe)238 static void DumpRomDirectorySub(int tab, FSDirEntry *pe)
239 {
240     FSFile  d;
241     FS_InitFile(&d);
242     OS_TPrintf("%*s%s/\n", tab, "", pe->name);
243     if (FS_SeekDir(&d, &pe->dir_id))
244     {
245         tab += 4;
246         while (FS_ReadDir(&d, pe))
247         {
248             if (pe->is_directory)
249             {
250                 DumpRomDirectorySub(tab, pe);
251             }
252             else
253             {
254                 OS_Printf("%*s%s\n", tab, "", pe->name);
255             }
256         }
257     }
258 }
DumpRomDir(const char * path)259 static void DumpRomDir(const char *path)
260 {
261     FSDirEntry  entry;
262     FSFile      dir;
263     FS_InitFile(&dir);
264     (void)FS_ChangeDir(path);
265     (void)FS_FindDir(&dir, "");
266     entry.name[0] = '\0';
267     (void)FS_TellDir(&dir, &entry.dir_id);
268     DumpRomDirectorySub(0, &entry);
269 }
270 
271 
NitroMain(void)272 void NitroMain(void)
273 {
274     static FSArchive custom_rom;
275 
276     // Initialize the OS and memory allocator
277     OS_Init();
278     {
279         OSHeapHandle hh;
280         void   *tmp;
281         tmp = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
282         OS_SetArenaLo(OS_ARENA_MAIN, tmp);
283         hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
284         if (hh < 0)
285         {
286             OS_TPanic("ARM9: Fail to create heap...\n");
287         }
288         (void)OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
289     }
290     (void)OS_EnableIrq();
291     // Initialize the FS
292     FS_Init(3);
293     {
294         u32     need_size = FS_GetTableSize();
295         void   *p_table = OS_Alloc(need_size);
296         SDK_ASSERT(p_table != NULL);
297         (void)FS_LoadTable(p_table, need_size);
298     }
299 
300     OS_TPrintf("\n"
301                "++++++++++++++++++++++++++++++++++++++++\n"
302                "test 1 : query default \"rom\" directories ... \n\n");
303 
304     DumpRomDir("rom:/");
305 
306 
307     OS_TPrintf("\n"
308                "++++++++++++++++++++++++++++++++++++++++\n"
309                "test 2 : query custom archive \"cst\" directories ... \n\n");
310 
311     CreateCustomArchive(&custom_rom, "cst");
312     DumpRomDir("cst:/");
313 
314     OS_TPrintf("\n" "++++++++++++++++++++++++++++++++++++++++\n" "end\n\n");
315     OS_Terminate();
316 }
317