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