Example #1
0
/// 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());
  }
}
Example #2
0
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;
}