1use core::mem::MaybeUninit;
2use std::{
3 convert::TryFrom,
4 io::{Error as IOError, IoSliceMut, Read, Result as IOResult},
5};
6
7use crate::{
8 AssetEntryHeadingPair, CompressionMethod, ContentFlags, entry::AssetNameRef,
9 entry_tree::EntryTreePointer,
10};
11use crc::crc32;
12use libflate::deflate as zlib;
13use peridot_native_io::{
14 MemoryMapBlob, PlatformNativeFileReader, PlatformNativeFileReaderAsync, RandomReadBlob,
15 RandomReadBlobAsync,
16};
17use peridot_serialization_utils::{VariableUInt, VariableULong};
18use pin_project::pin_project;
19
20#[non_exhaustive]
21#[derive(Debug)]
22pub enum ArchiveReadError {
23 IO(IOError),
24 IntegrityCheckFailed,
25 SignatureMismatch,
26 Lz4DecompressError(lz4_compression::decompress::Error),
27}
28impl From<IOError> for ArchiveReadError {
29 fn from(e: IOError) -> Self {
30 Self::IO(e)
31 }
32}
33impl From<lz4_compression::decompress::Error> for ArchiveReadError {
34 fn from(e: lz4_compression::decompress::Error) -> Self {
35 Self::Lz4DecompressError(e)
36 }
37}
38pub type ArchiveReadResult<T> = Result<T, ArchiveReadError>;
39impl From<ArchiveReadError> for IOError {
40 fn from(e: ArchiveReadError) -> Self {
41 match e {
42 ArchiveReadError::IO(e) => e,
43 ArchiveReadError::IntegrityCheckFailed => {
44 IOError::other("Archive Integrity check failed")
45 }
46 ArchiveReadError::SignatureMismatch => IOError::other("Archive Signature Mismatch"),
47 ArchiveReadError::Lz4DecompressError(e) => {
48 IOError::other(format!("Lz4DecompressError: {e:?}"))
49 }
50 }
51 }
52}
53
54fn list_entry(
55 head_size: usize,
56 hash_tree_root_exact: bool,
57 hash_tree_block: &[u8],
58 exact_match_block: &[u8],
59 mut callback: impl FnMut(AssetNameRef),
60) {
61 fn enumerate_exact_block_content(
62 block: &[u8],
63 pointer: usize,
64 callback: &mut impl FnMut(AssetNameRef),
65 ) {
66 let (VariableUInt(entry_count), entry_count_len) =
67 VariableUInt::from_bytes_head(&block[pointer..]);
68 let mut read_ptr = pointer + entry_count_len;
69 for _ in 0..entry_count {
70 let (VariableULong(n), name_bytes) = VariableULong::from_bytes_head(&block[read_ptr..]);
71 read_ptr += name_bytes;
72 let name_ext = &block[read_ptr..read_ptr + n as usize];
73 read_ptr += n as usize;
74 let (_, hlen) = AssetEntryHeadingPair::from_bytes_head(&block[read_ptr..]);
75 read_ptr += hlen;
76
77 let name_split = name_ext
78 .iter()
79 .position(|&x| x == 0)
80 .unwrap_or(name_ext.len());
81 let n = AssetNameRef {
82 name: unsafe { core::str::from_utf8_unchecked(&name_ext[..name_split]) },
83 ext: if name_split >= name_ext.len() - 1 {
84 ""
86 } else {
87 unsafe { core::str::from_utf8_unchecked(&name_ext[name_split + 1..]) }
88 },
89 };
90
91 callback(n);
92 }
93 }
94
95 fn enumerate_exact_tree<'b>(
96 block_view: &(impl crate::entry_tree::ExactBlockViewOps<'b> + ?Sized),
97 exact_match_block: &[u8],
98 callback: &mut impl FnMut(AssetNameRef),
99 ) {
100 for ptr in 0..block_view.entry_count() {
101 enumerate_exact_block_content(
102 exact_match_block,
103 block_view.entry(ptr).exact_block_offset() as _,
104 callback,
105 );
106 }
107 }
108
109 fn enumerate_tree(
110 block_view: &crate::entry_tree::BlockView,
111 hash_tree_block: &[u8],
112 exact_match_block: &[u8],
113 callback: &mut impl FnMut(AssetNameRef),
114 ) {
115 for ptr in 0..block_view.entry_count() {
116 let e = block_view.entry(ptr);
117 enumerate_subtree(
118 hash_tree_block,
119 exact_match_block,
120 callback,
121 e.smaller_tree_pointer(),
122 );
123 enumerate_exact_block_content(exact_match_block, e.exact_block_offset() as _, callback);
124 }
125
126 enumerate_subtree(
127 hash_tree_block,
128 exact_match_block,
129 callback,
130 block_view.larger_tree_pointer(),
131 );
132 }
133
134 fn enumerate_subtree(
135 hash_tree_block: &[u8],
136 exact_match_block: &[u8],
137 callback: &mut impl FnMut(AssetNameRef),
138 tree_pointer: EntryTreePointer,
139 ) {
140 if tree_pointer.is_exact_tree() {
141 enumerate_exact_tree(
143 &crate::entry_tree::ExactBlockView(
144 &hash_tree_block[tree_pointer.pointer_value() as usize..],
145 ),
146 exact_match_block,
147 callback,
148 );
149
150 return;
151 }
152
153 enumerate_tree(
155 &crate::entry_tree::BlockView::from_offset_and_element_count(
156 hash_tree_block,
157 tree_pointer.pointer_value() as _,
158 crate::entry_tree::MAX_ENTRY_COUNT,
159 ),
160 hash_tree_block,
161 exact_match_block,
162 callback,
163 );
164 }
165
166 if hash_tree_root_exact {
167 enumerate_exact_tree(
169 &crate::entry_tree::ExactRootBlockView(hash_tree_block),
170 exact_match_block,
171 &mut callback,
172 );
173
174 return;
175 }
176
177 enumerate_tree(
178 &crate::entry_tree::BlockView(
179 &hash_tree_block[..crate::entry_tree::trim_normal_tree_block_size(
180 crate::entry_tree::first_hash_tree_block_size(head_size),
181 )],
182 ),
183 hash_tree_block,
184 exact_match_block,
185 &mut callback,
186 );
187}
188
189fn find_entry(
190 head_size: usize,
191 name: &str,
192 ext: &str,
193 hash_tree_root_exact: bool,
194 hash_tree_block: &[u8],
195 exact_match_block: &[u8],
196) -> Option<AssetEntryHeadingPair> {
197 let name = AssetNameRef { name, ext };
198 let name_hash = name.hash();
199
200 fn find_exact<'b>(
201 block_view: &(impl crate::entry_tree::ExactBlockViewOps<'b> + ?Sized),
202 target: u64,
203 ) -> Option<u64> {
204 let (mut top, mut bottom) = (0, block_view.entry_count());
205 loop {
206 let ptr = (top + bottom) / 2;
207 let e = block_view.entry(ptr);
208
209 match target.cmp(&e.name_hash()) {
210 core::cmp::Ordering::Equal => return Some(e.exact_block_offset()),
212 core::cmp::Ordering::Less => {
213 bottom = ptr;
215 }
216 core::cmp::Ordering::Greater => {
217 top = ptr + 1;
218 }
219 }
220
221 if bottom <= top {
222 return None;
223 }
224 }
225 }
226
227 fn find(
228 block_view: &crate::entry_tree::BlockView,
229 target: u64,
230 ) -> Result<u64, EntryTreePointer> {
231 let e = block_view.largest_entry();
233 match target.cmp(&e.name_hash()) {
234 core::cmp::Ordering::Equal => return Ok(e.exact_block_offset()),
236 core::cmp::Ordering::Greater => return Err(block_view.larger_tree_pointer()),
238 core::cmp::Ordering::Less => (),
239 }
240
241 let e = block_view.smallest_entry();
242 match target.cmp(&e.name_hash()) {
243 core::cmp::Ordering::Equal => return Ok(e.exact_block_offset()),
245 core::cmp::Ordering::Less => return Err(e.smaller_tree_pointer()),
247 core::cmp::Ordering::Greater => (),
248 }
249
250 let (mut top, mut bottom) = (0, block_view.entry_count());
252 loop {
253 let ptr = (top + bottom) / 2;
254 let e = block_view.entry(ptr);
255
256 match target.cmp(&e.name_hash()) {
257 core::cmp::Ordering::Equal => return Ok(e.exact_block_offset()),
259 core::cmp::Ordering::Less => {
260 bottom = ptr;
262 }
263 core::cmp::Ordering::Greater => {
264 top = ptr + 1;
265 }
266 }
267
268 if bottom <= top {
269 return Err(e.smaller_tree_pointer());
271 }
272 }
273 }
274
275 let exact_block_offset = 'hash_tree_finder: {
276 if hash_tree_root_exact {
277 break 'hash_tree_finder find_exact(
279 &crate::entry_tree::ExactRootBlockView(hash_tree_block),
280 name_hash,
281 );
282 }
283
284 fn find_subtree(
285 name_hash: u64,
286 hash_tree_block: &[u8],
287 tree_pointer: EntryTreePointer,
288 ) -> Option<u64> {
289 if tree_pointer.is_exact_tree() {
290 return find_exact(
292 &crate::entry_tree::ExactBlockView(
293 &hash_tree_block[tree_pointer.pointer_value() as usize..],
294 ),
295 name_hash,
296 );
297 }
298
299 let block_view = crate::entry_tree::BlockView::from_offset_and_element_count(
301 hash_tree_block,
302 tree_pointer.pointer_value() as _,
303 crate::entry_tree::MAX_ENTRY_COUNT,
304 );
305
306 match find(&block_view, name_hash) {
307 Ok(x) => Some(x),
308 Err(p) => find_subtree(name_hash, hash_tree_block, p),
309 }
310 }
311
312 let block_view = crate::entry_tree::BlockView(
313 &hash_tree_block[..crate::entry_tree::trim_normal_tree_block_size(
314 crate::entry_tree::first_hash_tree_block_size(head_size),
315 )],
316 );
317
318 match find(&block_view, name_hash) {
319 Ok(x) => Some(x),
320 Err(p) => find_subtree(name_hash, hash_tree_block, p),
321 }
322 }?;
323
324 let (VariableUInt(exact_entry_count), exact_entry_offset) =
326 VariableUInt::from_bytes_head(&exact_match_block[exact_block_offset as usize..]);
327 let mut read_ptr = exact_block_offset as usize + exact_entry_offset;
328 for _ in 0..exact_entry_count {
329 let (VariableULong(n), name_bytes) =
330 VariableULong::from_bytes_head(&exact_match_block[read_ptr..]);
331 read_ptr += name_bytes;
332 let name_ext = &exact_match_block[read_ptr..read_ptr + n as usize];
333 read_ptr += n as usize;
334 let (h, hlen) = AssetEntryHeadingPair::from_bytes_head(&exact_match_block[read_ptr..]);
335 read_ptr += hlen;
336
337 let name_split = name_ext
338 .iter()
339 .position(|&x| x == 0)
340 .unwrap_or(name_ext.len());
341 let n = AssetNameRef {
342 name: unsafe { core::str::from_utf8_unchecked(&name_ext[..name_split]) },
343 ext: if name_split >= name_ext.len() - 1 {
344 ""
346 } else {
347 unsafe { core::str::from_utf8_unchecked(&name_ext[name_split + 1..]) }
348 },
349 };
350
351 if n == name {
352 return Some(h);
354 }
355 }
356
357 None
359}
360
361pub struct OnMemoryArchiveBinReadFuture<'a, 'b, 'aa> {
362 reader: &'a OnMemoryArchiveBinReader<'aa>,
363 pos: u64,
364 buf: &'b mut [MaybeUninit<u8>],
365}
366impl<'a, 'b, 'aa> Future for OnMemoryArchiveBinReadFuture<'a, 'b, 'aa> {
367 type Output = std::io::Result<usize>;
368
369 #[inline(always)]
370 fn poll(
371 self: std::pin::Pin<&mut Self>,
372 _cx: &mut std::task::Context<'_>,
373 ) -> std::task::Poll<Self::Output> {
374 let this = self.get_mut();
375
376 std::task::Poll::Ready(this.reader.read_at(this.pos, this.buf))
377 }
378}
379
380pub struct OnMemoryArchiveBinReadVecFuture<'a, 'b, 'aa, 'bb> {
381 reader: &'a OnMemoryArchiveBinReader<'aa>,
382 pos: u64,
383 buf: &'b mut [IoSliceMut<'bb>],
384}
385impl<'a, 'b, 'aa, 'bb> Future for OnMemoryArchiveBinReadVecFuture<'a, 'b, 'aa, 'bb> {
386 type Output = std::io::Result<usize>;
387
388 #[inline(always)]
389 fn poll(
390 self: std::pin::Pin<&mut Self>,
391 _cx: &mut std::task::Context<'_>,
392 ) -> std::task::Poll<Self::Output> {
393 let this = self.get_mut();
394
395 std::task::Poll::Ready(this.reader.readv_at(this.pos, this.buf))
396 }
397}
398
399pub struct OnMemoryArchiveBinReader<'a> {
400 pub archive: &'a OnMemoryArchive,
401 pub pointer_base: u64,
402 pub pointer: u64,
403 pub pointer_limit: u64,
404}
405impl OnMemoryArchiveBinReader<'_> {
406 fn read_at(&self, pos: u64, buf: &mut [MaybeUninit<u8>]) -> std::io::Result<usize> {
407 let pos_abs = self
408 .pointer_base
409 .checked_add(pos)
410 .ok_or(std::io::ErrorKind::InvalidInput)?;
411 let left_available = self
412 .pointer_limit
413 .checked_sub(pos_abs)
414 .and_then(|x| usize::try_from(x).ok())
415 .ok_or(std::io::ErrorKind::InvalidInput)?;
416 let archive_buf_offset =
417 usize::try_from(pos_abs).map_err(|_| std::io::ErrorKind::InvalidInput)?;
418
419 let read_len = buf.len().min(left_available);
420 if read_len > 0 {
421 unsafe {
422 core::ptr::copy_nonoverlapping(
423 self.archive.block.as_ptr().add(archive_buf_offset),
424 buf.as_mut_ptr().cast::<u8>(),
425 read_len,
426 );
427 }
428 }
429
430 Ok(read_len)
431 }
432
433 fn readv_at(&self, pos: u64, buf: &mut [IoSliceMut]) -> std::io::Result<usize> {
434 let pos_abs = self
435 .pointer_base
436 .checked_add(pos)
437 .ok_or(std::io::ErrorKind::InvalidInput)?;
438 let archive_buf_offset =
439 usize::try_from(pos_abs).map_err(|_| std::io::ErrorKind::InvalidInput)?;
440
441 std::io::Cursor::new(&self.archive.block[archive_buf_offset..]).read_vectored(buf)
442 }
443}
444impl std::io::Read for OnMemoryArchiveBinReader<'_> {
445 fn read(&mut self, buf: &mut [u8]) -> IOResult<usize> {
446 let read_len = buf.len().min((self.pointer_limit - self.pointer) as usize);
447 buf[..read_len].copy_from_slice(
448 &self.archive.block[self.pointer as usize..self.pointer as usize + read_len],
449 );
450 self.pointer += read_len as u64;
451
452 Ok(read_len)
453 }
454}
455impl std::io::Seek for OnMemoryArchiveBinReader<'_> {
456 fn seek(&mut self, pos: std::io::SeekFrom) -> IOResult<u64> {
457 self.pointer = match pos {
458 std::io::SeekFrom::Current(x) => (self.pointer as i64 + x) as _,
459 std::io::SeekFrom::Start(x) => self.pointer_base + x,
460 std::io::SeekFrom::End(x) => (self.pointer_limit as i64 + x) as _,
461 };
462
463 Ok(self.pointer - self.pointer_base)
464 }
465}
466#[cfg(feature = "async-rt-async-std")]
467impl async_std::io::Read for OnMemoryArchiveBinReader<'_> {
468 fn poll_read(
469 self: std::pin::Pin<&mut Self>,
470 _cx: &mut std::task::Context<'_>,
471 buf: &mut [u8],
472 ) -> std::task::Poll<IOResult<usize>> {
473 let read_len = buf.len().min((self.pointer_limit - self.pointer) as usize);
474 buf[..read_len].copy_from_slice(
475 &self.archive.block[self.pointer as usize..self.pointer as usize + read_len],
476 );
477 self.get_mut().pointer += read_len as u64;
478
479 std::task::Poll::Ready(Ok(read_len))
480 }
481}
482
483pub struct OnMemoryArchive {
484 pub head_size: usize,
485 pub block: Vec<u8>,
486 pub content_flags: ContentFlags,
487 pub hash_tree_block_range: core::ops::Range<usize>,
488 pub exact_match_block_range: core::ops::Range<usize>,
489 pub content_baseptr: usize,
490}
491impl OnMemoryArchive {
492 fn new(compression: CompressionMethod, body: Vec<u8>) -> ArchiveReadResult<Self> {
493 let (body, head_size) = match compression {
494 CompressionMethod::Lz4(_) => (lz4_compression::prelude::decompress(&body)?, 4 + 8 + 4),
495 CompressionMethod::Zlib(ub) => {
496 let mut sink = Vec::with_capacity(ub as _);
497 zlib::Decoder::new(std::io::Cursor::new(body)).read_to_end(&mut sink)?;
498 (sink, 4 + 8 + 4)
499 }
500 CompressionMethod::Zstd11(ub) => {
501 let mut sink = Vec::with_capacity(ub as _);
502 zstd::Decoder::new(std::io::Cursor::new(body))?.read_to_end(&mut sink)?;
503 (sink, 4 + 8 + 4)
504 }
505 CompressionMethod::None => (body, 4 + 4),
506 };
507
508 let content_flags = ContentFlags::from_bits_retain(body[0]);
509 let hash_tree_block_len =
510 (u32::from_le_bytes(unsafe { TryFrom::try_from(&body[1..5]).unwrap_unchecked() })
511 as u64)
512 << 3;
513 let exact_match_block_len =
514 u64::from_le_bytes(unsafe { TryFrom::try_from(&body[5..13]).unwrap_unchecked() });
515
516 Ok(Self {
517 head_size,
518 block: body,
519 content_flags,
520 hash_tree_block_range: 13..(13 + hash_tree_block_len) as usize,
521 exact_match_block_range: (13 + hash_tree_block_len) as usize
522 ..(13 + hash_tree_block_len + exact_match_block_len) as usize,
523 content_baseptr: (13 + hash_tree_block_len + exact_match_block_len) as usize,
524 })
525 }
526
527 fn list_entry(&self, callback: impl FnMut(AssetNameRef)) {
528 list_entry(
529 self.head_size,
530 self.content_flags
531 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
532 &self.block[self.hash_tree_block_range.clone()],
533 &self.block[self.exact_match_block_range.clone()],
534 callback,
535 )
536 }
537
538 fn find_entry(&self, name: &str, ext: &str) -> Option<AssetEntryHeadingPair> {
539 find_entry(
540 self.head_size,
541 name,
542 ext,
543 self.content_flags
544 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
545 &self.block[self.hash_tree_block_range.clone()],
546 &self.block[self.exact_match_block_range.clone()],
547 )
548 }
549
550 fn read_bin<'a>(&'a self, heading: AssetEntryHeadingPair) -> OnMemoryArchiveBinReader<'a> {
551 OnMemoryArchiveBinReader {
552 archive: self,
553 pointer_base: self.content_baseptr as u64 + heading.relative_offset,
554 pointer: self.content_baseptr as u64 + heading.relative_offset,
555 pointer_limit: self.content_baseptr as u64
556 + heading.relative_offset
557 + heading.byte_length,
558 }
559 }
560}
561
562pub struct FileStreamingArchiveBinReader<'a, R: RandomReadBlob + MemoryMapBlob> {
563 archive: &'a FileStreamingArchive<R>,
564 pointer_base: u64,
565 pointer: u64,
566 pointer_limit: u64,
567}
568impl<R: RandomReadBlob + MemoryMapBlob> FileStreamingArchiveBinReader<'_, R> {
569 fn read_at(&self, pos: u64, buf: &mut [MaybeUninit<u8>]) -> std::io::Result<usize> {
570 let pos_abs = self
571 .pointer_base
572 .checked_add(pos)
573 .ok_or(std::io::ErrorKind::InvalidInput)?
574 .min(self.pointer_limit);
575 let max_readable = usize::try_from(self.pointer_limit - pos_abs)
576 .unwrap_or(buf.len())
577 .min(buf.len());
578
579 self.archive.handle.read(pos_abs, &mut buf[..max_readable])
580 }
581
582 fn readv_at(&self, pos: u64, mut buf: &mut [IoSliceMut]) -> std::io::Result<usize> {
583 let pos_abs = self
584 .pointer_base
585 .checked_add(pos)
586 .ok_or(std::io::ErrorKind::InvalidInput)?
587 .min(self.pointer_limit);
588
589 if let Some(mut max_readable) = usize::try_from(self.pointer_limit - pos_abs).ok() {
590 let mut avail_count = 0;
592 while avail_count < buf.len() && max_readable > 0 {
593 if let Some(rem) = max_readable.checked_sub(buf[avail_count].len()) {
594 max_readable = rem;
596 avail_count += 1;
597 continue;
598 }
599
600 buf[avail_count] = IoSliceMut::new(unsafe {
602 core::slice::from_raw_parts_mut(buf[avail_count].as_mut_ptr(), max_readable)
603 });
604 avail_count += 1;
605 break;
606 }
607 buf = &mut buf[..avail_count];
608 }
609
610 self.archive.handle.readv(pos_abs, buf)
611 }
612}
613impl<R: RandomReadBlob + MemoryMapBlob> std::io::Read for FileStreamingArchiveBinReader<'_, R> {
614 #[inline]
615 fn read(&mut self, buf: &mut [u8]) -> IOResult<usize> {
616 let read_len = (buf.len() as u64).min(self.pointer_limit - self.pointer);
617 let r = self.archive.handle.read(self.pointer, unsafe {
618 core::mem::transmute::<&mut [u8], &mut [MaybeUninit<u8>]>(&mut buf[..read_len as _])
619 })?;
620 self.pointer += r as u64;
621
622 Ok(r as _)
623 }
624}
625impl<R: RandomReadBlob + MemoryMapBlob> std::io::Seek for FileStreamingArchiveBinReader<'_, R> {
626 #[inline]
627 fn seek(&mut self, pos: std::io::SeekFrom) -> IOResult<u64> {
628 self.pointer = match pos {
629 std::io::SeekFrom::Current(x) => (self.pointer as i64 + x) as _,
630 std::io::SeekFrom::Start(x) => self.pointer_base + x,
631 std::io::SeekFrom::End(x) => (self.pointer_limit as i64 + x) as _,
632 };
633
634 Ok(self.pointer - self.pointer_base)
635 }
636}
637
638#[pin_project(project = FileStreamingArchiveBinReadFutureStateP)]
639enum FileStreamingArchiveBinReadFutureState<F> {
640 Idle,
641 Pending(#[pin] F),
642}
643
644#[pin_project]
645pub struct FileStreamingArchiveBinReadFuture<
646 'a,
647 'aa,
648 'b,
649 R: RandomReadBlobAsync + MemoryMapBlob + 'aa,
650> {
651 reader: &'a FileStreamingArchiveBinReaderAsync<'aa, R>,
652 pos: u64,
653 buf: &'b mut [MaybeUninit<u8>],
654 #[pin]
655 state: FileStreamingArchiveBinReadFutureState<R::ReadFuture<'aa, 'b>>,
656}
657impl<'a, 'aa, 'b, R: RandomReadBlobAsync + MemoryMapBlob> Future
658 for FileStreamingArchiveBinReadFuture<'a, 'aa, 'b, R>
659{
660 type Output = std::io::Result<usize>;
661
662 fn poll(
663 self: std::pin::Pin<&mut Self>,
664 cx: &mut std::task::Context<'_>,
665 ) -> std::task::Poll<Self::Output> {
666 let mut this = self.project();
667
668 loop {
669 match this.state.as_mut().project() {
670 FileStreamingArchiveBinReadFutureStateP::Idle => {
671 let pos_abs = this
672 .reader
673 .pointer_base
674 .checked_add(*this.pos)
675 .ok_or(std::io::ErrorKind::InvalidInput)?
676 .min(this.reader.pointer_limit);
677 let max_readable = usize::try_from(this.reader.pointer_limit - pos_abs)
678 .unwrap_or(this.buf.len())
679 .min(this.buf.len());
680 println!("read async {pos_abs} {max_readable}");
681
682 this.state
683 .set(FileStreamingArchiveBinReadFutureState::Pending(
684 this.reader.archive.handle.read_async(pos_abs, unsafe {
685 core::mem::transmute(&mut this.buf[..max_readable])
686 }),
687 ));
688 }
689 FileStreamingArchiveBinReadFutureStateP::Pending(f) => {
690 let r = core::task::ready!(f.poll(cx));
691 this.state.set(FileStreamingArchiveBinReadFutureState::Idle);
692 return core::task::Poll::Ready(r);
693 }
694 }
695 }
696 }
697}
698
699#[pin_project]
700pub struct FileStreamingArchiveBinReadVecFuture<
701 'a,
702 'aa,
703 'b,
704 'bb,
705 R: RandomReadBlobAsync + MemoryMapBlob + 'aa,
706> where
707 'bb: 'b,
708{
709 reader: &'a FileStreamingArchiveBinReaderAsync<'aa, R>,
710 pos: u64,
711 buf: &'b mut [IoSliceMut<'bb>],
712 #[pin]
713 state: FileStreamingArchiveBinReadFutureState<R::ReadVecFuture<'aa, 'b, 'bb>>,
714}
715impl<'a, 'aa, 'b, 'bb, R: RandomReadBlobAsync + MemoryMapBlob> Future
716 for FileStreamingArchiveBinReadVecFuture<'a, 'aa, 'b, 'bb, R>
717where
718 'bb: 'b,
719{
720 type Output = std::io::Result<usize>;
721
722 fn poll(
723 self: std::pin::Pin<&mut Self>,
724 cx: &mut std::task::Context<'_>,
725 ) -> std::task::Poll<Self::Output> {
726 let mut this = self.project();
727
728 loop {
729 match this.state.as_mut().project() {
730 FileStreamingArchiveBinReadFutureStateP::Idle => {
731 let pos_abs = this
732 .reader
733 .pointer_base
734 .checked_add(*this.pos)
735 .ok_or(std::io::ErrorKind::InvalidInput)?
736 .min(this.reader.pointer_limit);
737
738 let mut buf = &mut this.buf[..];
739 if let Some(mut max_readable) =
740 usize::try_from(this.reader.pointer_limit - pos_abs).ok()
741 {
742 let mut avail_count = 0;
744 while avail_count < buf.len() && max_readable > 0 {
745 if let Some(rem) = max_readable.checked_sub(buf[avail_count].len()) {
746 max_readable = rem;
748 avail_count += 1;
749 continue;
750 }
751
752 buf[avail_count] = IoSliceMut::new(unsafe {
754 core::slice::from_raw_parts_mut(
755 buf[avail_count].as_mut_ptr(),
756 max_readable,
757 )
758 });
759 avail_count += 1;
760 break;
761 }
762 buf = &mut buf[..avail_count];
763 }
764
765 this.state
766 .set(FileStreamingArchiveBinReadFutureState::Pending(
767 this.reader
768 .archive
769 .handle
770 .readv_async(pos_abs, unsafe { core::mem::transmute(buf) }),
771 ));
772 }
773 FileStreamingArchiveBinReadFutureStateP::Pending(f) => {
774 let r = core::task::ready!(f.poll(cx));
775 this.state.set(FileStreamingArchiveBinReadFutureState::Idle);
776 return core::task::Poll::Ready(r);
777 }
778 }
779 }
780 }
781}
782
783pub struct FileStreamingArchiveBinReaderAsync<'a, R: RandomReadBlobAsync + MemoryMapBlob> {
784 archive: &'a FileStreamingArchiveAsync<R>,
785 pointer_base: u64,
786 pointer: u64,
787 pointer_limit: u64,
788}
789impl<'a, R: RandomReadBlobAsync + MemoryMapBlob> FileStreamingArchiveBinReaderAsync<'a, R> {
790 pub async fn read<'b>(&mut self, buf: &'b mut [u8]) -> IOResult<usize> {
791 let read_len = (buf.len() as u64).min(self.pointer_limit - self.pointer);
792 let bytes = self
793 .archive
794 .handle
795 .read_async(self.pointer, unsafe {
796 core::mem::transmute::<&mut [u8], &mut [MaybeUninit<u8>]>(
797 &mut buf[..read_len as usize],
798 )
799 })
800 .await?;
801 self.pointer += bytes as u64;
802
803 Ok(bytes)
804 }
805
806 pub async fn read_exact(&mut self, mut buf: &mut [u8]) -> IOResult<()> {
807 while !buf.is_empty() {
808 let r = self.read(buf).await?;
809 buf = &mut buf[r..];
810 }
811
812 Ok(())
813 }
814
815 pub async fn read_all(&mut self) -> IOResult<Vec<u8>> {
816 let mut b = vec![0u8; (self.pointer_limit - self.pointer) as usize];
817 self.read_exact(&mut b).await?;
818
819 Ok(b)
820 }
821
822 #[inline]
823 pub async fn seek(&mut self, pos: std::io::SeekFrom) -> IOResult<u64> {
824 self.pointer = match pos {
825 std::io::SeekFrom::Current(x) => (self.pointer as i64 + x) as _,
826 std::io::SeekFrom::Start(x) => self.pointer_base + x,
827 std::io::SeekFrom::End(x) => (self.pointer_limit as i64 + x) as _,
828 };
829
830 Ok(self.pointer - self.pointer_base)
831 }
832}
833
834pub struct FileStreamingArchiveAsync<R: RandomReadBlobAsync + MemoryMapBlob> {
835 pub handle: R,
836 pub entry_mapped_head: core::sync::atomic::AtomicPtr<core::ffi::c_void>,
837 pub entry_unmap_data: Option<R::MemoryUnmapData>,
838 pub content_flags: ContentFlags,
839 pub hash_tree_block_range: core::ops::Range<usize>,
840 pub exact_match_block_range: core::ops::Range<usize>,
841 pub content_baseptr: u64,
842}
843impl<R: RandomReadBlobAsync + MemoryMapBlob> FileStreamingArchiveAsync<R> {
844 async fn new(handle: R, body_start: u64) -> IOResult<Self> {
845 let mut content_flags_buf = [0u8];
846 let mut hash_tree_block_len_buf = [0u8; 4];
847 let mut exact_match_block_len_buf = [0u8; 8];
848
849 let mut ro = body_start;
850 handle
851 .readv_all_async(
852 ro,
853 &mut [
854 IoSliceMut::new(&mut content_flags_buf),
855 IoSliceMut::new(&mut hash_tree_block_len_buf),
856 IoSliceMut::new(&mut exact_match_block_len_buf),
857 ],
858 )
859 .await?;
860 ro += 1 + 4 + 8;
861
862 let content_flags = ContentFlags::from_bits_retain(content_flags_buf[0]);
863 let hash_tree_block_len = (u32::from_le_bytes(hash_tree_block_len_buf) as u64) << 3;
864 let exact_match_block_len = u64::from_le_bytes(exact_match_block_len_buf);
865
866 let entry_block_start_pos = ro;
867 let (entry_mapped_head, entry_unmap_data) = handle.mmap(
868 entry_block_start_pos,
869 (hash_tree_block_len + exact_match_block_len)
870 .try_into()
871 .expect("catalog block size is too large"),
872 )?;
873
874 Ok(Self {
875 handle,
876 entry_mapped_head: core::sync::atomic::AtomicPtr::new(entry_mapped_head),
877 entry_unmap_data: Some(entry_unmap_data),
878 content_flags,
879 hash_tree_block_range: 0..hash_tree_block_len as usize,
880 exact_match_block_range: hash_tree_block_len as usize
881 ..(hash_tree_block_len + exact_match_block_len) as usize,
882 content_baseptr: entry_block_start_pos + hash_tree_block_len + exact_match_block_len,
883 })
884 }
885
886 fn list_entry(&self, callback: impl FnMut(AssetNameRef)) {
887 let entry_ptr = self
888 .entry_mapped_head
889 .load(core::sync::atomic::Ordering::Acquire);
890
891 list_entry(
892 4 + 4,
894 self.content_flags
895 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
896 unsafe {
897 core::slice::from_raw_parts(
898 entry_ptr.byte_add(self.hash_tree_block_range.start) as *const u8,
899 self.hash_tree_block_range.len(),
900 )
901 },
902 unsafe {
903 core::slice::from_raw_parts(
904 entry_ptr.byte_add(self.exact_match_block_range.start) as *const u8,
905 self.exact_match_block_range.len(),
906 )
907 },
908 callback,
909 )
910 }
911
912 fn find_entry(&self, name: &str, ext: &str) -> Option<AssetEntryHeadingPair> {
913 let entry_ptr = self
914 .entry_mapped_head
915 .load(core::sync::atomic::Ordering::Acquire);
916
917 find_entry(
918 4 + 4,
920 name,
921 ext,
922 self.content_flags
923 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
924 unsafe {
925 core::slice::from_raw_parts(
926 entry_ptr.byte_add(self.hash_tree_block_range.start) as *const u8,
927 self.hash_tree_block_range.len(),
928 )
929 },
930 unsafe {
931 core::slice::from_raw_parts(
932 entry_ptr.byte_add(self.exact_match_block_range.start) as *const u8,
933 self.exact_match_block_range.len(),
934 )
935 },
936 )
937 }
938
939 fn read_bin<'a>(
940 &'a self,
941 heading: AssetEntryHeadingPair,
942 ) -> FileStreamingArchiveBinReaderAsync<'a, R> {
943 FileStreamingArchiveBinReaderAsync {
944 archive: self,
945 pointer_base: self.content_baseptr + heading.relative_offset,
946 pointer: self.content_baseptr + heading.relative_offset,
947 pointer_limit: self.content_baseptr + heading.relative_offset + heading.byte_length,
948 }
949 }
950}
951
952pub struct FileStreamingArchive<R: RandomReadBlob + MemoryMapBlob> {
953 pub handle: R,
954 pub entry_mapped_head: core::sync::atomic::AtomicPtr<core::ffi::c_void>,
955 pub entry_unmap_data: Option<R::MemoryUnmapData>,
956 pub content_flags: ContentFlags,
957 pub hash_tree_block_range: core::ops::Range<usize>,
958 pub exact_match_block_range: core::ops::Range<usize>,
959 pub content_baseptr: u64,
960}
961unsafe impl<R: RandomReadBlob + MemoryMapBlob + Send> Send for FileStreamingArchive<R> {}
962unsafe impl<R: RandomReadBlob + MemoryMapBlob + Sync> Sync for FileStreamingArchive<R> {}
963impl<R: RandomReadBlob + MemoryMapBlob> Drop for FileStreamingArchive<R> {
964 fn drop(&mut self) {
965 let _ = self
966 .handle
967 .munmap(self.entry_unmap_data.take().expect("drop twice!"));
968 }
969}
970impl<R: RandomReadBlob + MemoryMapBlob> FileStreamingArchive<R> {
971 fn new(handle: R, body_offset: u64) -> IOResult<Self> {
972 let mut content_flags_buf = [0u8];
973 let mut hash_tree_block_len_buf = [0u8; 4];
974 let mut exact_match_block_len_buf = [0u8; 8];
975
976 let mut ro = body_offset;
977 handle.readv_all(
978 ro,
979 &mut [
980 IoSliceMut::new(&mut content_flags_buf),
981 IoSliceMut::new(&mut hash_tree_block_len_buf),
982 IoSliceMut::new(&mut exact_match_block_len_buf),
983 ],
984 )?;
985 ro += 1 + 4 + 8;
986
987 let content_flags = ContentFlags::from_bits_retain(content_flags_buf[0]);
988 let hash_tree_block_len = (u32::from_le_bytes(hash_tree_block_len_buf) as u64) << 3;
989 let exact_match_block_len = u64::from_le_bytes(exact_match_block_len_buf);
990
991 let entry_block_start_pos = ro;
992 let (entry_mapped_head, entry_unmap_data) = handle.mmap(
993 dbg!(entry_block_start_pos),
994 (hash_tree_block_len + exact_match_block_len)
995 .try_into()
996 .expect("catalog block size is too large"),
997 )?;
998
999 Ok(Self {
1000 handle,
1001 entry_mapped_head: core::sync::atomic::AtomicPtr::new(entry_mapped_head),
1002 entry_unmap_data: Some(entry_unmap_data),
1003 content_flags,
1004 hash_tree_block_range: 0..hash_tree_block_len as usize,
1005 exact_match_block_range: hash_tree_block_len as usize
1006 ..(hash_tree_block_len + exact_match_block_len) as usize,
1007 content_baseptr: entry_block_start_pos + hash_tree_block_len + exact_match_block_len,
1008 })
1009 }
1010
1011 fn list_entry(&self, callback: impl FnMut(AssetNameRef)) {
1012 let entry_ptr = self
1013 .entry_mapped_head
1014 .load(core::sync::atomic::Ordering::Acquire);
1015
1016 list_entry(
1017 4 + 4,
1019 self.content_flags
1020 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
1021 unsafe {
1022 core::slice::from_raw_parts(
1023 entry_ptr.byte_add(self.hash_tree_block_range.start) as *const u8,
1024 self.hash_tree_block_range.len(),
1025 )
1026 },
1027 unsafe {
1028 core::slice::from_raw_parts(
1029 entry_ptr.byte_add(self.exact_match_block_range.start) as *const u8,
1030 self.exact_match_block_range.len(),
1031 )
1032 },
1033 callback,
1034 )
1035 }
1036
1037 fn find_entry(&self, name: &str, ext: &str) -> Option<AssetEntryHeadingPair> {
1038 let entry_ptr = self
1039 .entry_mapped_head
1040 .load(core::sync::atomic::Ordering::Acquire);
1041
1042 find_entry(
1043 4 + 4,
1045 name,
1046 ext,
1047 self.content_flags
1048 .contains(ContentFlags::ROOT_HASH_TREE_EXACT),
1049 unsafe {
1050 core::slice::from_raw_parts(
1051 entry_ptr.byte_add(self.hash_tree_block_range.start) as *const u8,
1052 self.hash_tree_block_range.len(),
1053 )
1054 },
1055 unsafe {
1056 core::slice::from_raw_parts(
1057 entry_ptr.byte_add(self.exact_match_block_range.start) as *const u8,
1058 self.exact_match_block_range.len(),
1059 )
1060 },
1061 )
1062 }
1063
1064 fn read_bin<'a>(
1065 &'a self,
1066 heading: AssetEntryHeadingPair,
1067 ) -> FileStreamingArchiveBinReader<'a, R> {
1068 FileStreamingArchiveBinReader {
1069 archive: self,
1070 pointer_base: self.content_baseptr + heading.relative_offset,
1071 pointer: self.content_baseptr + heading.relative_offset,
1072 pointer_limit: self.content_baseptr + heading.relative_offset + heading.byte_length,
1073 }
1074 }
1075}
1076
1077pub enum ArchiveBinReader<'a, R: RandomReadBlob + MemoryMapBlob> {
1078 OnMemory(OnMemoryArchiveBinReader<'a>),
1079 FileStreaming(FileStreamingArchiveBinReader<'a, R>),
1080}
1081impl<R: RandomReadBlob + MemoryMapBlob> peridot_native_io::BlobMetadata
1082 for ArchiveBinReader<'_, R>
1083{
1084 fn byte_length(&self) -> std::io::Result<u64> {
1085 match self {
1086 Self::OnMemory(r) => Ok(r.pointer_limit - r.pointer_base),
1087 Self::FileStreaming(r) => Ok(r.pointer_limit - r.pointer_base),
1088 }
1089 }
1090}
1091impl<R: RandomReadBlob + MemoryMapBlob> peridot_native_io::RandomReadBlob
1092 for ArchiveBinReader<'_, R>
1093{
1094 fn read(&self, pos: u64, buf: &mut [MaybeUninit<u8>]) -> std::io::Result<usize> {
1095 match self {
1096 Self::OnMemory(r) => r.read_at(pos, buf),
1097 Self::FileStreaming(r) => r.read_at(pos, buf),
1098 }
1099 }
1100
1101 fn readv(&self, offs: u64, iovecs: &mut [IoSliceMut]) -> std::io::Result<usize> {
1102 match self {
1103 Self::OnMemory(r) => r.readv_at(offs, iovecs),
1104 Self::FileStreaming(r) => r.readv_at(offs, iovecs),
1105 }
1106 }
1107}
1108impl<R: RandomReadBlob + MemoryMapBlob> std::io::Read for ArchiveBinReader<'_, R> {
1109 #[inline]
1110 fn read(&mut self, buf: &mut [u8]) -> IOResult<usize> {
1111 match *self {
1112 Self::OnMemory(ref mut x) => x.read(buf),
1113 Self::FileStreaming(ref mut x) => x.read(buf),
1114 }
1115 }
1116}
1117impl<R: RandomReadBlob + MemoryMapBlob> std::io::Seek for ArchiveBinReader<'_, R> {
1118 #[inline]
1119 fn seek(&mut self, pos: std::io::SeekFrom) -> IOResult<u64> {
1120 match *self {
1121 Self::OnMemory(ref mut x) => x.seek(pos),
1122 Self::FileStreaming(ref mut x) => x.seek(pos),
1123 }
1124 }
1125}
1126
1127#[pin_project(project = EnumDispatchFP)]
1128pub enum EnumDispatchF<OnMemoryF, FileStreamingF> {
1129 OnMemory(#[pin] OnMemoryF),
1130 FileStreaming(#[pin] FileStreamingF),
1131}
1132impl<OnMemoryF, FileStreamingF> Future for EnumDispatchF<OnMemoryF, FileStreamingF>
1133where
1134 OnMemoryF: Future,
1135 FileStreamingF: Future<Output = OnMemoryF::Output>,
1136{
1137 type Output = OnMemoryF::Output;
1138
1139 #[inline]
1140 fn poll(
1141 self: std::pin::Pin<&mut Self>,
1142 cx: &mut std::task::Context<'_>,
1143 ) -> std::task::Poll<Self::Output> {
1144 match self.project() {
1145 EnumDispatchFP::OnMemory(f) => f.poll(cx),
1146 EnumDispatchFP::FileStreaming(f) => f.poll(cx),
1147 }
1148 }
1149}
1150
1151pub enum ArchiveBinReaderAsync<'a, R: RandomReadBlobAsync + MemoryMapBlob> {
1152 OnMemory(OnMemoryArchiveBinReader<'a>),
1153 FileStreaming(FileStreamingArchiveBinReaderAsync<'a, R>),
1154}
1155impl<R: RandomReadBlobAsync + MemoryMapBlob> peridot_native_io::BlobMetadataAsync
1156 for ArchiveBinReaderAsync<'_, R>
1157{
1158 fn byte_length_async(&self) -> impl core::future::Future<Output = std::io::Result<u64>> {
1159 async move {
1160 match self {
1161 Self::OnMemory(r) => Ok(r.pointer_limit - r.pointer_base),
1162 Self::FileStreaming(r) => Ok(r.pointer_limit - r.pointer_base),
1163 }
1164 }
1165 }
1166}
1167impl<'aa, R: RandomReadBlobAsync + MemoryMapBlob + 'aa> peridot_native_io::RandomReadBlobAsync
1168 for ArchiveBinReaderAsync<'aa, R>
1169{
1170 type ReadFuture<'a, 'b>
1171 = EnumDispatchF<
1172 OnMemoryArchiveBinReadFuture<'a, 'b, 'aa>,
1173 FileStreamingArchiveBinReadFuture<'a, 'aa, 'b, R>,
1174 >
1175 where
1176 Self: 'a;
1177 type ReadVecFuture<'a, 'b, 'bb>
1178 = EnumDispatchF<
1179 OnMemoryArchiveBinReadVecFuture<'a, 'b, 'aa, 'bb>,
1180 FileStreamingArchiveBinReadVecFuture<'a, 'aa, 'b, 'bb, R>,
1181 >
1182 where
1183 Self: 'a,
1184 'bb: 'b;
1185
1186 fn read_async<'a, 'b>(
1187 &'a self,
1188 offs: u64,
1189 buf: &'b mut [MaybeUninit<u8>],
1190 ) -> Self::ReadFuture<'a, 'b> {
1191 match self {
1192 Self::OnMemory(r) => EnumDispatchF::OnMemory(OnMemoryArchiveBinReadFuture {
1193 reader: r,
1194 pos: offs,
1195 buf,
1196 }),
1197 Self::FileStreaming(r) => {
1198 EnumDispatchF::FileStreaming(FileStreamingArchiveBinReadFuture {
1199 reader: r,
1200 pos: offs,
1201 buf,
1202 state: FileStreamingArchiveBinReadFutureState::Idle,
1203 })
1204 }
1205 }
1206 }
1207
1208 fn readv_async<'a, 'b, 'bb>(
1209 &'a self,
1210 offs: u64,
1211 iovecs: &'b mut [IoSliceMut<'bb>],
1212 ) -> Self::ReadVecFuture<'a, 'b, 'bb> {
1213 match self {
1214 Self::OnMemory(r) => EnumDispatchF::OnMemory(OnMemoryArchiveBinReadVecFuture {
1215 reader: r,
1216 pos: offs,
1217 buf: iovecs,
1218 }),
1219 Self::FileStreaming(r) => {
1220 EnumDispatchF::FileStreaming(FileStreamingArchiveBinReadVecFuture {
1221 reader: r,
1222 pos: offs,
1223 buf: iovecs,
1224 state: FileStreamingArchiveBinReadFutureState::Idle,
1225 })
1226 }
1227 }
1228 }
1229}
1230impl<'a, R: RandomReadBlobAsync + MemoryMapBlob> ArchiveBinReaderAsync<'a, R> {
1231 #[inline]
1232 pub async fn read(&mut self, buf: &mut [u8]) -> IOResult<usize> {
1233 match *self {
1234 Self::OnMemory(ref mut x) => x.read(buf),
1235 Self::FileStreaming(ref mut x) => x.read(buf).await,
1236 }
1237 }
1238
1239 #[inline]
1240 pub async fn read_exact(&mut self, buf: &mut [u8]) -> IOResult<()> {
1241 match *self {
1242 Self::OnMemory(ref mut x) => x.read_exact(buf),
1243 Self::FileStreaming(ref mut x) => x.read_exact(buf).await,
1244 }
1245 }
1246
1247 #[inline]
1248 pub async fn read_all(&mut self) -> IOResult<Vec<u8>> {
1249 match *self {
1250 Self::OnMemory(ref mut x) => {
1251 let mut sink = Vec::new();
1252 x.read_to_end(&mut sink)?;
1253
1254 Ok(sink)
1255 }
1256 Self::FileStreaming(ref mut x) => x.read_all().await,
1257 }
1258 }
1259}
1260
1261pub enum ArchiveAsync {
1262 OnMemory(OnMemoryArchive),
1263 FileStreaming(FileStreamingArchiveAsync<PlatformNativeFileReaderAsync>),
1264}
1265impl ArchiveAsync {
1266 pub async fn new(
1268 blob: PlatformNativeFileReaderAsync,
1269 check_integrity: bool,
1270 ) -> ArchiveReadResult<Self> {
1271 let (comp, crc, body_start) = Self::read_file_header(&blob).await?;
1272 if check_integrity {
1273 let body = blob.read_to_end_async(body_start).await?;
1275 let input_crc = crc32::checksum_ieee(&body[..]);
1276 if input_crc != crc {
1277 return Err(ArchiveReadError::IntegrityCheckFailed);
1278 }
1279
1280 Ok(Self::OnMemory(OnMemoryArchive::new(comp, body)?))
1282 } else {
1283 match comp {
1284 CompressionMethod::None => Ok(Self::FileStreaming(
1285 FileStreamingArchiveAsync::new(blob, body_start).await?,
1286 )),
1287 _ => {
1288 let body = blob.read_to_end_async(body_start).await?;
1290 Ok(Self::OnMemory(OnMemoryArchive::new(comp, body)?))
1291 }
1292 }
1293 }
1294 }
1295
1296 async fn read_file_header(
1297 reader: &(impl RandomReadBlobAsync + ?Sized),
1298 ) -> ArchiveReadResult<(CompressionMethod, u32, u64)> {
1299 let mut read_ptr = 0;
1300 let mut signature = [const { MaybeUninit::uninit() }; 4];
1301 reader
1302 .read_exact_async(read_ptr, &mut signature[..])
1303 .await?;
1304 read_ptr += 4;
1305 let signature = unsafe { core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(signature) };
1306 let mut sink_64_bits = [const { MaybeUninit::uninit() }; 8];
1307 let comp: CompressionMethod;
1308 match &signature {
1309 b"par " => {
1310 comp = CompressionMethod::None;
1311 }
1312 b"pard" => {
1313 reader.read_exact_async(read_ptr, &mut sink_64_bits).await?;
1314 read_ptr += 8;
1315 comp = CompressionMethod::Zlib(u64::from_le_bytes(unsafe {
1316 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1317 }));
1318 }
1319 b"parz" => {
1320 reader.read_exact_async(read_ptr, &mut sink_64_bits).await?;
1321 read_ptr += 8;
1322 comp = CompressionMethod::Lz4(u64::from_le_bytes(unsafe {
1323 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1324 }));
1325 }
1326 b"par1" => {
1327 reader.read_exact_async(read_ptr, &mut sink_64_bits).await?;
1328 read_ptr += 8;
1329 comp = CompressionMethod::Zstd11(u64::from_le_bytes(unsafe {
1330 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1331 }));
1332 }
1333 _ => return Err(ArchiveReadError::SignatureMismatch),
1334 }
1335
1336 let mut crc32_bytes = [const { MaybeUninit::uninit() }; 4];
1337 reader.read_exact_async(read_ptr, &mut crc32_bytes).await?;
1338 read_ptr += 4;
1339 let crc32_bytes =
1340 unsafe { core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(crc32_bytes) };
1341
1342 Ok((comp, u32::from_le_bytes(crc32_bytes), read_ptr))
1343 }
1344
1345 #[inline]
1346 pub fn list_entry(&self, callback: impl FnMut(AssetNameRef)) {
1347 match *self {
1348 Self::OnMemory(ref x) => x.list_entry(callback),
1349 Self::FileStreaming(ref x) => x.list_entry(callback),
1350 }
1351 }
1352
1353 #[inline]
1354 pub fn find_entry(&self, name: &str, ext: &str) -> Option<AssetEntryHeadingPair> {
1355 match *self {
1356 Self::OnMemory(ref x) => x.find_entry(name, ext),
1357 Self::FileStreaming(ref x) => x.find_entry(name, ext),
1358 }
1359 }
1360
1361 #[inline]
1362 pub fn read_bin<'a>(
1363 &'a self,
1364 heading: AssetEntryHeadingPair,
1365 ) -> ArchiveBinReaderAsync<'a, PlatformNativeFileReaderAsync> {
1366 match *self {
1367 Self::OnMemory(ref x) => ArchiveBinReaderAsync::OnMemory(x.read_bin(heading)),
1368 Self::FileStreaming(ref x) => ArchiveBinReaderAsync::FileStreaming(x.read_bin(heading)),
1369 }
1370 }
1371}
1372
1373pub enum Archive {
1374 OnMemory(OnMemoryArchive),
1375 FileStreaming(FileStreamingArchive<PlatformNativeFileReader>),
1376}
1377impl Archive {
1378 pub fn new(blob: PlatformNativeFileReader, check_integrity: bool) -> ArchiveReadResult<Self> {
1380 let (comp, crc, body_start) = Self::read_file_header(&blob)?;
1381 if check_integrity {
1382 let body = blob.read_to_end(body_start)?;
1384 let input_crc = crc32::checksum_ieee(&body[..]);
1385 if input_crc != crc {
1386 return Err(ArchiveReadError::IntegrityCheckFailed);
1387 }
1388
1389 Ok(Self::OnMemory(OnMemoryArchive::new(comp, body)?))
1391 } else {
1392 match comp {
1393 CompressionMethod::None => Ok(Self::FileStreaming(FileStreamingArchive::new(
1394 blob, body_start,
1395 )?)),
1396 _ => {
1397 let body = blob.read_to_end(body_start)?;
1399 Ok(Self::OnMemory(OnMemoryArchive::new(comp, body)?))
1400 }
1401 }
1402 }
1403 }
1404
1405 fn read_file_header(
1406 reader: &(impl RandomReadBlob + ?Sized),
1407 ) -> ArchiveReadResult<(CompressionMethod, u32, u64)> {
1408 let mut read_ptr = 0;
1409 let mut signature = [const { MaybeUninit::uninit() }; 4];
1410 reader.read_exact(read_ptr, &mut signature[..])?;
1411 read_ptr += 4;
1412 let signature = unsafe { core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(signature) };
1413 let mut sink_64_bits = [const { MaybeUninit::uninit() }; 8];
1414 let comp = match &signature {
1415 b"par " => CompressionMethod::None,
1416 b"pard" => {
1417 reader.read_exact(read_ptr, &mut sink_64_bits)?;
1418 read_ptr += 8;
1419 CompressionMethod::Zlib(u64::from_le_bytes(unsafe {
1420 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1421 }))
1422 }
1423 b"parz" => {
1424 reader.read_exact(read_ptr, &mut sink_64_bits)?;
1425 read_ptr += 8;
1426 CompressionMethod::Lz4(u64::from_le_bytes(unsafe {
1427 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1428 }))
1429 }
1430 b"par1" => {
1431 reader.read_exact(read_ptr, &mut sink_64_bits)?;
1432 read_ptr += 8;
1433 CompressionMethod::Zstd11(u64::from_le_bytes(unsafe {
1434 core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(sink_64_bits)
1435 }))
1436 }
1437 _ => return Err(ArchiveReadError::SignatureMismatch),
1438 };
1439
1440 let mut crc32_bytes = [const { MaybeUninit::uninit() }; 4];
1441 reader.read_exact(read_ptr, &mut crc32_bytes)?;
1442 read_ptr += 4;
1443 let crc32_bytes =
1444 unsafe { core::mem::transmute::<[MaybeUninit<u8>; _], [u8; _]>(crc32_bytes) };
1445
1446 Ok((comp, u32::from_le_bytes(crc32_bytes), read_ptr))
1447 }
1448
1449 #[inline]
1450 pub fn list_entry(&self, callback: impl FnMut(AssetNameRef)) {
1451 match *self {
1452 Self::OnMemory(ref x) => x.list_entry(callback),
1453 Self::FileStreaming(ref x) => x.list_entry(callback),
1454 }
1455 }
1456
1457 #[inline]
1458 pub fn find_entry(&self, name: &str, ext: &str) -> Option<AssetEntryHeadingPair> {
1459 match *self {
1460 Self::OnMemory(ref x) => x.find_entry(name, ext),
1461 Self::FileStreaming(ref x) => x.find_entry(name, ext),
1462 }
1463 }
1464
1465 #[inline]
1466 pub fn read_bin<'a>(
1467 &'a self,
1468 heading: AssetEntryHeadingPair,
1469 ) -> ArchiveBinReader<'a, PlatformNativeFileReader> {
1470 match *self {
1471 Self::OnMemory(ref x) => ArchiveBinReader::OnMemory(x.read_bin(heading)),
1472 Self::FileStreaming(ref x) => ArchiveBinReader::FileStreaming(x.read_bin(heading)),
1473 }
1474 }
1475}