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("Alternative methods are unsupported, please report. The reference implementation doesn't support them either."));
926 }
927 }
928 folder.coders = coders;
929 let total_in_streams = assert_usize(total_in_streams, "totalInStreams")?;
930 let total_out_streams = assert_usize(total_out_streams, "totalOutStreams")?;
931 folder.total_input_streams = total_in_streams;
932 folder.total_output_streams = total_out_streams;
933
934 if total_out_streams == 0 {
935 return Err(Error::other("Total output streams can't be 0"));
936 }
937 let num_bind_pairs = total_out_streams - 1;
938 let mut bind_pairs = Vec::with_capacity(num_bind_pairs);
939 for _ in 0..num_bind_pairs {
940 let bp = BindPair {
941 in_index: read_u64(header)?,
942 out_index: read_u64(header)?,
943 };
944 bind_pairs.push(bp);
945 }
946 folder.bind_pairs = bind_pairs;
947
948 if total_in_streams < num_bind_pairs {
949 return Err(Error::other(
950 "Total input streams can't be less than the number of bind pairs",
951 ));
952 }
953 let num_packed_streams = total_in_streams - num_bind_pairs;
954 let mut packed_streams = vec![0; num_packed_streams];
955 if num_packed_streams == 1 {
956 let mut index = u64::MAX;
957 for i in 0..total_in_streams {
958 if folder.find_bind_pair_for_in_stream(i).is_none() {
959 index = i as u64;
960 break;
961 }
962 }
963 if index == u64::MAX {
964 return Err(Error::other("Couldn't find stream's bind pair index"));
965 }
966 packed_streams[0] = index;
967 } else {
968 for packed_stream in packed_streams.iter_mut() {
969 *packed_stream = read_u64(header)?;
970 }
971 }
972 folder.packed_streams = packed_streams;
973
974 Ok(folder)
975 }
976}
977
978#[inline]
979fn read_usize<R: Read>(reader: &mut R, field: &str) -> Result<usize, Error> {
980 let size = read_u64(reader)?;
981 assert_usize(size, field)
982}
983
984#[inline]
985fn assert_usize(size: u64, field: &str) -> Result<usize, Error> {
986 if size > usize::MAX as u64 {
987 return Err(Error::other(format!("Cannot handle {} {}", field, size)));
988 }
989 Ok(size as usize)
990}
991
992#[inline]
993fn read_u64le<R: Read>(reader: &mut R) -> Result<u64, Error> {
994 let mut buf = [0; 8];
995 reader.read_exact(&mut buf).map_err(Error::io)?;
996 Ok(u64::from_le_bytes(buf))
997}
998
999fn read_u64<R: Read>(reader: &mut R) -> Result<u64, Error> {
1000 let first = read_u8(reader)? as u64;
1001 let mut mask = 0x80_u64;
1002 let mut value = 0;
1003 for i in 0..8 {
1004 if (first & mask) == 0 {
1005 return Ok(value | ((first & (mask - 1)) << (8 * i)));
1006 }
1007 let b = read_u8(reader)? as u64;
1008 value |= b << (8 * i);
1009 mask >>= 1;
1010 }
1011 Ok(value)
1012}
1013
1014#[inline(always)]
1015fn read_u32<R: Read>(reader: &mut R) -> Result<u32, Error> {
1016 let mut buf = [0; 4];
1017 reader.read_exact(&mut buf).map_err(Error::io)?;
1018 Ok(u32::from_le_bytes(buf))
1019}
1020
1021#[inline(always)]
1022fn read_u8<R: Read>(reader: &mut R) -> Result<u8, Error> {
1023 let mut buf = [0];
1024 reader.read_exact(&mut buf).map_err(Error::io)?;
1025 Ok(buf[0])
1026}
1027
1028fn read_all_or_bits<R: Read>(header: &mut R, size: usize) -> Result<BitSet, Error> {
1029 let all = read_u8(header)?;
1030 if all != 0 {
1031 let mut bits = BitSet::with_capacity(size);
1032 for i in 0..size {
1033 bits.insert(i);
1034 }
1035 Ok(bits)
1036 } else {
1037 read_bits(header, size)
1038 }
1039}
1040
1041fn read_bits<R: Read>(header: &mut R, size: usize) -> Result<BitSet, Error> {
1042 let mut bits = BitSet::with_capacity(size);
1043 let mut mask = 0u32;
1044 let mut cache = 0u32;
1045 for i in 0..size {
1046 if mask == 0 {
1047 mask = 0x80;
1048 cache = read_u8(header)? as u32;
1049 }
1050 if (cache & mask) != 0 {
1051 bits.insert(i);
1052 }
1053 mask >>= 1;
1054 }
1055 Ok(bits)
1056}
1057
1058struct NamesReader<'a, R: Read> {
1059 max_bytes: usize,
1060 read_bytes: usize,
1061 cache: Vec<u16>,
1062 reader: &'a mut R,
1063}
1064
1065impl<'a, R: Read> NamesReader<'a, R> {
1066 fn new(reader: &'a mut R, max_bytes: usize) -> Self {
1067 Self {
1068 max_bytes,
1069 reader,
1070 read_bytes: 0,
1071 cache: Vec::with_capacity(16),
1072 }
1073 }
1074}
1075
1076impl<R: Read> Iterator for NamesReader<'_, R> {
1077 type Item = Result<String, Error>;
1078
1079 fn next(&mut self) -> Option<Self::Item> {
1080 if self.max_bytes <= self.read_bytes {
1081 return None;
1082 }
1083 self.cache.clear();
1084 let mut buf = [0; 2];
1085 while self.read_bytes < self.max_bytes {
1086 let r = self.reader.read_exact(&mut buf).map_err(Error::io);
1087 self.read_bytes += 2;
1088 if let Err(e) = r {
1089 return Some(Err(e));
1090 }
1091 let u = u16::from_le_bytes(buf);
1092 if u == 0 {
1093 break;
1094 }
1095 self.cache.push(u);
1096 }
1097
1098 Some(String::from_utf16(&self.cache).map_err(|e| Error::other(e.to_string())))
1099 }
1100}
1101
1102#[derive(Copy, Clone)]
1103struct IndexEntry {
1104 folder_index: Option<usize>,
1105 file_index: usize,
1106}
1107
1108pub struct SevenZReader<R: Read + Seek> {
1110 source: R,
1111 archive: Archive,
1112 password: Vec<u8>,
1113 index: HashMap<String, IndexEntry>,
1114}
1115
1116#[cfg(not(target_arch = "wasm32"))]
1117impl SevenZReader<File> {
1118 #[inline]
1120 pub fn open(path: impl AsRef<std::path::Path>, password: Password) -> Result<Self, Error> {
1121 let file = File::open(path.as_ref())
1122 .map_err(|e| Error::file_open(e, path.as_ref().to_string_lossy().to_string()))?;
1123 Self::new(file, password)
1124 }
1125}
1126
1127impl<R: Read + Seek> SevenZReader<R> {
1128 #[inline]
1130 pub fn new(mut source: R, password: Password) -> Result<Self, Error> {
1131 let password = password.to_vec();
1132 let archive = Archive::read(&mut source, &password)?;
1133
1134 let mut reader = Self {
1135 source,
1136 archive,
1137 password,
1138 index: HashMap::default(),
1139 };
1140
1141 reader.fill_index();
1142
1143 Ok(reader)
1144 }
1145
1146 #[inline]
1147 pub fn from_archive(archive: Archive, source: R, password: Password) -> Self {
1148 let mut reader = Self {
1149 source,
1150 archive,
1151 password: password.to_vec(),
1152 index: HashMap::default(),
1153 };
1154
1155 reader.fill_index();
1156
1157 reader
1158 }
1159
1160 fn fill_index(&mut self) {
1161 for (file_index, file) in self.archive.files.iter().enumerate() {
1162 let folder_index = self.archive.stream_map.file_folder_index[file_index];
1163
1164 self.index.insert(
1165 file.name.clone(),
1166 IndexEntry {
1167 folder_index,
1168 file_index,
1169 },
1170 );
1171 }
1172 }
1173
1174 #[inline]
1175 pub fn archive(&self) -> &Archive {
1176 &self.archive
1177 }
1178
1179 fn build_decode_stack<'r>(
1180 source: &'r mut R,
1181 archive: &Archive,
1182 folder_index: usize,
1183 password: &[u8],
1184 ) -> Result<(Box<dyn Read + 'r>, usize), Error> {
1185 let folder = &archive.folders[folder_index];
1186 if folder.total_input_streams > folder.total_output_streams {
1187 return Self::build_decode_stack2(source, archive, folder_index, password);
1188 }
1189 let first_pack_stream_index =
1190 archive.stream_map.folder_first_pack_stream_index[folder_index];
1191 let folder_offset = SIGNATURE_HEADER_SIZE
1192 + archive.pack_pos
1193 + archive.stream_map.pack_stream_offsets[first_pack_stream_index];
1194
1195 source
1196 .seek(SeekFrom::Start(folder_offset))
1197 .map_err(Error::io)?;
1198 let pack_size = archive.pack_sizes[first_pack_stream_index] as usize;
1199
1200 let mut decoder: Box<dyn Read> = Box::new(BoundedReader::new(source, pack_size));
1201 let folder = &archive.folders[folder_index];
1202 for (index, coder) in folder.ordered_coder_iter() {
1203 if coder.num_in_streams != 1 || coder.num_out_streams != 1 {
1204 return Err(Error::unsupported(
1205 "Multi input/output stream coders are not yet supported",
1206 ));
1207 }
1208 let next = add_decoder(
1209 decoder,
1210 folder.get_unpack_size_at_index(index) as usize,
1211 coder,
1212 password,
1213 MAX_MEM_LIMIT_KB,
1214 )?;
1215 decoder = Box::new(next);
1216 }
1217 if folder.has_crc {
1218 decoder = Box::new(Crc32VerifyingReader::new(
1219 decoder,
1220 folder.get_unpack_size() as usize,
1221 folder.crc,
1222 ));
1223 }
1224
1225 Ok((decoder, pack_size))
1226 }
1227
1228 fn build_decode_stack2<'r>(
1229 source: &'r mut R,
1230 archive: &Archive,
1231 folder_index: usize,
1232 password: &[u8],
1233 ) -> Result<(Box<dyn Read + 'r>, usize), Error> {
1234 const MAX_CODER_COUNT: usize = 32;
1235 let folder = &archive.folders[folder_index];
1236 if folder.coders.len() > MAX_CODER_COUNT {
1237 return Err(Error::unsupported(format!(
1238 "Too many coders: {}",
1239 folder.coders.len()
1240 )));
1241 }
1242
1243 assert!(folder.total_input_streams > folder.total_output_streams);
1244 let source = ReaderPointer::new(source);
1245 let first_pack_stream_index =
1246 archive.stream_map.folder_first_pack_stream_index[folder_index];
1247 let start_pos = SIGNATURE_HEADER_SIZE + archive.pack_pos;
1248 let offsets = &archive.stream_map.pack_stream_offsets[first_pack_stream_index..];
1249
1250 let mut sources = Vec::with_capacity(folder.packed_streams.len());
1251
1252 for (i, offset) in offsets[..folder.packed_streams.len()].iter().enumerate() {
1253 let pack_pos = start_pos + offset;
1254 let pack_size = archive.pack_sizes[first_pack_stream_index + i];
1255 let pack_reader =
1256 SeekableBoundedReader::new(source.clone(), (pack_pos, pack_pos + pack_size));
1257 sources.push(pack_reader);
1258 }
1259
1260 let mut coder_to_stream_map = [usize::MAX; MAX_CODER_COUNT];
1261
1262 let mut si = 0;
1263 for (i, coder) in folder.coders.iter().enumerate() {
1264 coder_to_stream_map[i] = si;
1265 si += coder.num_in_streams as usize;
1266 }
1267
1268 let main_coder_index = {
1269 let mut coder_used = [false; MAX_CODER_COUNT];
1270 for bp in folder.bind_pairs.iter() {
1271 coder_used[bp.out_index as usize] = true;
1272 }
1273 let mut mci = 0;
1274 for (i, used) in coder_used[..folder.coders.len()].iter().enumerate() {
1275 if !used {
1276 mci = i;
1277 break;
1278 }
1279 }
1280 mci
1281 };
1282
1283 let id = folder.coders[main_coder_index].decompression_method_id();
1284 if id != SevenZMethod::ID_BCJ2 {
1285 return Err(Error::unsupported(format!("Unsupported method: {:?}", id)));
1286 }
1287
1288 let num_in_streams = folder.coders[main_coder_index].num_in_streams as usize;
1289 let mut inputs: Vec<Box<dyn Read>> = Vec::with_capacity(num_in_streams);
1290 let start_i = coder_to_stream_map[main_coder_index];
1291 for i in start_i..num_in_streams + start_i {
1292 inputs.push(Self::get_in_stream(
1293 folder,
1294 &sources,
1295 &coder_to_stream_map,
1296 password,
1297 i,
1298 )?);
1299 }
1300 let mut decoder: Box<dyn Read> = Box::new(crate::bcj2::BCJ2Reader::new(
1301 inputs,
1302 folder.get_unpack_size(),
1303 ));
1304 if folder.has_crc {
1305 decoder = Box::new(Crc32VerifyingReader::new(
1306 decoder,
1307 folder.get_unpack_size() as usize,
1308 folder.crc,
1309 ));
1310 }
1311 Ok((
1312 decoder,
1313 archive.pack_sizes[first_pack_stream_index] as usize,
1314 ))
1315 }
1316
1317 fn get_in_stream<'r>(
1318 folder: &Folder,
1319 sources: &[SeekableBoundedReader<ReaderPointer<'r, R>>],
1320 coder_to_stream_map: &[usize],
1321 password: &[u8],
1322
1323 in_stream_index: usize,
1324 ) -> Result<Box<dyn Read + 'r>, Error>
1325 where
1326 R: 'r,
1327 {
1328 let index = folder
1329 .packed_streams
1330 .iter()
1331 .position(|&i| i == in_stream_index as u64);
1332 if let Some(index) = index {
1333 return Ok(Box::new(sources[index].clone()));
1334 }
1335
1336 let bp = folder
1337 .find_bind_pair_for_in_stream(in_stream_index)
1338 .ok_or_else(|| {
1339 Error::other(format!(
1340 "Couldn't find bind pair for stream {}",
1341 in_stream_index
1342 ))
1343 })?;
1344 let index = folder.bind_pairs[bp].out_index as usize;
1345
1346 Self::get_in_stream2(folder, sources, coder_to_stream_map, password, index)
1347 }
1348
1349 fn get_in_stream2<'r>(
1350 folder: &Folder,
1351 sources: &[SeekableBoundedReader<ReaderPointer<'r, R>>],
1352 coder_to_stream_map: &[usize],
1353 password: &[u8],
1354 in_stream_index: usize,
1355 ) -> Result<Box<dyn Read + 'r>, Error>
1356 where
1357 R: 'r,
1358 {
1359 let coder = &folder.coders[in_stream_index];
1360 let start_index = coder_to_stream_map[in_stream_index];
1361 if start_index == usize::MAX {
1362 return Err(Error::other("in_stream_index out of range"));
1363 }
1364 let uncompressed_len = folder.unpack_sizes[in_stream_index] as usize;
1365 if coder.num_in_streams == 1 {
1366 let input =
1367 Self::get_in_stream(folder, sources, coder_to_stream_map, password, start_index)?;
1368
1369 let decoder = add_decoder(input, uncompressed_len, coder, password, MAX_MEM_LIMIT_KB)?;
1370 return Ok(Box::new(decoder));
1371 }
1372 Err(Error::unsupported(
1373 "Multi input stream coders are not yet supported",
1374 ))
1375 }
1376
1377 pub fn for_each_entries<F: FnMut(&SevenZArchiveEntry, &mut dyn Read) -> Result<bool, Error>>(
1383 &mut self,
1384 mut each: F,
1385 ) -> Result<(), Error> {
1386 let folder_count = self.archive.folders.len();
1387 for folder_index in 0..folder_count {
1388 let forder_dec = BlockDecoder::new(
1389 folder_index,
1390 &self.archive,
1391 &self.password,
1392 &mut self.source,
1393 );
1394 forder_dec.for_each_entries(&mut each)?;
1395 }
1396 for file_index in 0..self.archive.files.len() {
1398 let folder_index = self.archive.stream_map.file_folder_index[file_index];
1399 if folder_index.is_none() {
1400 let file = &self.archive.files[file_index];
1401 let empty_reader: &mut dyn Read = &mut ([0u8; 0].as_slice());
1402 if !each(file, empty_reader)? {
1403 return Ok(());
1404 }
1405 }
1406 }
1407 Ok(())
1408 }
1409
1410 pub fn read_file(&mut self, name: &str) -> Result<Vec<u8>, Error> {
1416 let index_entry = *self.index.get(name).ok_or(Error::FileNotFound)?;
1417 let file = &self.archive.files[index_entry.file_index];
1418
1419 if !file.has_stream {
1420 return Ok(Vec::new());
1421 }
1422
1423 let folder_index = index_entry
1424 .folder_index
1425 .ok_or_else(|| Error::other("File has no associated folder"))?;
1426
1427 match self.archive.is_solid {
1428 true => {
1429 let mut result = None;
1430 let target_file_ptr = file as *const _;
1431
1432 BlockDecoder::new(
1433 folder_index,
1434 &self.archive,
1435 &self.password,
1436 &mut self.source,
1437 )
1438 .for_each_entries(&mut |archive_entry, reader| {
1439 let mut data = Vec::with_capacity(archive_entry.size as usize);
1440 reader.read_to_end(&mut data)?;
1441
1442 if archive_entry as *const _ == target_file_ptr {
1443 result = Some(data);
1444 Ok(false)
1445 } else {
1446 Ok(true)
1447 }
1448 })?;
1449
1450 result.ok_or(Error::FileNotFound)
1451 }
1452 false => {
1453 let pack_index =
1454 self.archive.stream_map.folder_first_pack_stream_index[folder_index];
1455 let pack_offset = self.archive.stream_map.pack_stream_offsets[pack_index];
1456 let folder_offset = SIGNATURE_HEADER_SIZE + self.archive.pack_pos + pack_offset;
1457
1458 self.source.seek(SeekFrom::Start(folder_offset))?;
1459
1460 let (mut folder_reader, _size) = Self::build_decode_stack(
1461 &mut self.source,
1462 &self.archive,
1463 folder_index,
1464 &self.password,
1465 )?;
1466
1467 let mut data = Vec::with_capacity(file.size as usize);
1468 let mut decoder: Box<dyn Read> =
1469 Box::new(BoundedReader::new(&mut folder_reader, file.size as usize));
1470
1471 if file.has_crc {
1472 decoder = Box::new(Crc32VerifyingReader::new(
1473 decoder,
1474 file.size as usize,
1475 file.crc,
1476 ));
1477 }
1478
1479 decoder.read_to_end(&mut data)?;
1480
1481 Ok(data)
1482 }
1483 }
1484 }
1485
1486 pub fn file_compression_methods(
1488 &self,
1489 file_name: &str,
1490 methods: &mut Vec<SevenZMethod>,
1491 ) -> Result<(), Error> {
1492 let index_entry = self.index.get(file_name).ok_or(Error::FileNotFound)?;
1493 let file = &self.archive.files[index_entry.file_index];
1494
1495 if !file.has_stream {
1496 return Ok(());
1497 }
1498
1499 let folder_index = index_entry
1500 .folder_index
1501 .ok_or_else(|| Error::other("File has no associated folder"))?;
1502
1503 let folder = self
1504 .archive
1505 .folders
1506 .get(folder_index)
1507 .ok_or_else(|| Error::other("Folder not found"))?;
1508
1509 folder
1510 .coders
1511 .iter()
1512 .filter_map(|coder| SevenZMethod::by_id(coder.decompression_method_id()))
1513 .for_each(|method| {
1514 methods.push(method);
1515 });
1516
1517 Ok(())
1518 }
1519}
1520
1521pub struct BlockDecoder<'a, R: Read + Seek> {
1522 folder_index: usize,
1523 archive: &'a Archive,
1524 password: &'a [u8],
1525 source: &'a mut R,
1526}
1527
1528impl<'a, R: Read + Seek> BlockDecoder<'a, R> {
1529 pub fn new(
1530 folder_index: usize,
1531 archive: &'a Archive,
1532 password: &'a [u8],
1533 source: &'a mut R,
1534 ) -> Self {
1535 Self {
1536 folder_index,
1537 archive,
1538 password,
1539 source,
1540 }
1541 }
1542
1543 pub fn entries(&self) -> &[SevenZArchiveEntry] {
1544 let start = self.archive.stream_map.folder_first_file_index[self.folder_index];
1545 let file_count = self.archive.folders[self.folder_index].num_unpack_sub_streams;
1546 &self.archive.files[start..(file_count + start)]
1547 }
1548
1549 pub fn entry_count(&self) -> usize {
1550 self.archive.folders[self.folder_index].num_unpack_sub_streams
1551 }
1552
1553 pub fn for_each_entries<F: FnMut(&SevenZArchiveEntry, &mut dyn Read) -> Result<bool, Error>>(
1560 self,
1561 each: &mut F,
1562 ) -> Result<bool, Error> {
1563 let Self {
1564 folder_index,
1565 archive,
1566 password,
1567 source,
1568 } = self;
1569 let (mut folder_reader, _size) =
1570 SevenZReader::build_decode_stack(source, archive, folder_index, password)?;
1571 let start = archive.stream_map.folder_first_file_index[folder_index];
1572 let file_count = archive.folders[folder_index].num_unpack_sub_streams;
1573
1574 for file_index in start..(file_count + start) {
1575 let file = &archive.files[file_index];
1576 if file.has_stream && file.size > 0 {
1577 let mut decoder: Box<dyn Read> =
1578 Box::new(BoundedReader::new(&mut folder_reader, file.size as usize));
1579 if file.has_crc {
1580 decoder = Box::new(Crc32VerifyingReader::new(
1581 decoder,
1582 file.size as usize,
1583 file.crc,
1584 ));
1585 }
1586 if !each(file, &mut decoder)
1587 .map_err(|e| e.maybe_bad_password(!self.password.is_empty()))?
1588 {
1589 return Ok(false);
1590 }
1591 } else {
1592 let empty_reader: &mut dyn Read = &mut ([0u8; 0].as_slice());
1593 if !each(file, empty_reader)? {
1594 return Ok(false);
1595 }
1596 }
1597 }
1598 Ok(true)
1599 }
1600}
1601
1602#[derive(Debug)]
1603#[repr(transparent)]
1604struct ReaderPointer<'a, R>(Rc<RefCell<&'a mut R>>);
1605
1606impl<R> Clone for ReaderPointer<'_, R> {
1607 fn clone(&self) -> Self {
1608 Self(Rc::clone(&self.0))
1609 }
1610}
1611
1612impl<'a, R> ReaderPointer<'a, R> {
1613 fn new(reader: &'a mut R) -> Self {
1614 Self(Rc::new(RefCell::new(reader)))
1615 }
1616}
1617
1618impl<R: Read> Read for ReaderPointer<'_, R> {
1619 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
1620 self.0.borrow_mut().read(buf)
1621 }
1622}
1623
1624impl<R: Seek> Seek for ReaderPointer<'_, R> {
1625 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
1626 self.0.borrow_mut().seek(pos)
1627 }
1628}