1#![cfg_attr(docsrs, feature(doc_cfg))]
13#![deny(
14 clippy::all,
15 clippy::correctness,
16 clippy::suspicious,
17 clippy::style,
18 clippy::complexity,
19 clippy::perf
20)]
21
22mod archive;
23pub mod codec;
24pub mod error;
25mod index;
26pub mod parse;
27mod sector;
28pub mod xtea;
29
30#[doc(inline)]
31pub use error::Error;
32use error::Result;
33
34pub const MAIN_DATA: &str = "main_file_cache.dat2";
35pub const REFERENCE_TABLE: &str = "main_file_cache.idx255";
36pub const REFERENCE_TABLE_ID: u8 = 255;
37
38pub use archive::*;
39pub use index::*;
40pub use sector::*;
41
42use crate::codec::{Buffer, Encoded};
43use error::ParseError;
44use memmap2::Mmap;
45use std::fs::File;
46use std::io::Write;
47use std::path::Path;
48
49#[derive(Debug)]
51pub struct Dat2(Mmap);
52
53impl Dat2 {
54 pub fn new<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
56 Ok(Self(unsafe { Mmap::map(&File::open(path.as_ref())?)? }))
57 }
58
59 pub fn read(&self, archive_ref: &ArchiveRef) -> crate::Result<Buffer<Encoded>> {
61 let mut buffer = Buffer::from(Vec::with_capacity(archive_ref.length));
62 self.read_into_writer(archive_ref, &mut buffer)?;
63
64 assert_eq!(buffer.len(), archive_ref.length);
65
66 Ok(buffer)
67 }
68
69 pub fn read_into_writer<W>(&self, archive_ref: &ArchiveRef, writer: &mut W) -> crate::Result<()>
71 where
72 W: Write,
73 {
74 let mut current = archive_ref.sector;
75 let header_size = SectorHeaderSize::from(archive_ref);
76
77 for (chunk, data_len) in archive_ref.data_blocks().enumerate() {
78 let offset = current * SECTOR_SIZE;
79
80 let data_block = &self.0[offset..offset + data_len];
81 match Sector::new(data_block, &header_size) {
82 Ok(sector) => {
83 sector
84 .header
85 .validate(archive_ref.id, chunk, archive_ref.index_id)?;
86 current = sector.header.next;
87 writer.write_all(sector.data_block)?;
88 }
89 Err(_) => return Err(ParseError::Sector(archive_ref.sector).into()),
90 };
91 }
92
93 Ok(())
94 }
95
96 pub fn metadata(&self, archive_ref: &ArchiveRef) -> crate::Result<IndexMetadata> {
97 let buffer = self.read(archive_ref)?.decode()?;
98 IndexMetadata::from_buffer(buffer)
99 }
100}
101
102#[cfg(test)]
103fn is_normal<T: Send + Sync + Sized + Unpin>() {}
104#[test]
105fn normal_types() {
106 is_normal::<Dat2>();
107}