async_zip/base/read/io/
entry.rs1use crate::base::read::counting::Counting;
5use crate::base::read::io::{compressed::CompressedReader, hashed::HashedReader, owned::OwnedReader};
6use crate::entry::ZipEntry;
7use crate::error::{Result, ZipError};
8use crate::spec::Compression;
9
10use std::pin::Pin;
11use std::task::{Context, Poll};
12
13use futures_lite::io::{AsyncBufRead, AsyncRead, AsyncReadExt, Take};
14use pin_project::pin_project;
15
16pub struct WithEntry<'a>(OwnedEntry<'a>);
18
19pub struct WithoutEntry;
21
22#[pin_project]
24pub struct ZipEntryReader<'a, R, E> {
25 #[pin]
26 reader: HashedReader<CompressedReader<Counting<Take<OwnedReader<'a, R>>>>>,
27 entry: E,
28}
29
30impl<'a, R> ZipEntryReader<'a, R, WithoutEntry>
31where
32 R: AsyncBufRead + Unpin,
33{
34 pub(crate) fn new_with_owned(reader: R, compression: Compression, size: u64) -> Self {
36 let reader =
37 HashedReader::new(CompressedReader::new(Counting::new(OwnedReader::Owned(reader).take(size)), compression));
38 Self { reader, entry: WithoutEntry }
39 }
40
41 pub(crate) fn new_with_borrow(reader: &'a mut R, compression: Compression, size: u64) -> Self {
43 let reader = HashedReader::new(CompressedReader::new(
44 Counting::new(OwnedReader::Borrow(reader).take(size)),
45 compression,
46 ));
47 Self { reader, entry: WithoutEntry }
48 }
49
50 pub(crate) fn into_with_entry(self, entry: &'a ZipEntry) -> ZipEntryReader<'a, R, WithEntry<'a>> {
51 ZipEntryReader { reader: self.reader, entry: WithEntry(OwnedEntry::Borrow(entry)) }
52 }
53
54 pub(crate) fn into_with_entry_owned(self, entry: ZipEntry) -> ZipEntryReader<'a, R, WithEntry<'a>> {
55 ZipEntryReader { reader: self.reader, entry: WithEntry(OwnedEntry::Owned(entry)) }
56 }
57}
58
59impl<'a, R, E> AsyncRead for ZipEntryReader<'a, R, E>
60where
61 R: AsyncBufRead + Unpin,
62{
63 fn poll_read(self: Pin<&mut Self>, c: &mut Context<'_>, b: &mut [u8]) -> Poll<std::io::Result<usize>> {
64 self.project().reader.poll_read(c, b)
65 }
66}
67
68impl<'a, R, E> ZipEntryReader<'a, R, E>
69where
70 R: AsyncBufRead + Unpin,
71{
72 pub fn compute_hash(&mut self) -> u32 {
76 self.reader.swap_and_compute_hash()
77 }
78
79 pub fn bytes_read(&self) -> u64 {
81 self.reader.inner().inner().bytes_read()
82 }
83
84 pub(crate) fn into_inner(self) -> R {
86 self.reader.into_inner().into_inner().into_inner().into_inner().owned_into_inner()
87 }
88}
89
90impl<R> ZipEntryReader<'_, R, WithEntry<'_>>
91where
92 R: AsyncBufRead + Unpin,
93{
94 pub fn entry(&self) -> &'_ ZipEntry {
96 self.entry.0.entry()
97 }
98
99 pub async fn read_to_end_checked(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
103 let read = self.read_to_end(buf).await?;
104
105 if self.compute_hash() == self.entry.0.entry().crc32() {
106 Ok(read)
107 } else {
108 Err(ZipError::CRC32CheckError)
109 }
110 }
111
112 pub async fn read_to_string_checked(&mut self, buf: &mut String) -> Result<usize> {
116 let read = self.read_to_string(buf).await?;
117
118 if self.compute_hash() == self.entry.0.entry().crc32() {
119 Ok(read)
120 } else {
121 Err(ZipError::CRC32CheckError)
122 }
123 }
124}
125
126enum OwnedEntry<'a> {
127 Owned(ZipEntry),
128 Borrow(&'a ZipEntry),
129}
130
131impl<'a> OwnedEntry<'a> {
132 pub fn entry(&self) -> &'_ ZipEntry {
133 match self {
134 OwnedEntry::Owned(entry) => entry,
135 OwnedEntry::Borrow(entry) => entry,
136 }
137 }
138}