From 6020b173a0b7b10c7965e95485ac19b5df1108ef Mon Sep 17 00:00:00 2001 From: Jean-Marie Mineau Date: Thu, 24 Aug 2023 18:51:06 +0200 Subject: [PATCH] add encoded scalar values --- androscalpel_serializer/src/annotation.rs | 18 + androscalpel_serializer/src/array.rs | 18 + androscalpel_serializer/src/lib.rs | 6 + androscalpel_serializer/src/value.rs | 671 ++++++++++++++++++++++ 4 files changed, 713 insertions(+) create mode 100644 androscalpel_serializer/src/annotation.rs create mode 100644 androscalpel_serializer/src/array.rs create mode 100644 androscalpel_serializer/src/value.rs diff --git a/androscalpel_serializer/src/annotation.rs b/androscalpel_serializer/src/annotation.rs new file mode 100644 index 0000000..9d3ae2d --- /dev/null +++ b/androscalpel_serializer/src/annotation.rs @@ -0,0 +1,18 @@ +use crate::{ReadSeek, Result, Serializable}; +use std::io::Write; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EncodedAnnotation; + +impl Serializable for EncodedAnnotation { + fn serialize(&self, _output: &mut dyn Write) -> Result<()> { + todo!() + } + fn deserialize(_input: &mut dyn ReadSeek) -> Result { + todo!() + } + + fn size(&self) -> usize { + todo!() + } +} diff --git a/androscalpel_serializer/src/array.rs b/androscalpel_serializer/src/array.rs new file mode 100644 index 0000000..d6772bc --- /dev/null +++ b/androscalpel_serializer/src/array.rs @@ -0,0 +1,18 @@ +use crate::{ReadSeek, Result, Serializable}; +use std::io::Write; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EncodedArray; + +impl Serializable for EncodedArray { + fn serialize(&self, _output: &mut dyn Write) -> Result<()> { + todo!() + } + fn deserialize(_input: &mut dyn ReadSeek) -> Result { + todo!() + } + + fn size(&self) -> usize { + todo!() + } +} diff --git a/androscalpel_serializer/src/lib.rs b/androscalpel_serializer/src/lib.rs index b68d672..2776e91 100644 --- a/androscalpel_serializer/src/lib.rs +++ b/androscalpel_serializer/src/lib.rs @@ -1,7 +1,13 @@ +pub mod annotation; +pub mod array; pub mod constant; pub mod core; +pub mod value; pub use androscalpel_serializer_derive::*; pub use crate::core::*; +pub use annotation::*; +pub use array::*; pub use constant::*; +pub use value::*; diff --git a/androscalpel_serializer/src/value.rs b/androscalpel_serializer/src/value.rs new file mode 100644 index 0000000..0baeca6 --- /dev/null +++ b/androscalpel_serializer/src/value.rs @@ -0,0 +1,671 @@ +//! The encoded value format: https://source.android.com/docs/core/runtime/dex-format#encoding + +use crate::{EncodedAnnotation, EncodedArray, Error, ReadSeek, Result, Serializable}; +use std::io::Write; + +// TODO: TESTS!!! +/// An encoded value of arbitrary hierachically structured data: +/// https://source.android.com/docs/core/runtime/dex-format#encoding +#[derive(Debug, Clone)] +pub enum EncodedValue { + Byte(i8), + Short(i16), + Char(u16), + Int(i32), + Long(i64), + Float(f32), + Double(f64), + MethodType(u32), + MethodHandle(u32), + String(u32), + Type(u32), + Field(u32), + Method(u32), + Enum(u32), + Array(EncodedArray), + Annotation(EncodedAnnotation), + Null, + Boolean(bool), +} + +/// The id of a type used by a value. +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct ValueType(u8); + +const VALUE_BYTE: ValueType = ValueType(0x00); +const VALUE_SHORT: ValueType = ValueType(0x02); +const VALUE_CHAR: ValueType = ValueType(0x03); +const VALUE_INT: ValueType = ValueType(0x04); +const VALUE_LONG: ValueType = ValueType(0x06); +const VALUE_FLOAT: ValueType = ValueType(0x10); +const VALUE_DOUBLE: ValueType = ValueType(0x11); +const VALUE_METHOD_TYPE: ValueType = ValueType(0x15); +const VALUE_METHOD_HANDLE: ValueType = ValueType(0x16); +const VALUE_STRING: ValueType = ValueType(0x17); +const VALUE_TYPE: ValueType = ValueType(0x18); +const VALUE_FIELD: ValueType = ValueType(0x19); +const VALUE_METHOD: ValueType = ValueType(0x1a); +const VALUE_ENUM: ValueType = ValueType(0x1b); +const VALUE_ARRAY: ValueType = ValueType(0x1c); +const VALUE_ANNOTATION: ValueType = ValueType(0x1d); +const VALUE_NULL: ValueType = ValueType(0x1e); +const VALUE_BOOLEAN: ValueType = ValueType(0x1f); + +impl PartialEq for EncodedValue { + fn eq(&self, item: &Self) -> bool { + match (self, item) { + (Self::Byte(val1), Self::Byte(val2)) => val1 == val2, + (Self::Short(val1), Self::Short(val2)) => val1 == val2, + (Self::Char(val1), Self::Char(val2)) => val1 == val2, + (Self::Int(val1), Self::Int(val2)) => val1 == val2, + (Self::Long(val1), Self::Long(val2)) => val1 == val2, + (Self::Float(val1), Self::Float(val2)) => val1.to_be_bytes() == val2.to_be_bytes(), + (Self::Double(val1), Self::Double(val2)) => val1.to_be_bytes() == val2.to_be_bytes(), + (Self::MethodType(val1), Self::MethodType(val2)) => val1 == val2, + (Self::MethodHandle(val1), Self::MethodHandle(val2)) => val1 == val2, + (Self::String(val1), Self::String(val2)) => val1 == val2, + (Self::Type(val1), Self::Type(val2)) => val1 == val2, + (Self::Field(val1), Self::Field(val2)) => val1 == val2, + (Self::Method(val1), Self::Method(val2)) => val1 == val2, + (Self::Enum(val1), Self::Enum(val2)) => val1 == val2, + (Self::Array(val1), Self::Array(val2)) => val1 == val2, + (Self::Annotation(val1), Self::Annotation(val2)) => val1 == val2, + (Self::Null, Self::Null) => true, + (Self::Boolean(val1), Self::Boolean(val2)) => val1 == val2, + _ => false, + } + } +} + +impl Eq for EncodedValue {} + +impl Serializable for EncodedValue { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + match self { + Self::Byte(byte) => { + let bytes = byte.to_be_bytes(); + output.write_all(&[VALUE_BYTE.0]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Byte to output: {err}" + )) + })?; + output.write_all(&bytes).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Byte to output: {err}" + )) + })?; + Ok(()) + } + Self::Short(val) => { + let size = self.size(); + let bytes: [u8; 2] = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_SHORT.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Short to output: {err}" + )) + })?; + output.write_all(&bytes[(2 - size + 1)..]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Short to output: {err}" + )) + })?; + Ok(()) + } + Self::Char(val) => { + let size = self.size(); + let bytes: [u8; 2] = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_CHAR.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Char to output: {err}" + )) + })?; + output.write_all(&bytes[(2 - size + 1)..]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Char to output: {err}" + )) + })?; + Ok(()) + } + Self::Int(val) => { + let size = self.size(); + let bytes: [u8; 4] = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_INT.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Int to output: {err}" + )) + })?; + output.write_all(&bytes[(2 - size + 1)..]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Int to output: {err}" + )) + })?; + Ok(()) + } + Self::Long(val) => { + let size = self.size(); + let bytes: [u8; 8] = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_LONG.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Long to output: {err}" + )) + })?; + output.write_all(&bytes[(2 - size + 1)..]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Long to output: {err}" + )) + })?; + Ok(()) + } + Self::Float(val) => { + let size = self.size(); + let bytes = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_FLOAT.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Float to output: {err}" + )) + })?; + output.write_all(&bytes[..(size - 1)]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Float to output: {err}" + )) + })?; + Ok(()) + } + Self::Double(val) => { + let size = self.size(); + let bytes = val.to_be_bytes(); + output + .write_all(&[((size as u8 - 2) << 5) | VALUE_DOUBLE.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Double to output: {err}" + )) + })?; + output.write_all(&bytes[..(size - 1)]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Double to output: {err}" + )) + })?; + Ok(()) + } + Self::MethodType(idx) => Idx(*idx, VALUE_METHOD_TYPE).serialize(output), + Self::MethodHandle(idx) => Idx(*idx, VALUE_METHOD_HANDLE).serialize(output), + Self::String(idx) => Idx(*idx, VALUE_STRING).serialize(output), + Self::Type(idx) => Idx(*idx, VALUE_TYPE).serialize(output), + Self::Field(idx) => Idx(*idx, VALUE_FIELD).serialize(output), + Self::Method(idx) => Idx(*idx, VALUE_METHOD).serialize(output), + Self::Enum(idx) => Idx(*idx, VALUE_ENUM).serialize(output), + Self::Array(arr) => { + output.write_all(&[VALUE_ARRAY.0]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Array to output: {err}" + )) + })?; + arr.serialize(output) + } + Self::Annotation(ann) => { + output.write_all(&[VALUE_ANNOTATION.0]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Annotation to output: {err}" + )) + })?; + ann.serialize(output) + } + Self::Null => { + output.write_all(&[VALUE_NULL.0]).map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Null to output: {err}" + )) + })?; + Ok(()) + } + Self::Boolean(b) => { + let val = if *b { 1 } else { 0 }; + output + .write_all(&[(val << 5) | VALUE_BOOLEAN.0]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Bool to output: {err}" + )) + })?; + Ok(()) + } + } + } + fn deserialize(input: &mut dyn ReadSeek) -> Result { + let mut buffer = [0u8; 1]; + input.read_exact(&mut buffer).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue from the input".into(), + ) + })?; + let [byte] = buffer; + let arg = (byte & 0b1110_0000) >> 5; + match ValueType(byte & 0b0011_1111) { + VALUE_BYTE => { + if arg != 0 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_BYTE" + ))) + } else { + let mut buffer = [0u8; 1]; + input.read_exact(&mut buffer).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Byte) from the input" + .into(), + ) + })?; + Ok(Self::Byte(i8::from_be_bytes(buffer))) + } + } + VALUE_SHORT => { + if arg >= 2 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_SHORT" + ))) + } else { + let mut buffer = [0x00u8; 2]; + let size = (arg + 1) as usize; + let first_byte = 2 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Short) from the input" + .into(), + ) + })?; + // Sign extention + if (buffer[first_byte] & 0b1000_0000) != 0 { + for b in buffer.iter_mut().take(first_byte - 1) { + *b = 0xff; + } + } + Ok(Self::Short(i16::from_be_bytes(buffer))) + } + } + VALUE_CHAR => { + if arg >= 2 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_CHAR" + ))) + } else { + let mut buffer = [0x00u8; 2]; + let size = (arg + 1) as usize; + let first_byte = 2 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Char) from the input" + .into(), + ) + })?; + Ok(Self::Char(u16::from_be_bytes(buffer))) + } + } + VALUE_INT => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_INT" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Int) from the input" + .into(), + ) + })?; + // Sign extention + if (buffer[first_byte] & 0b1000_0000) != 0 { + for b in buffer.iter_mut().take(first_byte - 1) { + *b = 0xff; + } + } + Ok(Self::Int(i32::from_be_bytes(buffer))) + } + } + VALUE_LONG => { + if arg >= 8 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 to 7 for VALUE_LONG" + ))) + } else { + let mut buffer = [0x00u8; 8]; + let size = (arg + 1) as usize; + let first_byte = 8 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Long) from the input" + .into(), + ) + })?; + // Sign extention + if (buffer[first_byte] & 0b1000_0000) != 0 { + for b in buffer.iter_mut().take(first_byte - 1) { + *b = 0xff; + } + } + Ok(Self::Long(i64::from_be_bytes(buffer))) + } + } + VALUE_FLOAT => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_FLOAT" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + input.read_exact(&mut buffer[..size]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Float) from the input" + .into(), + ) + })?; + Ok(Self::Float(f32::from_be_bytes(buffer))) + } + } + VALUE_DOUBLE => { + if arg >= 8 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 to 7 for VALUE_DOUBLE" + ))) + } else { + let mut buffer = [0x00u8; 8]; + let size = (arg + 1) as usize; + input.read_exact(&mut buffer[..size]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Double) from the input" + .into(), + ) + })?; + Ok(Self::Double(f64::from_be_bytes(buffer))) + } + } + VALUE_METHOD_TYPE => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD_TYPE" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (MethodType) from the input" + .into(), + ) + })?; + Ok(Self::MethodType(u32::from_be_bytes(buffer))) + } + } + VALUE_METHOD_HANDLE => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD_HANDLE" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (MethodHandle) from the input" + .into(), + ) + })?; + Ok(Self::MethodHandle(u32::from_be_bytes(buffer))) + } + } + VALUE_STRING => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_STRING" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (String) from the input" + .into(), + ) + })?; + Ok(Self::String(u32::from_be_bytes(buffer))) + } + } + VALUE_TYPE => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_TYPE" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Type) from the input" + .into(), + ) + })?; + Ok(Self::Type(u32::from_be_bytes(buffer))) + } + } + VALUE_FIELD => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_FIELD" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Field) from the input" + .into(), + ) + })?; + Ok(Self::Field(u32::from_be_bytes(buffer))) + } + } + VALUE_METHOD => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_METHOD" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Method) from the input" + .into(), + ) + })?; + Ok(Self::Method(u32::from_be_bytes(buffer))) + } + } + VALUE_ENUM => { + if arg >= 4 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0, 1, 2 or 3 for VALUE_ENUM" + ))) + } else { + let mut buffer = [0x00u8; 4]; + let size = (arg + 1) as usize; + let first_byte = 4 - size; + input.read_exact(&mut buffer[first_byte..]).map_err(|_| { + Error::InputTooSmall( + "Failed to read all bytes for the EncodedValue (Enum) from the input" + .into(), + ) + })?; + Ok(Self::Enum(u32::from_be_bytes(buffer))) + } + } + VALUE_ARRAY => { + if arg != 0 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_ARRAY" + ))) + } else { + Ok(Self::Array(EncodedArray::deserialize(input)?)) + } + } + VALUE_ANNOTATION => { + if arg != 0 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_ANNOTATION" + ))) + } else { + Ok(Self::Array(EncodedArray::deserialize(input)?)) + } + } + VALUE_NULL => { + if arg != 0 { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 for VALUE_NULL" + ))) + } else { + Ok(Self::Null) + } + } + VALUE_BOOLEAN => { + if arg == 0 { + Ok(Self::Boolean(false)) + } else if arg == 1 { + Ok(Self::Boolean(true)) + } else { + Err(Error::DeserializationError(format!( + "Unexpected value argument 0x{arg:02x}: expected 0 or 1 for VALUE_BOOLEAN" + ))) + } + } + ValueType(vt) => Err(Error::DeserializationError(format!( + "Unknown Value Type: 0x{vt:02x}" + ))), + } + } + + fn size(&self) -> usize { + match self { + Self::Byte(_) => 2, + Self::Short(val) => 1 + if *val <= 0x7f && *val >= -0x80 { 1 } else { 2 }, + Self::Char(val) => 1 + if *val <= 0xff { 1 } else { 2 }, + Self::Int(val) => { + 1 + if *val <= 0x7f && *val >= -0x80 { + 1 + } else if *val <= 0x7f_ff && *val >= -0x80_00 { + 2 + } else if *val <= 0x7f_ff_ff && *val >= -0x80_00_00 { + 3 + } else { + 4 + } + } + Self::Long(val) => { + 1 + if *val <= 0x7f && *val >= -0x80 { + 1 + } else if *val <= 0x7f_ff && *val >= -0x80_00 { + 2 + } else if *val <= 0x7f_ff_ff && *val >= -0x80_00_00 { + 3 + } else if *val <= 0x7f_ff_ff_ff && *val >= -0x80_00_00_00 { + 4 + } else if *val <= 0x7f_ff_ff_ff_ff && *val >= -0x80_00_00_00_00 { + 5 + } else if *val <= 0x7f_ff_ff_ff_ff_ff && *val >= -0x80_00_00_00_00_00 { + 6 + } else if *val <= 0x7f_ff_ff_ff_ff_ff_ff && *val >= -0x80_00_00_00_00_00 { + 7 + } else { + 8 + } + } + Self::Float(val) => { + let trailing_zeros = val + .to_be_bytes() + .iter() + .rev() + .take_while(|b| **b == 0) + .count(); + 1 + 4 - trailing_zeros + } + Self::Double(val) => { + let trailing_zeros = val + .to_be_bytes() + .iter() + .rev() + .take_while(|b| **b == 0) + .count(); + 1 + 8 - trailing_zeros + } + Self::MethodType(idx) => Idx(*idx, VALUE_TYPE).size(), + Self::MethodHandle(idx) => Idx(*idx, VALUE_METHOD_HANDLE).size(), + Self::String(idx) => Idx(*idx, VALUE_STRING).size(), + Self::Type(idx) => Idx(*idx, VALUE_TYPE).size(), + Self::Field(idx) => Idx(*idx, VALUE_FIELD).size(), + Self::Method(idx) => Idx(*idx, VALUE_METHOD).size(), + Self::Enum(idx) => Idx(*idx, VALUE_ENUM).size(), + Self::Array(arr) => 1 + arr.size(), + Self::Annotation(ann) => 1 + ann.size(), + Self::Null => 1, + Self::Boolean(_) => 1, + } + } +} + +/// Utility type to encode/decode an Idx. +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +struct Idx(u32, ValueType); +impl Serializable for Idx { + fn serialize(&self, output: &mut dyn Write) -> Result<()> { + let Idx(idx, ValueType(vt)) = self; + let size = self.size() - 2; + let bytes: [u8; 4] = idx.to_be_bytes(); + let vec = &bytes[(4 - size + 1)..]; + output + .write_all(&[((size as u8) << 5) | vt]) + .map_err(|err| { + Error::SerializationError(format!( + "Failed to write serialized Idx to output: {err}" + )) + })?; + output.write_all(vec).map_err(|err| { + Error::SerializationError(format!("Failed to write serialized Idx to output: {err}")) + })?; + Ok(()) + } + /// unimplemented, not used because the ValueType must be known before deserializing the idx. + fn deserialize(_input: &mut dyn ReadSeek) -> Result { + unimplemented!() + } + + fn size(&self) -> usize { + let Idx(idx, _) = *self; + 1 + if idx <= 0xff { + 1 + } else if idx <= 0xffff { + 2 + } else if idx <= 0xffffff { + 3 + } else { + 4 + } + } +}