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