0.2.4: fix length defines
This commit is contained in:
parent
484062b64a
commit
1605740937
36
.vscode/launch.json
vendored
Normal file
36
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'bin2hpp'",
|
||||
"cargo": {
|
||||
"args": ["build", "--bin=bin2hpp", "--package=bin2hpp"],
|
||||
"filter": {
|
||||
"name": "bin2hpp",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": ["-i", "/home/adam/my_library.dll"],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'bin2hpp'",
|
||||
"cargo": {
|
||||
"args": ["test", "--no-run", "--bin=bin2hpp", "--package=bin2hpp"],
|
||||
"filter": {
|
||||
"name": "bin2hpp",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -4,7 +4,7 @@ version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bin2hpp"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
@ -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"
|
||||
|
16
README.md
16
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 <stddef.h>
|
||||
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
|
||||
```
|
||||
|
||||
|
8
my_library_dll.h
Normal file
8
my_library_dll.h
Normal file
File diff suppressed because one or more lines are too long
@ -84,13 +84,13 @@ pub fn parse_config_from_args(args: &CliArgs) -> Result<Config, ProgramConfigErr
|
||||
));
|
||||
}
|
||||
};
|
||||
stem.retain(|c| c.is_ascii_alphanumeric());
|
||||
stem.retain(|c| c.is_ascii_alphanumeric() || c == '_');
|
||||
|
||||
let mut ext: String = match args.input_file_path.extension() {
|
||||
Some(s) => 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<Config, ProgramConfigErr
|
||||
));
|
||||
}
|
||||
};
|
||||
ext.retain(|c| c.is_ascii_alphanumeric());
|
||||
ext.retain(|c| c.is_ascii_alphanumeric() || c == '_');
|
||||
|
||||
format!("{}_{}", stem, ext)
|
||||
}
|
||||
|
115
src/generate.rs
115
src/generate.rs
@ -1,16 +1,21 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
HeaderGenerationError,
|
||||
cfg::Config,
|
||||
cli::{ByteType, Constness, ContainerType, Language},
|
||||
};
|
||||
|
||||
pub fn with_header(
|
||||
config: &Config,
|
||||
in_data: &[u8],
|
||||
buf: &mut String,
|
||||
) -> 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<String, HeaderGenerationError> {
|
||||
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 <stdint.h>"
|
||||
};
|
||||
|
||||
let stddef_h = if config.language == Language::Cpp {
|
||||
"#include <cstddef>"
|
||||
} else {
|
||||
"#include <stddef.h>"
|
||||
};
|
||||
|
||||
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 <array>{}", config.line_ending).unwrap();
|
||||
}
|
||||
ContainerType::CString => {
|
||||
write!(buf, "{}{}", stddef_h, config.line_ending).unwrap();
|
||||
}
|
||||
ContainerType::StdString => {
|
||||
write!(buf, "#include <string>{}", config.line_ending).unwrap();
|
||||
}
|
||||
ContainerType::StdStringView => {
|
||||
write!(buf, "#include <string_view>{}", 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
|
||||
}
|
||||
|
73
src/main.rs
73
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<Vec<u8>, 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<u8> = Vec::with_capacity(file_size as usize);
|
||||
let mut reader = BufReader::new(in_file);
|
||||
let mut in_data: Vec<u8> = 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(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user