/// Load ROM image from 2SF file. /// @param filename the path to 2sf file. /// @param rom the rom image to be loaded. /// @param lib_nest_level the nest level of psflib. /// @param first_load true for the first file. void load_2sf(const std::string & filename, std::vector<char> & rom, int lib_nest_level = 0, bool first_load = true) { // check the psflib nest level if (lib_nest_level >= kPSFLibMaxNestLevel) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Nest level error on psflib loading."; throw std::out_of_range(message_buffer.str()); } // save the current directory char pwd[PATH_MAX]; getcwd(pwd, PATH_MAX); // get the absolute path char absolute_path[PATH_MAX]; if (path_getabspath(filename.c_str(), absolute_path) == NULL) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Unable to determine absolute path."; throw std::out_of_range(message_buffer.str()); } // get the directory path char basedir[PATH_MAX]; strcpy(basedir, absolute_path); path_dirname(basedir); // load the psf file PSFFile psf(filename); // check CRC32 of the compressed program uint32_t actual_crc32 = ::crc32(0L, reinterpret_cast<const Bytef *>( psf.compressed_exe().data()), static_cast<uInt>(psf.compressed_exe().size())); if (psf.compressed_exe_crc32() != actual_crc32) { std::ostringstream message_buffer; message_buffer << filename << ": " << "CRC32 error at the compressed program."; throw std::runtime_error(message_buffer.str()); } // load psflibs int lib_index = 1; while (true) { // search for _libN tag std::ostringstream lib_tag_name_buffer; lib_tag_name_buffer << "_lib"; if (lib_index > 1) { lib_tag_name_buffer << lib_index; } std::string lib_tag_name = lib_tag_name_buffer.str(); // if no tag is present, end the lib loading if (psf.tags().count(lib_tag_name) == 0) { break; } // set the current directory to the parent psf directory chdir(basedir); // load the lib try { load_2sf(psf.tags()[lib_tag_name], rom, lib_nest_level + 1, first_load); } catch (std::exception) { chdir(pwd); throw; } chdir(pwd); first_load = false; // check the next lib lib_index++; } // read the exe header // - 4 bytes offset // - 4 bytes size ZlibReader compressed_exe(psf.compressed_exe().c_str(), psf.compressed_exe().size()); uint32_t load_offset; uint32_t load_size; bool read_success = true; read_success &= compressed_exe.readInt(load_offset); read_success &= compressed_exe.readInt(load_size); if (!read_success) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Unable to read the program header."; throw std::runtime_error(message_buffer.str()); } // ensure the rom buffer size if (load_offset + load_size > kNDSRomMaxSize) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Load offset/size of 2SF is too large. "; throw std::out_of_range(message_buffer.str()); } if (first_load) { rom.resize(load_offset + load_size, 0); } else { if (load_offset + load_size > rom.size()) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Load offset/size of 2SF is out of bound."; throw std::out_of_range(message_buffer.str()); } } // decompress the program area if (compressed_exe.read(&rom[load_offset], load_size) != load_size) { std::ostringstream message_buffer; message_buffer << filename << ": " << "Failed to deflate data. Program data is corrupted."; throw std::out_of_range(message_buffer.str()); } }
bool procyon_ripper::load_rom(const std::string & nds_filename) { if (verbose) { printf("Input NDS ROM \"%s\"\n", nds_filename.c_str()); printf("\n"); } off_t rom_size_off = path_getfilesize(nds_filename.c_str()); if (rom_size_off < 0x180) { return false; } size_t rom_size = (size_t)rom_size_off; if (!is_valid_nds_rom(nds_filename)) { fprintf(stderr, "Error: Invalid NDS ROM.\n"); return false; } FILE * fp = fopen(nds_filename.c_str(), "rb"); if (fp == NULL) { fprintf(stderr, "Error: Unable to open file.\n"); return false; } uint8_t header[0x180]; if (fread(header, 1, 0x180, fp) != 0x180) { fprintf(stderr, "Error: Unable to read header.\n"); fclose(fp); return false; } uint32_t arm9_rom_offset = mget4l(&header[0x20]); uint32_t arm9_load_address = mget4l(&header[0x28]); uint32_t arm9_size = mget4l(&header[0x2c]); if (exe != NULL) { delete[] exe; exe = NULL; rom = NULL; arm9 = NULL; } exe = new uint8_t[NDS2SF_EXE_HEADER_SIZE + rom_size]; if (exe == NULL) { fprintf(stderr, "Error: Unable to allocate memory.\n"); fclose(fp); return false; } NDS2SF::put_2sf_exe_header(exe, 0, rom_size); rewind(fp); if (fread(&exe[NDS2SF_EXE_HEADER_SIZE], 1, rom_size, fp) != rom_size) { fprintf(stderr, "Error: Unable to read ROM.\n"); delete[] exe; exe = NULL; fclose(fp); return false; } this->rom = &exe[NDS2SF_EXE_HEADER_SIZE]; this->rom_size = rom_size; this->arm9 = &rom[arm9_rom_offset]; this->arm9_rom_offset = arm9_rom_offset; this->arm9_load_address = arm9_load_address; this->arm9_size = arm9_size; char abspath[PATH_MAX]; path_getabspath(nds_filename.c_str(), abspath); this->nds_path.assign(abspath); nopRegions.clear(); driver_offset = 0; bgm_play_function_offset = 0; fclose(fp); return true; }