From 184fb9eda3a8f3962b3adf50e9193ed8e928ade0 Mon Sep 17 00:00:00 2001 From: "adam@2khz.xyz" Date: Sun, 17 Aug 2025 15:52:13 +0100 Subject: [PATCH] 0.2.4: fix length defines --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 16 +++---- src/cfg.rs | 6 +-- src/generate.rs | 115 +++++++++++++----------------------------------- src/main.rs | 73 +++++++++++++++--------------- 6 files changed, 78 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d442d0..955dc1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "bin2hpp" -version = "0.2.3" +version = "0.2.4" dependencies = [ "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 77604a2..74e658d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bin2hpp" -version = "0.2.3" +version = "0.2.4" authors = ["Adam Macdonald"] edition = "2024" license = "GPL-3.0-only" diff --git a/README.md b/README.md index cb173bf..1ea477d 100644 --- a/README.md +++ b/README.md @@ -12,18 +12,16 @@ CLI tool for converting files into header files which one can use to directly em ### Basic usage -`$ bin2hpp -i ~/my_image.bmp` will generate an `my_image_bmp.h` file in your current working directory containing something similar to the following: +`$ bin2hpp -i ~/my_library.dll --overwrite` will generate an `my_library_dll.h` file in your current working directory containing something similar to the following: ```c -// Generated by bin2hpp 0.2.0 -#ifndef MY_IMAGE_BMP_H -#define MY_IMAGE_BMP_H -#include -const size_t MYIMAGE_BMP_LEN = 36000054; -const unsigned char MYIMAGE_BMP[MYIMAGE_BMP_LEN] = {0x42,0x4d,0x36,0x51,0x25, ...} +// Generated by bin2hpp 0.2.4 +#ifndef MY_LIBRARY_DLL_H +#define MY_LIBRARY_DLL_H +#define MY_LIBRARY_DLL_LEN 9728 +const unsigned char MY_LIBRARY_DLL[MY_LIBRARY_DLL_LEN] = {0x4d,0x5a,0x90,0x0,0x3,0x0,0x0, ...}; #else -extern const size_t MYIMAGE_BMP_LEN; -extern const unsigned char MYIMAGE_BMP[MYIMAGE_BMP_LEN]; +extern const unsigned char MY_LIBRARY_DLL[MY_LIBRARY_DLL_LEN]; #endif ``` diff --git a/src/cfg.rs b/src/cfg.rs index ee33c34..e7eb8dc 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -84,13 +84,13 @@ pub fn parse_config_from_args(args: &CliArgs) -> Result format!("_{}", s.to_string_lossy()), None => "".to_string(), }; - ext.retain(|c| c.is_ascii_alphanumeric()); + ext.retain(|c| c.is_ascii_alphanumeric() || c == '_'); format!("{}{}", stem.to_ascii_uppercase(), ext.to_ascii_uppercase()) } @@ -132,7 +132,7 @@ pub fn parse_config_from_args(args: &CliArgs) -> Result Result<(), HeaderGenerationError> { +#[derive(Error, Debug)] +pub enum HeaderGenerationError { + #[error("input file doesn't contain valid UTF-8: \"{0}\"")] + InvalidUtf8String(String), +} + +pub fn header(config: &Config, in_data: &[u8]) -> Result { + let mut buf = String::with_capacity(in_data.len() * 6); + // Program banner at the top of the header file write!( buf, @@ -22,6 +27,7 @@ pub fn with_header( .unwrap(); // Header guard + if config.language == Language::Cpp { write!( buf, @@ -34,12 +40,16 @@ pub fn with_header( } write!(buf, "#define {}{}", config.guard_name, config.line_ending).unwrap(); - with_includes(config, buf); - with_contents(config, in_data, buf)?; + // Includes & main content + + with_includes(config, &mut buf); + with_contents(config, in_data, &mut buf)?; + + // End header guard write!(buf, "#endif{}", config.line_ending).unwrap(); - Ok(()) + Ok(buf) } pub fn with_contents( @@ -78,15 +88,8 @@ pub fn with_includes(config: &Config, buf: &mut String) { "#include " }; - let stddef_h = if config.language == Language::Cpp { - "#include " - } else { - "#include " - }; - match config.container_type { ContainerType::CArray(byte_type) => { - write!(buf, "{}{}", stddef_h, config.line_ending).unwrap(); match byte_type { ByteType::U8 => write!(buf, "{}{}", stdint_h, config.line_ending).unwrap(), ByteType::I8 => write!(buf, "{}{}", stdint_h, config.line_ending).unwrap(), @@ -102,15 +105,13 @@ pub fn with_includes(config: &Config, buf: &mut String) { write!(buf, "#include {}", config.line_ending).unwrap(); } - ContainerType::CString => { - write!(buf, "{}{}", stddef_h, config.line_ending).unwrap(); - } ContainerType::StdString => { write!(buf, "#include {}", config.line_ending).unwrap(); } ContainerType::StdStringView => { write!(buf, "#include {}", config.line_ending).unwrap(); } + _ => (), }; } @@ -152,37 +153,19 @@ pub fn with_definition( buf: &mut String, ) -> Result<(), HeaderGenerationError> { let length: usize = match config.container_type { - ContainerType::CString => in_data.len() + 1, + ContainerType::CString => in_data.len() + 1, // +1 for NUL terminator _ => in_data.len(), }; let modifiers = definition_modifiers(config); - match config.container_type { - ContainerType::CArray(_) => { - write!( - buf, - "{}{} = {};{}", - modifiers, - length_data_type_symbol(config), - length, - config.line_ending - ) - .unwrap(); - } - ContainerType::CString => { - write!( - buf, - "{}{} = {};{}", - modifiers, - length_data_type_symbol(config), - length, - config.line_ending - ) - .unwrap(); - } - _ => (), - }; + write!( + buf, + "{}{}", + length_define(config, length), + config.line_ending + ) + .unwrap(); write!( buf, @@ -204,23 +187,6 @@ pub fn with_definition( pub fn with_declaration(config: &Config, in_data: &[u8], buf: &mut String) { let modifiers = declaration_modifiers(config); - match config.container_type { - ContainerType::CArray(_) => { - write!(buf, "{}{};{}", modifiers, in_data.len(), config.line_ending).unwrap(); - } - ContainerType::CString => { - write!( - buf, - "{}{};{}", - modifiers, - in_data.len() + 1, - config.line_ending - ) - .unwrap(); - } - _ => (), - }; - write!( buf, "{}{};{}", @@ -264,15 +230,10 @@ pub fn with_string_initialiser( Ok(out_str) } -pub fn length_data_type_symbol(config: &Config) -> String { +pub fn length_define(config: &Config, length: usize) -> String { let mut out_str = String::with_capacity(36 + config.symbol_name.len()); - let size_type = match config.language { - Language::C => "size_t", - Language::Cpp => "std::size_t", - }; - - write!(out_str, "{} {}", size_type, length_symbol(config)).unwrap(); + write!(out_str, "#define {} {}", length_symbol(config), length).unwrap(); out_str } @@ -280,21 +241,7 @@ pub fn length_data_type_symbol(config: &Config) -> String { pub fn length_symbol(config: &Config) -> String { let mut out_str = String::with_capacity(config.symbol_name.len() + 5); - write!( - out_str, - "{}{}", - config.symbol_name, - if config - .symbol_name - .chars() - .all(|c| c.is_uppercase() || c == '_') - { - "_LEN" - } else { - "_len" - }, - ) - .unwrap(); + write!(out_str, "{}_LEN", config.symbol_name.to_uppercase(),).unwrap(); out_str } diff --git a/src/main.rs b/src/main.rs index 0b0185d..a816224 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,7 @@ -use std::io::{BufReader, BufWriter, Read, Write}; +use std::io::{self, BufReader, BufWriter, Read, Write}; +use std::path::Path; use std::{env, fs::OpenOptions, process::ExitCode}; -use thiserror::Error; - -use crate::cfg::Config; - mod cfg; mod cli; mod constants; @@ -43,10 +40,25 @@ fn main() -> ExitCode { } }; - match write_header(&cfg) { + let in_data = match read_input_file(&cfg.input_file_path) { + Ok(v) => v, + Err(e) => { + eprintln!("Failed to read input file: {}", e); + return ExitCode::FAILURE; + } + }; + let header_src = match generate::header(&cfg, &in_data) { + Ok(s) => s, + Err(e) => { + eprintln!("Failed to generate header source file: {}", e); + return ExitCode::FAILURE; + } + }; + + match write_output_file(header_src.as_bytes(), cfg.overwrite, &cfg.output_file_path) { Ok(_) => (), Err(e) => { - eprintln!("{}", e); + eprintln!("Failed to write output file: {}", e); return ExitCode::FAILURE; } }; @@ -54,48 +66,33 @@ fn main() -> ExitCode { return ExitCode::SUCCESS; } -#[derive(Error, Debug)] -pub enum HeaderGenerationError { - #[error("I/O error: \"{0}\"")] - IOError(String), - #[error("input file doesn't contain valid UTF-8: \"{0}\"")] - InvalidUtf8String(String), -} - -fn write_header(config: &Config) -> Result<(), HeaderGenerationError> { +fn read_input_file(input_path: &Path) -> Result, io::Error> { let in_file = OpenOptions::new() .read(true) .write(false) - .open(config.input_file_path.clone()) - .expect("failed to open input file"); - - let mut buf = String::with_capacity(if let Ok(meta) = in_file.metadata() { - meta.len() as usize - } else { - 0 - }); + .open(input_path)?; + let file_size = in_file.metadata()?.len(); + let mut in_data: Vec = Vec::with_capacity(file_size as usize); let mut reader = BufReader::new(in_file); - let mut in_data: Vec = Vec::new(); - let n_bytes_read = match reader.read_to_end(&mut in_data) { - Ok(n) => n, - Err(e) => return Err(HeaderGenerationError::IOError(e.to_string())), - }; - generate::with_header(config, &in_data[..n_bytes_read], &mut buf)?; + let _ = reader.read_to_end(&mut in_data)?; + Ok(in_data) +} + +fn write_output_file(buf: &[u8], overwrite: bool, output_path: &Path) -> Result<(), io::Error> { + if overwrite { + let _ = std::fs::remove_file(output_path); + } let out_file = OpenOptions::new() .write(true) - .truncate(config.overwrite) - .create(true) - .open(config.output_file_path.clone()) - .expect("failed to open input file"); + .create_new(true) + .open(output_path)?; + let mut writer = BufWriter::new(out_file); - match writer.write_all(buf.as_bytes()) { - Ok(_) => (), - Err(e) => return Err(HeaderGenerationError::IOError(e.to_string())), - }; + writer.write_all(buf)?; Ok(()) }