Encapsulate header parsing logic

This commit is contained in:
Timothy Warren 2020-12-01 09:32:18 -05:00
parent 6cb42ec21b
commit 2c96172e9d
4 changed files with 48 additions and 11 deletions

View File

@ -6,6 +6,29 @@ static HEADER_STRING: &[u8] = &[
83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0, 83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0,
]; ];
/// A value stored as a Write Format Verson or
/// Read Format Version
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum FormatVersion {
/// Represents the rollback journal mode
Legacy,
/// Represents the Write Ahead Log mode
WriteAheadLog,
/// Represents any mode not 1 or 2, the value
/// will be provided
Unknown(u8),
}
impl From<u8> for FormatVersion {
fn from(v: u8) -> Self {
match v {
1 => Self::Legacy,
2 => Self::WriteAheadLog,
_ => Self::Unknown(v),
}
}
}
/// This struct will wrap our 32bit number allowing us /// This struct will wrap our 32bit number allowing us
/// to control how it gets used later. /// to control how it gets used later.
#[derive(Debug)] #[derive(Debug)]
@ -39,12 +62,27 @@ impl TryFrom<u16> for PageSize {
} }
} }
pub fn parse_header(bytes: &[u8]) -> Result<(PageSize, FormatVersion, FormatVersion), Error> {
// Check that the first 16 bytes match the header string
validate_magic_string(&bytes)?;
// capture the page size
let page_size = parse_page_size(bytes)?;
// capture the write format version
let write_version = FormatVersion::from(bytes[18]);
// capture the read format version
let read_version = FormatVersion::from(bytes[19]);
Ok((page_size, write_version, read_version))
}
/// Validate that the bytes provided match the special string /// Validate that the bytes provided match the special string
/// at the start of Sqlite3 files /// at the start of Sqlite3 files
pub fn validate_magic_string(bytes: &[u8]) -> Result<(), Error> { pub fn validate_magic_string(bytes: &[u8]) -> Result<(), Error> {
let buf = &bytes[0..16]; let buf = &bytes[0..16];
if buf != HEADER_STRING { if buf != HEADER_STRING {
return Err(Error::HeaderString(String::from_utf8_lossy(buf).to_string())); return Err(Error::HeaderString(
String::from_utf8_lossy(buf).to_string(),
));
} }
Ok(()) Ok(())

View File

@ -1,5 +1,5 @@
use sqlite_parser::{ use sqlite_parser::{
header::{validate_magic_string, parse_page_size}, header::parse_header,
error::Error, error::Error,
}; };
use std::fs::read; use std::fs::read;
@ -7,13 +7,12 @@ use std::fs::read;
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
// first, read in all the bytes of our file // first, read in all the bytes of our file
// using unwrap to just panic if this fails // using unwrap to just panic if this fails
let contents = read("data.sqlite").unwrap(); let contents = read("data.sqlite")
.expect("Failed to read data.sqlite");
validate_magic_string(&contents)?; let (page_size, write_format, read_format) = parse_header(&contents[0..100])?;
let page_size = parse_page_size(&contents)?; println!("page_size {:?}, write_format {:?}, read_format {:?}", page_size, write_format, read_format);
println!("{:?}", page_size);
Ok(()) Ok(())
} }