1use std::collections::HashMap;
15use std::io::{self, BufReader, IsTerminal, Read, Seek, Write};
16
17use crate::object::EntityId;
18
19#[derive(Debug)]
21#[non_exhaustive]
22pub enum RleState {
23 Init,
25 Literal { remaining: u16 },
27 Repeat { byte: u8, remaining: u16 },
29 Eod,
31}
32
33#[non_exhaustive]
35pub enum FilterKind {
36 ASCIIHexDecode,
38 ASCII85Decode {
40 group: Vec<u8>,
41 },
42 RunLengthDecode {
43 state: RleState,
44 },
45 FlateDecode {
46 decompressor: flate2::Decompress,
47 raw_buf: Vec<u8>,
48 predictor: u8,
49 columns: u32,
50 colors: u32,
51 bpc: u32,
52 prev_row: Vec<u8>,
53 },
54 LZWDecode {
55 decoder: weezl::decode::Decoder,
56 raw_buf: Vec<u8>,
57 },
58 DCTDecode {
60 decoded: bool,
61 color_transform: Option<bool>,
62 },
63 JBIG2Decode {
67 decoded: bool,
68 globals: Option<Vec<u8>>,
72 },
73 JPXDecode {
77 decoded: bool,
78 },
79 SubFileDecode {
80 eod_string: Vec<u8>,
81 eod_count: i32,
82 bytes_remaining: Option<i64>,
83 },
84 CCITTFaxDecode {
86 decoded: bool,
88 k: i32,
90 columns: u32,
92 rows: u32,
94 end_of_line: bool,
96 encoded_byte_align: bool,
98 end_of_block: bool,
100 black_is1: bool,
102 },
103 EexecDecode {
105 r: u16,
107 is_hex: Option<bool>,
109 skip_count: u32,
111 hex_leftover: Option<u8>,
113 },
114 ASCIIHexEncode,
117 ASCII85Encode {
119 buf: Vec<u8>,
121 col: usize,
123 },
124 RunLengthEncode {
127 pending: Vec<u8>,
129 run_byte: Option<u8>,
131 run_count: usize,
133 },
134 FlateEncode {
136 compressor: flate2::Compress,
137 predictor: u8,
138 columns: u32,
139 colors: u32,
140 bpc: u32,
141 row_width: usize,
143 bpp: usize,
145 encode_buf: Vec<u8>,
147 prev_row: Vec<u8>,
149 },
150 LZWEncode {
152 encoder: weezl::encode::Encoder,
153 },
154 NullEncode,
156 DCTEncode {
158 buf: Vec<u8>,
159 columns: u32,
160 rows: u32,
161 colors: u32,
162 quality: u8,
163 color_transform: bool,
164 },
165}
166
167pub struct FilterState {
169 pub kind: FilterKind,
170 pub source: EntityId,
171 pub output_buf: Vec<u8>,
172 pub output_pos: usize,
173 pub putback: Vec<u8>,
174 pub eof: bool,
175 pub bytes_read: u64,
177}
178
179pub enum FileHandle {
181 Real(BufReader<std::fs::File>),
183 Stdin,
185 Stdout,
187 Stderr,
189 Closed,
191 Filter(Box<FilterState>),
193 StringSource { data: Vec<u8>, pos: usize },
195}
196
197fn rle_emit_literals(pending: &[u8]) -> Vec<u8> {
201 if pending.is_empty() {
202 return Vec::new();
203 }
204 let mut out = Vec::with_capacity(pending.len() + 1);
205 out.push((pending.len() - 1) as u8);
206 out.extend_from_slice(pending);
207 out
208}
209
210fn rle_emit_repeat(byte: u8, count: usize) -> [u8; 2] {
212 [(257 - count) as u8, byte]
213}
214
215pub struct FileEntry {
217 pub handle: FileHandle,
218 pub name: String,
219 pub mode: String,
220 pub line_num: u32,
222 pub pending_newlines: u32,
226}
227
228pub struct FileStore {
230 files: Vec<FileEntry>,
231 embedded_files: HashMap<String, &'static [u8]>,
234}
235
236pub const FILE_STDIN: EntityId = EntityId(0);
238pub const FILE_STDOUT: EntityId = EntityId(1);
239pub const FILE_STDERR: EntityId = EntityId(2);
240
241impl FileStore {
242 pub fn new() -> Self {
244 let mut store = Self {
245 files: Vec::new(),
246 embedded_files: HashMap::new(),
247 };
248 store.files.push(FileEntry {
250 handle: FileHandle::Stdin,
251 name: "%stdin".to_string(),
252 mode: "r".to_string(),
253 line_num: 1,
254 pending_newlines: 0,
255 });
256 store.files.push(FileEntry {
257 handle: FileHandle::Stdout,
258 name: "%stdout".to_string(),
259 mode: "w".to_string(),
260 line_num: 1,
261 pending_newlines: 0,
262 });
263 store.files.push(FileEntry {
264 handle: FileHandle::Stderr,
265 name: "%stderr".to_string(),
266 mode: "w".to_string(),
267 line_num: 1,
268 pending_newlines: 0,
269 });
270 store
271 }
272
273 pub fn add_embedded_file(&mut self, path: &str, data: &'static [u8]) {
275 self.embedded_files.insert(path.to_string(), data);
276 }
277
278 pub fn get_embedded_file(&self, path: &str) -> Option<&'static [u8]> {
283 if let Some(data) = self.embedded_files.get(path) {
284 return Some(*data);
285 }
286 let normalized = path.trim_start_matches('/').replace("//", "/");
288 if normalized != path {
289 return self.embedded_files.get(normalized.as_str()).copied();
290 }
291 None
292 }
293
294 pub fn open(&mut self, name: &str, mode: &str) -> io::Result<EntityId> {
298 match name {
300 "%stdin" => {
301 if mode != "r" {
302 return Err(io::Error::new(
303 io::ErrorKind::PermissionDenied,
304 "%stdin is read-only",
305 ));
306 }
307 return Ok(FILE_STDIN);
308 }
309 "%stdout" => {
310 if mode != "w" {
311 return Err(io::Error::new(
312 io::ErrorKind::PermissionDenied,
313 "%stdout is write-only",
314 ));
315 }
316 return Ok(FILE_STDOUT);
317 }
318 "%stderr" => {
319 if mode != "w" {
320 return Err(io::Error::new(
321 io::ErrorKind::PermissionDenied,
322 "%stderr is write-only",
323 ));
324 }
325 return Ok(FILE_STDERR);
326 }
327 "%lineedit" | "%statementedit" => {
328 if mode != "r" {
329 return Err(io::Error::new(
330 io::ErrorKind::PermissionDenied,
331 "read-only special file",
332 ));
333 }
334 let mut line = String::new();
336 let n = io::stdin().read_line(&mut line)?;
337 if n == 0 {
338 return Err(io::Error::new(io::ErrorKind::NotFound, "EOF on stdin"));
340 }
341 if line.ends_with('\n') {
342 line.pop();
343 if line.ends_with('\r') {
344 line.pop();
345 }
346 }
347 return Ok(self.create_string_source(line.into_bytes()));
348 }
349 _ => {}
350 }
351
352 if mode == "r"
354 && let Some(data) = self.embedded_files.get(name)
355 {
356 let id = EntityId(self.files.len() as u32);
357 self.files.push(FileEntry {
358 handle: FileHandle::StringSource {
359 data: data.to_vec(),
360 pos: 0,
361 },
362 name: name.to_string(),
363 mode: mode.to_string(),
364 line_num: 1,
365 pending_newlines: 0,
366 });
367 return Ok(id);
368 }
369
370 let file = match mode {
371 "r" => std::fs::File::open(name)?,
372 "w" => std::fs::File::create(name)?,
373 "a" => std::fs::OpenOptions::new()
374 .append(true)
375 .create(true)
376 .open(name)?,
377 "r+" => std::fs::OpenOptions::new()
378 .read(true)
379 .write(true)
380 .open(name)?,
381 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid mode")),
382 };
383
384 let id = EntityId(self.files.len() as u32);
385 self.files.push(FileEntry {
386 handle: FileHandle::Real(BufReader::new(file)),
387 name: name.to_string(),
388 mode: mode.to_string(),
389 line_num: 1,
390 pending_newlines: 0,
391 });
392 Ok(id)
393 }
394
395 pub fn create_filter(&mut self, source: EntityId, kind: FilterKind) -> EntityId {
397 let id = EntityId(self.files.len() as u32);
398 self.files.push(FileEntry {
399 handle: FileHandle::Filter(Box::new(FilterState {
400 kind,
401 source,
402 output_buf: Vec::new(),
403 output_pos: 0,
404 putback: Vec::new(),
405 eof: false,
406 bytes_read: 0,
407 })),
408 name: "%filter".to_string(),
409 mode: "r".to_string(),
410 line_num: 1,
411 pending_newlines: 0,
412 });
413 id
414 }
415
416 pub fn create_filter_with_data(
418 &mut self,
419 source: EntityId,
420 kind: FilterKind,
421 data: Vec<u8>,
422 ) -> EntityId {
423 let id = EntityId(self.files.len() as u32);
424 self.files.push(FileEntry {
425 handle: FileHandle::Filter(Box::new(FilterState {
426 kind,
427 source,
428 output_buf: data,
429 output_pos: 0,
430 putback: Vec::new(),
431 eof: false,
432 bytes_read: 0,
433 })),
434 name: "%filter".to_string(),
435 mode: "r".to_string(),
436 line_num: 1,
437 pending_newlines: 0,
438 });
439 id
440 }
441
442 pub fn create_encode_filter(&mut self, target: EntityId, kind: FilterKind) -> EntityId {
444 let id = EntityId(self.files.len() as u32);
445 self.files.push(FileEntry {
446 handle: FileHandle::Filter(Box::new(FilterState {
447 kind,
448 source: target, output_buf: Vec::new(),
450 output_pos: 0,
451 putback: Vec::new(),
452 eof: false,
453 bytes_read: 0,
454 })),
455 name: "%filter".to_string(),
456 mode: "w".to_string(),
457 line_num: 1,
458 pending_newlines: 0,
459 });
460 id
461 }
462
463 pub fn create_string_source(&mut self, data: Vec<u8>) -> EntityId {
465 let id = EntityId(self.files.len() as u32);
466 self.files.push(FileEntry {
467 handle: FileHandle::StringSource { data, pos: 0 },
468 name: "%stringsource".to_string(),
469 mode: "r".to_string(),
470 line_num: 1,
471 pending_newlines: 0,
472 });
473 id
474 }
475
476 pub fn get_remaining_bytes(&self, entity: EntityId) -> &[u8] {
481 let entry = &self.files[entity.0 as usize];
482 match &entry.handle {
483 FileHandle::StringSource { data, pos } => &data[*pos..],
484 _ => &[],
485 }
486 }
487
488 pub fn advance_position(&mut self, entity: EntityId, n: usize) {
490 let entry = &mut self.files[entity.0 as usize];
491 if let FileHandle::StringSource { pos, .. } = &mut entry.handle {
492 *pos += n;
493 }
494 }
495
496 pub fn line_num(&self, entity: EntityId) -> u32 {
498 self.files[entity.0 as usize].line_num
499 }
500
501 pub fn add_pending_newlines(&mut self, entity: EntityId, count: u32) {
504 self.files[entity.0 as usize].pending_newlines += count;
505 }
506
507 pub fn flush_pending_newlines(&mut self, entity: EntityId) {
510 let entry = &mut self.files[entity.0 as usize];
511 entry.line_num += entry.pending_newlines;
512 entry.pending_newlines = 0;
513 }
514
515 pub fn close(&mut self, entity: EntityId) -> io::Result<()> {
517 let is_encode = matches!(
519 &self.files[entity.0 as usize].handle,
520 FileHandle::Filter(state) if state.kind.is_encode()
521 );
522 if is_encode {
523 return self.close_encode_filter(entity);
524 }
525
526 let entry = &mut self.files[entity.0 as usize];
527 match entry.handle {
528 FileHandle::Stdin | FileHandle::Stdout | FileHandle::Stderr => Ok(()),
529 FileHandle::Closed => Ok(()),
530 FileHandle::Filter(_) => {
531 entry.handle = FileHandle::Closed;
533 Ok(())
534 }
535 _ => {
536 entry.handle = FileHandle::Closed;
537 Ok(())
538 }
539 }
540 }
541
542 pub fn read_byte(&mut self, entity: EntityId) -> io::Result<Option<u8>> {
544 let entry = &mut self.files[entity.0 as usize];
545 match &mut entry.handle {
546 FileHandle::Real(f) => {
547 let mut buf = [0u8; 1];
548 let n = f.read(&mut buf)?;
549 if n == 0 { Ok(None) } else { Ok(Some(buf[0])) }
550 }
551 FileHandle::Stdin => {
552 if std::io::stdin().is_terminal() {
553 Ok(None) } else {
555 let mut buf = [0u8; 1];
556 let n = io::stdin().read(&mut buf)?;
557 if n == 0 { Ok(None) } else { Ok(Some(buf[0])) }
558 }
559 }
560 FileHandle::StringSource { data, pos } => {
561 if *pos < data.len() {
562 let b = data[*pos];
563 *pos += 1;
564 Ok(Some(b))
565 } else {
566 Ok(None)
567 }
568 }
569 FileHandle::Filter(_) => {
570 self.read_byte_filter(entity)
572 }
573 FileHandle::Closed => Ok(None), _ => Err(io::Error::other("not readable")),
575 }
576 }
577
578 fn read_byte_filter(&mut self, entity: EntityId) -> io::Result<Option<u8>> {
580 let entry = &mut self.files[entity.0 as usize];
581 let mut state = match std::mem::replace(&mut entry.handle, FileHandle::Closed) {
582 FileHandle::Filter(s) => s,
583 other => {
584 entry.handle = other;
585 return Err(io::Error::other("not a filter"));
586 }
587 };
588
589 if let Some(b) = state.putback.pop() {
591 state.bytes_read += 1;
592 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
593 return Ok(Some(b));
594 }
595
596 if state.output_pos < state.output_buf.len() {
598 let b = state.output_buf[state.output_pos];
599 state.output_pos += 1;
600 state.bytes_read += 1;
601 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
602 return Ok(Some(b));
603 }
604
605 if state.eof {
607 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
608 return Ok(None);
609 }
610
611 self.refill_filter(&mut state)?;
613
614 let result = if state.output_pos < state.output_buf.len() {
615 let b = state.output_buf[state.output_pos];
616 state.output_pos += 1;
617 state.bytes_read += 1;
618 Ok(Some(b))
619 } else {
620 Ok(None)
621 };
622
623 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
624 result
625 }
626
627 pub fn read_into(&mut self, entity: EntityId, buf: &mut [u8]) -> io::Result<usize> {
629 let entry = &mut self.files[entity.0 as usize];
630 match &mut entry.handle {
631 FileHandle::Real(f) => f.read(buf),
632 FileHandle::Stdin => {
633 if std::io::stdin().is_terminal() {
636 Ok(0)
637 } else {
638 io::stdin().read(buf)
639 }
640 }
641 FileHandle::StringSource { data, pos } => {
642 let remaining = data.len() - *pos;
643 let n = buf.len().min(remaining);
644 buf[..n].copy_from_slice(&data[*pos..*pos + n]);
645 *pos += n;
646 Ok(n)
647 }
648 FileHandle::Filter(_) => {
649 let mut count = 0;
651 for slot in buf.iter_mut() {
652 match self.read_byte(entity)? {
653 Some(b) => {
654 *slot = b;
655 count += 1;
656 }
657 None => break,
658 }
659 }
660 Ok(count)
661 }
662 FileHandle::Closed => Err(io::Error::other("file closed")),
663 _ => Err(io::Error::other("not readable")),
664 }
665 }
666
667 pub fn write_byte(&mut self, entity: EntityId, byte: u8) -> io::Result<()> {
669 self.write_from(entity, &[byte])
670 }
671
672 pub fn write_from(&mut self, entity: EntityId, buf: &[u8]) -> io::Result<()> {
674 let is_encode = matches!(
676 &self.files[entity.0 as usize].handle,
677 FileHandle::Filter(state) if state.kind.is_encode()
678 );
679 if is_encode {
680 return self.encode_write(entity, buf);
681 }
682 let entry = &mut self.files[entity.0 as usize];
683 match &mut entry.handle {
684 FileHandle::Real(f) => f.get_mut().write_all(buf),
685 FileHandle::Stdout => io::stdout().write_all(buf),
686 FileHandle::Stderr => io::stderr().write_all(buf),
687 FileHandle::Closed => Err(io::Error::other("file closed")),
688 _ => Err(io::Error::other("not writable")),
689 }
690 }
691
692 fn encode_write(&mut self, entity: EntityId, data: &[u8]) -> io::Result<()> {
694 let entry = &mut self.files[entity.0 as usize];
696 let mut state = match std::mem::replace(&mut entry.handle, FileHandle::Closed) {
697 FileHandle::Filter(s) => s,
698 other => {
699 entry.handle = other;
700 return Err(io::Error::other("not an encode filter"));
701 }
702 };
703
704 let target = state.source;
705 let result = match &mut state.kind {
706 FilterKind::ASCIIHexEncode => {
707 let mut hex = Vec::with_capacity(data.len() * 2);
709 for &b in data {
710 hex.push(b"0123456789ABCDEF"[(b >> 4) as usize]);
711 hex.push(b"0123456789ABCDEF"[(b & 0xF) as usize]);
712 }
713 self.write_from(target, &hex)
714 }
715 FilterKind::ASCII85Encode { buf, col } => {
716 let mut encoded = Vec::new();
717 for &byte in data {
718 buf.push(byte);
719 if buf.len() == 4 {
720 let val = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
721 if val == 0 {
722 encoded.push(b'z');
723 *col += 1;
724 } else {
725 let mut chars = [0u8; 5];
726 let mut v = val;
727 for c in chars.iter_mut().rev() {
728 *c = (v % 85) as u8 + b'!';
729 v /= 85;
730 }
731 encoded.extend_from_slice(&chars);
732 *col += 5;
733 }
734 buf.clear();
735 if *col >= 75 {
736 encoded.push(b'\n');
737 *col = 0;
738 }
739 }
740 }
741 if encoded.is_empty() {
742 Ok(())
743 } else {
744 self.write_from(target, &encoded)
745 }
746 }
747 FilterKind::RunLengthEncode {
748 pending,
749 run_byte,
750 run_count,
751 } => {
752 for &b in data {
754 if let Some(rb) = *run_byte {
755 if b == rb {
756 *run_count += 1;
757 if *run_count >= 128 {
758 let lit = rle_emit_literals(pending);
760 if !lit.is_empty() {
761 self.write_from(target, &lit)?;
762 pending.clear();
763 }
764 let rep = rle_emit_repeat(rb, 128);
765 self.write_from(target, &rep)?;
766 *run_byte = None;
767 *run_count = 0;
768 }
769 } else {
770 if *run_count >= 3 {
772 let lit = rle_emit_literals(pending);
774 if !lit.is_empty() {
775 self.write_from(target, &lit)?;
776 pending.clear();
777 }
778 let rep = rle_emit_repeat(rb, *run_count);
779 self.write_from(target, &rep)?;
780 } else {
781 for _ in 0..*run_count {
783 pending.push(rb);
784 }
785 if pending.len() >= 128 {
786 let lit = rle_emit_literals(pending);
787 self.write_from(target, &lit)?;
788 pending.clear();
789 }
790 }
791 *run_byte = Some(b);
792 *run_count = 1;
793 }
794 } else {
795 *run_byte = Some(b);
797 *run_count = 1;
798 }
799 }
800 Ok(())
801 }
802 FilterKind::FlateEncode {
803 compressor,
804 predictor,
805 row_width,
806 bpp,
807 encode_buf,
808 prev_row,
809 ..
810 } => {
811 if *predictor <= 1 {
812 flate_compress_data(compressor, data, |chunk| self.write_from(target, chunk))
814 } else {
815 encode_buf.extend_from_slice(data);
817 let rw = *row_width;
818 let pred = *predictor;
819 let bp = *bpp;
820 while encode_buf.len() >= rw {
821 let row: Vec<u8> = encode_buf.drain(..rw).collect();
822 let encoded = if pred >= 10 {
823 encode_png_row(&row, bp)
824 } else {
825 encode_tiff_row(&row, bp)
826 };
827 prev_row.copy_from_slice(&row);
828 flate_compress_data(compressor, &encoded, |chunk| {
829 self.write_from(target, chunk)
830 })?;
831 }
832 Ok(())
833 }
834 }
835 FilterKind::LZWEncode { encoder } => {
836 let mut out = vec![0u8; data.len() * 2 + 64];
837 let result = encoder.encode_bytes(data, &mut out);
838 if result.consumed_out > 0 {
839 self.write_from(target, &out[..result.consumed_out])?;
840 }
841 Ok(())
842 }
843 FilterKind::NullEncode => self.write_from(target, data),
844 FilterKind::DCTEncode { buf, .. } => {
845 buf.extend_from_slice(data);
849 Ok(())
850 }
851 _ => Err(io::Error::other("not an encode filter")),
852 };
853
854 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
856 result
857 }
858
859 fn close_encode_filter(&mut self, entity: EntityId) -> io::Result<()> {
861 let entry = &mut self.files[entity.0 as usize];
863 let mut state = match std::mem::replace(&mut entry.handle, FileHandle::Closed) {
864 FileHandle::Filter(s) => s,
865 other => {
866 entry.handle = other;
867 return Ok(());
868 }
869 };
870
871 let target = state.source;
872 match &mut state.kind {
873 FilterKind::ASCIIHexEncode => {
874 self.write_from(target, b">")?;
875 }
876 FilterKind::ASCII85Encode { buf, .. } => {
877 if !buf.is_empty() {
879 let n = buf.len();
880 while buf.len() < 4 {
882 buf.push(0);
883 }
884 let val = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
885 let mut chars = [0u8; 5];
886 let mut v = val;
887 for c in chars.iter_mut().rev() {
888 *c = (v % 85) as u8 + b'!';
889 v /= 85;
890 }
891 self.write_from(target, &chars[..n + 1])?;
893 }
894 self.write_from(target, b"~>")?;
895 }
896 FilterKind::RunLengthEncode {
897 pending,
898 run_byte,
899 run_count,
900 } => {
901 if let Some(rb) = *run_byte {
903 if *run_count >= 3 {
904 let lit = rle_emit_literals(pending);
905 if !lit.is_empty() {
906 self.write_from(target, &lit)?;
907 }
908 let rep = rle_emit_repeat(rb, *run_count);
909 self.write_from(target, &rep)?;
910 } else {
911 for _ in 0..*run_count {
912 pending.push(rb);
913 }
914 let lit = rle_emit_literals(pending);
915 if !lit.is_empty() {
916 self.write_from(target, &lit)?;
917 }
918 }
919 } else if !pending.is_empty() {
920 let lit = rle_emit_literals(pending);
921 self.write_from(target, &lit)?;
922 }
923 self.write_from(target, &[128])?;
925 }
926 FilterKind::FlateEncode {
927 compressor,
928 predictor,
929 row_width,
930 bpp,
931 encode_buf,
932 ..
933 } => {
934 if *predictor > 1 && !encode_buf.is_empty() {
936 let rw = *row_width;
937 let pred = *predictor;
938 let bp = *bpp;
939 encode_buf.resize(rw, 0);
941 let row: Vec<u8> = std::mem::take(encode_buf);
942 let encoded = if pred >= 10 {
943 encode_png_row(&row, bp)
944 } else {
945 encode_tiff_row(&row, bp)
946 };
947 flate_compress_data(compressor, &encoded, |chunk| {
948 self.write_from(target, chunk)
949 })?;
950 }
951 let mut out = vec![0u8; 256];
953 loop {
954 let before_out = compressor.total_out() as usize;
955 let status = compressor
956 .compress(&[], &mut out, flate2::FlushCompress::Finish)
957 .map_err(|e| io::Error::other(e.to_string()))?;
958 let produced = compressor.total_out() as usize - before_out;
959 if produced > 0 {
960 self.write_from(target, &out[..produced])?;
961 }
962 if matches!(status, flate2::Status::StreamEnd) {
963 break;
964 }
965 }
966 }
967 FilterKind::LZWEncode { encoder } => {
968 encoder.finish();
970 let mut out = vec![0u8; 256];
971 loop {
972 let result = encoder.encode_bytes(&[], &mut out);
973 if result.consumed_out > 0 {
974 self.write_from(target, &out[..result.consumed_out])?;
975 }
976 if result.consumed_out == 0 {
977 break;
978 }
979 }
980 }
981 FilterKind::NullEncode => {}
982 FilterKind::DCTEncode {
983 buf,
984 columns,
985 rows,
986 colors,
987 quality,
988 color_transform,
989 } => {
990 let w = *columns as u16;
991 let h = *rows as u16;
992 let nc = *colors as u8;
993 let q = *quality;
994 let _ct = *color_transform;
995
996 let color_type = match nc {
998 1 => jpeg_encoder::ColorType::Luma,
999 3 => jpeg_encoder::ColorType::Rgb,
1000 4 => jpeg_encoder::ColorType::Cmyk,
1001 _ => jpeg_encoder::ColorType::Rgb,
1002 };
1003
1004 let expected_len = w as usize * h as usize * nc as usize;
1005 buf.resize(expected_len, 0);
1007
1008 let mut jpeg_data = Vec::new();
1009 let encoder = jpeg_encoder::Encoder::new(&mut jpeg_data, q);
1010 encoder
1011 .encode(buf, w, h, color_type)
1012 .map_err(|e| io::Error::other(format!("JPEG encode error: {e}")))?;
1013 self.write_from(target, &jpeg_data)?;
1014 }
1015 _ => {}
1016 }
1017
1018 self.close(target)?;
1020
1021 Ok(())
1023 }
1024
1025 pub fn readline(&mut self, entity: EntityId, buf: &mut [u8]) -> io::Result<(usize, bool)> {
1027 let mut count = 0;
1028 let mut hit_newline = false;
1029 loop {
1030 if count >= buf.len() {
1031 break;
1032 }
1033 match self.read_byte(entity)? {
1034 None => break,
1035 Some(b'\n') => {
1036 hit_newline = true;
1037 break;
1038 }
1039 Some(b'\r') => {
1040 hit_newline = true;
1041 match self.read_byte(entity)? {
1043 Some(b'\n') => {} Some(other) => self.putback_bytes(entity, &[other]),
1045 None => {}
1046 }
1047 break;
1048 }
1049 Some(b) => {
1050 buf[count] = b;
1051 count += 1;
1052 }
1053 }
1054 }
1055 Ok((count, hit_newline))
1056 }
1057
1058 pub fn position(&mut self, entity: EntityId) -> io::Result<u64> {
1060 let entry = &mut self.files[entity.0 as usize];
1061 match &mut entry.handle {
1062 FileHandle::Real(f) => f.stream_position(),
1063 FileHandle::StringSource { pos, .. } => Ok(*pos as u64),
1064 FileHandle::Filter(state) => Ok(state.bytes_read),
1065 _ => Err(io::Error::other("not seekable")),
1066 }
1067 }
1068
1069 pub fn set_position(&mut self, entity: EntityId, pos: u64) -> io::Result<()> {
1071 let entry = &mut self.files[entity.0 as usize];
1072 match &mut entry.handle {
1073 FileHandle::Real(f) => {
1074 f.seek(io::SeekFrom::Start(pos))?;
1075 Ok(())
1076 }
1077 FileHandle::StringSource { data, pos: p } => {
1078 *p = (pos as usize).min(data.len());
1079 Ok(())
1080 }
1081 _ => Err(io::Error::other("not seekable")),
1082 }
1083 }
1084
1085 pub fn flush(&mut self, entity: EntityId) -> io::Result<()> {
1087 let entry = &self.files[entity.0 as usize];
1088 match &entry.handle {
1089 FileHandle::Real(_) => {
1090 let entry = &mut self.files[entity.0 as usize];
1091 if entry.mode.starts_with('r') {
1092 entry.handle = FileHandle::Closed;
1094 } else if let FileHandle::Real(f) = &mut entry.handle {
1095 f.get_mut().flush()?;
1096 }
1097 }
1098 FileHandle::Stdout => io::stdout().flush()?,
1099 FileHandle::Stderr => io::stderr().flush()?,
1100 FileHandle::Filter(_) => {
1101 let mut buf = [0u8; 4096];
1105 loop {
1106 match self.read_into(entity, &mut buf) {
1107 Ok(0) => break,
1108 Ok(_) => continue,
1109 Err(_) => break,
1110 }
1111 }
1112 }
1113 FileHandle::StringSource { .. } => {
1114 let entry = &mut self.files[entity.0 as usize];
1116 if let FileHandle::StringSource { data, pos } = &mut entry.handle {
1117 *pos = data.len();
1118 }
1119 }
1120 _ => {}
1121 }
1122 Ok(())
1123 }
1124
1125 pub fn is_open(&self, entity: EntityId) -> bool {
1127 if (entity.0 as usize) >= self.files.len() {
1128 return false;
1129 }
1130 !matches!(self.files[entity.0 as usize].handle, FileHandle::Closed)
1131 }
1132
1133 pub fn is_readable(&self, entity: EntityId) -> bool {
1135 if (entity.0 as usize) >= self.files.len() {
1136 return false;
1137 }
1138 !matches!(
1139 self.files[entity.0 as usize].handle,
1140 FileHandle::Closed | FileHandle::Stdout | FileHandle::Stderr
1141 )
1142 }
1143
1144 pub fn read_n_bytes(&mut self, entity: EntityId, n: usize) -> io::Result<Vec<u8>> {
1146 let mut result = Vec::with_capacity(n);
1147 for _ in 0..n {
1148 match self.read_byte(entity)? {
1149 Some(b) => result.push(b),
1150 None => return Err(io::Error::other("unexpected EOF")),
1151 }
1152 }
1153 Ok(result)
1154 }
1155
1156 pub fn putback_bytes(&mut self, entity: EntityId, bytes: &[u8]) {
1160 let entry = &mut self.files[entity.0 as usize];
1161 match &mut entry.handle {
1162 FileHandle::Filter(state) => {
1163 for &b in bytes.iter().rev() {
1165 state.putback.push(b);
1166 }
1167 }
1168 FileHandle::StringSource { pos, .. } => {
1169 *pos = pos.saturating_sub(bytes.len());
1170 }
1171 FileHandle::Real(f) => {
1172 let _ = f.seek(std::io::SeekFrom::Current(-(bytes.len() as i64)));
1174 }
1175 _ => {}
1176 }
1177 }
1178
1179 pub fn is_seekable(&self, entity: EntityId) -> bool {
1181 matches!(self.files[entity.0 as usize].handle, FileHandle::Real(_))
1182 }
1183
1184 pub fn bytes_available(&mut self, entity: EntityId) -> i32 {
1188 let entry = &mut self.files[entity.0 as usize];
1189 if entry.mode.starts_with('w') || entry.mode.starts_with('a') {
1191 return -1;
1192 }
1193 match &mut entry.handle {
1194 FileHandle::Real(f) => {
1195 if let Ok(cur) = f.stream_position() {
1196 if let Ok(end) = f.seek(io::SeekFrom::End(0)) {
1197 let _ = f.seek(io::SeekFrom::Start(cur));
1198 let remaining = end.saturating_sub(cur);
1199 if remaining == 0 {
1200 -1 } else {
1202 remaining.min(i32::MAX as u64) as i32
1203 }
1204 } else {
1205 -1
1206 }
1207 } else {
1208 -1
1209 }
1210 }
1211 FileHandle::StringSource { data, pos } => {
1212 let remaining = data.len() - *pos;
1213 if remaining == 0 { -1 } else { remaining as i32 }
1214 }
1215 FileHandle::Closed => -1,
1216 _ => -1,
1217 }
1218 }
1219
1220 pub fn name(&self, entity: EntityId) -> &str {
1222 &self.files[entity.0 as usize].name
1223 }
1224
1225 pub fn set_name(&mut self, entity: EntityId, name: String) {
1227 self.files[entity.0 as usize].name = name;
1228 }
1229
1230 pub fn mode(&self, entity: EntityId) -> &str {
1232 &self.files[entity.0 as usize].mode
1233 }
1234
1235 pub fn len(&self) -> usize {
1237 self.files.len()
1238 }
1239
1240 pub fn is_empty(&self) -> bool {
1242 self.files.is_empty()
1243 }
1244
1245 pub fn putback_byte(&mut self, entity: EntityId, byte: u8) {
1247 let entry = &mut self.files[entity.0 as usize];
1248 if let FileHandle::Filter(ref mut state) = entry.handle {
1249 state.putback.push(byte);
1250 }
1251 }
1252
1253 pub fn read_all(&mut self, entity: EntityId) -> io::Result<Vec<u8>> {
1255 let mut data = Vec::new();
1256 while let Some(b) = self.read_byte(entity)? {
1257 data.push(b);
1258 }
1259 Ok(data)
1260 }
1261
1262 fn refill_filter(&mut self, state: &mut FilterState) -> io::Result<()> {
1266 state.output_buf.clear();
1267 state.output_pos = 0;
1268
1269 match &mut state.kind {
1270 FilterKind::ASCIIHexDecode => {
1271 self.refill_ascii_hex(state.source, &mut state.output_buf, &mut state.eof)?;
1272 }
1273 FilterKind::ASCII85Decode { .. } => {
1274 let source = state.source;
1276 self.refill_ascii85(
1277 source,
1278 &mut state.kind,
1279 &mut state.output_buf,
1280 &mut state.eof,
1281 )?;
1282 }
1283 FilterKind::RunLengthDecode { .. } => {
1284 let source = state.source;
1285 self.refill_rle(
1286 source,
1287 &mut state.kind,
1288 &mut state.output_buf,
1289 &mut state.eof,
1290 )?;
1291 }
1292 FilterKind::FlateDecode { .. } => {
1293 let source = state.source;
1294 self.refill_flate(
1295 source,
1296 &mut state.kind,
1297 &mut state.output_buf,
1298 &mut state.eof,
1299 )?;
1300 }
1301 FilterKind::LZWDecode { .. } => {
1302 let source = state.source;
1303 self.refill_lzw(
1304 source,
1305 &mut state.kind,
1306 &mut state.output_buf,
1307 &mut state.eof,
1308 )?;
1309 }
1310 FilterKind::DCTDecode { decoded, .. } => {
1311 if !*decoded {
1312 let source = state.source;
1314 let jpeg_data = self.read_all(source)?;
1315 let mut decoder = jpeg_decoder::Decoder::new(jpeg_data.as_slice());
1316 let pixels = decoder
1317 .decode()
1318 .map_err(|e| io::Error::other(format!("JPEG decode error: {e}")))?;
1319 state.output_buf = pixels;
1320 state.output_pos = 0;
1321 *decoded = true;
1322 } else {
1323 state.eof = true;
1324 }
1325 }
1326 FilterKind::JBIG2Decode { decoded, .. } => {
1327 if !*decoded {
1328 let source = state.source;
1329 let raw = self.read_all(source)?;
1330 let globals = match &state.kind {
1332 FilterKind::JBIG2Decode { globals, .. } => globals.clone(),
1333 _ => None,
1334 };
1335 let image = hayro_jbig2::decode_embedded(&raw, globals.as_deref())
1336 .map_err(|e| io::Error::other(format!("JBIG2 decode error: {e}")))?;
1337 let row_bytes = (image.width as usize).div_ceil(8);
1342 let mut packed = vec![0xFFu8; row_bytes * image.height as usize];
1343 for y in 0..image.height as usize {
1344 for x in 0..image.width as usize {
1345 if image.data[y * image.width as usize + x] {
1346 packed[y * row_bytes + x / 8] &= !(0x80 >> (x % 8));
1347 }
1348 }
1349 }
1350 state.output_buf = packed;
1351 state.output_pos = 0;
1352 if let FilterKind::JBIG2Decode { decoded, .. } = &mut state.kind {
1353 *decoded = true;
1354 }
1355 } else {
1356 state.eof = true;
1357 }
1358 }
1359 FilterKind::JPXDecode { decoded } => {
1360 if !*decoded {
1361 let source = state.source;
1362 let raw = self.read_all(source)?;
1363 let image = hayro_jpeg2000::Image::new(
1364 &raw,
1365 &hayro_jpeg2000::DecodeSettings::default(),
1366 )
1367 .map_err(|e| io::Error::other(format!("JPXDecode error: {e}")))?;
1368 let pixels = image
1369 .decode()
1370 .map_err(|e| io::Error::other(format!("JPXDecode error: {e}")))?;
1371 state.output_buf = pixels;
1372 state.output_pos = 0;
1373 *decoded = true;
1374 } else {
1375 state.eof = true;
1376 }
1377 }
1378 FilterKind::CCITTFaxDecode { decoded, .. } => {
1379 if !*decoded {
1380 let source = state.source;
1381 let ccitt_data = self.read_all(source)?;
1382 let decoded_bytes = Self::decode_ccittfax(&ccitt_data, &mut state.kind)?;
1383 state.output_buf = decoded_bytes;
1384 state.output_pos = 0;
1385 if let FilterKind::CCITTFaxDecode { decoded, .. } = &mut state.kind {
1387 *decoded = true;
1388 }
1389 } else {
1390 state.eof = true;
1391 }
1392 }
1393 FilterKind::SubFileDecode { .. } => {
1394 let source = state.source;
1395 self.refill_subfile(
1396 source,
1397 &mut state.kind,
1398 &mut state.output_buf,
1399 &mut state.eof,
1400 )?;
1401 }
1402 FilterKind::EexecDecode { .. } => {
1403 let source = state.source;
1404 self.refill_eexec(
1405 source,
1406 &mut state.kind,
1407 &mut state.output_buf,
1408 &mut state.eof,
1409 )?;
1410 }
1411 _ => {
1413 state.eof = true;
1414 }
1415 }
1416 Ok(())
1417 }
1418
1419 fn refill_ascii_hex(
1421 &mut self,
1422 source: EntityId,
1423 out: &mut Vec<u8>,
1424 eof: &mut bool,
1425 ) -> io::Result<()> {
1426 let mut nibble: Option<u8> = None;
1427 let target = 4096;
1428
1429 while out.len() < target {
1430 match self.read_byte(source)? {
1431 None => {
1432 if let Some(high) = nibble.take() {
1434 out.push(high << 4);
1435 }
1436 *eof = true;
1437 return Ok(());
1438 }
1439 Some(b'>') => {
1440 if let Some(high) = nibble.take() {
1442 out.push(high << 4);
1443 }
1444 *eof = true;
1445 return Ok(());
1446 }
1447 Some(b) => {
1448 let nib = match b {
1449 b'0'..=b'9' => Some(b - b'0'),
1450 b'a'..=b'f' => Some(b - b'a' + 10),
1451 b'A'..=b'F' => Some(b - b'A' + 10),
1452 _ => None, };
1454 if let Some(n) = nib {
1455 match nibble.take() {
1456 None => nibble = Some(n),
1457 Some(high) => out.push((high << 4) | n),
1458 }
1459 }
1460 }
1461 }
1462 }
1463 Ok(())
1464 }
1465
1466 fn refill_ascii85(
1468 &mut self,
1469 source: EntityId,
1470 kind: &mut FilterKind,
1471 out: &mut Vec<u8>,
1472 eof: &mut bool,
1473 ) -> io::Result<()> {
1474 let group = match kind {
1475 FilterKind::ASCII85Decode { group } => group,
1476 _ => return Err(io::Error::other("not ASCII85")),
1477 };
1478 let target = 4096;
1479
1480 while out.len() < target {
1481 match self.read_byte(source)? {
1482 None => {
1483 if group.len() >= 2 {
1485 ascii85_decode_partial(group, out);
1486 }
1487 group.clear();
1488 *eof = true;
1489 return Ok(());
1490 }
1491 Some(b'~') => {
1492 let _ = self.read_byte(source)?; if group.len() >= 2 {
1495 ascii85_decode_partial(group, out);
1496 }
1497 group.clear();
1498 *eof = true;
1499 return Ok(());
1500 }
1501 Some(b'z') => {
1502 out.extend_from_slice(&[0, 0, 0, 0]);
1504 }
1505 Some(b) if b.is_ascii_whitespace() => {
1506 }
1508 Some(b) if (b'!'..=b'u').contains(&b) => {
1509 group.push(b - b'!');
1510 if group.len() == 5 {
1511 let val = group[0] as u64 * 85 * 85 * 85 * 85
1513 + group[1] as u64 * 85 * 85 * 85
1514 + group[2] as u64 * 85 * 85
1515 + group[3] as u64 * 85
1516 + group[4] as u64;
1517 out.push((val >> 24) as u8);
1518 out.push((val >> 16) as u8);
1519 out.push((val >> 8) as u8);
1520 out.push(val as u8);
1521 group.clear();
1522 }
1523 }
1524 Some(_) => {
1525 }
1527 }
1528 }
1529 Ok(())
1530 }
1531
1532 fn refill_rle(
1534 &mut self,
1535 source: EntityId,
1536 kind: &mut FilterKind,
1537 out: &mut Vec<u8>,
1538 eof: &mut bool,
1539 ) -> io::Result<()> {
1540 let rle_state = match kind {
1541 FilterKind::RunLengthDecode { state } => state,
1542 _ => return Err(io::Error::other("not RLE")),
1543 };
1544 let target = 4096;
1545
1546 while out.len() < target {
1547 match rle_state {
1548 RleState::Init => {
1549 match self.read_byte(source)? {
1550 None | Some(128) => {
1551 *rle_state = RleState::Eod;
1552 *eof = true;
1553 return Ok(());
1554 }
1555 Some(b) if b < 128 => {
1556 *rle_state = RleState::Literal {
1557 remaining: b as u16 + 1,
1558 };
1559 }
1560 Some(b) => {
1561 let count = 257 - b as u16;
1563 match self.read_byte(source)? {
1564 None => {
1565 *rle_state = RleState::Eod;
1566 *eof = true;
1567 return Ok(());
1568 }
1569 Some(val) => {
1570 *rle_state = RleState::Repeat {
1571 byte: val,
1572 remaining: count,
1573 };
1574 }
1575 }
1576 }
1577 }
1578 }
1579 RleState::Literal { remaining } => {
1580 if *remaining == 0 {
1581 *rle_state = RleState::Init;
1582 continue;
1583 }
1584 match self.read_byte(source)? {
1585 None => {
1586 *rle_state = RleState::Eod;
1587 *eof = true;
1588 return Ok(());
1589 }
1590 Some(b) => {
1591 out.push(b);
1592 *remaining -= 1;
1593 }
1594 }
1595 }
1596 RleState::Repeat { byte, remaining } => {
1597 if *remaining == 0 {
1598 *rle_state = RleState::Init;
1599 continue;
1600 }
1601 out.push(*byte);
1602 *remaining -= 1;
1603 }
1604 RleState::Eod => {
1605 *eof = true;
1606 return Ok(());
1607 }
1608 }
1609 }
1610 Ok(())
1611 }
1612
1613 fn refill_flate(
1615 &mut self,
1616 source: EntityId,
1617 kind: &mut FilterKind,
1618 out: &mut Vec<u8>,
1619 eof: &mut bool,
1620 ) -> io::Result<()> {
1621 let (decompressor, raw_buf, predictor, columns, colors, bpc, prev_row) = match kind {
1622 FilterKind::FlateDecode {
1623 decompressor,
1624 raw_buf,
1625 predictor,
1626 columns,
1627 colors,
1628 bpc,
1629 prev_row,
1630 } => (
1631 decompressor,
1632 raw_buf,
1633 *predictor,
1634 *columns,
1635 *colors,
1636 *bpc,
1637 prev_row,
1638 ),
1639 _ => return Err(io::Error::other("not Flate")),
1640 };
1641
1642 if raw_buf.is_empty() {
1644 let mut chunk = vec![0u8; 8192];
1645 let mut total = 0;
1646 while let Some(b) = self.read_byte(source)? {
1648 chunk[total] = b;
1649 total += 1;
1650 if total >= chunk.len() {
1651 break;
1652 }
1653 }
1654 if total == 0 {
1655 *eof = true;
1656 return Ok(());
1657 }
1658 raw_buf.extend_from_slice(&chunk[..total]);
1659 }
1660
1661 let mut decompressed = vec![0u8; 16384];
1663 let before_in = decompressor.total_in();
1664 let before_out = decompressor.total_out();
1665 let status = decompressor
1666 .decompress(raw_buf, &mut decompressed, flate2::FlushDecompress::None)
1667 .map_err(|e| io::Error::other(format!("flate2 decompress error: {}", e)))?;
1668
1669 let consumed = (decompressor.total_in() - before_in) as usize;
1670 let produced = (decompressor.total_out() - before_out) as usize;
1671
1672 raw_buf.drain(..consumed);
1674
1675 if status == flate2::Status::StreamEnd {
1676 *eof = true;
1677 }
1678
1679 let decompressed = &decompressed[..produced];
1680
1681 if predictor == 1 || predictor == 0 {
1683 out.extend_from_slice(decompressed);
1685 } else if predictor == 2 {
1686 apply_tiff_predictor(decompressed, out, columns, colors, bpc);
1688 } else if (10..=15).contains(&predictor) {
1689 apply_png_predictor(decompressed, out, columns, colors, bpc, prev_row);
1691 } else {
1692 out.extend_from_slice(decompressed);
1693 }
1694
1695 Ok(())
1696 }
1697
1698 fn refill_lzw(
1700 &mut self,
1701 source: EntityId,
1702 kind: &mut FilterKind,
1703 out: &mut Vec<u8>,
1704 eof: &mut bool,
1705 ) -> io::Result<()> {
1706 let (decoder, raw_buf) = match kind {
1707 FilterKind::LZWDecode { decoder, raw_buf } => (decoder, raw_buf),
1708 _ => return Err(io::Error::other("not LZW")),
1709 };
1710
1711 let mut decompressed = vec![0u8; 16384];
1712
1713 loop {
1714 if raw_buf.is_empty() {
1716 let mut chunk = vec![0u8; 8192];
1717 let mut total = 0;
1718 while let Some(b) = self.read_byte(source)? {
1719 chunk[total] = b;
1720 total += 1;
1721 if total >= chunk.len() {
1722 break;
1723 }
1724 }
1725 if total == 0 {
1726 let result = decoder.decode_bytes(&[], &mut decompressed);
1728 if result.consumed_out > 0 {
1729 out.extend_from_slice(&decompressed[..result.consumed_out]);
1730 }
1731 *eof = true;
1732 return Ok(());
1733 }
1734 raw_buf.extend_from_slice(&chunk[..total]);
1735 }
1736
1737 let result = decoder.decode_bytes(raw_buf, &mut decompressed);
1739 let consumed_in = result.consumed_in;
1740 let consumed_out = result.consumed_out;
1741
1742 raw_buf.drain(..consumed_in);
1744
1745 match result.status {
1746 Ok(weezl::LzwStatus::Done) => {
1747 out.extend_from_slice(&decompressed[..consumed_out]);
1748 *eof = true;
1749 return Ok(());
1750 }
1751 Ok(weezl::LzwStatus::NoProgress) => {
1752 if consumed_out > 0 {
1753 out.extend_from_slice(&decompressed[..consumed_out]);
1754 return Ok(());
1755 }
1756 if raw_buf.is_empty() {
1758 continue; }
1760 *eof = true;
1762 return Ok(());
1763 }
1764 Ok(weezl::LzwStatus::Ok) => {
1765 out.extend_from_slice(&decompressed[..consumed_out]);
1766 if consumed_out > 0 {
1767 return Ok(());
1768 }
1769 continue;
1771 }
1772 Err(e) => {
1773 return Err(io::Error::other(format!("LZW decode error: {}", e)));
1774 }
1775 }
1776 }
1777 }
1778
1779 fn refill_subfile(
1781 &mut self,
1782 source: EntityId,
1783 kind: &mut FilterKind,
1784 out: &mut Vec<u8>,
1785 eof: &mut bool,
1786 ) -> io::Result<()> {
1787 let (eod_string, eod_count, bytes_remaining) = match kind {
1788 FilterKind::SubFileDecode {
1789 eod_string,
1790 eod_count,
1791 bytes_remaining,
1792 } => (eod_string, eod_count, bytes_remaining),
1793 _ => return Err(io::Error::other("not SubFile")),
1794 };
1795
1796 if eod_string.is_empty() {
1797 if let Some(remaining) = bytes_remaining {
1799 let target = (*remaining).min(4096) as usize;
1800 for _ in 0..target {
1801 match self.read_byte(source)? {
1802 Some(b) => {
1803 out.push(b);
1804 *remaining -= 1;
1805 }
1806 None => {
1807 *eof = true;
1808 return Ok(());
1809 }
1810 }
1811 }
1812 if *remaining <= 0 {
1813 *eof = true;
1814 }
1815 } else {
1816 *eof = true;
1817 }
1818 } else {
1819 let eod = eod_string.clone();
1821 let target_count = *eod_count;
1822 let mut match_pos = 0;
1823 let mut found_count = 0;
1824
1825 for _ in 0..4096 {
1826 match self.read_byte(source)? {
1827 None => {
1828 *eof = true;
1829 return Ok(());
1830 }
1831 Some(b) => {
1832 if b == eod[match_pos] {
1833 match_pos += 1;
1834 if match_pos == eod.len() {
1835 found_count += 1;
1836 out.extend_from_slice(&eod);
1838 match_pos = 0;
1839 if found_count >= target_count {
1840 *eof = true;
1841 return Ok(());
1842 }
1843 }
1844 } else {
1845 if match_pos > 0 {
1847 out.extend_from_slice(&eod[..match_pos]);
1848 match_pos = 0;
1849 }
1850 out.push(b);
1851 }
1852 }
1853 }
1854 }
1855 }
1856
1857 Ok(())
1858 }
1859
1860 fn decode_ccittfax(data: &[u8], kind: &mut FilterKind) -> io::Result<Vec<u8>> {
1862 let FilterKind::CCITTFaxDecode {
1863 k,
1864 columns,
1865 rows,
1866 end_of_block,
1867 black_is1,
1868 ..
1869 } = kind
1870 else {
1871 return Err(io::Error::other("not a CCITTFaxDecode filter"));
1872 };
1873 let k = *k;
1874 let width = *columns as u16;
1875 let rows_limit = *rows;
1876 let end_of_block = *end_of_block;
1877 let black_is1 = *black_is1;
1878
1879 let row_bytes = (width as usize).div_ceil(8);
1881 let mut output = Vec::new();
1882 let mut line_count: u32 = 0;
1883
1884 let mut process_line = |transitions: &[u16]| {
1886 if !end_of_block && rows_limit > 0 && line_count >= rows_limit {
1888 return;
1889 }
1890
1891 let line = fax::decoder::Line { transitions, width };
1893 let mut row = vec![0u8; row_bytes];
1894 for (i, color) in line.pels().enumerate() {
1895 if i >= width as usize {
1896 break;
1897 }
1898 let is_set = matches!(color, fax::Color::Black);
1901 if is_set {
1902 row[i / 8] |= 0x80 >> (i % 8);
1903 }
1904 }
1905
1906 if !black_is1 {
1911 for byte in &mut row {
1912 *byte = !*byte;
1913 }
1914 }
1915
1916 output.extend_from_slice(&row);
1917 line_count += 1;
1918 };
1919
1920 if k < 0 {
1921 let height = if rows_limit > 0 {
1923 Some(rows_limit as u16)
1924 } else {
1925 None
1926 };
1927 fax::decoder::decode_g4(data.iter().copied(), width, height, |transitions| {
1928 process_line(transitions)
1929 });
1930 } else {
1931 fax::decoder::decode_g3(data.iter().copied(), |transitions| {
1933 process_line(transitions);
1934 });
1935 }
1936
1937 Ok(output)
1938 }
1939
1940 fn refill_eexec(
1944 &mut self,
1945 source: EntityId,
1946 kind: &mut FilterKind,
1947 out: &mut Vec<u8>,
1948 eof: &mut bool,
1949 ) -> io::Result<()> {
1950 let FilterKind::EexecDecode {
1951 r,
1952 is_hex,
1953 skip_count,
1954 hex_leftover,
1955 } = kind
1956 else {
1957 return Ok(());
1958 };
1959
1960 const C1: u16 = 52845;
1961 const C2: u16 = 22719;
1962 const TARGET: usize = 1;
1967
1968 if is_hex.is_none() {
1970 let mut probe = Vec::with_capacity(8);
1971 for _ in 0..8 {
1972 match self.read_byte(source)? {
1973 Some(b) => probe.push(b),
1974 None => break,
1975 }
1976 }
1977 if probe.is_empty() {
1978 *eof = true;
1979 return Ok(());
1980 }
1981 let hex = probe
1982 .iter()
1983 .all(|&b| b.is_ascii_hexdigit() || is_ps_whitespace(b));
1984 *is_hex = Some(hex);
1985
1986 if hex {
1988 let mut hex_digits = Vec::new();
1989 for &b in &probe {
1990 if b.is_ascii_hexdigit() {
1991 hex_digits.push(b);
1992 }
1993 }
1994 let mut i = 0;
1995 while i + 1 < hex_digits.len() {
1996 let cipher = (hex_val(hex_digits[i]) << 4) | hex_val(hex_digits[i + 1]);
1997 let plain = cipher ^ (*r >> 8) as u8;
1998 *r = (cipher as u16)
1999 .wrapping_add(*r)
2000 .wrapping_mul(C1)
2001 .wrapping_add(C2);
2002 if *skip_count < 4 {
2003 *skip_count += 1;
2004 } else {
2005 out.push(plain);
2006 }
2007 i += 2;
2008 }
2009 if i < hex_digits.len() {
2010 *hex_leftover = Some(hex_digits[i]);
2011 }
2012 } else {
2013 for &cipher in &probe {
2014 let plain = cipher ^ (*r >> 8) as u8;
2015 *r = (cipher as u16)
2016 .wrapping_add(*r)
2017 .wrapping_mul(C1)
2018 .wrapping_add(C2);
2019 if *skip_count < 4 {
2020 *skip_count += 1;
2021 } else {
2022 out.push(plain);
2023 }
2024 }
2025 }
2026 }
2027
2028 while out.len() < TARGET {
2030 let cipher_byte = if *is_hex == Some(true) {
2031 let hi = if let Some(h) = hex_leftover.take() {
2033 h
2034 } else {
2035 match read_next_hex_digit(self, source)? {
2036 Some(d) => d,
2037 None => {
2038 *eof = true;
2039 return Ok(());
2040 }
2041 }
2042 };
2043 let lo = read_next_hex_digit(self, source)?.unwrap_or(b'0');
2045 (hex_val(hi) << 4) | hex_val(lo)
2046 } else {
2047 match self.read_byte(source)? {
2049 Some(b) => b,
2050 None => {
2051 *eof = true;
2052 return Ok(());
2053 }
2054 }
2055 };
2056
2057 let plain = cipher_byte ^ (*r >> 8) as u8;
2058 *r = (cipher_byte as u16)
2059 .wrapping_add(*r)
2060 .wrapping_mul(C1)
2061 .wrapping_add(C2);
2062 if *skip_count < 4 {
2063 *skip_count += 1;
2064 } else {
2065 out.push(plain);
2066 }
2067 }
2068
2069 Ok(())
2070 }
2071}
2072
2073fn read_next_hex_digit(store: &mut FileStore, source: EntityId) -> io::Result<Option<u8>> {
2075 loop {
2076 match store.read_byte(source)? {
2077 Some(b) if b.is_ascii_hexdigit() => return Ok(Some(b)),
2078 Some(b) if is_ps_whitespace(b) => continue,
2079 Some(_) | None => return Ok(None),
2080 }
2081 }
2082}
2083
2084fn is_ps_whitespace(b: u8) -> bool {
2086 matches!(b, b'\0' | b'\t' | b'\n' | 0x0C | b'\r' | b' ')
2087}
2088
2089fn hex_val(b: u8) -> u8 {
2091 match b {
2092 b'0'..=b'9' => b - b'0',
2093 b'a'..=b'f' => b - b'a' + 10,
2094 b'A'..=b'F' => b - b'A' + 10,
2095 _ => 0,
2096 }
2097}
2098
2099fn ascii85_decode_partial(group: &[u8], out: &mut Vec<u8>) {
2101 let n = group.len();
2102 if n < 2 {
2103 return;
2104 }
2105 let mut padded = [84u8; 5];
2107 padded[..n].copy_from_slice(group);
2108
2109 let val = padded[0] as u64 * 85 * 85 * 85 * 85
2110 + padded[1] as u64 * 85 * 85 * 85
2111 + padded[2] as u64 * 85 * 85
2112 + padded[3] as u64 * 85
2113 + padded[4] as u64;
2114
2115 let bytes = [
2116 (val >> 24) as u8,
2117 (val >> 16) as u8,
2118 (val >> 8) as u8,
2119 val as u8,
2120 ];
2121 out.extend_from_slice(&bytes[..n - 1]);
2123}
2124
2125fn flate_compress_data(
2127 compressor: &mut flate2::Compress,
2128 data: &[u8],
2129 mut write_fn: impl FnMut(&[u8]) -> io::Result<()>,
2130) -> io::Result<()> {
2131 let mut out = vec![0u8; data.len() + 64];
2132 let mut input_pos = 0;
2133 loop {
2134 let before_in = compressor.total_in() as usize;
2135 let before_out = compressor.total_out() as usize;
2136 let status = compressor
2137 .compress(&data[input_pos..], &mut out, flate2::FlushCompress::None)
2138 .map_err(|e| io::Error::other(e.to_string()))?;
2139 let consumed = compressor.total_in() as usize - before_in;
2140 let produced = compressor.total_out() as usize - before_out;
2141 input_pos += consumed;
2142 if produced > 0 {
2143 write_fn(&out[..produced])?;
2144 }
2145 if input_pos >= data.len() || matches!(status, flate2::Status::StreamEnd) {
2146 break;
2147 }
2148 }
2149 Ok(())
2150}
2151
2152fn encode_png_row(row: &[u8], bpp: usize) -> Vec<u8> {
2154 let mut encoded = Vec::with_capacity(1 + row.len());
2155 encoded.push(1); for i in 0..row.len() {
2157 let left = if i >= bpp { row[i - bpp] } else { 0 };
2158 encoded.push(row[i].wrapping_sub(left));
2159 }
2160 encoded
2161}
2162
2163fn encode_tiff_row(row: &[u8], colors: usize) -> Vec<u8> {
2165 let mut encoded = Vec::from(row);
2166 for i in (colors..encoded.len()).rev() {
2168 encoded[i] = encoded[i].wrapping_sub(encoded[i - colors]);
2169 }
2170 encoded
2171}
2172
2173fn apply_tiff_predictor(data: &[u8], out: &mut Vec<u8>, columns: u32, colors: u32, bpc: u32) {
2175 let bytes_per_pixel = (colors * bpc).div_ceil(8);
2176 let row_bytes = (columns * colors * bpc).div_ceil(8);
2177
2178 for row in data.chunks(row_bytes as usize) {
2179 let mut prev = vec![0u8; bytes_per_pixel as usize];
2180 for (i, &b) in row.iter().enumerate() {
2181 let pi = i % bytes_per_pixel as usize;
2182 let val = b.wrapping_add(prev[pi]);
2183 out.push(val);
2184 prev[pi] = val;
2185 }
2186 }
2187}
2188
2189fn apply_png_predictor(
2191 data: &[u8],
2192 out: &mut Vec<u8>,
2193 columns: u32,
2194 colors: u32,
2195 bpc: u32,
2196 prev_row: &mut Vec<u8>,
2197) {
2198 let bytes_per_pixel = (colors * bpc).div_ceil(8) as usize;
2199 let row_bytes = (columns * colors * bpc).div_ceil(8) as usize;
2200 let stride = row_bytes + 1; if prev_row.is_empty() {
2203 prev_row.resize(row_bytes, 0);
2204 }
2205
2206 let mut pos = 0;
2207 while pos + stride <= data.len() {
2208 let filter_type = data[pos];
2209 let row_data = &data[pos + 1..pos + stride];
2210 let mut decoded_row = vec![0u8; row_bytes];
2211
2212 for i in 0..row_bytes {
2213 let raw = row_data[i];
2214 let a = if i >= bytes_per_pixel {
2215 decoded_row[i - bytes_per_pixel]
2216 } else {
2217 0
2218 };
2219 let b = prev_row[i];
2220 let c = if i >= bytes_per_pixel {
2221 prev_row[i - bytes_per_pixel]
2222 } else {
2223 0
2224 };
2225
2226 decoded_row[i] = match filter_type {
2227 0 => raw, 1 => raw.wrapping_add(a), 2 => raw.wrapping_add(b), 3 => raw.wrapping_add(((a as u16 + b as u16) / 2) as u8), 4 => raw.wrapping_add(paeth_predictor(a, b, c)), _ => raw,
2233 };
2234 }
2235
2236 out.extend_from_slice(&decoded_row);
2237 prev_row.copy_from_slice(&decoded_row);
2238 pos += stride;
2239 }
2240
2241 if pos < data.len() {
2243 out.extend_from_slice(&data[pos..]);
2244 }
2245}
2246
2247fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
2249 let p = a as i32 + b as i32 - c as i32;
2250 let pa = (p - a as i32).abs();
2251 let pb = (p - b as i32).abs();
2252 let pc = (p - c as i32).abs();
2253 if pa <= pb && pa <= pc {
2254 a
2255 } else if pb <= pc {
2256 b
2257 } else {
2258 c
2259 }
2260}
2261
2262impl FilterKind {
2263 pub fn ascii_hex_decode() -> Self {
2265 Self::ASCIIHexDecode
2266 }
2267
2268 pub fn ascii85_decode() -> Self {
2270 Self::ASCII85Decode { group: Vec::new() }
2271 }
2272
2273 pub fn run_length_decode() -> Self {
2275 Self::RunLengthDecode {
2276 state: RleState::Init,
2277 }
2278 }
2279
2280 pub fn flate_decode(predictor: u8, columns: u32, colors: u32, bpc: u32) -> Self {
2282 Self::FlateDecode {
2283 decompressor: flate2::Decompress::new(true),
2284 raw_buf: Vec::new(),
2285 predictor,
2286 columns,
2287 colors,
2288 bpc,
2289 prev_row: Vec::new(),
2290 }
2291 }
2292
2293 pub fn lzw_decode(early_change: bool) -> Self {
2295 let decoder = if early_change {
2296 weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8)
2297 } else {
2298 weezl::decode::Decoder::new(weezl::BitOrder::Msb, 8)
2299 };
2300 Self::LZWDecode {
2301 decoder,
2302 raw_buf: Vec::new(),
2303 }
2304 }
2305
2306 pub fn dct_decode(color_transform: Option<bool>) -> Self {
2308 Self::DCTDecode {
2309 decoded: false,
2310 color_transform,
2311 }
2312 }
2313
2314 pub fn jbig2_decode(globals: Option<Vec<u8>>) -> Self {
2319 Self::JBIG2Decode {
2320 decoded: false,
2321 globals,
2322 }
2323 }
2324
2325 pub fn jpx_decode() -> Self {
2327 Self::JPXDecode { decoded: false }
2328 }
2329
2330 pub fn dct_encode(
2332 columns: u32,
2333 rows: u32,
2334 colors: u32,
2335 quality: u8,
2336 color_transform: bool,
2337 ) -> Self {
2338 Self::DCTEncode {
2339 buf: Vec::new(),
2340 columns,
2341 rows,
2342 colors,
2343 quality,
2344 color_transform,
2345 }
2346 }
2347
2348 pub fn sub_file_decode(
2350 eod_string: Vec<u8>,
2351 eod_count: i32,
2352 bytes_remaining: Option<i64>,
2353 ) -> Self {
2354 Self::SubFileDecode {
2355 eod_string,
2356 eod_count,
2357 bytes_remaining,
2358 }
2359 }
2360
2361 pub fn ccittfax_decode(
2363 k: i32,
2364 columns: u32,
2365 rows: u32,
2366 end_of_line: bool,
2367 encoded_byte_align: bool,
2368 end_of_block: bool,
2369 black_is1: bool,
2370 ) -> Self {
2371 Self::CCITTFaxDecode {
2372 decoded: false,
2373 k,
2374 columns,
2375 rows,
2376 end_of_line,
2377 encoded_byte_align,
2378 end_of_block,
2379 black_is1,
2380 }
2381 }
2382
2383 pub fn eexec_decode() -> Self {
2385 Self::EexecDecode {
2386 r: 55665,
2387 is_hex: None,
2388 skip_count: 0,
2389 hex_leftover: None,
2390 }
2391 }
2392
2393 pub fn ascii_hex_encode() -> Self {
2395 Self::ASCIIHexEncode
2396 }
2397
2398 pub fn ascii85_encode() -> Self {
2400 Self::ASCII85Encode {
2401 buf: Vec::with_capacity(4),
2402 col: 0,
2403 }
2404 }
2405
2406 pub fn run_length_encode() -> Self {
2408 Self::RunLengthEncode {
2409 pending: Vec::new(),
2410 run_byte: None,
2411 run_count: 0,
2412 }
2413 }
2414
2415 pub fn flate_encode(predictor: u8, columns: u32, colors: u32, bpc: u32) -> Self {
2417 let row_width = (columns as usize * colors as usize * bpc as usize).div_ceil(8);
2418 let bpp = (colors as usize * bpc as usize).div_ceil(8);
2419 Self::FlateEncode {
2420 compressor: flate2::Compress::new(flate2::Compression::default(), true),
2421 predictor,
2422 columns,
2423 colors,
2424 bpc,
2425 row_width,
2426 bpp: bpp.max(1),
2427 encode_buf: Vec::new(),
2428 prev_row: vec![0u8; row_width],
2429 }
2430 }
2431
2432 pub fn lzw_encode(early_change: bool) -> Self {
2434 let encoder = if early_change {
2435 weezl::encode::Encoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8)
2436 } else {
2437 weezl::encode::Encoder::new(weezl::BitOrder::Msb, 8)
2438 };
2439 Self::LZWEncode { encoder }
2440 }
2441
2442 pub fn null_encode() -> Self {
2444 Self::NullEncode
2445 }
2446
2447 pub fn is_encode(&self) -> bool {
2449 matches!(
2450 self,
2451 Self::ASCIIHexEncode
2452 | Self::ASCII85Encode { .. }
2453 | Self::RunLengthEncode { .. }
2454 | Self::FlateEncode { .. }
2455 | Self::LZWEncode { .. }
2456 | Self::NullEncode
2457 | Self::DCTEncode { .. }
2458 )
2459 }
2460}
2461
2462impl FileStore {
2463 pub fn create_dct_filter(
2465 &mut self,
2466 source: EntityId,
2467 color_transform: Option<bool>,
2468 ) -> EntityId {
2469 self.create_filter(source, FilterKind::dct_decode(color_transform))
2470 }
2471
2472 pub fn create_dct_encode_filter(
2474 &mut self,
2475 target: EntityId,
2476 columns: u32,
2477 rows: u32,
2478 colors: u32,
2479 quality: u8,
2480 color_transform: bool,
2481 ) -> EntityId {
2482 self.create_encode_filter(
2483 target,
2484 FilterKind::dct_encode(columns, rows, colors, quality, color_transform),
2485 )
2486 }
2487}
2488
2489impl Default for FileStore {
2490 fn default() -> Self {
2491 Self::new()
2492 }
2493}
2494
2495#[cfg(test)]
2496mod tests {
2497 use super::*;
2498 use std::io::Write;
2499
2500 fn tmp_path(name: &str) -> String {
2504 std::env::temp_dir()
2505 .join(name)
2506 .to_string_lossy()
2507 .into_owned()
2508 }
2509
2510 #[test]
2511 fn test_prealloc_standard_streams() {
2512 let store = FileStore::new();
2513 assert_eq!(store.len(), 3);
2514 assert!(store.is_open(FILE_STDIN));
2515 assert!(store.is_open(FILE_STDOUT));
2516 assert!(store.is_open(FILE_STDERR));
2517 assert_eq!(store.name(FILE_STDIN), "%stdin");
2518 }
2519
2520 #[test]
2521 fn test_open_special_names() {
2522 let mut store = FileStore::new();
2523 assert_eq!(store.open("%stdin", "r").unwrap(), FILE_STDIN);
2524 assert_eq!(store.open("%stdout", "w").unwrap(), FILE_STDOUT);
2525 assert_eq!(store.open("%stderr", "w").unwrap(), FILE_STDERR);
2526 }
2527
2528 #[test]
2529 fn test_file_round_trip() {
2530 let mut store = FileStore::new();
2531 let path = tmp_path("stet_test_file_store.txt");
2532 let path = path.as_str();
2533
2534 let wid = store.open(path, "w").unwrap();
2536 store.write_from(wid, b"hello\n").unwrap();
2537 store.flush(wid).unwrap();
2538 store.close(wid).unwrap();
2539
2540 let rid = store.open(path, "r").unwrap();
2542 let mut buf = vec![0u8; 6];
2543 let n = store.read_into(rid, &mut buf).unwrap();
2544 assert_eq!(n, 6);
2545 assert_eq!(&buf, b"hello\n");
2546 store.close(rid).unwrap();
2547
2548 std::fs::remove_file(path).ok();
2550 }
2551
2552 #[test]
2553 fn test_readline() {
2554 let mut store = FileStore::new();
2555 let path = tmp_path("stet_test_readline.txt");
2556 let path = path.as_str();
2557
2558 {
2560 let mut f = std::fs::File::create(path).unwrap();
2561 f.write_all(b"line1\nline2\n").unwrap();
2562 }
2563
2564 let id = store.open(path, "r").unwrap();
2565 let mut buf = vec![0u8; 20];
2566 let (n, nl) = store.readline(id, &mut buf).unwrap();
2567 assert_eq!(&buf[..n], b"line1");
2568 assert!(nl);
2569
2570 let (n, nl) = store.readline(id, &mut buf).unwrap();
2571 assert_eq!(&buf[..n], b"line2");
2572 assert!(nl);
2573
2574 store.close(id).unwrap();
2575 std::fs::remove_file(path).ok();
2576 }
2577
2578 #[test]
2579 fn test_file_position() {
2580 let mut store = FileStore::new();
2581 let path = tmp_path("stet_test_filepos.txt");
2582 let path = path.as_str();
2583 {
2584 let mut f = std::fs::File::create(path).unwrap();
2585 f.write_all(b"abcdef").unwrap();
2586 }
2587
2588 let id = store.open(path, "r").unwrap();
2589 assert_eq!(store.position(id).unwrap(), 0);
2590 let mut buf = [0u8; 3];
2591 store.read_into(id, &mut buf).unwrap();
2592 assert_eq!(store.position(id).unwrap(), 3);
2593 store.set_position(id, 0).unwrap();
2594 assert_eq!(store.position(id).unwrap(), 0);
2595 store.close(id).unwrap();
2596 std::fs::remove_file(path).ok();
2597 }
2598
2599 #[test]
2600 fn test_close_and_reopen() {
2601 let mut store = FileStore::new();
2602 let path = tmp_path("stet_test_close.txt");
2603 let path = path.as_str();
2604 let id = store.open(path, "w").unwrap();
2605 store.write_from(id, b"test").unwrap();
2606 store.close(id).unwrap();
2607 assert!(!store.is_open(id));
2608 std::fs::remove_file(path).ok();
2609 }
2610
2611 #[test]
2612 fn test_invalid_mode() {
2613 let mut store = FileStore::new();
2614 assert!(
2615 store
2616 .open(&tmp_path("stet_test_invalid_mode"), "z")
2617 .is_err()
2618 );
2619 }
2620
2621 #[test]
2622 fn test_read_byte() {
2623 let mut store = FileStore::new();
2624 let path = tmp_path("stet_test_readbyte.txt");
2625 let path = path.as_str();
2626 {
2627 let mut f = std::fs::File::create(path).unwrap();
2628 f.write_all(b"AB").unwrap();
2629 }
2630 let id = store.open(path, "r").unwrap();
2631 assert_eq!(store.read_byte(id).unwrap(), Some(b'A'));
2632 assert_eq!(store.read_byte(id).unwrap(), Some(b'B'));
2633 assert_eq!(store.read_byte(id).unwrap(), None);
2634 store.close(id).unwrap();
2635 std::fs::remove_file(path).ok();
2636 }
2637
2638 #[test]
2641 fn test_string_source() {
2642 let mut store = FileStore::new();
2643 let id = store.create_string_source(b"Hello".to_vec());
2644 assert_eq!(store.read_byte(id).unwrap(), Some(b'H'));
2645 assert_eq!(store.read_byte(id).unwrap(), Some(b'e'));
2646 let mut buf = [0u8; 3];
2647 let n = store.read_into(id, &mut buf).unwrap();
2648 assert_eq!(n, 3);
2649 assert_eq!(&buf, b"llo");
2650 assert_eq!(store.read_byte(id).unwrap(), None);
2651 }
2652
2653 #[test]
2654 fn test_string_source_empty() {
2655 let mut store = FileStore::new();
2656 let id = store.create_string_source(Vec::new());
2657 assert_eq!(store.read_byte(id).unwrap(), None);
2658 }
2659
2660 #[test]
2663 fn test_ascii_hex_decode() {
2664 let mut store = FileStore::new();
2665 let src = store.create_string_source(b"48 65 6C 6C 6F>".to_vec());
2666 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2667 let mut result = Vec::new();
2668 loop {
2669 match store.read_byte(filt).unwrap() {
2670 Some(b) => result.push(b),
2671 None => break,
2672 }
2673 }
2674 assert_eq!(&result, b"Hello");
2675 }
2676
2677 #[test]
2678 fn test_ascii_hex_decode_odd_nibble() {
2679 let mut store = FileStore::new();
2680 let src = store.create_string_source(b"4>".to_vec());
2681 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2682 let b = store.read_byte(filt).unwrap().unwrap();
2683 assert_eq!(b, 0x40);
2684 assert_eq!(store.read_byte(filt).unwrap(), None);
2685 }
2686
2687 #[test]
2688 fn test_ascii_hex_decode_whitespace() {
2689 let mut store = FileStore::new();
2690 let src = store.create_string_source(b"4 1\n4 2>".to_vec());
2691 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2692 let mut result = Vec::new();
2693 loop {
2694 match store.read_byte(filt).unwrap() {
2695 Some(b) => result.push(b),
2696 None => break,
2697 }
2698 }
2699 assert_eq!(&result, &[0x41, 0x42]);
2700 }
2701
2702 #[test]
2705 fn test_ascii85_decode() {
2706 let mut store = FileStore::new();
2707 let src = store.create_string_source(b"9jqo^~>".to_vec());
2709 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2710 let mut result = Vec::new();
2711 loop {
2712 match store.read_byte(filt).unwrap() {
2713 Some(b) => result.push(b),
2714 None => break,
2715 }
2716 }
2717 assert_eq!(&result, b"Man ");
2718 }
2719
2720 #[test]
2721 fn test_ascii85_decode_z() {
2722 let mut store = FileStore::new();
2723 let src = store.create_string_source(b"z~>".to_vec());
2724 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2725 let mut result = Vec::new();
2726 loop {
2727 match store.read_byte(filt).unwrap() {
2728 Some(b) => result.push(b),
2729 None => break,
2730 }
2731 }
2732 assert_eq!(&result, &[0, 0, 0, 0]);
2733 }
2734
2735 #[test]
2736 fn test_ascii85_decode_partial() {
2737 let mut store = FileStore::new();
2738 let src = store.create_string_source(b"9j~>".to_vec());
2740 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2741 let mut result = Vec::new();
2742 loop {
2743 match store.read_byte(filt).unwrap() {
2744 Some(b) => result.push(b),
2745 None => break,
2746 }
2747 }
2748 assert_eq!(result.len(), 1);
2749 }
2750
2751 #[test]
2754 fn test_rle_literal() {
2755 let mut store = FileStore::new();
2756 let src = store.create_string_source(vec![2, b'A', b'B', b'C', 128]);
2758 let filt = store.create_filter(
2759 src,
2760 FilterKind::RunLengthDecode {
2761 state: RleState::Init,
2762 },
2763 );
2764 let mut result = Vec::new();
2765 loop {
2766 match store.read_byte(filt).unwrap() {
2767 Some(b) => result.push(b),
2768 None => break,
2769 }
2770 }
2771 assert_eq!(&result, b"ABC");
2772 }
2773
2774 #[test]
2775 fn test_rle_repeat() {
2776 let mut store = FileStore::new();
2777 let src = store.create_string_source(vec![253, b'X', 128]);
2779 let filt = store.create_filter(
2780 src,
2781 FilterKind::RunLengthDecode {
2782 state: RleState::Init,
2783 },
2784 );
2785 let mut result = Vec::new();
2786 loop {
2787 match store.read_byte(filt).unwrap() {
2788 Some(b) => result.push(b),
2789 None => break,
2790 }
2791 }
2792 assert_eq!(&result, b"XXXX");
2793 }
2794
2795 #[test]
2798 fn test_subfile_byte_count() {
2799 let mut store = FileStore::new();
2800 let src = store.create_string_source(b"Hello, World!".to_vec());
2801 let filt = store.create_filter(
2802 src,
2803 FilterKind::SubFileDecode {
2804 eod_string: Vec::new(),
2805 eod_count: 0,
2806 bytes_remaining: Some(5),
2807 },
2808 );
2809 let mut result = Vec::new();
2810 loop {
2811 match store.read_byte(filt).unwrap() {
2812 Some(b) => result.push(b),
2813 None => break,
2814 }
2815 }
2816 assert_eq!(&result, b"Hello");
2817 }
2818
2819 #[test]
2822 fn test_flate_decode() {
2823 use flate2::Compression;
2824 use flate2::write::ZlibEncoder;
2825
2826 let original = b"Hello, stet PostScript interpreter! This is a test of FlateDecode.";
2828 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
2829 encoder.write_all(original).unwrap();
2830 let compressed = encoder.finish().unwrap();
2831
2832 let mut store = FileStore::new();
2833 let src = store.create_string_source(compressed);
2834 let filt = store.create_filter(
2835 src,
2836 FilterKind::FlateDecode {
2837 decompressor: flate2::Decompress::new(true),
2838 raw_buf: Vec::new(),
2839 predictor: 1,
2840 columns: 0,
2841 colors: 0,
2842 bpc: 8,
2843 prev_row: Vec::new(),
2844 },
2845 );
2846 let mut result = Vec::new();
2847 loop {
2848 match store.read_byte(filt).unwrap() {
2849 Some(b) => result.push(b),
2850 None => break,
2851 }
2852 }
2853 assert_eq!(&result, original);
2854 }
2855
2856 #[test]
2859 fn test_lzw_decode() {
2860 let original = b"TOBEORNOTTOBEORTOBEORNOT";
2863 let mut encoder = weezl::encode::Encoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
2864 let compressed = encoder.encode(original).unwrap();
2865
2866 let mut store = FileStore::new();
2867 let src = store.create_string_source(compressed);
2868 let filt = store.create_filter(src, FilterKind::lzw_decode(true));
2869 let mut result = Vec::new();
2870 loop {
2871 match store.read_byte(filt).unwrap() {
2872 Some(b) => result.push(b),
2873 None => break,
2874 }
2875 }
2876 assert_eq!(&result, original);
2877 }
2878
2879 #[test]
2880 fn test_lzw_encode_single_byte() {
2881 let mut store = FileStore::new();
2882 let path = tmp_path("stet_test_lzw_single.bin");
2883 let path = path.as_str();
2884
2885 let target = store.open(path, "w").unwrap();
2886 let enc = store.create_encode_filter(target, FilterKind::lzw_encode(true));
2887 store.write_from(enc, b"Q").unwrap();
2888 store.close(enc).unwrap();
2889
2890 let src = store.open(path, "r").unwrap();
2891 let dec = store.create_filter(src, FilterKind::lzw_decode(true));
2892 let mut result = Vec::new();
2893 loop {
2894 match store.read_byte(dec).unwrap() {
2895 Some(b) => result.push(b),
2896 None => break,
2897 }
2898 }
2899 assert_eq!(&result, b"Q");
2900 std::fs::remove_file(path).ok();
2901 }
2902
2903 #[test]
2904 fn test_lzw_encode_roundtrip() {
2905 let mut store = FileStore::new();
2906 let original = b"Hello LZW!";
2907
2908 let path = tmp_path("stet_test_lzw_encode.bin");
2910 let path = path.as_str();
2911 let target = store.open(path, "w").unwrap();
2912 let enc = store.create_encode_filter(target, FilterKind::lzw_encode(true));
2913
2914 store.write_from(enc, original).unwrap();
2916 store.close(enc).unwrap();
2917
2918 let src = store.open(path, "r").unwrap();
2920 let dec = store.create_filter(src, FilterKind::lzw_decode(true));
2921 let mut result = Vec::new();
2922 loop {
2923 match store.read_byte(dec).unwrap() {
2924 Some(b) => result.push(b),
2925 None => break,
2926 }
2927 }
2928 assert_eq!(&result, original);
2929 std::fs::remove_file(path).ok();
2930 }
2931
2932 #[test]
2933 fn test_ascii_hex_encode_roundtrip() {
2934 let mut store = FileStore::new();
2935 let original = b"Hello";
2936 let path = tmp_path("stet_test_hex_encode.bin");
2937 let path = path.as_str();
2938
2939 let target = store.open(path, "w").unwrap();
2940 let enc = store.create_encode_filter(target, FilterKind::ascii_hex_encode());
2941 store.write_from(enc, original).unwrap();
2942 store.close(enc).unwrap();
2943
2944 let src = store.open(path, "r").unwrap();
2945 let dec = store.create_filter(src, FilterKind::ascii_hex_decode());
2946 let mut result = Vec::new();
2947 loop {
2948 match store.read_byte(dec).unwrap() {
2949 Some(b) => result.push(b),
2950 None => break,
2951 }
2952 }
2953 assert_eq!(&result, original);
2954 std::fs::remove_file(path).ok();
2955 }
2956
2957 #[test]
2958 fn test_ascii85_encode_roundtrip() {
2959 let mut store = FileStore::new();
2960 let original = b"Man sure.";
2961 let path = tmp_path("stet_test_a85_encode.bin");
2962 let path = path.as_str();
2963
2964 let target = store.open(path, "w").unwrap();
2965 let enc = store.create_encode_filter(target, FilterKind::ascii85_encode());
2966 store.write_from(enc, original).unwrap();
2967 store.close(enc).unwrap();
2968
2969 let src = store.open(path, "r").unwrap();
2970 let dec = store.create_filter(src, FilterKind::ascii85_decode());
2971 let mut result = Vec::new();
2972 loop {
2973 match store.read_byte(dec).unwrap() {
2974 Some(b) => result.push(b),
2975 None => break,
2976 }
2977 }
2978 assert_eq!(&result, original);
2979 std::fs::remove_file(path).ok();
2980 }
2981
2982 #[test]
2983 fn test_rle_encode_roundtrip() {
2984 let mut store = FileStore::new();
2985 let original = b"AAAAAABCBCBCBC";
2986 let path = tmp_path("stet_test_rle_encode.bin");
2987 let path = path.as_str();
2988
2989 let target = store.open(path, "w").unwrap();
2990 let enc = store.create_encode_filter(target, FilterKind::run_length_encode());
2991 store.write_from(enc, original).unwrap();
2992 store.close(enc).unwrap();
2993
2994 let src = store.open(path, "r").unwrap();
2995 let dec = store.create_filter(src, FilterKind::run_length_decode());
2996 let mut result = Vec::new();
2997 loop {
2998 match store.read_byte(dec).unwrap() {
2999 Some(b) => result.push(b),
3000 None => break,
3001 }
3002 }
3003 assert_eq!(&result, original);
3004 std::fs::remove_file(path).ok();
3005 }
3006
3007 #[test]
3008 fn test_flate_encode_roundtrip() {
3009 let mut store = FileStore::new();
3010 let original = b"Hello Flate compression test data!";
3011 let path = tmp_path("stet_test_flate_encode.bin");
3012 let path = path.as_str();
3013
3014 let target = store.open(path, "w").unwrap();
3015 let enc = store.create_encode_filter(target, FilterKind::flate_encode(1, 1, 1, 8));
3016 store.write_from(enc, original).unwrap();
3017 store.close(enc).unwrap();
3018
3019 let src = store.open(path, "r").unwrap();
3020 let dec = store.create_filter(src, FilterKind::flate_decode(1, 1, 1, 8));
3021 let mut result = Vec::new();
3022 loop {
3023 match store.read_byte(dec).unwrap() {
3024 Some(b) => result.push(b),
3025 None => break,
3026 }
3027 }
3028 assert_eq!(&result, original);
3029 std::fs::remove_file(path).ok();
3030 }
3031
3032 #[test]
3035 fn test_jbig2_decode_constructor() {
3036 let kind = FilterKind::jbig2_decode(None);
3037 match kind {
3038 FilterKind::JBIG2Decode {
3039 decoded: false,
3040 globals: None,
3041 } => {}
3042 _ => panic!("unexpected variant"),
3043 }
3044 let kind = FilterKind::jbig2_decode(Some(vec![1, 2, 3]));
3045 match kind {
3046 FilterKind::JBIG2Decode {
3047 decoded: false,
3048 globals: Some(ref g),
3049 } if g == &[1, 2, 3] => {}
3050 _ => panic!("globals not stored"),
3051 }
3052 }
3053
3054 #[test]
3055 fn test_jpx_decode_constructor() {
3056 let kind = FilterKind::jpx_decode();
3057 match kind {
3058 FilterKind::JPXDecode { decoded: false } => {}
3059 _ => panic!("unexpected variant"),
3060 }
3061 }
3062
3063 #[test]
3064 fn test_jbig2_decode_malformed_returns_ioerror() {
3065 let mut store = FileStore::new();
3070 let src = store.create_string_source(b"not a jbig2 stream".to_vec());
3071 let filt = store.create_filter(src, FilterKind::jbig2_decode(None));
3072 assert!(store.read_byte(filt).is_err());
3073 }
3074
3075 #[test]
3076 fn test_jpx_decode_malformed_returns_ioerror() {
3077 let mut store = FileStore::new();
3078 let src = store.create_string_source(b"not a jpeg2000 stream".to_vec());
3079 let filt = store.create_filter(src, FilterKind::jpx_decode());
3080 assert!(store.read_byte(filt).is_err());
3081 }
3082}