Skip to content

Commit

Permalink
feat: implement entry data parsing
Browse files Browse the repository at this point in the history
The only thing left to do is to put all the parsing methods together and
implement the `Packfile::new` method.

---------

Co-authored-by: UserIsntAvailable <pinedap.angel@gmail.com>
  • Loading branch information
nenikitov and UserIsntAvailable authored Nov 9, 2023
1 parent a3a5cf9 commit 5f27768
Showing 1 changed file with 92 additions and 12 deletions.
104 changes: 92 additions & 12 deletions lib/src/packfile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
mod nom;

use flate2::read::ZlibDecoder;
#[allow(clippy::wildcard_imports)]
use nom::*;
use std::io::Read;

#[derive(Debug, PartialEq)]
enum EntryKind {}
enum EntryKind {
// TODO(nenikitov): Add more kinds
Unknown,
}

#[derive(Debug, PartialEq)]
struct EntryHeader {
offset: u32,
size: u32,
}

#[derive(Debug, PartialEq)]
pub struct EntryData {
Expand All @@ -20,17 +31,11 @@ pub struct PackFile {
entries: Vec<EntryData>,
}

#[derive(Debug, PartialEq)]
struct EntryHeader {
offset: u32,
size: u32,
}

impl PackFile {
const HEADER: &'static str = "PMAN";
const COPYRIGHT_LENGTH: usize = 56;

pub fn new(bytes: &[u8]) -> Result<Self> {
pub fn new(input: &[u8]) -> Result<Self> {
todo!()
}

Expand All @@ -47,8 +52,8 @@ impl PackFile {
Ok((input, (copyright, total_entries)))
}

fn entries(input: &[u8], total_entries: u32) -> Result<Vec<EntryHeader>> {
fn entry(input: &[u8]) -> Result<EntryHeader> {
fn entry_headers(input: &[u8], total_entries: u32) -> Result<Vec<EntryHeader>> {
fn entry_header(input: &[u8]) -> Result<EntryHeader> {
// TODO(nenikitov): add check for `asset_kind == 0`
let (input, asset_kind) = number::le_u32(input)?;

Expand All @@ -62,7 +67,40 @@ impl PackFile {
Ok((input, EntryHeader { offset, size }))
}

multi::count(entry, total_entries as usize)(input)
multi::count(entry_header, total_entries as usize)(input)
}

#[allow(clippy::unnecessary_wraps)] // TODO(Unavailable): Rewrite using nom
fn entries<'a>(
input: &'a [u8],
entry_headers: &'_ [EntryHeader],
) -> Result<'a, Vec<EntryData>> {
fn entry(input: &[u8], entry_header: &EntryHeader) -> EntryData {
let bytes = &input[entry_header.offset as usize..][..entry_header.size as usize];
let bytes = if let [b'Z', b'L', s1, s2, s3, bytes @ ..] = bytes {
let size = u32::from_le_bytes([*s1, *s2, *s3, 0]);

let mut decoder = ZlibDecoder::new(bytes);
let mut data = Vec::with_capacity(size as usize);
decoder
.read_to_end(&mut data)
.expect("Data should be a valid zlib stream");
// TODO(nenikitov): Check if `data.len() == size`

data
} else {
bytes.to_vec()
};

EntryData {
bytes,
kind: EntryKind::Unknown,
}
}

let entries = entry_headers.iter().map(|h| entry(input, h)).collect();

Ok((&[], entries))
}
}

Expand All @@ -75,6 +113,9 @@ mod tests {

#[test]
fn packfile_header_works() -> eyre::Result<()> {
// TODO(Unavailable): Both other tests have manual written tests, so we
// might as well write this also without the need of a real packfile.dat

let (_, (copyright, file_count)) = PackFile::header(INPUT)?;

assert_eq!(copyright, "Copyright (c) 2004 Torus Games Pty. Ltd.");
Expand All @@ -86,7 +127,7 @@ mod tests {
#[test]
fn packfile_entries_works() -> eyre::Result<()> {
#[rustfmt::skip]
let (_, entries) = PackFile::entries(
let (_, entries) = PackFile::entry_headers(
&[
// File 1
0x00, 0x00, 0x00, 0x00,
Expand Down Expand Up @@ -118,4 +159,43 @@ mod tests {

Ok(())
}

#[test]
fn packfile_entry_data_works() -> eyre::Result<()> {
#[rustfmt::skip]
let (_, entries) = PackFile::entries(
&[
// File 1
b'A', b's', b'h', b'e', b'n',
// File 2
b'Z', b'L', // Asset Zlib signature
0x06, 0x00, 0x00, // Stream size
0x78, 0xDA, // Actual Zlib signature
0x73, 0x2C, 0xCE, 0x48, 0xCD, 0xE3, 0x02, 0x00, 0x07, 0x80, 0x01, 0xFA,
],
&[
EntryHeader { offset: 0, size: 5 },
EntryHeader {
offset: 5,
size: 19,
},
],
)?;

assert_eq!(
entries,
[
EntryData {
bytes: b"Ashen".to_vec(),
kind: EntryKind::Unknown
},
EntryData {
bytes: b"Ashen\n".to_vec(),
kind: EntryKind::Unknown
}
]
);

Ok(())
}
}

0 comments on commit 5f27768

Please sign in to comment.