diff --git a/Cargo.toml b/Cargo.toml index 445e5e1..73dfbaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ as GNU Longname. The maximum supported file name length is 100 characters includ The maximum supported file size is 8GiB. Also, directories are not supported yet but only flat collections of files. """ -version = "0.1.1" +version = "0.1.2" edition = "2018" keywords = ["tar", "tarball", "archive"] categories = ["data-structures", "no-std", "parser-implementations"] diff --git a/README.md b/README.md index 82e8f49..0eea2e2 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,15 @@ fn main() { std::env::set_var("RUST_LOG", "trace"); env_logger::init(); - // also works in no_std environment + // also works in no_std environment (except the println!, of course) let archive = include_bytes!("../tests/gnu_tar_default.tar"); let archive = TarArchive::new(archive); + // Vec needs an allocator of course, but the library itself doesn't need one let entries = archive.entries().collect::>(); println!("{:#?}", entries); + println!("content of last file:"); + let last_file_content = unsafe { core::str::from_utf8_unchecked(entries[2].data()) }; + println!("{:#?}", last_file_content); } ``` diff --git a/examples/minimal.rs b/examples/minimal.rs index cda422b..628790b 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -28,9 +28,13 @@ fn main() { std::env::set_var("RUST_LOG", "trace"); env_logger::init(); - // also works in no_std environment + // also works in no_std environment (except the println!, of course) let archive = include_bytes!("../tests/gnu_tar_default.tar"); let archive = TarArchive::new(archive); + // Vec needs an allocator of course, but the library itself doesn't need one let entries = archive.entries().collect::>(); println!("{:#?}", entries); + println!("content of last file:"); + let last_file_content = unsafe { core::str::from_utf8_unchecked(entries[2].data()) }; + println!("{:#?}", last_file_content); } diff --git a/src/archive.rs b/src/archive.rs index 4e13412..2ef864f 100644 --- a/src/archive.rs +++ b/src/archive.rs @@ -162,16 +162,20 @@ impl<'a> Iterator for ArchiveIterator<'a> { } // fetch data of file from next block(s) - let block_count = hdr.payload_block_count(); - let i_begin = self.block_index * BLOCKSIZE; - let i_end = i_begin + block_count * BLOCKSIZE; - debug_assert!(i_end <= self.archive.data.len(), "index ouf of range!"); - // +1: hdr itself + data blocks - self.block_index += block_count + 1; - + let data_block_count = hdr.payload_block_count(); + // +1: skip hdr block itself and start at data! + // i_begin is the byte begin index of this file in the array of the whole archive + let i_begin = (self.block_index + 1) * BLOCKSIZE; + // i_end is the exclusive byte end index of the data of the current file + let i_end = i_begin + data_block_count * BLOCKSIZE; let file_block_bytes = &self.archive.data[i_begin..i_end]; + // because each block is 512 bytes long, the file is not necessarily a multiple of 512 bytes let file_bytes = &file_block_bytes[0..hdr.size.val()]; + // in next iteration: start at next Archive entry header + // +1 for current hdr block itself + all data blocks + self.block_index += data_block_count + 1; + Some(ArchiveEntry::new( ArrayString::from_str(hdr.name.as_string().as_str()).unwrap(), file_bytes, @@ -182,6 +186,7 @@ impl<'a> Iterator for ArchiveIterator<'a> { #[cfg(test)] mod tests { use super::*; + use core::str; use std::vec::Vec; #[test] @@ -230,11 +235,26 @@ mod tests { assert_eq!(entries[0].filename().as_str(), "bye_world_513b.txt"); assert_eq!(entries[0].size(), 513); assert_eq!(entries[0].data().len(), 513); + assert_eq!( + unsafe { str::from_utf8_unchecked(entries[0].data) }, + include_str!("../tests/bye_world_513b.txt") + ); + assert_eq!(entries[1].filename().as_str(), "hello_world_513b.txt"); assert_eq!(entries[1].size(), 513); assert_eq!(entries[1].data().len(), 513); + assert_eq!( + unsafe { str::from_utf8_unchecked(entries[1].data) }, + include_str!("../tests/hello_world_513b.txt") + ); + assert_eq!(entries[2].filename().as_str(), "hello_world.txt"); assert_eq!(entries[2].size(), 12); assert_eq!(entries[2].data().len(), 12); + assert_eq!( + unsafe { str::from_utf8_unchecked(entries[2].data) }, + "Hello World\n", + "file content must match" + ); } } diff --git a/src/lib.rs b/src/lib.rs index cd35e9e..1918543 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,27 @@ SOFTWARE. //! GNU Extensions such as sparse files, incremental archives, and long filename extension are not supported yet. //! [This link](https://www.gnu.org/software/tar/manual/html_section/Formats.html) gives a good overview over possible //! archive formats and their limitations. +//! +//! # Example +//! ```rust +//! use tar_no_std::TarArchive; +//! +//! fn main() { +//! // log: not mandatory +//! std::env::set_var("RUST_LOG", "trace"); +//! env_logger::init(); +//! +//! // also works in no_std environment (except the println!, of course) +//! let archive = include_bytes!("../tests/gnu_tar_default.tar"); +//! let archive = TarArchive::new(archive); +//! // Vec needs an allocator of course, but the library itself doesn't need one +//! let entries = archive.entries().collect::>(); +//! println!("{:#?}", entries); +//! println!("content of last file:"); +//! let last_file_content = unsafe { core::str::from_utf8_unchecked(entries[2].data()) }; +//! println!("{:#?}", last_file_content); +//! } +//! ``` #![cfg_attr(not(test), no_std)] #![deny(rustdoc::all)]