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