1mod counting_writer;
2#[cfg(all(feature = "util", not(target_arch = "wasm32")))]
3mod lazy_file_reader;
4mod pack_info;
5mod seq_reader;
6mod source_reader;
7mod unpack_info;
8
9use std::{
10 cell::Cell,
11 io::{Read, Seek, Write},
12 rc::Rc,
13 sync::Arc,
14};
15#[cfg(not(target_arch = "wasm32"))]
16use std::{fs::File, path::Path};
17
18pub(crate) use counting_writer::CountingWriter;
19use crc32fast::Hasher;
20
21#[cfg(all(feature = "util", not(target_arch = "wasm32")))]
22pub(crate) use self::lazy_file_reader::LazyFileReader;
23pub(crate) use self::seq_reader::SeqReader;
24pub use self::source_reader::SourceReader;
25use self::{pack_info::PackInfo, unpack_info::UnpackInfo};
26use crate::{
27 ArchiveEntry, AutoFinish, AutoFinisher, ByteWriter, Error,
28 archive::*,
29 bitset::{BitSet, write_bit_set},
30 encoder,
31};
32
33macro_rules! write_times {
34 ($fn_name:tt, $nid:expr, $has_time:tt, $time:tt) => {
36 write_times!($fn_name, $nid, $has_time, $time, write_u64);
37 };
38 ($fn_name:tt, $nid:expr, $has_time:tt, $time:tt, $write_fn:tt) => {
39 fn $fn_name<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
40 let mut num = 0;
41 for entry in self.files.iter() {
42 if entry.$has_time {
43 num += 1;
44 }
45 }
46 if num > 0 {
47 header.write_u8($nid)?;
48 let mut temp: Vec<u8> = Vec::with_capacity(128);
49 let mut out = &mut temp;
50 if num != self.files.len() {
51 out.write_u8(0)?;
52 let mut times = BitSet::with_capacity(self.files.len());
53 for i in 0..self.files.len() {
54 if self.files[i].$has_time {
55 times.insert(i);
56 }
57 }
58 write_bit_set(&mut out, ×)?;
59 } else {
60 out.write_u8(1)?;
61 }
62 out.write_u8(0)?;
63 for file in self.files.iter() {
64 if file.$has_time {
65 out.$write_fn((file.$time).into())?;
66 }
67 }
68 out.flush()?;
69 write_u64(header, temp.len() as u64)?;
70 header.write_all(&temp)?;
71 }
72 Ok(())
73 }
74 };
75}
76
77type Result<T> = std::result::Result<T, Error>;
78
79pub struct ArchiveWriter<W: Write> {
81 output: W,
82 files: Vec<ArchiveEntry>,
83 content_methods: Arc<Vec<EncoderConfiguration>>,
84 pack_info: PackInfo,
85 unpack_info: UnpackInfo,
86 encrypt_header: bool,
87}
88
89#[cfg(not(target_arch = "wasm32"))]
90impl ArchiveWriter<File> {
91 pub fn create(path: impl AsRef<Path>) -> Result<Self> {
93 let file = File::create(path.as_ref())
94 .map_err(|e| Error::file_open(e, path.as_ref().to_string_lossy().to_string()))?;
95 Self::new(file)
96 }
97}
98
99fn entries_names(entries: &[ArchiveEntry]) -> String {
102 let mut names = String::with_capacity(512);
103 for ele in entries.iter() {
104 names.push_str(&ele.name);
105 names.push(';');
106 if names.len() > 512 {
107 break;
108 }
109 }
110 names
111}
112
113impl<W: Write + Seek> ArchiveWriter<W> {
114 pub fn new(mut writer: W) -> Result<Self> {
116 writer.seek(std::io::SeekFrom::Start(SIGNATURE_HEADER_SIZE))?;
117
118 Ok(Self {
119 output: writer,
120 files: Default::default(),
121 content_methods: Arc::new(vec![EncoderConfiguration::new(EncoderMethod::LZMA2)]),
122 pack_info: Default::default(),
123 unpack_info: Default::default(),
124 encrypt_header: true,
125 })
126 }
127
128 pub fn auto_finish(self) -> AutoFinisher<Self> {
130 AutoFinisher(Some(self))
131 }
132
133 pub fn set_content_methods(&mut self, content_methods: Vec<EncoderConfiguration>) -> &mut Self {
135 if content_methods.is_empty() {
136 return self;
137 }
138 self.content_methods = Arc::new(content_methods);
139 self
140 }
141
142 pub fn set_encrypt_header(&mut self, enabled: bool) {
144 self.encrypt_header = enabled;
145 }
146
147 pub fn push_archive_entry<R: Read>(
167 &mut self,
168 mut entry: ArchiveEntry,
169 reader: Option<R>,
170 ) -> Result<&ArchiveEntry> {
171 if !entry.is_directory
172 && let Some(mut r) = reader
173 {
174 let mut compressed_len = 0;
175 let mut compressed = CompressWrapWriter::new(&mut self.output, &mut compressed_len);
176
177 let mut more_sizes: Vec<Rc<Cell<usize>>> =
178 Vec::with_capacity(self.content_methods.len() - 1);
179
180 let (crc, size) = {
181 let mut w =
182 Self::create_writer(&self.content_methods, &mut compressed, &mut more_sizes)?;
183 let mut write_len = 0;
184 let mut w = CompressWrapWriter::new(&mut w, &mut write_len);
185 let mut buf = [0u8; 4096];
186 loop {
187 match r.read(&mut buf) {
188 Ok(n) => {
189 if n == 0 {
190 break;
191 }
192 w.write_all(&buf[..n]).map_err(|e| {
193 Error::io_msg(e, format!("Encode entry:{}", entry.name()))
194 })?;
195 }
196 Err(e) => {
197 return Err(Error::io_msg(e, format!("Encode entry:{}", entry.name())));
198 }
199 }
200 }
201 w.flush()
202 .map_err(|e| Error::io_msg(e, format!("Encode entry:{}", entry.name())))?;
203 w.write(&[])
204 .map_err(|e| Error::io_msg(e, format!("Encode entry:{}", entry.name())))?;
205
206 (w.crc_value(), write_len)
207 };
208 let compressed_crc = compressed.crc_value();
209 entry.has_stream = true;
210 entry.size = size as u64;
211 entry.crc = crc as u64;
212 entry.has_crc = true;
213 entry.compressed_crc = compressed_crc as u64;
214 entry.compressed_size = compressed_len as u64;
215 self.pack_info
216 .add_stream(compressed_len as u64, Some(compressed_crc));
217
218 let mut sizes = Vec::with_capacity(more_sizes.len() + 1);
219 sizes.extend(more_sizes.iter().map(|s| s.get() as u64));
220 sizes.push(size as u64);
221
222 self.unpack_info
223 .add(self.content_methods.clone(), sizes, crc);
224
225 self.files.push(entry);
226 return Ok(self.files.last().unwrap());
227 }
228 entry.has_stream = false;
229 entry.size = 0;
230 entry.compressed_size = 0;
231 entry.has_crc = false;
232 self.files.push(entry);
233 Ok(self.files.last().unwrap())
234 }
235
236 pub fn push_prepared_block(&mut self, block: PreparedBlock) -> Result<&mut Self> {
245 if block.is_empty() {
246 return Ok(self);
247 }
248
249 let PreparedBlock {
250 compressed,
251 compressed_crc,
252 entries,
253 methods,
254 sizes,
255 crc,
256 sub_stream_sizes,
257 sub_stream_crcs,
258 } = block;
259
260 let compressed_len = compressed.len() as u64;
261 self.output
262 .write_all(&compressed)
263 .map_err(|e| Error::io_msg(e, "push_prepared_block: write".to_string()))?;
264
265 self.pack_info
266 .add_stream(compressed_len, Some(compressed_crc));
267 self.unpack_info.add_multiple(
268 methods,
269 sizes,
270 crc,
271 entries.len() as u64,
272 sub_stream_sizes,
273 sub_stream_crcs,
274 );
275 self.files.extend(entries);
276 Ok(self)
277 }
278
279 pub fn push_raw_block<R: Read + Seek>(
299 &mut self,
300 archive: &Archive,
301 block_index: usize,
302 source: &mut R,
303 mut rename: impl FnMut(&ArchiveEntry) -> String,
304 ) -> Result<&mut Self> {
305 let block = archive
306 .blocks
307 .get(block_index)
308 .ok_or_else(|| Error::other(format!("push_raw_block: no block {block_index}")))?;
309 let map = &archive.stream_map;
310 let unmapped = || {
313 Error::other(format!(
314 "push_raw_block: block {block_index} is missing from the stream map"
315 ))
316 };
317
318 let first_sub_stream = *map
320 .block_first_sub_stream_index
321 .get(block_index)
322 .ok_or_else(unmapped)?;
323 let sub_streams = first_sub_stream..first_sub_stream + block.num_unpack_sub_streams;
324 let info = archive.sub_streams_info.as_ref();
325 let mut sub_stream_sizes = Vec::with_capacity(sub_streams.len());
326 let mut sub_stream_crcs = Vec::with_capacity(sub_streams.len());
327 for index in sub_streams {
328 let crc = match info {
329 Some(info) if info.has_crc.contains(index) => info.crcs[index] as u32,
330 _ if block.num_unpack_sub_streams == 1 && block.has_crc => block.crc as u32,
332 _ => {
333 return Err(Error::other(format!(
334 "push_raw_block: block {block_index} has an entry without a CRC"
335 )));
336 }
337 };
338 sub_stream_crcs.push(crc);
339 sub_stream_sizes
340 .push(info.map_or(block.get_unpack_size(), |info| info.unpack_sizes[index]));
341 }
342
343 let entries: Vec<ArchiveEntry> = archive
346 .files
347 .iter()
348 .zip(&map.file_block_index)
349 .filter(|(entry, block)| entry.has_stream && **block == Some(block_index))
350 .map(|(entry, _)| ArchiveEntry {
351 name: rename(entry),
352 ..entry.clone()
353 })
354 .collect();
355 if entries.len() != block.num_unpack_sub_streams {
356 return Err(Error::other(format!(
357 "push_raw_block: block {block_index} has {} entries for {} sub-streams",
358 entries.len(),
359 block.num_unpack_sub_streams
360 )));
361 }
362
363 let first_pack_stream = *map
365 .block_first_pack_stream_index
366 .get(block_index)
367 .ok_or_else(unmapped)?;
368 for pack_stream in first_pack_stream..first_pack_stream + block.packed_streams.len() {
369 let (Some(&size), Some(&stream_offset)) = (
370 archive.pack_sizes.get(pack_stream),
371 map.pack_stream_offsets.get(pack_stream),
372 ) else {
373 return Err(unmapped());
374 };
375 let offset = SIGNATURE_HEADER_SIZE
377 .checked_add(archive.pack_pos)
378 .and_then(|offset| offset.checked_add(stream_offset))
379 .ok_or_else(|| {
380 Error::other(format!(
381 "push_raw_block: block {block_index} lies past the end of any file"
382 ))
383 })?;
384 source.seek(std::io::SeekFrom::Start(offset))?;
385 let copied = std::io::copy(&mut (&mut *source).take(size), &mut self.output)?;
386 if copied != size {
387 return Err(Error::other(format!(
388 "push_raw_block: block {block_index} is truncated"
389 )));
390 }
391 let crc = archive
392 .pack_crcs_defined
393 .contains(pack_stream)
394 .then(|| archive.pack_crcs[pack_stream] as u32);
395 self.pack_info.add_stream(size, crc);
396 }
397
398 self.unpack_info.add_raw(
399 block,
400 block.num_unpack_sub_streams as u64,
401 sub_stream_sizes,
402 sub_stream_crcs,
403 );
404 self.files.extend(entries);
405 Ok(self)
406 }
407
408 pub fn push_archive_entries<R: Read>(
413 &mut self,
414 entries: Vec<ArchiveEntry>,
415 reader: Vec<SourceReader<R>>,
416 ) -> Result<&mut Self> {
417 let mut entries = entries;
418 let mut r = SeqReader::new(reader);
419 assert_eq!(r.reader_len(), entries.len());
420 let mut compressed_len = 0;
421 let mut compressed = CompressWrapWriter::new(&mut self.output, &mut compressed_len);
422 let content_methods = &self.content_methods;
423 let mut more_sizes: Vec<Rc<Cell<usize>>> = Vec::with_capacity(content_methods.len() - 1);
424
425 let (crc, size) = {
426 let mut w = Self::create_writer(content_methods, &mut compressed, &mut more_sizes)?;
427 let mut write_len = 0;
428 let mut w = CompressWrapWriter::new(&mut w, &mut write_len);
429 let mut buf = [0u8; 4096];
430
431 loop {
432 match r.read(&mut buf) {
433 Ok(n) => {
434 if n == 0 {
435 break;
436 }
437 w.write_all(&buf[..n]).map_err(|e| {
438 Error::io_msg(e, format!("Encode entries:{}", entries_names(&entries)))
439 })?;
440 }
441 Err(e) => {
442 return Err(Error::io_msg(
443 e,
444 format!("Encode entries:{}", entries_names(&entries)),
445 ));
446 }
447 }
448 }
449 w.flush().map_err(|e| {
450 let mut names = String::with_capacity(512);
451 for ele in entries.iter() {
452 names.push_str(&ele.name);
453 names.push(';');
454 if names.len() > 512 {
455 break;
456 }
457 }
458 Error::io_msg(e, format!("Encode entry:{names}"))
459 })?;
460 w.write(&[]).map_err(|e| {
461 Error::io_msg(e, format!("Encode entry:{}", entries_names(&entries)))
462 })?;
463
464 (w.crc_value(), write_len)
465 };
466 let compressed_crc = compressed.crc_value();
467 let mut sub_stream_crcs = Vec::with_capacity(entries.len());
468 let mut sub_stream_sizes = Vec::with_capacity(entries.len());
469 for i in 0..entries.len() {
470 let entry = &mut entries[i];
471 let ri = &r[i];
472 entry.crc = ri.crc_value() as u64;
473 entry.size = ri.read_count() as u64;
474 sub_stream_crcs.push(entry.crc as u32);
475 sub_stream_sizes.push(entry.size);
476 entry.has_crc = true;
477 }
478
479 self.pack_info
480 .add_stream(compressed_len as u64, Some(compressed_crc));
481
482 let mut sizes = Vec::with_capacity(more_sizes.len() + 1);
483 sizes.extend(more_sizes.iter().map(|s| s.get() as u64));
484 sizes.push(size as u64);
485
486 self.unpack_info.add_multiple(
487 content_methods.clone(),
488 sizes,
489 crc,
490 entries.len() as u64,
491 sub_stream_sizes,
492 sub_stream_crcs,
493 );
494
495 self.files.extend(entries);
496 Ok(self)
497 }
498
499 fn create_writer<'a, O: Write + 'a>(
500 methods: &[EncoderConfiguration],
501 out: O,
502 more_sized: &mut Vec<Rc<Cell<usize>>>,
503 ) -> Result<Box<dyn Write + 'a>> {
504 let mut encoder: Box<dyn Write> = Box::new(out);
505 let mut first = true;
506 for mc in methods.iter() {
507 if !first {
508 let counting = CountingWriter::new(encoder);
509 more_sized.push(counting.counting());
510 encoder = Box::new(encoder::add_encoder(counting, mc)?);
511 } else {
512 let counting = CountingWriter::new(encoder);
513 encoder = Box::new(encoder::add_encoder(counting, mc)?);
514 }
515 first = false;
516 }
517 Ok(encoder)
518 }
519
520 pub fn finish(mut self) -> std::io::Result<W> {
522 let mut header: Vec<u8> = Vec::with_capacity(64 * 1024);
523 self.write_encoded_header(&mut header)?;
524 let header_pos = self.output.stream_position()?;
525 self.output.write_all(&header)?;
526 let crc32 = crc32fast::hash(&header);
527 let mut hh = [0u8; SIGNATURE_HEADER_SIZE as usize];
528 {
529 let mut hhw = hh.as_mut_slice();
530 hhw.write_all(SEVEN_Z_SIGNATURE)?;
532 hhw.write_u8(0)?;
534 hhw.write_u8(4)?;
535 hhw.write_u32(0)?;
537
538 hhw.write_u64(header_pos - SIGNATURE_HEADER_SIZE)?;
540 hhw.write_u64(0xFFFFFFFF & header.len() as u64)?;
541 hhw.write_u32(crc32)?;
542 }
543 let crc32 = crc32fast::hash(&hh[12..]);
544 hh[8..12].copy_from_slice(&crc32.to_le_bytes());
545
546 self.output.seek(std::io::SeekFrom::Start(0))?;
547 self.output.write_all(&hh)?;
548 self.output.flush()?;
549 Ok(self.output)
550 }
551
552 fn write_header<H: Write>(&mut self, header: &mut H) -> std::io::Result<()> {
553 header.write_u8(K_HEADER)?;
554 header.write_u8(K_MAIN_STREAMS_INFO)?;
555 self.write_streams_info(header)?;
556 self.write_files_info(header)?;
557 header.write_u8(K_END)?;
558 Ok(())
559 }
560
561 fn write_encoded_header<H: Write>(&mut self, header: &mut H) -> std::io::Result<()> {
562 let mut raw_header = Vec::with_capacity(64 * 1024);
563 self.write_header(&mut raw_header)?;
564 let mut pack_info = PackInfo::default();
565
566 let position = self.output.stream_position()?;
567 let pos = position - SIGNATURE_HEADER_SIZE;
568 pack_info.pos = pos;
569
570 let mut more_sizes = vec![];
571 let size = raw_header.len() as u64;
572 let crc32 = crc32fast::hash(&raw_header);
573 let mut methods = vec![];
574
575 let mut must_encrypt_header = false;
576
577 if self.encrypt_header {
578 for conf in self.content_methods.iter() {
579 if conf.method.id() == EncoderMethod::AES256_SHA256.id() {
580 methods.push(conf.clone());
581 must_encrypt_header = true;
582 break;
583 }
584 }
585 }
586
587 methods.push(EncoderConfiguration::new(EncoderMethod::LZMA));
588
589 let methods = Arc::new(methods);
590
591 let mut encoded_data = Vec::with_capacity(size as usize / 2);
592
593 let mut compress_size = 0;
594 let mut compressed = CompressWrapWriter::new(&mut encoded_data, &mut compress_size);
595 {
596 let mut encoder = Self::create_writer(&methods, &mut compressed, &mut more_sizes)
597 .map_err(std::io::Error::other)?;
598 encoder.write_all(&raw_header)?;
599 encoder.flush()?;
600 let _ = encoder.write(&[])?;
601 }
602
603 let compress_crc = compressed.crc_value();
604 let compress_size = *compressed.bytes_written;
605
606 if !must_encrypt_header && compress_size as u64 + 20 >= size {
607 header.write_all(&raw_header)?;
610 return Ok(());
611 }
612 self.output.write_all(&encoded_data[..compress_size])?;
613
614 pack_info.add_stream(compress_size as u64, Some(compress_crc));
615
616 let mut unpack_info = UnpackInfo::default();
617 let mut sizes = Vec::with_capacity(1 + more_sizes.len());
618 sizes.extend(more_sizes.iter().map(|s| s.get() as u64));
619 sizes.push(size);
620 unpack_info.add(methods, sizes, crc32);
621
622 header.write_u8(K_ENCODED_HEADER)?;
623
624 pack_info.write_to(header)?;
625 unpack_info.write_to(header)?;
626 unpack_info.write_substreams(header)?;
627
628 header.write_u8(K_END)?;
629
630 Ok(())
631 }
632
633 fn write_streams_info<H: Write>(&mut self, header: &mut H) -> std::io::Result<()> {
634 if self.pack_info.len() > 0 {
635 self.pack_info.write_to(header)?;
636 self.unpack_info.write_to(header)?;
637 }
638 self.unpack_info.write_substreams(header)?;
639
640 header.write_u8(K_END)?;
641 Ok(())
642 }
643
644 fn write_files_info<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
645 header.write_u8(K_FILES_INFO)?;
646 write_u64(header, self.files.len() as u64)?;
647 self.write_file_empty_streams(header)?;
648 self.write_file_empty_files(header)?;
649 self.write_file_anti_items(header)?;
650 self.write_file_names(header)?;
651 self.write_file_ctimes(header)?;
652 self.write_file_atimes(header)?;
653 self.write_file_mtimes(header)?;
654 self.write_file_windows_attrs(header)?;
655 header.write_u8(K_END)?;
656 Ok(())
657 }
658
659 fn write_file_empty_streams<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
660 let mut has_empty = false;
661 for entry in self.files.iter() {
662 if !entry.has_stream {
663 has_empty = true;
664 break;
665 }
666 }
667 if has_empty {
668 header.write_u8(K_EMPTY_STREAM)?;
669 let mut bitset = BitSet::with_capacity(self.files.len());
670 for (i, entry) in self.files.iter().enumerate() {
671 if !entry.has_stream {
672 bitset.insert(i);
673 }
674 }
675 let mut temp: Vec<u8> = Vec::with_capacity(bitset.len() / 8 + 1);
676 write_bit_set(&mut temp, &bitset)?;
677 write_u64(header, temp.len() as u64)?;
678 header.write_all(temp.as_slice())?;
679 }
680 Ok(())
681 }
682
683 fn write_file_empty_files<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
684 let mut has_empty = false;
685 let mut empty_stream_counter = 0;
686 let mut bitset = BitSet::new();
687 for entry in self.files.iter() {
688 if !entry.has_stream {
689 let is_dir = entry.is_directory();
690 has_empty |= !is_dir;
691 if !is_dir {
692 bitset.insert(empty_stream_counter);
693 }
694 empty_stream_counter += 1;
695 }
696 }
697 if has_empty {
698 header.write_u8(K_EMPTY_FILE)?;
699
700 let mut temp: Vec<u8> = Vec::with_capacity(bitset.len() / 8 + 1);
701 write_bit_set(&mut temp, &bitset)?;
702 write_u64(header, temp.len() as u64)?;
703 header.write_all(&temp)?;
704 }
705 Ok(())
706 }
707
708 fn write_file_anti_items<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
709 let mut has_anti = false;
710 let mut counter = 0;
711 let mut bitset = BitSet::new();
712 for entry in self.files.iter() {
713 if !entry.has_stream {
714 let is_anti = entry.is_anti_item();
715 has_anti |= is_anti;
716 if is_anti {
717 bitset.insert(counter);
718 }
719 counter += 1;
720 }
721 }
722 if has_anti {
723 header.write_u8(K_ANTI)?;
724
725 let mut temp: Vec<u8> = Vec::with_capacity(bitset.len() / 8 + 1);
726 write_bit_set(&mut temp, &bitset)?;
727 write_u64(header, temp.len() as u64)?;
728 header.write_all(temp.as_slice())?;
729 }
730 Ok(())
731 }
732
733 fn write_file_names<H: Write>(&self, header: &mut H) -> std::io::Result<()> {
734 header.write_u8(K_NAME)?;
735 let mut temp: Vec<u8> = Vec::with_capacity(128);
736 let out = &mut temp;
737 out.write_u8(0)?;
738 for file in self.files.iter() {
739 for c in file.name().encode_utf16() {
740 let buf = c.to_le_bytes();
741 out.write_all(&buf)?;
742 }
743 out.write_all(&[0u8; 2])?;
744 }
745 write_u64(header, temp.len() as u64)?;
746 header.write_all(temp.as_slice())?;
747 Ok(())
748 }
749
750 write_times!(
751 write_file_ctimes,
752 K_C_TIME,
753 has_creation_date,
754 creation_date
755 );
756 write_times!(write_file_atimes, K_A_TIME, has_access_date, access_date);
757 write_times!(
758 write_file_mtimes,
759 K_M_TIME,
760 has_last_modified_date,
761 last_modified_date
762 );
763 write_times!(
764 write_file_windows_attrs,
765 K_WIN_ATTRIBUTES,
766 has_windows_attributes,
767 windows_attributes,
768 write_u32
769 );
770}
771
772impl<W: Write + Seek> AutoFinish for ArchiveWriter<W> {
773 fn finish_ignore_error(self) {
774 let _ = self.finish();
775 }
776}
777
778pub(crate) fn write_u64<W: Write>(header: &mut W, mut value: u64) -> std::io::Result<()> {
779 let mut first = 0;
780 let mut mask = 0x80;
781 let mut i = 0;
782 while i < 8 {
783 if value < (1u64 << (7 * (i + 1))) {
784 first |= value >> (8 * i);
785 break;
786 }
787 first |= mask;
788 mask >>= 1;
789 i += 1;
790 }
791 header.write_u8((first & 0xFF) as u8)?;
792 while i > 0 {
793 header.write_u8((value & 0xFF) as u8)?;
794 value >>= 8;
795 i -= 1;
796 }
797 Ok(())
798}
799
800struct CompressWrapWriter<'a, W> {
801 writer: W,
802 crc: Hasher,
803 cache: Vec<u8>,
804 bytes_written: &'a mut usize,
805}
806
807impl<'a, W: Write> CompressWrapWriter<'a, W> {
808 pub fn new(writer: W, bytes_written: &'a mut usize) -> Self {
809 Self {
810 writer,
811 crc: Hasher::new(),
812 cache: Vec::with_capacity(8192),
813 bytes_written,
814 }
815 }
816
817 pub fn crc_value(&mut self) -> u32 {
818 let crc = std::mem::replace(&mut self.crc, Hasher::new());
819 crc.finalize()
820 }
821}
822
823impl<W: Write> Write for CompressWrapWriter<'_, W> {
824 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
825 self.cache.resize(buf.len(), Default::default());
826 let len = self.writer.write(buf)?;
827 self.crc.update(&buf[..len]);
828 *self.bytes_written += len;
829 Ok(len)
830 }
831
832 fn flush(&mut self) -> std::io::Result<()> {
833 self.writer.flush()
834 }
835}
836
837#[derive(Debug)]
845pub struct PreparedBlock {
846 compressed: Vec<u8>,
847 compressed_crc: u32,
848 entries: Vec<ArchiveEntry>,
849 methods: Arc<Vec<EncoderConfiguration>>,
850 sizes: Vec<u64>,
851 crc: u32,
852 sub_stream_sizes: Vec<u64>,
853 sub_stream_crcs: Vec<u32>,
854}
855
856impl PreparedBlock {
857 pub fn compressed_len(&self) -> usize {
859 self.compressed.len()
860 }
861
862 pub fn len(&self) -> usize {
864 self.entries.len()
865 }
866
867 pub fn is_empty(&self) -> bool {
869 self.entries.is_empty()
870 }
871}
872
873pub fn prepare_block<R: Read>(
881 methods: Arc<Vec<EncoderConfiguration>>,
882 entries: Vec<ArchiveEntry>,
883 reader: Vec<SourceReader<R>>,
884) -> Result<PreparedBlock> {
885 if methods.is_empty() {
886 return Err(Error::other("prepare_block: `methods` must not be empty"));
887 }
888
889 let mut entries = entries;
890 let mut r = SeqReader::new(reader);
891 if r.reader_len() != entries.len() {
892 return Err(Error::other(format!(
893 "prepare_block: {} entries against {} readers",
894 entries.len(),
895 r.reader_len()
896 )));
897 }
898
899 let mut out: Vec<u8> = Vec::new();
900 let mut more_sizes: Vec<Rc<Cell<usize>>> = Vec::with_capacity(methods.len() - 1);
901
902 let (crc, size, compressed_crc) = {
903 let mut compressed_len = 0;
907 let mut compressed = CompressWrapWriter::new(&mut out, &mut compressed_len);
908 let (crc, size) = {
909 let mut w = ArchiveWriter::<std::io::Cursor<Vec<u8>>>::create_writer(
910 &methods,
911 &mut compressed,
912 &mut more_sizes,
913 )?;
914 let mut write_len = 0;
915 let mut w = CompressWrapWriter::new(&mut w, &mut write_len);
916 let mut buf = [0u8; 4096];
917 loop {
918 let n = r.read(&mut buf).map_err(|e| {
919 Error::io_msg(
920 e,
921 format!("prepare_block: read source:{}", entries_names(&entries)),
922 )
923 })?;
924 if n == 0 {
925 break;
926 }
927 w.write_all(&buf[..n]).map_err(|e| {
928 Error::io_msg(
929 e,
930 format!("prepare_block: encode:{}", entries_names(&entries)),
931 )
932 })?;
933 }
934 w.flush().map_err(|e| {
935 Error::io_msg(
936 e,
937 format!("prepare_block: flush:{}", entries_names(&entries)),
938 )
939 })?;
940 w.write(&[]).map_err(|e| {
941 Error::io_msg(
942 e,
943 format!("prepare_block: finish:{}", entries_names(&entries)),
944 )
945 })?;
946 (w.crc_value(), write_len)
947 };
948 (crc, size, compressed.crc_value())
949 };
950
951 let mut sub_stream_crcs = Vec::with_capacity(entries.len());
952 let mut sub_stream_sizes = Vec::with_capacity(entries.len());
953 for i in 0..entries.len() {
954 let entry = &mut entries[i];
955 let ri = &r[i];
956 entry.crc = ri.crc_value() as u64;
957 entry.size = ri.read_count() as u64;
958 sub_stream_crcs.push(entry.crc as u32);
959 sub_stream_sizes.push(entry.size);
960 entry.has_crc = true;
961 }
962
963 let mut sizes = Vec::with_capacity(more_sizes.len() + 1);
964 sizes.extend(more_sizes.iter().map(|s| s.get() as u64));
965 sizes.push(size as u64);
966
967 Ok(PreparedBlock {
968 compressed: out,
969 compressed_crc,
970 entries,
971 methods,
972 sizes,
973 crc,
974 sub_stream_sizes,
975 sub_stream_crcs,
976 })
977}