diff options
Diffstat (limited to 'arm9/lib/src')
-rw-r--r-- | arm9/lib/src/FS_command_default.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/arm9/lib/src/FS_command_default.c b/arm9/lib/src/FS_command_default.c index bd04f740..85287fa9 100644 --- a/arm9/lib/src/FS_command_default.c +++ b/arm9/lib/src/FS_command_default.c @@ -3,6 +3,8 @@ #include "FS_command.h" #include "FS_archive.h" #include "MI_byteAccess.h" +#include "MI_memory.h" +#include "FSi_util.h" typedef struct { @@ -106,3 +108,361 @@ FSResult FSi_WriteFileCommand(FSFile * p_file) p_file->prop.file.pos += len; return (*p_arc->write_func)(p_arc, src, pos, len); } + +FSResult FSi_SeekDirCommand(FSFile * p_dir) +{ + FSResult ret; + FSArchive *const p_arc = p_dir->arc; + const FSDirPos *const arg = &p_dir->arg.seekdir.pos; + + FSArchiveFNT fnt_entry; + FSiSyncReadParam param; + param.arc = p_arc; + param.pos = p_arc->fnt + arg->own_id * sizeof(fnt_entry); + ret = FSi_ReadTable(¶m, &fnt_entry, sizeof(fnt_entry)); + if (ret == FS_RESULT_SUCCESS) + { + p_dir->prop.dir.pos = *arg; + if ((arg->index == 0) && (arg->pos == 0)) + { + p_dir->prop.dir.pos.index = fnt_entry.index; + p_dir->prop.dir.pos.pos = p_arc->fnt + fnt_entry.start; + } + p_dir->prop.dir.parent = (u32) (fnt_entry.parent & BIT_MASK(12)); + } + return ret; +} + +FSResult FSi_ReadDirCommand(FSFile *p_dir) +{ + FSDirEntry *p_entry = p_dir->arg.readdir.p_entry; + FSResult ret; + + FSiSyncReadParam param; + param.arc = p_dir->arc; + param.pos = p_dir->prop.dir.pos.pos; + + { + u8 len; + ret = FSi_ReadTable(¶m, &len, sizeof(len)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_entry->name_len = (u32)(len & BIT_MASK(7)); + p_entry->is_directory = (u32)((len >> 7) & 1); + } + if (p_entry->name_len == 0) + return FS_RESULT_FAILURE; + + if (!p_dir->arg.readdir.skip_string) + { + ret = FSi_ReadTable(¶m, p_entry->name, p_entry->name_len); + if (ret != FS_RESULT_SUCCESS) + return ret; + MI_WriteByte((u8 *)p_entry->name + p_entry->name_len, (u8)'\0'); + } + else + { + param.pos += p_entry->name_len; + } + + if (p_entry->is_directory) + { + u16 id; + ret = FSi_ReadTable(¶m, &id, sizeof(id)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_entry->dir_id.arc = p_dir->arc; + p_entry->dir_id.own_id = (u16)(id & BIT_MASK(12)); + p_entry->dir_id.index = 0; + p_entry->dir_id.pos = 0; + } + else + { + p_entry->file_id.arc = p_dir->arc; + p_entry->file_id.file_id = p_dir->prop.dir.pos.index; + ++p_dir->prop.dir.pos.index; + } + p_dir->prop.dir.pos.pos = param.pos; + + return ret; +} + +FSResult FSi_FindPathCommand(FSFile *p_dir) +{ + const char *path = p_dir->arg.findpath.path; + const BOOL is_dir = p_dir->arg.findpath.find_directory; + p_dir->arg.seekdir.pos = p_dir->arg.findpath.pos; + (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR); + for (; MI_ReadByte(path); path += (MI_ReadByte(path) ? 1 : 0)) + { + u32 is_directory; + int name_len = 0; + while ((is_directory = MI_ReadByte(path + name_len)), + (is_directory && !FSi_IsSlash(is_directory))) + ++name_len; + if (is_directory || is_dir) + is_directory = 1; + if (name_len == 0) + { + return FS_RESULT_FAILURE; + } + else if (MI_ReadByte(path) == '.') + { + if (name_len == 1) + { + path += 1; + continue; + } + else if ((name_len == 2) & (MI_ReadByte(path + 1) == '.')) + { + if (p_dir->prop.dir.pos.own_id != 0) + FSi_SeekDirDirect(p_dir, p_dir->prop.dir.parent); + path += 2; + continue; + } + } + if (name_len > FS_FILE_NAME_MAX) + { + return FS_RESULT_FAILURE; + } + else + { + FSDirEntry etr; + p_dir->arg.readdir.p_entry = &etr; + p_dir->arg.readdir.skip_string = FALSE; + for (;;) + { + if (FSi_TranslateCommand(p_dir, FS_COMMAND_READDIR) != FS_RESULT_SUCCESS) + return FS_RESULT_FAILURE; + if ((is_directory != etr.is_directory) || + (name_len != etr.name_len) || FSi_StrNICmp(path, etr.name, (u32)name_len)) + continue; + if (is_directory) + { + path += name_len; + p_dir->arg.seekdir.pos = etr.dir_id; + (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR); + break; + } + else if (is_dir) + { + return FS_RESULT_FAILURE; + } + else + { + *p_dir->arg.findpath.result.file = etr.file_id; + return FS_RESULT_SUCCESS; + } + } + } + } + if (!is_dir) + return FS_RESULT_FAILURE; + *p_dir->arg.findpath.result.dir = p_dir->prop.dir.pos; + return FS_RESULT_SUCCESS; +} + +FSResult FSi_GetPathCommand(FSFile *p_file) +{ + FSArchive *const p_arc = p_file->arc; + + FSGetPathInfo *p_info = &p_file->arg.getpath; + + FSDirEntry entry; + FSFile tmp; + u32 dir_id; + u32 file_id; + u32 id; + u32 len; + + enum + { INVALID_ID = 0x10000 }; + + FS_InitFile(&tmp); + tmp.arc = p_file->arc; + + if (FS_IsDir(p_file)) + { + dir_id = p_file->prop.dir.pos.own_id; + file_id = INVALID_ID; + } + else + { + file_id = p_file->prop.file.own_id; + if (p_info->total_len != 0) + { + dir_id = p_info->dir_id; + } + else + { + u32 pos = 0; + u32 num_dir = 0; + dir_id = INVALID_ID; + do + { + FSi_SeekDirDirect(&tmp, pos); + if (!pos) + num_dir = tmp.prop.dir.parent; + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = TRUE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (!entry.is_directory && (entry.file_id.file_id == file_id)) + { + dir_id = tmp.prop.dir.pos.own_id; + break; + } + } + } + while ((dir_id == INVALID_ID) && (++pos < num_dir)); + } + } + if (dir_id == INVALID_ID) + { + p_info->total_len = 0; + return FS_RESULT_FAILURE; + } + if (p_info->total_len == 0) + { + len = 0; + if (p_arc->name.pack <= 0x000000FF) + len += 1; + else if (p_arc->name.pack <= 0x0000FF00) + len += 2; + else + len += 3; + len += 1 + 1; + if (file_id != INVALID_ID) + len += entry.name_len; + id = dir_id; + if (id != 0) + { + FSi_SeekDirDirect(&tmp, id); + do + { + FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent); + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = TRUE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (entry.is_directory && (entry.dir_id.own_id == id)) + { + len += entry.name_len + 1; + break; + } + } + id = tmp.prop.dir.pos.own_id; + } + while (id != 0); + } + p_info->total_len = (u16)(len + 1); + p_info->dir_id = (u16)dir_id; + } + if (!p_info->buf) + return FS_RESULT_SUCCESS; + if (p_info->buf_len < p_info->total_len) + return FS_RESULT_FAILURE; + else + { + u8 *dst = p_info->buf; + u32 total = p_info->total_len; + u32 pos = 0; + if (p_arc->name.pack <= 0x000000FF) + len = 1; + else if (p_arc->name.pack <= 0x0000FF00) + len = 2; + else + len = 3; + MI_CpuCopy8(p_arc->name.ptr, dst + pos, len); + pos += len; + MI_CpuCopy8(":/", dst + pos, 2); + pos += 2; + id = dir_id; + FSi_SeekDirDirect(&tmp, id); + if (file_id != INVALID_ID) + { + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = FALSE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (!entry.is_directory && (entry.file_id.file_id == file_id)) + break; + } + len = entry.name_len + 1; + MI_CpuCopy8(entry.name, dst + total - len, len); + total -= len; + } + else + { + MI_WriteByte(dst + total - 1, '\0'); + total -= 1; + } + if (id != 0) + { + do + { + FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent); + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = FALSE; + MI_WriteByte(dst + total - 1, '/'); + total -= 1; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (entry.is_directory && (entry.dir_id.own_id == id)) + { + len = entry.name_len; + MI_CpuCopy8(entry.name, dst + total - len, len); + total -= len; + break; + } + } + id = tmp.prop.dir.pos.own_id; + } + while (id != 0); + } + } + + return FS_RESULT_SUCCESS; +} + +FSResult FSi_OpenFileFastCommand(FSFile * p_file) +{ + FSArchive *const p_arc = p_file->arc; + const FSFileID *p_id = &p_file->arg.openfilefast.id; + const u32 index = p_id->file_id; + FSResult ret; + + { + u32 pos = (u32)(index * sizeof(FSArchiveFAT)); + if (pos >= p_arc->fat_size) + return FS_RESULT_FAILURE; + else + { + FSArchiveFAT fat; + FSiSyncReadParam param; + param.arc = p_arc; + param.pos = p_arc->fat + pos; + ret = FSi_ReadTable(¶m, &fat, sizeof(fat)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_file->arg.openfiledirect.top = fat.top; + p_file->arg.openfiledirect.bottom = fat.bottom; + p_file->arg.openfiledirect.index = index; + return FSi_TranslateCommand(p_file, FS_COMMAND_OPENFILEDIRECT); + } + } +} + +FSResult FSi_OpenFileDirectCommand(FSFile * p_file) +{ + p_file->prop.file.top = p_file->arg.openfiledirect.top; + p_file->prop.file.pos = p_file->arg.openfiledirect.top; + p_file->prop.file.bottom = p_file->arg.openfiledirect.bottom; + p_file->prop.file.own_id = p_file->arg.openfiledirect.index; + return FS_RESULT_SUCCESS; +} + +FSResult FSi_CloseFileCommand(FSFile * p_file) +{ + return FS_RESULT_SUCCESS; +} |