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 #[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 #[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 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 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 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 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
1110pub 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 #[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 #[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 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 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 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 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 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}