Crate byte_chisel

Crate byte_chisel 

Source
Expand description

A library for decoding (“chiselling”) structures out of a byte-stream.

This crate primarily provides the Chisel type, an abstraction for reading values of primitive type.

§Usage

First, create a Chisel, e.g. from an array of bytes:

use byte_chisel::prelude::*;

let bytes = [ 239, 190, 173, 222 ];
let mut chisel = Chisel::from_array(&bytes);

You can then read a u32 from the array via:

let value = chisel.u32(Endianness::Little)?;
assert_eq!(value, 0xDEADBEEF);

If you provide more data, you can read multiple values:

let bytes = [ 239, 190, 173, 222, 103, 10 ];
let mut chisel = Chisel::from_array(&bytes);
let val1 = chisel.u32(Endianness::Little)?;
let val2 = chisel.u16(Endianness::Little)?;
assert_eq!(val1, 0xDEADBEEF);
assert_eq!(val2, 0x0A67);

Most formats use a consistent endianness. You can use a wrapper to avoid repeating it:

let mut chisel_be = chisel.big_endian();

// both of these `u16` are read as big-endian
let hi = chisel_be.u16()?;
let lo = chisel_be.u16()?;

§Errors

This crate distinguishes between three types of errors during chiselling: Format Errors, Source Errors and EndOfInput. The byte offset an error occurred at is included for ease of debugging.

See the documentation on ChiselError for details.

§“Breaking”

In most cases, when a chiselling operation returns an error, the Chisel is said to “break”. (This is called out in the documentation with the phrase “the chisel breaks” and a link to this section.)

A “broken” Chisel no longer accurately tracks the underlying byte-stream:

  • Some bytes that are present in the byte-stream are “lost” and inaccessible.
  • The tracked byte offset no longer reflects the position in the byte-stream.

Continuing to use a “broken” Chisel is discouraged. Note that idiomatic use of the ? operator prevents broken Chisel usage.

§API Considerations

For composability, it is recommended that chiselling functions take the input Chisel by mutable reference:

fn chisel_resource_header<S : ChiselSource>(
	chisel: &mut Chisel<S>
) -> ChiselResult<ResourceHeader, HeaderError, S> {
	todo!()
}

This allows using such functions as part of larger decodings:

let count = chisel.u16(Endianness::Little).forward()?;
let mut headers = Vec::with_capacity(count as usize);
for _ in 0..count {
	let header = chisel_resource_header(&mut chisel)
		.map_err(|e| e.map(FileError::BadHeader))?
	;
	headers.push(header)
}
/* parse the rest of the file... */

§Examples

Decode (“chisel”) a simple resource header consisting of

  • a little-endian 32-bit integer id
  • a 1-byte tag and
  • a null-terminated name
use byte_chisel::prelude::*;
 
fn chisel_resource_header<S : ChiselSource>(
	chisel: &mut Chisel<S>
) -> ChiselResult<ResourceHeader, HeaderError, S> {
	// read the id
	let id = chisel.u32(Endianness::Little).forward()?;

	// read the type tag
	let typ = chisel.u8().forward()?;

	// parse the type tag, only allowing ones we support
	let typ = match typ {
		0 => ResourceType::Image,
		// ...
		5 => ResourceType::Text,
		// if we encounter an unknown type, report a format error
		ty => return Err(chisel.error(HeaderError::UnknownType(ty), 1))
	};
	
	// save the name offaet for reporting later
	let name_offset = chisel.offset();

	let mut name = Vec::new();

	// read the name as a null-terminated string
	// note that `name` will not contain the terminating null!
	chisel.read_until(0, &mut name).forward()?;

	// convert to `String` for ease of use
	let name = String::from_utf8(name).map_err(
		// if the conversion fails (due to invalid utf-8), report a format error
		|_| ChiselError::format(name_offset, HeaderError::IllegalName)
	)?;
	
	Ok(ResourceHeader {
		id,
		typ,
		name
	})
}

Re-exports§

pub use source::ChiselSource;
pub use source::ChiselSourceError;

Modules§

prelude
byte-chisel prelude
source
ChiselSource and implementations.

Structs§

Chisel
An object providing structured access to an underlying byte-stream.
ChiselBigEndian
A Chisel, with big-endian byte order.
ChiselError
The error type for chiseling operations.
ChiselLittleEndian
A Chisel, with little-endian byte order.

Enums§

ChiselErrorData
The error data type for chiseling operations.
Endianness
Used to define byte order or “endianness”.
ReadUntilStopReason
Used to indicate why a read_until_or_end operation stopped.

Traits§

InfalliableFormatResultExt
Extension trait for InfallibleFormatResult.

Type Aliases§

ChiselResult
The result type of attempting to chisel a T from a source S, with format errors described by E.
InfallibleFormatError
The error type of attempting to chisel a value from a source S; where all byte sequences produce valid values (“infallible format”).
InfallibleFormatResult
The error type of attempting to chisel a T from a source S. All byte sequences produce valid Ts (“infallible format”).