// Copyright (C) 2021 "Maxime “pep” Buquet " // // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU Affero General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License // for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . use std::env; use std::fmt; use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::error::Error as StdError; use std::path::Path; use quote::{format_ident, quote}; use pkstrings::{self, PKString}; #[derive(Debug, Eq, PartialEq)] pub enum Error { EnvVariableError(env::VarError), PKStringError(pkstrings::Error), ROMDoesntExist, UnableToOpenROM, } impl StdError for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { Error::EnvVariableError(e) => write!(f, "POKEMON_ROM env var error: {}", e), Error::PKStringError(e) => write!(f, "PKString error: {}", e), Error::ROMDoesntExist => write!(f, "ROM doesn't exist"), Error::UnableToOpenROM => write!(f, "Unable to open ROM"), } } } impl From for Error { fn from(err: env::VarError) -> Error { Error::EnvVariableError(err) } } impl From for Error { fn from(err: pkstrings::Error) -> Error { Error::PKStringError(err) } } fn get_rom() -> Result, Error> { let env_romp = env::var("POKEMON_ROM")?; let romp = Path::new(&env_romp); if ! romp.exists() { return Err(Error::ROMDoesntExist); } Ok(match fs::read(romp) { Ok(v) => v, Err(_) => return Err(Error::UnableToOpenROM), }) } /// Get pokemon names from ROM slice. /// The data that gets in is a list of encoded strings of 10 chars each, over 255 pokemons. fn get_pokemon_list(data: &[u8]) -> Result, Error> { let mut buffer: String = String::with_capacity(10); let mut res: Vec = Vec::with_capacity(255); // TODO: Ensure we have the right length? a multiple of 10 for (offset, ord) in data.iter().enumerate() { if offset != 0 && (offset % 10) == 0 { res.push(buffer.clone()); buffer.clear() } if *ord == 0x50 { // End char, '@'. continue } let pkstr = match PKString::try_from(&[*ord][..]) { Ok(pkstr) => pkstr, Err(e) => { println!("BUFFER: {:?}", buffer); return Err(Error::PKStringError(e)); }, }; buffer.push_str(String::from(&pkstr).as_str()); } res.push(buffer.clone()); Ok(res) } fn main() -> Result<(), Error> { let output = Path::new(&env::var("OUT_DIR").unwrap()).join("output.rs"); let mut output = BufWriter::new(File::create(&output).unwrap()); let rom: Vec = get_rom()?; let pkmn: Vec<_> = { let start = 0x1c21e; let end = start + 10 * 190; // Only the first 190 are valid get_pokemon_list(&rom[start..end])? }; let pkmn_names: Vec<_> = [ "Rhydon", "Kangashkan", "NidoranM", ].iter() .map(|n| format_ident!("{}", n)) .collect(); let tokens = quote! { /// Generated file containing various resources extracted from the provided ROM. pub enum PokemonNames { #(#pkmn_names),* } let foo = vec![#(#pkmn),*]; }; write!(output, "{}", tokens).unwrap(); Ok(()) }