sevenz_rust2/
reader.rs

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