use crate::error::Error; use std::convert::{TryFrom, TryInto}; static HEADER_STRING: &[u8] = &[ //S q l i t e ` ` f o r m a t ` ` 3 \u{0} 83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0, ]; /// This struct will wrap our 32bit number allowing us /// to control how it gets used later. #[derive(Debug)] pub struct PageSize(u32); impl TryFrom for PageSize { type Error = Error; fn try_from(v: u16) -> Result { match v { // Special case for the largest page size 1 => Ok(PageSize(65_536u32)), // < 512, != 1 0 | 2..=511 => Err(Error::InvalidPageSize(format!( "value must be >= 512, found: {}", v ))), _ => { if v.is_power_of_two() { Ok(PageSize(v as u32)) } else { Err(Error::InvalidPageSize(format!( "value must be a power of 2, found: {}", v ))) } } } } } /// Validate that the bytes provided match the special string /// at the start of Sqlite3 files pub fn validate_magic_string(bytes: &[u8]) -> Result<(), Error> { let buf = &bytes[0..16]; if buf != HEADER_STRING { return Err(Error::HeaderString(String::from_utf8_lossy(buf).to_string())); } Ok(()) } /// Attempt to generate the appropriate `PageSize` struct pub fn parse_page_size(bytes: &[u8]) -> Result { // Convert into array, and convert error if needed, so that the `?` operator works let page_size_bytes: [u8; 2] = bytes[16..18].try_into().map_err(|_| { Error::InvalidPageSize(format!("expected a 2 byte slice, found: {:?}", bytes)) })?; u16::from_be_bytes(page_size_bytes).try_into() }