sevenz_rust2/
reader.rs

1use std::{
2    cell::RefCell,
3    collections::HashMap,
4    fs::File,
5    io::{Read, Seek, SeekFrom},
6    rc::Rc,
7};
8
9use crc32fast::Hasher;
10
11use crate::{Password, archive::*, bitset::BitSet, block::*, decoder::add_decoder, error::Error};
12
13const MAX_MEM_LIMIT_KB: usize = usize::MAX / 1024;
14
15pub struct BoundedReader<R: Read> {
16    inner: R,
17    remain: usize,
18}
19
20impl<R: Read> BoundedReader<R> {
21    pub fn new(inner: R, max_size: usize) -> Self {
22        Self {
23            inner,
24            remain: max_size,
25        }
26    }
27}
28
29impl<R: Read> Read for BoundedReader<R> {
30    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
31        if self.remain == 0 {
32            return Ok(0);
33        }
34        let remain = self.remain;
35        let buf2 = if buf.len() < remain {
36            buf
37        } else {
38            &mut buf[..remain]
39        };
40        match self.inner.read(buf2) {
41            Ok(size) => {
42                if self.remain < size {
43                    self.remain = 0;
44                } else {
45                    self.remain -= size;
46                }
47                Ok(size)
48            }
49            Err(e) => Err(e),
50        }
51    }
52}
53
54#[derive(Debug, Default, Clone)]
55pub struct SeekableBoundedReader<R: Read + Seek> {
56    inner: R,
57    cur: u64,
58    bounds: (u64, u64),
59}
60
61impl<R: Read + Seek> Seek for SeekableBoundedReader<R> {
62    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
63        let new_pos = match pos {
64            SeekFrom::Start(pos) => self.bounds.0 as i64 + pos as i64,
65            SeekFrom::End(pos) => self.bounds.1 as i64 + pos,
66            SeekFrom::Current(pos) => self.cur as i64 + pos,
67        };
68        if new_pos < 0 {
69            return Err(std::io::Error::other("SeekBeforeStart"));
70        }
71        self.cur = new_pos as u64;
72        self.inner.seek(SeekFrom::Start(self.cur))
73    }
74}
75
76impl<R: Read + Seek> Read for SeekableBoundedReader<R> {
77    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
78        if self.cur >= self.bounds.1 {
79            return Ok(0);
80        }
81        if self.stream_position()? != self.cur {
82            self.inner.seek(SeekFrom::Start(self.cur))?;
83        }
84        let buf2 = if buf.len() < (self.bounds.1 - self.cur) as usize {
85            buf
86        } else {
87            &mut buf[..(self.bounds.1 - self.cur) as usize]
88        };
89        let size = self.inner.read(buf2)?;
90        self.cur += size as u64;
91        Ok(size)
92    }
93}
94
95impl<R: Read + Seek> SeekableBoundedReader<R> {
96    pub fn new(inner: R, bounds: (u64, u64)) -> Self {
97        Self {
98            inner,
99            cur: bounds.0,
100            bounds,
101        }
102    }
103}
104
105struct Crc32VerifyingReader<R> {
106    inner: R,
107    crc_digest: Hasher,
108    expected_value: u64,
109    remaining: i64,
110}
111
112impl<R: Read> Crc32VerifyingReader<R> {
113    fn new(inner: R, remaining: usize, expected_value: u64) -> Self {
114        Self {
115            inner,
116            crc_digest: Hasher::new(),
117            expected_value,
118            remaining: remaining as i64,
119        }
120    }
121}
122
123impl<R: Read> Read for Crc32VerifyingReader<R> {
124    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
125        if self.remaining <= 0 {
126            return Ok(0);
127        }
128        let size = self.inner.read(buf)?;
129        if size > 0 {
130            self.remaining -= size as i64;
131            self.crc_digest.update(&buf[..size]);
132        }
133        if self.remaining <= 0 {
134            let d = std::mem::replace(&mut self.crc_digest, Hasher::new()).finalize();
135            if d as u64 != self.expected_value {
136                return Err(std::io::Error::other(Error::ChecksumVerificationFailed));
137            }
138        }
139        Ok(size)
140    }
141}
142
143impl Archive {
144    /// Open 7z file under specified `path`.
145    #[inline]
146    pub fn open(path: impl AsRef<std::path::Path>) -> Result<Archive, Error> {
147        Self::open_with_password(path, &Password::empty())
148    }
149
150    /// Open an encrypted 7z file under specified `path` with `password`.
151    #[inline]
152    pub fn open_with_password(
153        path: impl AsRef<std::path::Path>,
154        password: &Password,
155    ) -> Result<Archive, Error> {
156        let mut file = File::open(path)?;
157        Self::read(&mut file, password)
158    }
159
160    /// Read 7z file archive info use the specified `reader`.
161    ///
162    /// # Parameters
163    /// - `reader`   - the reader of the 7z filr archive
164    /// - `password` - archive password encoded in utf16 little endian
165    ///
166    /// # Example
167    ///
168    /// ```no_run
169    /// use std::{
170    ///     fs::File,
171    ///     io::{Read, Seek},
172    /// };
173    ///
174    /// use sevenz_rust2::*;
175    ///
176    /// let mut reader = File::open("example.7z").unwrap();
177    ///
178    /// let password = Password::from("the password");
179    /// let archive = Archive::read(&mut reader, &password).unwrap();
180    ///
181    /// for entry in &archive.files {
182    ///     println!("{}", entry.name());
183    /// }
184    /// ```
185    pub fn read<R: Read + Seek>(reader: &mut R, password: &Password) -> Result<Archive, Error> {
186        let reader_len = reader.seek(SeekFrom::End(0))?;
187        reader.seek(SeekFrom::Start(0))?;
188
189        let mut signature = [0; 6];
190        reader.read_exact(&mut signature).map_err(Error::io)?;
191        if signature != SEVEN_Z_SIGNATURE {
192            return Err(Error::BadSignature(signature));
193        }
194        let mut versions = [0; 2];
195        reader.read_exact(&mut versions).map_err(Error::io)?;
196        let version_major = versions[0];
197        let version_minor = versions[1];
198        if version_major != 0 {
199            return Err(Error::UnsupportedVersion {
200                major: version_major,
201                minor: version_minor,
202            });
203        }
204
205        let start_header_crc = read_u32(reader)?;
206
207        let header_valid = if start_header_crc == 0 {
208            let current_position = reader.stream_position().map_err(Error::io)?;
209            let mut buf = [0; 20];
210            reader.read_exact(&mut buf).map_err(Error::io)?;
211            reader
212                .seek(SeekFrom::Start(current_position))
213                .map_err(Error::io)?;
214            buf.iter().any(|a| *a != 0)
215        } else {
216            true
217        };
218        if header_valid {
219            let start_header = Self::read_start_header(reader, start_header_crc)?;
220            Self::init_archive(reader, start_header, password, true)
221        } else {
222            Self::try_to_locale_end_header(reader, reader_len, password)
223        }
224    }
225
226    fn read_start_header<R: Read>(
227        reader: &mut R,
228        start_header_crc: u32,
229    ) -> Result<StartHeader, Error> {
230        let mut buf = [0; 20];
231        reader.read_exact(&mut buf).map_err(Error::io)?;
232        let crc32 = crc32fast::hash(&buf);
233        if crc32 != start_header_crc {
234            return Err(Error::ChecksumVerificationFailed);
235        }
236        let mut buf_read = buf.as_slice();
237        let offset = read_u64le(&mut buf_read)?;
238
239        let size = read_u64le(&mut buf_read)?;
240        let crc = read_u32(&mut buf_read)?;
241        Ok(StartHeader {
242            next_header_offset: offset,
243            next_header_size: size,
244            next_header_crc: crc as u64,
245        })
246    }
247
248    fn read_header<R: Read + Seek>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
249        let mut nid = read_u8(header)?;
250        if nid == K_ARCHIVE_PROPERTIES {
251            Self::read_archive_properties(header)?;
252            nid = read_u8(header)?;
253        }
254
255        if nid == K_ADDITIONAL_STREAMS_INFO {
256            return Err(Error::other("Additional streams unsupported"));
257        }
258        if nid == K_MAIN_STREAMS_INFO {
259            Self::read_streams_info(header, archive)?;
260            nid = read_u8(header)?;
261        }
262        if nid == K_FILES_INFO {
263            Self::read_files_info(header, archive)?;
264            nid = read_u8(header)?;
265        }
266        if nid != K_END {
267            return Err(Error::BadTerminatedheader(nid));
268        }
269
270        Ok(())
271    }
272
273    fn read_archive_properties<R: Read + Seek>(header: &mut R) -> Result<(), Error> {
274        let mut nid = read_u8(header)?;
275        while nid != K_END {
276            let property_size = read_usize(header, "propertySize")?;
277            header
278                .seek(SeekFrom::Current(property_size as i64))
279                .map_err(Error::io)?;
280            nid = read_u8(header)?;
281        }
282        Ok(())
283    }
284
285    fn try_to_locale_end_header<R: Read + Seek>(
286        reader: &mut R,
287        reader_len: u64,
288        password: &Password,
289    ) -> Result<Self, Error> {
290        let search_limit = 1024 * 1024;
291        let prev_data_size = reader.stream_position().map_err(Error::io)? + 20;
292        let size = reader_len;
293        let min_pos = if reader.stream_position().map_err(Error::io)? + search_limit > size {
294            reader.stream_position().map_err(Error::io)?
295        } else {
296            size - search_limit
297        };
298        let mut pos = reader_len - 1;
299        while pos > min_pos {
300            pos -= 1;
301
302            reader.seek(SeekFrom::Start(pos)).map_err(Error::io)?;
303            let nid = read_u8(reader)?;
304            if nid == K_ENCODED_HEADER || nid == K_HEADER {
305                let start_header = StartHeader {
306                    next_header_offset: pos - prev_data_size,
307                    next_header_size: reader_len - pos,
308                    next_header_crc: 0,
309                };
310                let result = Self::init_archive(reader, start_header, password, false)?;
311
312                if !result.files.is_empty() {
313                    return Ok(result);
314                }
315            }
316        }
317        Err(Error::other(
318            "Start header corrupt and unable to guess end header",
319        ))
320    }
321
322    fn init_archive<R: Read + Seek>(
323        reader: &mut R,
324        start_header: StartHeader,
325        password: &Password,
326        verify_crc: bool,
327    ) -> Result<Self, Error> {
328        if start_header.next_header_size > usize::MAX as u64 {
329            return Err(Error::other(format!(
330                "Cannot handle next_header_size {}",
331                start_header.next_header_size
332            )));
333        }
334
335        let next_header_size_int = start_header.next_header_size as usize;
336
337        reader
338            .seek(SeekFrom::Start(
339                SIGNATURE_HEADER_SIZE + start_header.next_header_offset,
340            ))
341            .map_err(Error::io)?;
342
343        let mut buf = vec![0; next_header_size_int];
344        reader.read_exact(&mut buf).map_err(Error::io)?;
345        if verify_crc && crc32fast::hash(&buf) as u64 != start_header.next_header_crc {
346            return Err(Error::NextHeaderCrcMismatch);
347        }
348
349        let mut archive = Archive::default();
350        let mut buf_reader = buf.as_slice();
351        let mut nid = read_u8(&mut buf_reader)?;
352        let mut header = if nid == K_ENCODED_HEADER {
353            let (mut out_reader, buf_size) =
354                Self::read_encoded_header(&mut buf_reader, reader, &mut archive, password)?;
355            buf.clear();
356            buf.resize(buf_size, 0);
357            out_reader
358                .read_exact(&mut buf)
359                .map_err(|e| Error::bad_password(e, !password.is_empty()))?;
360            archive = Archive::default();
361            buf_reader = buf.as_slice();
362            nid = read_u8(&mut buf_reader)?;
363            buf_reader
364        } else {
365            buf_reader
366        };
367        let mut header = std::io::Cursor::new(&mut header);
368        if nid == K_HEADER {
369            Self::read_header(&mut header, &mut archive)?;
370        } else {
371            return Err(Error::other("Broken or unsupported archive: no Header"));
372        }
373
374        archive.is_solid = archive
375            .blocks
376            .iter()
377            .any(|block| block.num_unpack_sub_streams > 1);
378
379        Ok(archive)
380    }
381
382    fn read_encoded_header<'r, R: Read, RI: 'r + Read + Seek>(
383        header: &mut R,
384        reader: &'r mut RI,
385        archive: &mut Archive,
386        password: &Password,
387    ) -> Result<(Box<dyn Read + 'r>, usize), Error> {
388        Self::read_streams_info(header, archive)?;
389        let block = archive
390            .blocks
391            .first()
392            .ok_or(Error::other("no blocks, can't read encoded header"))?;
393        let first_pack_stream_index = 0;
394        let block_offset = SIGNATURE_HEADER_SIZE + archive.pack_pos;
395        if archive.pack_sizes.is_empty() {
396            return Err(Error::other("no packed streams, can't read encoded header"));
397        }
398
399        reader
400            .seek(SeekFrom::Start(block_offset))
401            .map_err(Error::io)?;
402        let coder_len = block.coders.len();
403        let unpack_size = block.get_unpack_size() as usize;
404        let pack_size = archive.pack_sizes[first_pack_stream_index] as usize;
405        let input_reader =
406            SeekableBoundedReader::new(reader, (block_offset, block_offset + pack_size as u64));
407        let mut decoder: Box<dyn Read> = Box::new(input_reader);
408        let mut decoder = if coder_len > 0 {
409            for (index, coder) in block.ordered_coder_iter() {
410                if coder.num_in_streams != 1 || coder.num_out_streams != 1 {
411                    return Err(Error::other(
412                        "Multi input/output stream coders are not yet supported",
413                    ));
414                }
415                let next = add_decoder(
416                    decoder,
417                    block.get_unpack_size_at_index(index) as usize,
418                    coder,
419                    password,
420                    MAX_MEM_LIMIT_KB,
421                )?;
422                decoder = Box::new(next);
423            }
424            decoder
425        } else {
426            decoder
427        };
428        if block.has_crc {
429            decoder = Box::new(Crc32VerifyingReader::new(decoder, unpack_size, block.crc));
430        }
431
432        Ok((decoder, unpack_size))
433    }
434
435    fn read_streams_info<R: Read>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
436        let mut nid = read_u8(header)?;
437        if nid == K_PACK_INFO {
438            Self::read_pack_info(header, archive)?;
439            nid = read_u8(header)?;
440        }
441
442        if nid == K_UNPACK_INFO {
443            Self::read_unpack_info(header, archive)?;
444            nid = read_u8(header)?;
445        } else {
446            archive.blocks.clear();
447        }
448        if nid == K_SUB_STREAMS_INFO {
449            Self::read_sub_streams_info(header, archive)?;
450            nid = read_u8(header)?;
451        }
452        if nid != K_END {
453            return Err(Error::BadTerminatedStreamsInfo(nid));
454        }
455
456        Ok(())
457    }
458
459    fn read_files_info<R: Read + Seek>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
460        let num_files = read_usize(header, "num files")?;
461        let mut files: Vec<ArchiveEntry> = vec![Default::default(); num_files];
462
463        let mut is_empty_stream: Option<BitSet> = None;
464        let mut is_empty_file: Option<BitSet> = None;
465        let mut is_anti: Option<BitSet> = None;
466        loop {
467            let prop_type = read_u8(header)?;
468            if prop_type == 0 {
469                break;
470            }
471            let size = read_u64(header)?;
472            match prop_type {
473                K_EMPTY_STREAM => {
474                    is_empty_stream = Some(read_bits(header, num_files)?);
475                }
476                K_EMPTY_FILE => {
477                    let n = if let Some(s) = &is_empty_stream {
478                        s.len()
479                    } else {
480                        return Err(Error::other(
481                            "Header format error: kEmptyStream must appear before kEmptyFile",
482                        ));
483                    };
484                    is_empty_file = Some(read_bits(header, n)?);
485                }
486                K_ANTI => {
487                    let n = if let Some(s) = is_empty_stream.as_ref() {
488                        s.len()
489                    } else {
490                        return Err(Error::other(
491                            "Header format error: kEmptyStream must appear before kEmptyFile",
492                        ));
493                    };
494                    is_anti = Some(read_bits(header, n)?);
495                }
496                K_NAME => {
497                    let external = read_u8(header)?;
498                    if external != 0 {
499                        return Err(Error::other("Not implemented:external != 0"));
500                    }
501                    if (size - 1) & 1 != 0 {
502                        return Err(Error::other("file names length invalid"));
503                    }
504
505                    let size = assert_usize(size, "file names length")?;
506                    // let mut names = vec![0u8; size - 1];
507                    // header.read_exact(&mut names).map_err(Error::io)?;
508                    let names_reader = NamesReader::new(header, size - 1);
509
510                    let mut next_file = 0;
511                    for s in names_reader {
512                        files[next_file].name = s?;
513                        next_file += 1;
514                    }
515
516                    if next_file != files.len() {
517                        return Err(Error::other("Error parsing file names"));
518                    }
519                }
520                K_C_TIME => {
521                    let times_defined = read_all_or_bits(header, num_files)?;
522                    let external = read_u8(header)?;
523                    if external != 0 {
524                        return Err(Error::other(format!(
525                            "kCTime Unimplemented:external={external}"
526                        )));
527                    }
528                    for (i, file) in files.iter_mut().enumerate() {
529                        file.has_creation_date = times_defined.contains(i);
530                        if file.has_creation_date {
531                            file.creation_date = read_u64le(header)?.into();
532                        }
533                    }
534                }
535                K_A_TIME => {
536                    let times_defined = read_all_or_bits(header, num_files)?;
537                    let external = read_u8(header)?;
538                    if external != 0 {
539                        return Err(Error::other(format!(
540                            "kATime Unimplemented:external={external}"
541                        )));
542                    }
543                    for (i, file) in files.iter_mut().enumerate() {
544                        file.has_access_date = times_defined.contains(i);
545                        if file.has_access_date {
546                            file.access_date = read_u64le(header)?.into();
547                        }
548                    }
549                }
550                K_M_TIME => {
551                    let times_defined = read_all_or_bits(header, num_files)?;
552                    let external = read_u8(header)?;
553                    if external != 0 {
554                        return Err(Error::other(format!(
555                            "kMTime Unimplemented:external={external}"
556                        )));
557                    }
558                    for (i, file) in files.iter_mut().enumerate() {
559                        file.has_last_modified_date = times_defined.contains(i);
560                        if file.has_last_modified_date {
561                            file.last_modified_date = read_u64le(header)?.into();
562                        }
563                    }
564                }
565                K_WIN_ATTRIBUTES => {
566                    let times_defined = read_all_or_bits(header, num_files)?;
567                    let external = read_u8(header)?;
568                    if external != 0 {
569                        return Err(Error::other(format!(
570                            "kWinAttributes Unimplemented:external={external}"
571                        )));
572                    }
573                    for (i, file) in files.iter_mut().enumerate() {
574                        file.has_windows_attributes = times_defined.contains(i);
575                        if file.has_windows_attributes {
576                            file.windows_attributes = read_u32(header)?;
577                        }
578                    }
579                }
580                K_START_POS => return Err(Error::other("kStartPos is unsupported, please report")),
581                K_DUMMY => {
582                    header
583                        .seek(SeekFrom::Current(size as i64))
584                        .map_err(Error::io)?;
585                }
586                _ => {
587                    header
588                        .seek(SeekFrom::Current(size as i64))
589                        .map_err(Error::io)?;
590                }
591            };
592        }
593
594        let mut non_empty_file_counter = 0;
595        let mut empty_file_counter = 0;
596        for (i, file) in files.iter_mut().enumerate() {
597            file.has_stream = is_empty_stream
598                .as_ref()
599                .map(|s| !s.contains(i))
600                .unwrap_or(true);
601            if file.has_stream {
602                let sub_stream_info = if let Some(s) = archive.sub_streams_info.as_ref() {
603                    s
604                } else {
605                    return Err(Error::other(
606                        "Archive contains file with streams but no subStreamsInfo",
607                    ));
608                };
609                file.is_directory = false;
610                file.is_anti_item = false;
611                file.has_crc = sub_stream_info.has_crc.contains(non_empty_file_counter);
612                file.crc = sub_stream_info.crcs[non_empty_file_counter];
613                file.size = sub_stream_info.unpack_sizes[non_empty_file_counter];
614                non_empty_file_counter += 1;
615            } else {
616                file.is_directory = if let Some(s) = &is_empty_file {
617                    !s.contains(empty_file_counter)
618                } else {
619                    true
620                };
621                file.is_anti_item = is_anti
622                    .as_ref()
623                    .map(|s| s.contains(empty_file_counter))
624                    .unwrap_or(false);
625                file.has_crc = false;
626                file.size = 0;
627                empty_file_counter += 1;
628            }
629        }
630        archive.files = files;
631
632        Self::calculate_stream_map(archive)?;
633        Ok(())
634    }
635
636    fn calculate_stream_map(archive: &mut Archive) -> Result<(), Error> {
637        let mut stream_map = StreamMap::default();
638
639        let mut next_block_pack_stream_index = 0;
640        let num_blocks = archive.blocks.len();
641        stream_map.block_first_pack_stream_index = vec![0; num_blocks];
642        for i in 0..num_blocks {
643            stream_map.block_first_pack_stream_index[i] = next_block_pack_stream_index;
644            next_block_pack_stream_index += archive.blocks[i].packed_streams.len();
645        }
646
647        let mut next_pack_stream_offset = 0;
648        let num_pack_sizes = archive.pack_sizes.len();
649        stream_map.pack_stream_offsets = vec![0; num_pack_sizes];
650        for i in 0..num_pack_sizes {
651            stream_map.pack_stream_offsets[i] = next_pack_stream_offset;
652            next_pack_stream_offset += archive.pack_sizes[i];
653        }
654
655        stream_map.block_first_file_index = vec![0; num_blocks];
656        stream_map.file_block_index = vec![None; archive.files.len()];
657        let mut next_block_index = 0;
658        let mut next_block_unpack_stream_index = 0;
659        for i in 0..archive.files.len() {
660            if !archive.files[i].has_stream && next_block_unpack_stream_index == 0 {
661                stream_map.file_block_index[i] = None;
662                continue;
663            }
664            if next_block_unpack_stream_index == 0 {
665                while next_block_index < archive.blocks.len() {
666                    stream_map.block_first_file_index[next_block_index] = i;
667                    if archive.blocks[next_block_index].num_unpack_sub_streams > 0 {
668                        break;
669                    }
670                    next_block_index += 1;
671                }
672                if next_block_index >= archive.blocks.len() {
673                    return Err(Error::other("Too few blocks in archive"));
674                }
675            }
676            stream_map.file_block_index[i] = Some(next_block_index);
677            if !archive.files[i].has_stream {
678                continue;
679            }
680
681            //set `compressed_size` of first file in block
682            if stream_map.block_first_file_index[next_block_index] == i {
683                let first_pack_stream_index =
684                    stream_map.block_first_pack_stream_index[next_block_index];
685                let pack_size = archive.pack_sizes[first_pack_stream_index];
686
687                archive.files[i].compressed_size = pack_size;
688            }
689
690            next_block_unpack_stream_index += 1;
691            if next_block_unpack_stream_index
692                >= archive.blocks[next_block_index].num_unpack_sub_streams
693            {
694                next_block_index += 1;
695                next_block_unpack_stream_index = 0;
696            }
697        }
698
699        archive.stream_map = stream_map;
700        Ok(())
701    }
702
703    fn read_pack_info<R: Read>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
704        archive.pack_pos = read_u64(header)?;
705        let num_pack_streams = read_usize(header, "num pack streams")?;
706        let mut nid = read_u8(header)?;
707        if nid == K_SIZE {
708            archive.pack_sizes = vec![0u64; num_pack_streams];
709            for i in 0..archive.pack_sizes.len() {
710                archive.pack_sizes[i] = read_u64(header)?;
711            }
712            nid = read_u8(header)?;
713        }
714
715        if nid == K_CRC {
716            archive.pack_crcs_defined = read_all_or_bits(header, num_pack_streams)?;
717            archive.pack_crcs = vec![0; num_pack_streams];
718            for i in 0..num_pack_streams {
719                if archive.pack_crcs_defined.contains(i) {
720                    archive.pack_crcs[i] = read_u32(header)? as u64;
721                }
722            }
723            nid = read_u8(header)?;
724        }
725
726        if nid != K_END {
727            return Err(Error::BadTerminatedPackInfo(nid));
728        }
729
730        Ok(())
731    }
732    fn read_unpack_info<R: Read>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
733        let nid = read_u8(header)?;
734        if nid != K_FOLDER {
735            return Err(Error::other(format!("Expected kFolder, got {nid}")));
736        }
737        let num_blocks = read_usize(header, "num blocks")?;
738
739        archive.blocks.reserve_exact(num_blocks);
740        let external = read_u8(header)?;
741        if external != 0 {
742            return Err(Error::ExternalUnsupported);
743        }
744
745        for _ in 0..num_blocks {
746            archive.blocks.push(Self::read_block(header)?);
747        }
748
749        let nid = read_u8(header)?;
750        if nid != K_CODERS_UNPACK_SIZE {
751            return Err(Error::other(format!(
752                "Expected kCodersUnpackSize, got {nid}"
753            )));
754        }
755
756        for block in archive.blocks.iter_mut() {
757            let tos = block.total_output_streams;
758            block.unpack_sizes.reserve_exact(tos);
759            for _ in 0..tos {
760                block.unpack_sizes.push(read_u64(header)?);
761            }
762        }
763
764        let mut nid = read_u8(header)?;
765        if nid == K_CRC {
766            let crcs_defined = read_all_or_bits(header, num_blocks)?;
767            for i in 0..num_blocks {
768                if crcs_defined.contains(i) {
769                    archive.blocks[i].has_crc = true;
770                    archive.blocks[i].crc = read_u32(header)? as u64;
771                } else {
772                    archive.blocks[i].has_crc = false;
773                }
774            }
775            nid = read_u8(header)?;
776        }
777        if nid != K_END {
778            return Err(Error::BadTerminatedUnpackInfo);
779        }
780
781        Ok(())
782    }
783
784    fn read_sub_streams_info<R: Read>(header: &mut R, archive: &mut Archive) -> Result<(), Error> {
785        for block in archive.blocks.iter_mut() {
786            block.num_unpack_sub_streams = 1;
787        }
788        let mut total_unpack_streams = archive.blocks.len();
789
790        let mut nid = read_u8(header)?;
791        if nid == K_NUM_UNPACK_STREAM {
792            total_unpack_streams = 0;
793            for block in archive.blocks.iter_mut() {
794                let num_streams = read_usize(header, "numStreams")?;
795                block.num_unpack_sub_streams = num_streams;
796                total_unpack_streams += num_streams;
797            }
798            nid = read_u8(header)?;
799        }
800
801        let mut sub_streams_info = SubStreamsInfo::default();
802        sub_streams_info
803            .unpack_sizes
804            .resize(total_unpack_streams, Default::default());
805        sub_streams_info
806            .has_crc
807            .reserve_len_exact(total_unpack_streams);
808        sub_streams_info.crcs = vec![0; total_unpack_streams];
809
810        let mut next_unpack_stream = 0;
811        for block in archive.blocks.iter() {
812            if block.num_unpack_sub_streams == 0 {
813                continue;
814            }
815            let mut sum = 0;
816            if nid == K_SIZE {
817                for _i in 0..block.num_unpack_sub_streams - 1 {
818                    let size = read_u64(header)?;
819                    sub_streams_info.unpack_sizes[next_unpack_stream] = size;
820                    next_unpack_stream += 1;
821                    sum += size;
822                }
823            }
824            if sum > block.get_unpack_size() {
825                return Err(Error::other(
826                    "sum of unpack sizes of block exceeds total unpack size",
827                ));
828            }
829            sub_streams_info.unpack_sizes[next_unpack_stream] = block.get_unpack_size() - sum;
830            next_unpack_stream += 1;
831        }
832        if nid == K_SIZE {
833            nid = read_u8(header)?;
834        }
835
836        let mut num_digests = 0;
837        for block in archive.blocks.iter() {
838            if block.num_unpack_sub_streams != 1 || !block.has_crc {
839                num_digests += block.num_unpack_sub_streams;
840            }
841        }
842
843        if nid == K_CRC {
844            let has_missing_crc = read_all_or_bits(header, num_digests)?;
845            let mut missing_crcs = vec![0; num_digests];
846            for (i, missing_crc) in missing_crcs.iter_mut().enumerate() {
847                if has_missing_crc.contains(i) {
848                    *missing_crc = read_u32(header)? as u64;
849                }
850            }
851            let mut next_crc = 0;
852            let mut next_missing_crc = 0;
853            for block in archive.blocks.iter() {
854                if block.num_unpack_sub_streams == 1 && block.has_crc {
855                    sub_streams_info.has_crc.insert(next_crc);
856                    sub_streams_info.crcs[next_crc] = block.crc;
857                    next_crc += 1;
858                } else {
859                    for _i in 0..block.num_unpack_sub_streams {
860                        if has_missing_crc.contains(next_missing_crc) {
861                            sub_streams_info.has_crc.insert(next_crc);
862                        } else {
863                            sub_streams_info.has_crc.remove(next_crc);
864                        }
865                        sub_streams_info.crcs[next_crc] = missing_crcs[next_missing_crc];
866                        next_crc += 1;
867                        next_missing_crc += 1;
868                    }
869                }
870            }
871
872            nid = read_u8(header)?;
873        }
874
875        if nid != K_END {
876            return Err(Error::BadTerminatedSubStreamsInfo);
877        }
878
879        archive.sub_streams_info = Some(sub_streams_info);
880        Ok(())
881    }
882
883    fn read_block<R: Read>(header: &mut R) -> Result<Block, Error> {
884        let mut block = Block::default();
885
886        let num_coders = read_usize(header, "num coders")?;
887        let mut coders = Vec::with_capacity(num_coders);
888        let mut total_in_streams = 0;
889        let mut total_out_streams = 0;
890        for _i in 0..num_coders {
891            let mut coder = Coder::default();
892            let bits = read_u8(header)?;
893            let id_size = bits & 0xF;
894            let is_simple = (bits & 0x10) == 0;
895            let has_attributes = (bits & 0x20) != 0;
896            let more_alternative_methods = (bits & 0x80) != 0;
897
898            coder.id_size = id_size as usize;
899
900            header
901                .read(coder.decompression_method_id_mut())
902                .map_err(Error::io)?;
903            if is_simple {
904                coder.num_in_streams = 1;
905                coder.num_out_streams = 1;
906            } else {
907                coder.num_in_streams = read_u64(header)?;
908                coder.num_out_streams = read_u64(header)?;
909            }
910            total_in_streams += coder.num_in_streams;
911            total_out_streams += coder.num_out_streams;
912            if has_attributes {
913                let properties_size = read_usize(header, "properties size")?;
914                let mut props = vec![0u8; properties_size];
915                header.read(&mut props).map_err(Error::io)?;
916                coder.properties = props;
917            }
918            coders.push(coder);
919            // would need to keep looping as above:
920            if more_alternative_methods {
921                return Err(Error::other(
922                    "Alternative methods are unsupported, please report. The reference implementation doesn't support them either.",
923                ));
924            }
925        }
926        block.coders = coders;
927        let total_in_streams = assert_usize(total_in_streams, "totalInStreams")?;
928        let total_out_streams = assert_usize(total_out_streams, "totalOutStreams")?;
929        block.total_input_streams = total_in_streams;
930        block.total_output_streams = total_out_streams;
931
932        if total_out_streams == 0 {
933            return Err(Error::other("Total output streams can't be 0"));
934        }
935        let num_bind_pairs = total_out_streams - 1;
936        let mut bind_pairs = Vec::with_capacity(num_bind_pairs);
937        for _ in 0..num_bind_pairs {
938            let bp = BindPair {
939                in_index: read_u64(header)?,
940                out_index: read_u64(header)?,
941            };
942            bind_pairs.push(bp);
943        }
944        block.bind_pairs = bind_pairs;
945
946        if total_in_streams < num_bind_pairs {
947            return Err(Error::other(
948                "Total input streams can't be less than the number of bind pairs",
949            ));
950        }
951        let num_packed_streams = total_in_streams - num_bind_pairs;
952        let mut packed_streams = vec![0; num_packed_streams];
953        if num_packed_streams == 1 {
954            let mut index = u64::MAX;
955            for i in 0..total_in_streams {
956                if block.find_bind_pair_for_in_stream(i).is_none() {
957                    index = i as u64;
958                    break;
959                }
960            }
961            if index == u64::MAX {
962                return Err(Error::other("Couldn't find stream's bind pair index"));
963            }
964            packed_streams[0] = index;
965        } else {
966            for packed_stream in packed_streams.iter_mut() {
967                *packed_stream = read_u64(header)?;
968            }
969        }
970        block.packed_streams = packed_streams;
971
972        Ok(block)
973    }
974}
975
976#[inline]
977fn read_usize<R: Read>(reader: &mut R, field: &str) -> Result<usize, Error> {
978    let size = read_u64(reader)?;
979    assert_usize(size, field)
980}
981
982#[inline]
983fn assert_usize(size: u64, field: &str) -> Result<usize, Error> {
984    if size > usize::MAX as u64 {
985        return Err(Error::other(format!("Cannot handle {field} {size}")));
986    }
987    Ok(size as usize)
988}
989
990#[inline]
991fn read_u64le<R: Read>(reader: &mut R) -> Result<u64, Error> {
992    let mut buf = [0; 8];
993    reader.read_exact(&mut buf).map_err(Error::io)?;
994    Ok(u64::from_le_bytes(buf))
995}
996
997fn read_u64<R: Read>(reader: &mut R) -> Result<u64, Error> {
998    let first = read_u8(reader)? as u64;
999    let mut mask = 0x80_u64;
1000    let mut value = 0;
1001    for i in 0..8 {
1002        if (first & mask) == 0 {
1003            return Ok(value | ((first & (mask - 1)) << (8 * i)));
1004        }
1005        let b = read_u8(reader)? as u64;
1006        value |= b << (8 * i);
1007        mask >>= 1;
1008    }
1009    Ok(value)
1010}
1011
1012#[inline(always)]
1013fn read_u32<R: Read>(reader: &mut R) -> Result<u32, Error> {
1014    let mut buf = [0; 4];
1015    reader.read_exact(&mut buf).map_err(Error::io)?;
1016    Ok(u32::from_le_bytes(buf))
1017}
1018
1019#[inline(always)]
1020fn read_u8<R: Read>(reader: &mut R) -> Result<u8, Error> {
1021    let mut buf = [0];
1022    reader.read_exact(&mut buf).map_err(Error::io)?;
1023    Ok(buf[0])
1024}
1025
1026fn read_all_or_bits<R: Read>(header: &mut R, size: usize) -> Result<BitSet, Error> {
1027    let all = read_u8(header)?;
1028    if all != 0 {
1029        let mut bits = BitSet::with_capacity(size);
1030        for i in 0..size {
1031            bits.insert(i);
1032        }
1033        Ok(bits)
1034    } else {
1035        read_bits(header, size)
1036    }
1037}
1038
1039fn read_bits<R: Read>(header: &mut R, size: usize) -> Result<BitSet, Error> {
1040    let mut bits = BitSet::with_capacity(size);
1041    let mut mask = 0u32;
1042    let mut cache = 0u32;
1043    for i in 0..size {
1044        if mask == 0 {
1045            mask = 0x80;
1046            cache = read_u8(header)? as u32;
1047        }
1048        if (cache & mask) != 0 {
1049            bits.insert(i);
1050        }
1051        mask >>= 1;
1052    }
1053    Ok(bits)
1054}
1055
1056struct NamesReader<'a, R: Read> {
1057    max_bytes: usize,
1058    read_bytes: usize,
1059    cache: Vec<u16>,
1060    reader: &'a mut R,
1061}
1062
1063impl<'a, R: Read> NamesReader<'a, R> {
1064    fn new(reader: &'a mut R, max_bytes: usize) -> Self {
1065        Self {
1066            max_bytes,
1067            reader,
1068            read_bytes: 0,
1069            cache: Vec::with_capacity(16),
1070        }
1071    }
1072}
1073
1074impl<R: Read> Iterator for NamesReader<'_, R> {
1075    type Item = Result<String, Error>;
1076
1077    fn next(&mut self) -> Option<Self::Item> {
1078        if self.max_bytes <= self.read_bytes {
1079            return None;
1080        }
1081        self.cache.clear();
1082        let mut buf = [0; 2];
1083        while self.read_bytes < self.max_bytes {
1084            let r = self.reader.read_exact(&mut buf).map_err(Error::io);
1085            self.read_bytes += 2;
1086            if let Err(e) = r {
1087                return Some(Err(e));
1088            }
1089            let u = u16::from_le_bytes(buf);
1090            if u == 0 {
1091                break;
1092            }
1093            self.cache.push(u);
1094        }
1095
1096        Some(String::from_utf16(&self.cache).map_err(|e| Error::other(e.to_string())))
1097    }
1098}
1099
1100#[derive(Copy, Clone)]
1101struct IndexEntry {
1102    block_index: Option<usize>,
1103    file_index: usize,
1104}
1105
1106/// Reads a 7z archive file.
1107pub struct ArchiveReader<R: Read + Seek> {
1108    source: R,
1109    archive: Archive,
1110    password: Password,
1111    index: HashMap<String, IndexEntry>,
1112}
1113
1114#[cfg(not(target_arch = "wasm32"))]
1115impl ArchiveReader<File> {
1116    /// Opens a 7z archive file at the given `path` and creates a [`ArchiveReader`] to read it.
1117    #[inline]
1118    pub fn open(path: impl AsRef<std::path::Path>, password: Password) -> Result<Self, Error> {
1119        let file = File::open(path.as_ref())
1120            .map_err(|e| Error::file_open(e, path.as_ref().to_string_lossy().to_string()))?;
1121        Self::new(file, password)
1122    }
1123}
1124
1125impl<R: Read + Seek> ArchiveReader<R> {
1126    /// Creates a [`ArchiveReader`] to read a 7z archive file from the given `source` reader.
1127    #[inline]
1128    pub fn new(mut source: R, password: Password) -> Result<Self, Error> {
1129        let archive = Archive::read(&mut source, &password)?;
1130
1131        let mut reader = Self {
1132            source,
1133            archive,
1134            password,
1135            index: HashMap::default(),
1136        };
1137
1138        reader.fill_index();
1139
1140        Ok(reader)
1141    }
1142
1143    #[inline]
1144    pub fn from_archive(archive: Archive, source: R, password: Password) -> Self {
1145        let mut reader = Self {
1146            source,
1147            archive,
1148            password,
1149            index: HashMap::default(),
1150        };
1151
1152        reader.fill_index();
1153
1154        reader
1155    }
1156
1157    fn fill_index(&mut self) {
1158        for (file_index, file) in self.archive.files.iter().enumerate() {
1159            let block_index = self.archive.stream_map.file_block_index[file_index];
1160
1161            self.index.insert(
1162                file.name.clone(),
1163                IndexEntry {
1164                    block_index,
1165                    file_index,
1166                },
1167            );
1168        }
1169    }
1170
1171    #[inline]
1172    pub fn archive(&self) -> &Archive {
1173        &self.archive
1174    }
1175
1176    fn build_decode_stack<'r>(
1177        source: &'r mut R,
1178        archive: &Archive,
1179        block_index: usize,
1180        password: &Password,
1181    ) -> Result<(Box<dyn Read + 'r>, usize), Error> {
1182        let block = &archive.blocks[block_index];
1183        if block.total_input_streams > block.total_output_streams {
1184            return Self::build_decode_stack2(source, archive, block_index, password);
1185        }
1186        let first_pack_stream_index = archive.stream_map.block_first_pack_stream_index[block_index];
1187        let block_offset = SIGNATURE_HEADER_SIZE
1188            + archive.pack_pos
1189            + archive.stream_map.pack_stream_offsets[first_pack_stream_index];
1190
1191        source
1192            .seek(SeekFrom::Start(block_offset))
1193            .map_err(Error::io)?;
1194        let pack_size = archive.pack_sizes[first_pack_stream_index] as usize;
1195
1196        let mut decoder: Box<dyn Read> = Box::new(BoundedReader::new(source, pack_size));
1197        let block = &archive.blocks[block_index];
1198        for (index, coder) in block.ordered_coder_iter() {
1199            if coder.num_in_streams != 1 || coder.num_out_streams != 1 {
1200                return Err(Error::unsupported(
1201                    "Multi input/output stream coders are not yet supported",
1202                ));
1203            }
1204            let next = add_decoder(
1205                decoder,
1206                block.get_unpack_size_at_index(index) as usize,
1207                coder,
1208                password,
1209                MAX_MEM_LIMIT_KB,
1210            )?;
1211            decoder = Box::new(next);
1212        }
1213        if block.has_crc {
1214            decoder = Box::new(Crc32VerifyingReader::new(
1215                decoder,
1216                block.get_unpack_size() as usize,
1217                block.crc,
1218            ));
1219        }
1220
1221        Ok((decoder, pack_size))
1222    }
1223
1224    fn build_decode_stack2<'r>(
1225        source: &'r mut R,
1226        archive: &Archive,
1227        block_index: usize,
1228        password: &Password,
1229    ) -> Result<(Box<dyn Read + 'r>, usize), Error> {
1230        const MAX_CODER_COUNT: usize = 32;
1231        let block = &archive.blocks[block_index];
1232        if block.coders.len() > MAX_CODER_COUNT {
1233            return Err(Error::unsupported(format!(
1234                "Too many coders: {}",
1235                block.coders.len()
1236            )));
1237        }
1238
1239        assert!(block.total_input_streams > block.total_output_streams);
1240        let source = ReaderPointer::new(source);
1241        let first_pack_stream_index = archive.stream_map.block_first_pack_stream_index[block_index];
1242        let start_pos = SIGNATURE_HEADER_SIZE + archive.pack_pos;
1243        let offsets = &archive.stream_map.pack_stream_offsets[first_pack_stream_index..];
1244
1245        let mut sources = Vec::with_capacity(block.packed_streams.len());
1246
1247        for (i, offset) in offsets[..block.packed_streams.len()].iter().enumerate() {
1248            let pack_pos = start_pos + offset;
1249            let pack_size = archive.pack_sizes[first_pack_stream_index + i];
1250            let pack_reader =
1251                SeekableBoundedReader::new(source.clone(), (pack_pos, pack_pos + pack_size));
1252            sources.push(pack_reader);
1253        }
1254
1255        let mut coder_to_stream_map = [usize::MAX; MAX_CODER_COUNT];
1256
1257        let mut si = 0;
1258        for (i, coder) in block.coders.iter().enumerate() {
1259            coder_to_stream_map[i] = si;
1260            si += coder.num_in_streams as usize;
1261        }
1262
1263        let main_coder_index = {
1264            let mut coder_used = [false; MAX_CODER_COUNT];
1265            for bp in block.bind_pairs.iter() {
1266                coder_used[bp.out_index as usize] = true;
1267            }
1268            let mut mci = 0;
1269            for (i, used) in coder_used[..block.coders.len()].iter().enumerate() {
1270                if !used {
1271                    mci = i;
1272                    break;
1273                }
1274            }
1275            mci
1276        };
1277
1278        let id = block.coders[main_coder_index].encoder_method_id();
1279        if id != EncoderMethod::ID_BCJ2 {
1280            return Err(Error::unsupported(format!("Unsupported method: {id:?}")));
1281        }
1282
1283        let num_in_streams = block.coders[main_coder_index].num_in_streams as usize;
1284        let mut inputs: Vec<Box<dyn Read>> = Vec::with_capacity(num_in_streams);
1285        let start_i = coder_to_stream_map[main_coder_index];
1286        for i in start_i..num_in_streams + start_i {
1287            inputs.push(Self::get_in_stream(
1288                block,
1289                &sources,
1290                &coder_to_stream_map,
1291                password,
1292                i,
1293            )?);
1294        }
1295        let mut decoder: Box<dyn Read> = Box::new(crate::filter::bcj2::BCJ2Reader::new(
1296            inputs,
1297            block.get_unpack_size(),
1298        ));
1299        if block.has_crc {
1300            decoder = Box::new(Crc32VerifyingReader::new(
1301                decoder,
1302                block.get_unpack_size() as usize,
1303                block.crc,
1304            ));
1305        }
1306        Ok((
1307            decoder,
1308            archive.pack_sizes[first_pack_stream_index] as usize,
1309        ))
1310    }
1311
1312    fn get_in_stream<'r>(
1313        block: &Block,
1314        sources: &[SeekableBoundedReader<ReaderPointer<'r, R>>],
1315        coder_to_stream_map: &[usize],
1316        password: &Password,
1317
1318        in_stream_index: usize,
1319    ) -> Result<Box<dyn Read + 'r>, Error>
1320    where
1321        R: 'r,
1322    {
1323        let index = block
1324            .packed_streams
1325            .iter()
1326            .position(|&i| i == in_stream_index as u64);
1327        if let Some(index) = index {
1328            return Ok(Box::new(sources[index].clone()));
1329        }
1330
1331        let bp = block
1332            .find_bind_pair_for_in_stream(in_stream_index)
1333            .ok_or_else(|| {
1334                Error::other(format!(
1335                    "Couldn't find bind pair for stream {in_stream_index}"
1336                ))
1337            })?;
1338        let index = block.bind_pairs[bp].out_index as usize;
1339
1340        Self::get_in_stream2(block, sources, coder_to_stream_map, password, index)
1341    }
1342
1343    fn get_in_stream2<'r>(
1344        block: &Block,
1345        sources: &[SeekableBoundedReader<ReaderPointer<'r, R>>],
1346        coder_to_stream_map: &[usize],
1347        password: &Password,
1348        in_stream_index: usize,
1349    ) -> Result<Box<dyn Read + 'r>, Error>
1350    where
1351        R: 'r,
1352    {
1353        let coder = &block.coders[in_stream_index];
1354        let start_index = coder_to_stream_map[in_stream_index];
1355        if start_index == usize::MAX {
1356            return Err(Error::other("in_stream_index out of range"));
1357        }
1358        let uncompressed_len = block.unpack_sizes[in_stream_index] as usize;
1359        if coder.num_in_streams == 1 {
1360            let input =
1361                Self::get_in_stream(block, sources, coder_to_stream_map, password, start_index)?;
1362
1363            let decoder = add_decoder(input, uncompressed_len, coder, password, MAX_MEM_LIMIT_KB)?;
1364            return Ok(Box::new(decoder));
1365        }
1366        Err(Error::unsupported(
1367            "Multi input stream coders are not yet supported",
1368        ))
1369    }
1370
1371    /// Takes a closure to decode each files in the archive.
1372    ///
1373    /// Attention about solid archive:
1374    /// When decoding a solid archive, the data to be decompressed depends on the data in front of it,
1375    /// you cannot simply skip the previous data and only decompress the data in the back.
1376    pub fn for_each_entries<F: FnMut(&ArchiveEntry, &mut dyn Read) -> Result<bool, Error>>(
1377        &mut self,
1378        mut each: F,
1379    ) -> Result<(), Error> {
1380        let block_count = self.archive.blocks.len();
1381        for block_index in 0..block_count {
1382            let forder_dec =
1383                BlockDecoder::new(block_index, &self.archive, &self.password, &mut self.source);
1384            forder_dec.for_each_entries(&mut each)?;
1385        }
1386        // decode empty files
1387        for file_index in 0..self.archive.files.len() {
1388            let block_index = self.archive.stream_map.file_block_index[file_index];
1389            if block_index.is_none() {
1390                let file = &self.archive.files[file_index];
1391                let empty_reader: &mut dyn Read = &mut ([0u8; 0].as_slice());
1392                if !each(file, empty_reader)? {
1393                    return Ok(());
1394                }
1395            }
1396        }
1397        Ok(())
1398    }
1399
1400    /// Returns the data of a file with the given path inside the archive.
1401    ///
1402    /// # Notice
1403    /// This function is very inefficient when used with solid archives, since
1404    /// it needs to decode all data before the actual file.
1405    pub fn read_file(&mut self, name: &str) -> Result<Vec<u8>, Error> {
1406        let index_entry = *self.index.get(name).ok_or(Error::FileNotFound)?;
1407        let file = &self.archive.files[index_entry.file_index];
1408
1409        if !file.has_stream {
1410            return Ok(Vec::new());
1411        }
1412
1413        let block_index = index_entry
1414            .block_index
1415            .ok_or_else(|| Error::other("File has no associated block"))?;
1416
1417        match self.archive.is_solid {
1418            true => {
1419                let mut result = None;
1420                let target_file_ptr = file as *const _;
1421
1422                BlockDecoder::new(block_index, &self.archive, &self.password, &mut self.source)
1423                    .for_each_entries(&mut |archive_entry, reader| {
1424                        let mut data = Vec::with_capacity(archive_entry.size as usize);
1425                        reader.read_to_end(&mut data)?;
1426
1427                        if std::ptr::eq(archive_entry, target_file_ptr) {
1428                            result = Some(data);
1429                            Ok(false)
1430                        } else {
1431                            Ok(true)
1432                        }
1433                    })?;
1434
1435                result.ok_or(Error::FileNotFound)
1436            }
1437            false => {
1438                let pack_index = self.archive.stream_map.block_first_pack_stream_index[block_index];
1439                let pack_offset = self.archive.stream_map.pack_stream_offsets[pack_index];
1440                let block_offset = SIGNATURE_HEADER_SIZE + self.archive.pack_pos + pack_offset;
1441
1442                self.source.seek(SeekFrom::Start(block_offset))?;
1443
1444                let (mut block_reader, _size) = Self::build_decode_stack(
1445                    &mut self.source,
1446                    &self.archive,
1447                    block_index,
1448                    &self.password,
1449                )?;
1450
1451                let mut data = Vec::with_capacity(file.size as usize);
1452                let mut decoder: Box<dyn Read> =
1453                    Box::new(BoundedReader::new(&mut block_reader, file.size as usize));
1454
1455                if file.has_crc {
1456                    decoder = Box::new(Crc32VerifyingReader::new(
1457                        decoder,
1458                        file.size as usize,
1459                        file.crc,
1460                    ));
1461                }
1462
1463                decoder.read_to_end(&mut data)?;
1464
1465                Ok(data)
1466            }
1467        }
1468    }
1469
1470    /// Get the compression method(s) used for a specific file in the archive.
1471    pub fn file_compression_methods(
1472        &self,
1473        file_name: &str,
1474        methods: &mut Vec<EncoderMethod>,
1475    ) -> Result<(), Error> {
1476        let index_entry = self.index.get(file_name).ok_or(Error::FileNotFound)?;
1477        let file = &self.archive.files[index_entry.file_index];
1478
1479        if !file.has_stream {
1480            return Ok(());
1481        }
1482
1483        let block_index = index_entry
1484            .block_index
1485            .ok_or_else(|| Error::other("File has no associated block"))?;
1486
1487        let block = self
1488            .archive
1489            .blocks
1490            .get(block_index)
1491            .ok_or_else(|| Error::other("Block not found"))?;
1492
1493        block
1494            .coders
1495            .iter()
1496            .filter_map(|coder| EncoderMethod::by_id(coder.encoder_method_id()))
1497            .for_each(|method| {
1498                methods.push(method);
1499            });
1500
1501        Ok(())
1502    }
1503}
1504
1505pub struct BlockDecoder<'a, R: Read + Seek> {
1506    block_index: usize,
1507    archive: &'a Archive,
1508    password: &'a Password,
1509    source: &'a mut R,
1510}
1511
1512impl<'a, R: Read + Seek> BlockDecoder<'a, R> {
1513    pub fn new(
1514        block_index: usize,
1515        archive: &'a Archive,
1516        password: &'a Password,
1517        source: &'a mut R,
1518    ) -> Self {
1519        Self {
1520            block_index,
1521            archive,
1522            password,
1523            source,
1524        }
1525    }
1526
1527    pub fn entries(&self) -> &[ArchiveEntry] {
1528        let start = self.archive.stream_map.block_first_file_index[self.block_index];
1529        let file_count = self.archive.blocks[self.block_index].num_unpack_sub_streams;
1530        &self.archive.files[start..(file_count + start)]
1531    }
1532
1533    pub fn entry_count(&self) -> usize {
1534        self.archive.blocks[self.block_index].num_unpack_sub_streams
1535    }
1536
1537    /// Takes a closure to decode each files in this block.
1538    ///
1539    /// When decoding files in a block, the data to be decompressed depends on the data in front of
1540    /// it, you cannot simply skip the previous data and only decompress the data in the back.
1541    ///
1542    /// Non-solid archives use one block per file and allow more effective decoding of single files.
1543    pub fn for_each_entries<F: FnMut(&ArchiveEntry, &mut dyn Read) -> Result<bool, Error>>(
1544        self,
1545        each: &mut F,
1546    ) -> Result<bool, Error> {
1547        let Self {
1548            block_index,
1549            archive,
1550            password,
1551            source,
1552        } = self;
1553        let (mut block_reader, _size) =
1554            ArchiveReader::build_decode_stack(source, archive, block_index, password)?;
1555        let start = archive.stream_map.block_first_file_index[block_index];
1556        let file_count = archive.blocks[block_index].num_unpack_sub_streams;
1557
1558        for file_index in start..(file_count + start) {
1559            let file = &archive.files[file_index];
1560            if file.has_stream && file.size > 0 {
1561                let mut decoder: Box<dyn Read> =
1562                    Box::new(BoundedReader::new(&mut block_reader, file.size as usize));
1563                if file.has_crc {
1564                    decoder = Box::new(Crc32VerifyingReader::new(
1565                        decoder,
1566                        file.size as usize,
1567                        file.crc,
1568                    ));
1569                }
1570                if !each(file, &mut decoder)
1571                    .map_err(|e| e.maybe_bad_password(!self.password.is_empty()))?
1572                {
1573                    return Ok(false);
1574                }
1575            } else {
1576                let empty_reader: &mut dyn Read = &mut ([0u8; 0].as_slice());
1577                if !each(file, empty_reader)? {
1578                    return Ok(false);
1579                }
1580            }
1581        }
1582        Ok(true)
1583    }
1584}
1585
1586#[derive(Debug)]
1587#[repr(transparent)]
1588struct ReaderPointer<'a, R>(Rc<RefCell<&'a mut R>>);
1589
1590impl<R> Clone for ReaderPointer<'_, R> {
1591    fn clone(&self) -> Self {
1592        Self(Rc::clone(&self.0))
1593    }
1594}
1595
1596impl<'a, R> ReaderPointer<'a, R> {
1597    fn new(reader: &'a mut R) -> Self {
1598        Self(Rc::new(RefCell::new(reader)))
1599    }
1600}
1601
1602impl<R: Read> Read for ReaderPointer<'_, R> {
1603    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1604        self.0.borrow_mut().read(buf)
1605    }
1606}
1607
1608impl<R: Seek> Seek for ReaderPointer<'_, R> {
1609    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1610        self.0.borrow_mut().seek(pos)
1611    }
1612}