Created
June 5, 2023 17:44
-
-
Save ITotalJustice/241028c00e7f3ffaba52521b0d64055f to your computer and use it in GitHub Desktop.
nro scanning code. new code is faster by 0.07 seconds (64 entries, 48 nros) total time 0.30 seconds
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auto nro_parse(FsFileSystem* fs, const char* path, const char* star_path, NroEntry& entry) -> bool { | |
Result rc{}; | |
FsFile f{}; | |
u64 bytes_read{}; | |
if (R_FAILED(rc = fsFsOpenFile(fs, path, FsOpenMode_Read, &f))) { | |
// std::printf("failed to open: %s\n", path); | |
return false; | |
} | |
NroData data; | |
NroAssetHeader asset; | |
if (R_FAILED(rc = fsFileRead(&f, 0, &data, sizeof(data), 0, &bytes_read)) || | |
data.header.magic != NROHEADER_MAGIC) { | |
// std::printf("bad headermagic: %X %X\n", data.header.magic, NROHEADER_MAGIC); | |
fsFileClose(&f); | |
return false; | |
} | |
if (R_FAILED(rc = fsFileRead(&f, data.header.size, &asset, sizeof(asset), 0, &bytes_read)) || | |
asset.magic != NROASSETHEADER_MAGIC) { | |
// std::printf("bad NROASSETHEADER_MAGIC: %X %X\n", asset.magic, NROASSETHEADER_MAGIC); | |
fsFileClose(&f); | |
return false; | |
} | |
entry.icon.resize(asset.icon.size); | |
if (R_FAILED(rc = fsFileRead(&f, data.header.size + asset.icon.offset, entry.icon.data(), entry.icon.size(), 0, &bytes_read))) { | |
fsFileClose(&f); | |
return false; | |
} | |
if (R_FAILED(rc = fsFileRead(&f, data.header.size + asset.nacp.offset, &entry.nacp, sizeof(entry.nacp), 0, &bytes_read))) { | |
fsFileClose(&f); | |
return false; | |
} | |
std::strcpy(entry.path, path); | |
std::strcpy(entry.star_path, star_path); | |
fsFileClose(&f); | |
// check if it favourited | |
if (R_SUCCEEDED(fsFsOpenFile(fs, star_path, FsOpenMode_Read, &f))) { | |
entry.is_star = true; | |
fsFileClose(&f); | |
} | |
return true; | |
} | |
// this function is recursive by 1 level deep | |
// if the nro is in switch/folder/folder2/app.nro it will NOT be found | |
// switch/folder/app.nro for example will work fine. | |
auto nro_scan_internal(const char* _path, std::vector<NroEntry>& nros, bool root) -> bool { | |
Result rc{}; | |
FsDir d{}; | |
s64 count{}; | |
char path[FS_MAX_PATH]{}; | |
char fullpath[FS_MAX_PATH]{}; | |
char starpath[FS_MAX_PATH]{}; | |
strncpy(path, _path, sizeof(path)-1); | |
// fs is already open by fsdev | |
// NOTE: this only applies to applications, | |
// applets should open fs themselves! | |
auto fs = fsdevGetDeviceFileSystem("sdmc"); | |
if (!fs) { | |
std::printf("failed to get device fs system :(\n"); | |
return false; | |
} | |
if (R_FAILED(rc = fsFsOpenDirectory(fs, path, FsDirOpenMode_ReadDirs | FsDirOpenMode_ReadFiles | FsDirOpenMode_NoFileSize, &d))) { | |
std::printf("failed to open dir\n"); | |
return false; | |
} | |
if (R_FAILED(rc = fsDirGetEntryCount(&d, &count))) { | |
std::printf("failed to get dir count\n"); | |
fsDirClose(&d); | |
return false; | |
} | |
// we won't run out of memory here | |
std::vector<FsDirectoryEntry> entries(count); | |
if (R_FAILED(rc = fsDirRead(&d, &count, entries.size(), entries.data()))) { | |
std::printf("failed to read dir :/\n"); | |
fsDirClose(&d); | |
return false; | |
} | |
std::printf("count %ld found: %zu\n", count, entries.size()); | |
fsDirClose(&d); | |
// size may of changed | |
entries.resize(count); | |
for (const auto& e : entries) { | |
// skip hidden files / folders | |
if ('.' == e.name[0]) { | |
continue; | |
} | |
// todo: only scan | |
if (e.type == FsDirEntryType_Dir) { | |
if (root) { | |
std::snprintf(fullpath, sizeof(fullpath)-1, "%s/%s", path, e.name); | |
nro_scan_internal(fullpath, nros, false); | |
} | |
} else if (e.type == FsDirEntryType_File && std::string_view{e.name}.ends_with(".nro")) { | |
NroEntry entry{}; | |
std::snprintf(fullpath, sizeof(fullpath)-1, "%s/%s", path, e.name); | |
std::snprintf(starpath, sizeof(starpath)-1, "%s/.%s.star", path, e.name); | |
if (nro_parse(fs, fullpath, starpath, entry)) { | |
nros.emplace_back(entry); | |
// std::printf("added: %s\n", fullpath); | |
if (root == false) { | |
fsDirClose(&d); | |
return true; | |
} | |
} else { | |
std::printf("error when trying to parse %s\n", fullpath); | |
} | |
} | |
} | |
return true; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auto nro_parse(const char* path, const char* star_path, NroEntry& entry) -> bool { | |
auto fp = std::fopen(path, "rb"); | |
if (!fp) { | |
return false; | |
} | |
// todo: error check and handle | |
NroData data; | |
NroAssetHeader asset; | |
std::fread(&data, 1, sizeof(data), fp); | |
if (data.header.magic != NROHEADER_MAGIC) { | |
// std::printf("bad headermagic: %X %X\n", data.header.magic, NROHEADER_MAGIC); | |
fclose(fp); | |
return false; | |
} | |
std::fseek(fp, data.header.size, SEEK_SET); | |
std::fread(&asset, 1, sizeof(asset), fp); | |
if (asset.magic != NROASSETHEADER_MAGIC) { | |
// std::printf("bad NROASSETHEADER_MAGIC: %X %X\n", asset.magic, NROASSETHEADER_MAGIC); | |
fclose(fp); | |
return false; | |
} | |
entry.icon.resize(asset.icon.size); | |
std::fseek(fp, data.header.size + asset.icon.offset, SEEK_SET); | |
std::fread(entry.icon.data(), 1, entry.icon.size(), fp); | |
std::fseek(fp, data.header.size + asset.nacp.offset, SEEK_SET); | |
std::fread(&entry.nacp, 1, sizeof(entry.nacp), fp); | |
std::strcpy(entry.path, path); | |
std::strcpy(entry.star_path, star_path); | |
fclose(fp); | |
// check if it favourited | |
if (auto f = fopen(star_path, "rb")) { | |
entry.is_star = true; | |
fclose(f); | |
} | |
return true; | |
} | |
auto nro_scan_internal(const char* path, std::vector<NroEntry>& nros, bool root) -> bool { | |
char fullpath[FS_MAX_PATH]{}; | |
char starpath[FS_MAX_PATH]{}; | |
auto dir = opendir(path); | |
if (!dir) { | |
std::printf("failed to open dir: %s\n", path); | |
return false; | |
} | |
while (auto d = readdir(dir)) { | |
if ('.' == d->d_name[0]) { | |
continue; | |
} | |
if (d->d_type == DT_DIR) { | |
if (root) { | |
std::sprintf(fullpath, "%s/%s", path, d->d_name); | |
nro_scan_internal(fullpath, nros, false); | |
} | |
} else if (d->d_type == DT_REG && std::string_view{d->d_name}.ends_with(".nro")) { | |
std::sprintf(fullpath, "%s/%s", path, d->d_name); | |
std::sprintf(starpath, "%s/.%s.star", path, d->d_name); | |
NroEntry entry{}; | |
if (nro_parse(fullpath, starpath, entry)) { | |
nros.emplace_back(entry); | |
// std::printf("added: %s\n", fullpath); | |
if (root == false) { | |
closedir(dir); | |
return true; | |
} | |
} else { | |
std::printf("error when trying to parse %s\n", fullpath); | |
} | |
} | |
} | |
closedir(dir); | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment