From 96c3d00e30e7d197eab6e02180fe6109d4fb802a Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 17:49:09 +0300 Subject: [PATCH 1/9] Add new public API --- src/lib.rs | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b4bbca7..fdab547 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,10 +12,11 @@ //! //! ```rust,no_run //! use std::fs::read; +//! use std::io::Cursor; //! use ovba::open_project; //! //! let data = read("vbaProject.bin")?; -//! let project = open_project(data)?; +//! let project = open_project(Cursor::new(data))?; //! # Ok::<(), ovba::Error>(()) //! ``` //! @@ -23,10 +24,11 @@ //! //! ```rust,no_run //! use std::fs::{read, write}; +//! use std::io::Cursor; //! use ovba::open_project; //! //! let data = read("vbaProject.bin")?; -//! let project = open_project(data)?; +//! let project = open_project(Cursor::new(data))?; //! //! for module in &project.modules { //! let src_code = project.module_source_raw(&module.name)?; @@ -40,10 +42,11 @@ //! //! ```rust,no_run //! use std::fs::read; +//! use std::io::Cursor; //! use ovba::open_project; //! //! let data = read("vbaProject.bin")?; -//! let project = open_project(data)?; +//! let project = open_project(Cursor::new(data))?; //! for (name, path) in &project.list()? { //! println!(r#"Name: "{}"; Path: "{}""#, name, path); //! } @@ -66,15 +69,16 @@ use parser::cp_to_string; use std::{ cell::RefCell, - io::{Cursor, Read}, + io::{Read, Seek}, path::Path, + rc::Rc, }; /// Represents a VBA project. /// /// This type serves as the entry point into this crate's functionality and exposes the /// public API surface. -pub struct Project { +pub struct Project { /// Specifies version-independent information for the VBA project. pub information: Information, /// Specifies the external references of the VBA project. @@ -84,7 +88,7 @@ pub struct Project { // TODO: Figure out how to make this generic (attempts have failed with // trait bound violations). This would allow [`open_project`] to // accept a wider range of input types. - container: RefCell>>>, + container: Rc>>, } /// Specifies the platform for which the VBA project is created. @@ -222,7 +226,7 @@ pub struct Module { pub private: bool, } -impl Project { +impl Project { /// Returns a stream's decompressed data. /// /// This function reads a stream referenced by `stream_path` and passes the data @@ -323,22 +327,39 @@ impl Project { Ok(buffer) } + + /// Returns the underlying `CompoundFile`. + pub fn as_container(&self) -> Rc>> { + self.container.clone() + } } /// Opens a VBA project. /// /// This function consumes `raw` and returns a [`Project`] struct on success, populated /// with data from the parsed binary input. -pub fn open_project(raw: Vec) -> Result { - let cursor = Cursor::new(raw); - let mut container = CompoundFile::open(cursor).map_err(Error::Cfb)?; - +pub fn open_project(raw: R) -> Result> { + let container = CompoundFile::open(raw).map_err(Error::Cfb)?; + let container = Rc::new(RefCell::new(container)); // Read *dir* stream const DIR_STREAM_PATH: &str = r#"/VBA\dir"#; + open_project_by_path(DIR_STREAM_PATH, container) +} + +/// Opens a VBA project. +/// +/// This function get path to VBA project in container and returns a [`Project`] struct on success +pub fn open_project_by_path, R: Read + Seek>( + root: P, + container: Rc>>, +) -> Result> { + // Read *dir* stream + let path = root.as_ref().join("dir"); let mut buffer = Vec::new(); container - .open_stream(DIR_STREAM_PATH) + .borrow_mut() + .open_stream(path) .map_err(Error::Cfb)? .read_to_end(&mut buffer) .map_err(Error::Cfb)?; @@ -356,7 +377,7 @@ pub fn open_project(raw: Vec) -> Result { information: information.information, references: information.references, modules: information.modules, - container: RefCell::new(container), + container, }) } From 9afd5b6595435eef86efdec5cdd9d459bdace0fc Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 17:59:10 +0300 Subject: [PATCH 2/9] Remove Rc --- src/lib.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fdab547..1b16b19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,6 @@ use std::{ cell::RefCell, io::{Read, Seek}, path::Path, - rc::Rc, }; /// Represents a VBA project. @@ -88,7 +87,7 @@ pub struct Project { // TODO: Figure out how to make this generic (attempts have failed with // trait bound violations). This would allow [`open_project`] to // accept a wider range of input types. - container: Rc>>, + container: RefCell>, } /// Specifies the platform for which the VBA project is created. @@ -327,11 +326,6 @@ impl Project { Ok(buffer) } - - /// Returns the underlying `CompoundFile`. - pub fn as_container(&self) -> Rc>> { - self.container.clone() - } } /// Opens a VBA project. @@ -340,7 +334,6 @@ impl Project { /// with data from the parsed binary input. pub fn open_project(raw: R) -> Result> { let container = CompoundFile::open(raw).map_err(Error::Cfb)?; - let container = Rc::new(RefCell::new(container)); // Read *dir* stream const DIR_STREAM_PATH: &str = r#"/VBA\dir"#; open_project_by_path(DIR_STREAM_PATH, container) @@ -351,14 +344,13 @@ pub fn open_project(raw: R) -> Result> { /// This function get path to VBA project in container and returns a [`Project`] struct on success pub fn open_project_by_path, R: Read + Seek>( root: P, - container: Rc>>, + mut container: CompoundFile, ) -> Result> { // Read *dir* stream let path = root.as_ref().join("dir"); let mut buffer = Vec::new(); container - .borrow_mut() .open_stream(path) .map_err(Error::Cfb)? .read_to_end(&mut buffer) @@ -377,7 +369,7 @@ pub fn open_project_by_path, R: Read + Seek>( information: information.information, references: information.references, modules: information.modules, - container, + container: RefCell::new(container), }) } From 56bab8783fec237d7d0405cc31da59c7b1f7f98f Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 18:06:57 +0300 Subject: [PATCH 3/9] Add root path --- src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1b16b19..d75661a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,7 @@ use std::{ cell::RefCell, io::{Read, Seek}, path::Path, + path::PathBuf, }; /// Represents a VBA project. @@ -78,6 +79,7 @@ use std::{ /// This type serves as the entry point into this crate's functionality and exposes the /// public API surface. pub struct Project { + root_path: PathBuf, /// Specifies version-independent information for the VBA project. pub information: Information, /// Specifies the external references of the VBA project. @@ -301,8 +303,8 @@ impl Project { .find(|&module| module.name == name) .ok_or_else(|| Error::ModuleNotFound(name.to_owned()))?; - let path = format!("/VBA\\{}", &module.stream_name); let offset = module.text_offset; + let path = self.root_path.join(&module.stream_name); let src_code = self.decompress_stream_from(&path, offset)?; Ok(src_code) @@ -334,9 +336,7 @@ impl Project { /// with data from the parsed binary input. pub fn open_project(raw: R) -> Result> { let container = CompoundFile::open(raw).map_err(Error::Cfb)?; - // Read *dir* stream - const DIR_STREAM_PATH: &str = r#"/VBA\dir"#; - open_project_by_path(DIR_STREAM_PATH, container) + open_project_by_path("/", container) } /// Opens a VBA project. @@ -347,7 +347,7 @@ pub fn open_project_by_path, R: Read + Seek>( mut container: CompoundFile, ) -> Result> { // Read *dir* stream - let path = root.as_ref().join("dir"); + let path = root.as_ref().join("VBA").join("dir"); let mut buffer = Vec::new(); container @@ -366,6 +366,7 @@ pub fn open_project_by_path, R: Read + Seek>( debug_assert_eq!(remainder.len(), 0, "Stream not fully consumed"); Ok(Project { + root_path: root.as_ref().to_path_buf(), information: information.information, references: information.references, modules: information.modules, From e124302f2818b51a3231d2cf5cf60668a7f57bb9 Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 18:15:54 +0300 Subject: [PATCH 4/9] Upgrade dependencies --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8c7e0e7..3023333 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ keywords = ["parser", "office", "vba"] categories = ["parser-implementations"] [dependencies] -cfb = "0.3" +cfb = "0.7" codepage = "0.1" encoding_rs = "0.8" nom = "5.1" From a0c85d2656619fdaf43b70c754751d717d11be27 Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 18:33:57 +0300 Subject: [PATCH 5/9] Add method into_inner --- src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d75661a..d8fa7a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -328,6 +328,11 @@ impl Project { Ok(buffer) } + + /// Consumes the `Project`, returning the underlying `CompoundFile`. + pub fn into_inner(self) -> CompoundFile { + self.container.into_inner() + } } /// Opens a VBA project. From f75aa22b5bddc66674718f719bedb34ab59cd368 Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 18:54:10 +0300 Subject: [PATCH 6/9] Add new method --- src/lib.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d8fa7a8..c0fffcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -337,17 +337,29 @@ impl Project { /// Opens a VBA project. /// -/// This function consumes `raw` and returns a [`Project`] struct on success, populated +/// This function consumes `reader` and returns a [`Project`] struct on success, populated /// with data from the parsed binary input. -pub fn open_project(raw: R) -> Result> { - let container = CompoundFile::open(raw).map_err(Error::Cfb)?; - open_project_by_path("/", container) +pub fn open_project(reader: R) -> Result> { + let container = CompoundFile::open(reader).map_err(Error::Cfb)?; + open_project_with_path_container("/", container) +} + +/// Opens a VBA project. +/// +/// This function consumes `path` and `reader` and returns a [`Project`] struct on success, populated +/// with data from the parsed binary input. +pub fn open_project_with_path, R: Read + Seek>( + root: P, + reader: R, +) -> Result> { + let container = CompoundFile::open(reader).map_err(Error::Cfb)?; + open_project_with_path_container(root, container) } /// Opens a VBA project. /// /// This function get path to VBA project in container and returns a [`Project`] struct on success -pub fn open_project_by_path, R: Read + Seek>( +pub fn open_project_with_path_container, R: Read + Seek>( root: P, mut container: CompoundFile, ) -> Result> { From c6cce363f7d7ebc943a3628202507233e7856e07 Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 18:55:22 +0300 Subject: [PATCH 7/9] Change field name --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c0fffcc..b6c226e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,7 +79,7 @@ use std::{ /// This type serves as the entry point into this crate's functionality and exposes the /// public API surface. pub struct Project { - root_path: PathBuf, + root: PathBuf, /// Specifies version-independent information for the VBA project. pub information: Information, /// Specifies the external references of the VBA project. @@ -304,7 +304,7 @@ impl Project { .ok_or_else(|| Error::ModuleNotFound(name.to_owned()))?; let offset = module.text_offset; - let path = self.root_path.join(&module.stream_name); + let path = self.root.join(&module.stream_name); let src_code = self.decompress_stream_from(&path, offset)?; Ok(src_code) @@ -383,7 +383,7 @@ pub fn open_project_with_path_container, R: Read + Seek>( debug_assert_eq!(remainder.len(), 0, "Stream not fully consumed"); Ok(Project { - root_path: root.as_ref().to_path_buf(), + root: root.as_ref().to_path_buf(), information: information.information, references: information.references, modules: information.modules, From 532d34e22e0304d795ba0f6d9bf4e0ac2a441bde Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Wed, 27 Jul 2022 20:38:29 +0300 Subject: [PATCH 8/9] Fix clippy warnings --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index b6c226e..cbb9c79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ #![forbid(unsafe_code)] #![warn(rust_2018_idioms, missing_docs)] +#![allow(dead_code)] mod error; pub use crate::error::{Error, Result}; From 882de05798e445833369a8425abbd3c9b1f3439d Mon Sep 17 00:00:00 2001 From: Ivan Krivosheev Date: Mon, 8 Aug 2022 19:22:56 +0300 Subject: [PATCH 9/9] Upgrade nom --- Cargo.toml | 2 +- src/parser.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3023333..18ca894 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ categories = ["parser-implementations"] cfb = "0.7" codepage = "0.1" encoding_rs = "0.8" -nom = "5.1" +nom = "7.1" diff --git a/src/parser.rs b/src/parser.rs index 7bb5b35..06e8af5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -134,7 +134,7 @@ pub(crate) fn decompress(i: &[u8]) -> IResult<&[u8], Vec, FormatError<&[u8]> // * If all data has been consumed, return an `Ok()` value. nom::combinator::all_consuming(nom::multi::fold_many1( chunk_parser, - Vec::new(), + Vec::new, |mut acc: Vec<_>, data| { acc.extend(data); acc