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) -> Result<Self> {
36 let reader = HashedReader::new(CompressedReader::new(
37 Counting::new(OwnedReader::Owned(reader).take(size)),
38 compression,
39 )?);
40 Ok(Self { reader, entry: WithoutEntry })
41 }
42
43 pub(crate) fn new_with_borrow(reader: &'a mut R, compression: Compression, size: u64) -> Result<Self> {
45 let reader = HashedReader::new(CompressedReader::new(
46 Counting::new(OwnedReader::Borrow(reader).take(size)),
47 compression,
48 )?);
49 Ok(Self { reader, entry: WithoutEntry })
50 }
51
52 pub(crate) fn into_with_entry(self, entry: &'a ZipEntry) -> ZipEntryReader<'a, R, WithEntry<'a>> {
53 ZipEntryReader { reader: self.reader, entry: WithEntry(OwnedEntry::Borrow(entry)) }
54 }
55
56 pub(crate) fn into_with_entry_owned(self, entry: ZipEntry) -> ZipEntryReader<'a, R, WithEntry<'a>> {
57 ZipEntryReader { reader: self.reader, entry: WithEntry(OwnedEntry::Owned(entry)) }
58 }
59}
60
61impl<'a, R, E> AsyncRead for ZipEntryReader<'a, R, E>
62where
63 R: AsyncBufRead + Unpin,
64{
65 fn poll_read(self: Pin<&mut Self>, c: &mut Context<'_>, b: &mut [u8]) -> Poll<std::io::Result<usize>> {
66 self.project().reader.poll_read(c, b)
67 }
68}
69
70impl<'a, R, E> ZipEntryReader<'a, R, E>
71where
72 R: AsyncBufRead + Unpin,
73{
74 pub fn compute_hash(&mut self) -> u32 {
78 self.reader.swap_and_compute_hash()
79 }
80
81 pub fn bytes_read(&self) -> u64 {
83 self.reader.inner().inner().bytes_read()
84 }
85
86 pub(crate) fn into_inner(self) -> R {
88 self.reader.into_inner().into_inner().into_inner().into_inner().owned_into_inner()
89 }
90}
91
92impl<R> ZipEntryReader<'_, R, WithEntry<'_>>
93where
94 R: AsyncBufRead + Unpin,
95{
96 pub fn entry(&self) -> &'_ ZipEntry {
98 self.entry.0.entry()
99 }
100
101 pub async fn read_to_end_checked(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
105 let read = self.read_to_end(buf).await?;
106
107 if self.compute_hash() == self.entry.0.entry().crc32() {
108 Ok(read)
109 } else {
110 Err(ZipError::CRC32CheckError)
111 }
112 }
113
114 pub async fn read_to_string_checked(&mut self, buf: &mut String) -> Result<usize> {
118 let read = self.read_to_string(buf).await?;
119
120 if self.compute_hash() == self.entry.0.entry().crc32() {
121 Ok(read)
122 } else {
123 Err(ZipError::CRC32CheckError)
124 }
125 }
126}
127
128enum OwnedEntry<'a> {
129 Owned(ZipEntry),
130 Borrow(&'a ZipEntry),
131}
132
133impl<'a> OwnedEntry<'a> {
134 pub fn entry(&self) -> &'_ ZipEntry {
135 match self {
136 OwnedEntry::Owned(entry) => entry,
137 OwnedEntry::Borrow(entry) => entry,
138 }
139 }
140}