# HG changeset patch # User Nathan Goldbaum # Date 1560180310 14400 # Mon Jun 10 11:25:10 2019 -0400 # Node ID 18cff5dfd47d45ed6167c4dd5a51f8e1b2d0e82f # Parent 0585ddebf295fc6ce623086dc4904671b579aaec refactor revlogs into submodules for content, headers, and entries diff --git a/src/revlogs/content.rs b/src/revlogs/content.rs new file mode 100644 --- /dev/null +++ b/src/revlogs/content.rs @@ -0,0 +1,25 @@ +use std::fmt; + +#[derive(Debug)] +pub enum RevlogContent { + Generic(Vec), +} + +impl fmt::Display for RevlogContent { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let printable = match self { + RevlogContent::Generic(s) => match std::str::from_utf8(s) { + Ok(parsed) => parsed.to_string(), + Err(_) => s + .iter() + .map(|c| { + std::ascii::escape_default(*c) + .map(|b| b as char) + .collect::() + }) + .collect::(), + }, + }; + write!(f, "{}", printable) + } +} diff --git a/src/revlogs/entry.rs b/src/revlogs/entry.rs new file mode 100644 --- /dev/null +++ b/src/revlogs/entry.rs @@ -0,0 +1,43 @@ +use flate2::read::ZlibDecoder; +use std::fmt; +use std::fs::File; +use std::io; +use std::io::Read; + +use super::content::RevlogContent; +use super::header::RevlogHeader; + +#[derive(Debug)] +pub struct RevlogEntry { + pub header: RevlogHeader, + pub content: RevlogContent, +} + +impl RevlogEntry { + pub fn new(f: &mut File, header_buffer: &[u8; 64]) -> Result { + let header = RevlogHeader::new(&header_buffer)?; + let mut content_buffer = vec![0u8; header.compressedlength as usize]; + f.read_exact(&mut content_buffer)?; + let decompressed_data = match content_buffer[0] { + 0 => vec![0u8; 0], + 0x75 => content_buffer[1..].to_vec(), + 0x78 => { + let mut gz = ZlibDecoder::new(&content_buffer[..]); + let mut decompressed_data = String::new(); + gz.read_to_string(&mut decompressed_data)?; + decompressed_data.into_bytes() + } + _ => panic!(), + }; + Ok(RevlogEntry { + header: header, + content: RevlogContent::Generic(decompressed_data), + }) + } +} + +impl fmt::Display for RevlogEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "header:\n{}\ncontent: {}\n", self.header, self.content) + } +} diff --git a/src/revlogs/header.rs b/src/revlogs/header.rs new file mode 100644 --- /dev/null +++ b/src/revlogs/header.rs @@ -0,0 +1,66 @@ +use byteorder::{BigEndian, ReadBytesExt}; +use std::fmt; +use std::io; +use std::io::Cursor; +use std::io::Read; + +#[derive(Debug)] +pub struct RevlogHeader { + pub offset: u64, // really 6 bytes but easier to represent as a u64 + pub bitflags: [u8; 2], + pub compressedlength: u32, + pub uncompressedlength: u32, + pub baserev: i32, + pub linkrev: i32, + pub p1rev: i32, + pub p2rev: i32, + pub hash: [u8; 32], +} + +impl RevlogHeader { + pub fn new(buffer: &[u8; 64]) -> Result { + let mut cursor = Cursor::new(buffer as &[u8]); + Ok(RevlogHeader { + offset: cursor.read_u48::()? as u64, + bitflags: cursor.read_u16::()?.to_be_bytes(), + compressedlength: cursor.read_u32::()?, + uncompressedlength: cursor.read_u32::()?, + baserev: cursor.read_i32::()?, + linkrev: cursor.read_i32::()?, + p1rev: cursor.read_i32::()?, + p2rev: cursor.read_i32::()?, + hash: { + let mut res = [0u8; 32]; + cursor.read_exact(&mut res)?; + res + }, + }) + } +} + +impl fmt::Display for RevlogHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let hash: Vec = self.hash.iter().map(|b| format!("{:02x}", b)).collect(); + write!( + f, + "offset: {}\n\ + bitflags: {:?}\n\ + compressed length: {}\n\ + uncompressed length: {}\n\ + base revision: {}\n\ + linked revision: {}\n\ + p1: {}\n\ + p2: {}\n\ + hash: {}\n", + self.offset, + self.bitflags, + self.compressedlength, + self.uncompressedlength, + self.baserev, + self.linkrev, + self.p1rev, + self.p2rev, + hash.join("") + ) + } +} diff --git a/src/revlogs/mod.rs b/src/revlogs/mod.rs --- a/src/revlogs/mod.rs +++ b/src/revlogs/mod.rs @@ -1,131 +1,17 @@ -use byteorder::{BigEndian, ReadBytesExt}; -use flate2::read::ZlibDecoder; use std::fmt; use std::fs::File; use std::io; -use std::io::prelude::*; -use std::io::Cursor; +use std::io::Read; +use std::io::Seek; use std::io::SeekFrom; -#[derive(Debug)] -struct RevlogHeader { - offset: u64, // really 6 bytes but easier to represent as a u64 - bitflags: [u8; 2], - compressedlength: u32, - uncompressedlength: u32, - baserev: i32, - linkrev: i32, - p1rev: i32, - p2rev: i32, - hash: [u8; 32], -} - -impl RevlogHeader { - fn new(buffer: &[u8; 64]) -> Result { - let mut cursor = Cursor::new(buffer as &[u8]); - Ok(RevlogHeader { - offset: cursor.read_u48::()? as u64, - bitflags: cursor.read_u16::()?.to_be_bytes(), - compressedlength: cursor.read_u32::()?, - uncompressedlength: cursor.read_u32::()?, - baserev: cursor.read_i32::()?, - linkrev: cursor.read_i32::()?, - p1rev: cursor.read_i32::()?, - p2rev: cursor.read_i32::()?, - hash: { - let mut res = [0u8; 32]; - cursor.read_exact(&mut res)?; - res - }, - }) - } -} - -#[derive(Debug)] -struct RevlogEntry { - header: RevlogHeader, - content: RevlogContent, -} - -#[derive(Debug)] -enum RevlogContent { - Generic(Vec), -} +pub mod content; +pub mod entry; +pub mod header; -impl RevlogEntry { - fn new(f: &mut File, header_buffer: &[u8; 64]) -> Result { - let header = RevlogHeader::new(&header_buffer)?; - let mut content_buffer = vec![0u8; header.compressedlength as usize]; - f.read_exact(&mut content_buffer)?; - let decompressed_data = match content_buffer[0] { - 0 => vec![0u8; 0], - 0x75 => content_buffer[1..].to_vec(), - 0x78 => { - let mut gz = ZlibDecoder::new(&content_buffer[..]); - let mut decompressed_data = String::new(); - gz.read_to_string(&mut decompressed_data)?; - decompressed_data.into_bytes() - } - _ => panic!(), - }; - Ok(RevlogEntry { - header: header, - content: RevlogContent::Generic(decompressed_data), - }) - } -} - -impl fmt::Display for RevlogHeader { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let hash: Vec = self.hash.iter().map(|b| format!("{:02x}", b)).collect(); - write!( - f, - "offset: {}\n\ - bitflags: {:?}\n\ - compressed length: {}\n\ - uncompressed length: {}\n\ - base revision: {}\n\ - linked revision: {}\n\ - p1: {}\n\ - p2: {}\n\ - hash: {}\n", - self.offset, - self.bitflags, - self.compressedlength, - self.uncompressedlength, - self.baserev, - self.linkrev, - self.p1rev, - self.p2rev, - hash.join("") - ) - } -} - -impl fmt::Display for RevlogEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "header:\n{}\ncontent: {}\n", self.header, self.content) - } -} - -impl fmt::Display for RevlogContent { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let printable = match self { - RevlogContent::Generic(s) => match std::str::from_utf8(s) { - Ok(parsed) => parsed.to_string(), - Err(_) => s - .iter() - .map(|c| { - std::ascii::escape_default(*c) - .map(|b| b as char) - .collect::() - }) - .collect::(), - }, - }; - write!(f, "{}", printable) - } -} +pub use content::RevlogContent; +pub use entry::RevlogEntry; +pub use header::RevlogHeader; #[derive(Debug)] pub struct Revlog {