assembly_pack/common/
mod.rs

1//! # Common elements
2//!
3//! Both PK files and the PKI files are organised as
4
5use std::{
6    borrow::{Borrow, BorrowMut},
7    collections::BTreeMap,
8    fmt,
9    ops::{ControlFlow, Deref, DerefMut},
10};
11
12use serde::{Deserialize, Serialize};
13
14use crate::md5::MD5Sum;
15
16pub mod fs;
17#[cfg(feature = "common-parser")]
18pub mod parser;
19pub mod writer;
20
21/// Node in a CRC tree
22#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
23pub struct CRCTreeNode<D> {
24    /// The [CRC][`crate::crc`] value of this file
25    pub crc: u32,
26    /// Binary tree node to the left
27    pub left: i32,
28    /// Binary tree node to the right
29    pub right: i32,
30    /// The data in this node
31    pub data: D,
32}
33
34impl<D> Borrow<D> for CRCTreeNode<D> {
35    fn borrow(&self) -> &D {
36        &self.data
37    }
38}
39
40impl<D> BorrowMut<D> for CRCTreeNode<D> {
41    fn borrow_mut(&mut self) -> &mut D {
42        &mut self.data
43    }
44}
45
46impl<D> Deref for CRCTreeNode<D> {
47    type Target = D;
48
49    fn deref(&self) -> &Self::Target {
50        &self.data
51    }
52}
53
54impl<D> DerefMut for CRCTreeNode<D> {
55    fn deref_mut(&mut self) -> &mut Self::Target {
56        &mut self.data
57    }
58}
59
60/// Datastructure to hold a CRC tree.
61///
62/// Within the file, the trees are sorted by CRC value and organised in
63/// binary tree. This is not necessarily the same as the Rust B-Tree, but
64/// the ordering is good enough for what we need.
65pub type CRCTree<T> = BTreeMap<u32, T>;
66
67/// A trait to visit a CRC tree from a reader
68pub trait CRCTreeVisitor<T> {
69    /// The type of data to return on a premature break
70    type Break;
71
72    /// Called once for every
73    fn visit(&mut self, crc: u32, data: T) -> ControlFlow<Self::Break>;
74}
75
76/// Simple visitor that collects a CRC tree to an instance of []
77#[derive(Debug, Default, Clone, PartialEq, Eq)]
78pub struct CRCTreeCollector<T> {
79    inner: CRCTree<T>,
80}
81
82impl<T> CRCTreeCollector<T> {
83    /// Create a new collector
84    pub fn new() -> Self {
85        Self {
86            inner: CRCTree::new(),
87        }
88    }
89
90    /// Return the contained map
91    pub fn into_inner(self) -> CRCTree<T> {
92        self.inner
93    }
94}
95
96impl<T> CRCTreeVisitor<T> for CRCTreeCollector<T> {
97    type Break = ();
98
99    fn visit(&mut self, crc: u32, data: T) -> ControlFlow<Self::Break> {
100        self.inner.insert(crc, data);
101        ControlFlow::Continue(())
102    }
103}
104
105/// Metadata for a single file
106#[derive(Debug, Copy, Clone, PartialEq, Eq)]
107pub struct FileMeta {
108    /// Size of the file
109    pub size: u32,
110    /// md5sum of the file
111    pub hash: MD5Sum,
112}
113
114impl fmt::Display for FileMeta {
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        write!(f, "{},{}", self.size, self.hash)
117    }
118}
119
120/// Metadata for a file, raw and compressed
121#[derive(Debug, Copy, Clone, PartialEq, Eq)]
122pub struct FileMetaPair {
123    /// The raw metadata
124    pub raw: FileMeta,
125    /// The compressed metadata
126    pub compressed: FileMeta,
127}
128
129impl FileMetaPair {
130    /// Create a new File-Meta pair
131    pub fn new(raw: FileMeta, compressed: FileMeta) -> Self {
132        Self { raw, compressed }
133    }
134
135    /// Get the (relative) patcher URL for this file
136    pub fn to_path(&self) -> String {
137        let hash = format!("{:?}", self.raw.hash);
138        let mut chars = hash.chars();
139        let c1 = chars.next().unwrap();
140        let c2 = chars.next().unwrap();
141        format!("{}/{}/{}.sd0", c1, c2, hash)
142    }
143}
144
145impl fmt::Display for FileMetaPair {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        write!(f, "{},{}", self.raw, self.compressed)
148    }
149}