sevenz_rust2/
reader.rs

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