1use std::collections::HashMap;
15use std::io::{self, BufReader, IsTerminal, Read, Seek, Write};
16
17use crate::object::{EntityId, PsObject};
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 PendingProc { proc: PsObject },
208}
209
210fn rle_emit_literals(pending: &[u8]) -> Vec<u8> {
214 if pending.is_empty() {
215 return Vec::new();
216 }
217 let mut out = Vec::with_capacity(pending.len() + 1);
218 out.push((pending.len() - 1) as u8);
219 out.extend_from_slice(pending);
220 out
221}
222
223fn rle_emit_repeat(byte: u8, count: usize) -> [u8; 2] {
225 [(257 - count) as u8, byte]
226}
227
228pub struct FileEntry {
230 pub handle: FileHandle,
231 pub name: String,
232 pub mode: String,
233 pub line_num: u32,
235 pub pending_newlines: u32,
239}
240
241pub struct FileStore {
243 files: Vec<FileEntry>,
244 pending_procs: usize,
251 embedded_files: HashMap<String, &'static [u8]>,
254}
255
256pub const FILE_STDIN: EntityId = EntityId(0);
258pub const FILE_STDOUT: EntityId = EntityId(1);
259pub const FILE_STDERR: EntityId = EntityId(2);
260
261impl FileStore {
262 pub fn new() -> Self {
264 let mut store = Self {
265 files: Vec::new(),
266 pending_procs: 0,
267 embedded_files: HashMap::new(),
268 };
269 store.files.push(FileEntry {
271 handle: FileHandle::Stdin,
272 name: "%stdin".to_string(),
273 mode: "r".to_string(),
274 line_num: 1,
275 pending_newlines: 0,
276 });
277 store.files.push(FileEntry {
278 handle: FileHandle::Stdout,
279 name: "%stdout".to_string(),
280 mode: "w".to_string(),
281 line_num: 1,
282 pending_newlines: 0,
283 });
284 store.files.push(FileEntry {
285 handle: FileHandle::Stderr,
286 name: "%stderr".to_string(),
287 mode: "w".to_string(),
288 line_num: 1,
289 pending_newlines: 0,
290 });
291 store
292 }
293
294 pub fn add_embedded_file(&mut self, path: &str, data: &'static [u8]) {
296 self.embedded_files.insert(path.to_string(), data);
297 }
298
299 pub fn get_embedded_file(&self, path: &str) -> Option<&'static [u8]> {
304 if let Some(data) = self.embedded_files.get(path) {
305 return Some(*data);
306 }
307 let normalized = path.trim_start_matches('/').replace("//", "/");
309 if normalized != path {
310 return self.embedded_files.get(normalized.as_str()).copied();
311 }
312 None
313 }
314
315 pub fn open(&mut self, name: &str, mode: &str) -> io::Result<EntityId> {
319 match name {
321 "%stdin" => {
322 if mode != "r" {
323 return Err(io::Error::new(
324 io::ErrorKind::PermissionDenied,
325 "%stdin is read-only",
326 ));
327 }
328 return Ok(FILE_STDIN);
329 }
330 "%stdout" => {
331 if mode != "w" {
332 return Err(io::Error::new(
333 io::ErrorKind::PermissionDenied,
334 "%stdout is write-only",
335 ));
336 }
337 return Ok(FILE_STDOUT);
338 }
339 "%stderr" => {
340 if mode != "w" {
341 return Err(io::Error::new(
342 io::ErrorKind::PermissionDenied,
343 "%stderr is write-only",
344 ));
345 }
346 return Ok(FILE_STDERR);
347 }
348 "%lineedit" | "%statementedit" => {
349 if mode != "r" {
350 return Err(io::Error::new(
351 io::ErrorKind::PermissionDenied,
352 "read-only special file",
353 ));
354 }
355 let mut line = String::new();
357 let n = io::stdin().read_line(&mut line)?;
358 if n == 0 {
359 return Err(io::Error::new(io::ErrorKind::NotFound, "EOF on stdin"));
361 }
362 if line.ends_with('\n') {
363 line.pop();
364 if line.ends_with('\r') {
365 line.pop();
366 }
367 }
368 return Ok(self.create_string_source(line.into_bytes()));
369 }
370 _ => {}
371 }
372
373 if mode == "r"
375 && let Some(data) = self.embedded_files.get(name)
376 {
377 let id = EntityId(self.files.len() as u32);
378 self.files.push(FileEntry {
379 handle: FileHandle::StringSource {
380 data: data.to_vec(),
381 pos: 0,
382 },
383 name: name.to_string(),
384 mode: mode.to_string(),
385 line_num: 1,
386 pending_newlines: 0,
387 });
388 return Ok(id);
389 }
390
391 let file = match mode {
392 "r" => std::fs::File::open(name)?,
393 "w" => std::fs::File::create(name)?,
394 "a" => std::fs::OpenOptions::new()
395 .append(true)
396 .create(true)
397 .open(name)?,
398 "r+" => std::fs::OpenOptions::new()
399 .read(true)
400 .write(true)
401 .open(name)?,
402 _ => return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid mode")),
403 };
404
405 let id = EntityId(self.files.len() as u32);
406 self.files.push(FileEntry {
407 handle: FileHandle::Real(BufReader::new(file)),
408 name: name.to_string(),
409 mode: mode.to_string(),
410 line_num: 1,
411 pending_newlines: 0,
412 });
413 Ok(id)
414 }
415
416 pub fn create_filter(&mut self, source: EntityId, kind: FilterKind) -> EntityId {
418 let id = EntityId(self.files.len() as u32);
419 self.files.push(FileEntry {
420 handle: FileHandle::Filter(Box::new(FilterState {
421 kind,
422 source,
423 output_buf: Vec::new(),
424 output_pos: 0,
425 putback: Vec::new(),
426 eof: false,
427 bytes_read: 0,
428 })),
429 name: "%filter".to_string(),
430 mode: "r".to_string(),
431 line_num: 1,
432 pending_newlines: 0,
433 });
434 id
435 }
436
437 pub fn create_filter_with_data(
439 &mut self,
440 source: EntityId,
441 kind: FilterKind,
442 data: Vec<u8>,
443 ) -> 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,
449 output_buf: data,
450 output_pos: 0,
451 putback: Vec::new(),
452 eof: false,
453 bytes_read: 0,
454 })),
455 name: "%filter".to_string(),
456 mode: "r".to_string(),
457 line_num: 1,
458 pending_newlines: 0,
459 });
460 id
461 }
462
463 pub fn create_encode_filter(&mut self, target: EntityId, kind: FilterKind) -> EntityId {
465 let id = EntityId(self.files.len() as u32);
466 self.files.push(FileEntry {
467 handle: FileHandle::Filter(Box::new(FilterState {
468 kind,
469 source: target, output_buf: Vec::new(),
471 output_pos: 0,
472 putback: Vec::new(),
473 eof: false,
474 bytes_read: 0,
475 })),
476 name: "%filter".to_string(),
477 mode: "w".to_string(),
478 line_num: 1,
479 pending_newlines: 0,
480 });
481 id
482 }
483
484 pub fn create_string_source(&mut self, data: Vec<u8>) -> EntityId {
486 let id = EntityId(self.files.len() as u32);
487 self.files.push(FileEntry {
488 handle: FileHandle::StringSource { data, pos: 0 },
489 name: "%stringsource".to_string(),
490 mode: "r".to_string(),
491 line_num: 1,
492 pending_newlines: 0,
493 });
494 id
495 }
496
497 pub fn create_proc_source(&mut self, proc: PsObject) -> EntityId {
503 let id = EntityId(self.files.len() as u32);
504 self.pending_procs += 1;
505 self.files.push(FileEntry {
506 handle: FileHandle::PendingProc { proc },
507 name: "%procsource".to_string(),
508 mode: "r".to_string(),
509 line_num: 1,
510 pending_newlines: 0,
511 });
512 id
513 }
514
515 pub fn pending_proc_source(&self, entity: EntityId) -> Option<(EntityId, PsObject, bool)> {
522 if self.pending_procs == 0 {
523 return None;
524 }
525 let mut cur = entity;
526 let mut saw_flate = false;
527 for _ in 0..256 {
530 match self.files.get(cur.0 as usize).map(|e| &e.handle) {
531 Some(FileHandle::PendingProc { proc }) => {
532 return Some((cur, *proc, saw_flate));
533 }
534 Some(FileHandle::Filter(state)) => {
535 if matches!(state.kind, FilterKind::FlateDecode { .. }) {
536 saw_flate = true;
537 }
538 cur = state.source;
539 }
540 _ => return None,
541 }
542 }
543 None
544 }
545
546 pub fn close_pending_proc(&mut self, entity: EntityId) {
554 let entry = &mut self.files[entity.0 as usize];
555 if matches!(entry.handle, FileHandle::PendingProc { .. }) {
556 entry.handle = FileHandle::Closed;
557 self.pending_procs = self.pending_procs.saturating_sub(1);
558 }
559 }
560
561 pub fn pending_proc_handles(&self) -> Vec<(EntityId, PsObject)> {
567 if self.pending_procs == 0 {
568 return Vec::new();
569 }
570 self.files
571 .iter()
572 .enumerate()
573 .filter_map(|(i, e)| match e.handle {
574 FileHandle::PendingProc { proc } => Some((EntityId(i as u32), proc)),
575 _ => None,
576 })
577 .collect()
578 }
579
580 pub fn install_proc_data(&mut self, entity: EntityId, data: Vec<u8>) {
582 let entry = &mut self.files[entity.0 as usize];
583 debug_assert!(
584 matches!(entry.handle, FileHandle::PendingProc { .. }),
585 "install_proc_data on a handle that is not a pending procedure source"
586 );
587 entry.handle = FileHandle::StringSource { data, pos: 0 };
588 self.pending_procs = self.pending_procs.saturating_sub(1);
589 }
590
591 pub fn get_remaining_bytes(&self, entity: EntityId) -> &[u8] {
596 let entry = &self.files[entity.0 as usize];
597 match &entry.handle {
598 FileHandle::StringSource { data, pos } => &data[*pos..],
599 _ => &[],
600 }
601 }
602
603 pub fn advance_position(&mut self, entity: EntityId, n: usize) {
605 let entry = &mut self.files[entity.0 as usize];
606 if let FileHandle::StringSource { pos, .. } = &mut entry.handle {
607 *pos += n;
608 }
609 }
610
611 pub fn line_num(&self, entity: EntityId) -> u32 {
613 self.files[entity.0 as usize].line_num
614 }
615
616 pub fn add_pending_newlines(&mut self, entity: EntityId, count: u32) {
619 self.files[entity.0 as usize].pending_newlines += count;
620 }
621
622 pub fn flush_pending_newlines(&mut self, entity: EntityId) {
625 let entry = &mut self.files[entity.0 as usize];
626 entry.line_num += entry.pending_newlines;
627 entry.pending_newlines = 0;
628 }
629
630 pub fn close(&mut self, entity: EntityId) -> io::Result<()> {
632 let is_encode = matches!(
634 &self.files[entity.0 as usize].handle,
635 FileHandle::Filter(state) if state.kind.is_encode()
636 );
637 if is_encode {
638 return self.close_encode_filter(entity);
639 }
640
641 let entry = &mut self.files[entity.0 as usize];
642 match entry.handle {
643 FileHandle::Stdin | FileHandle::Stdout | FileHandle::Stderr => Ok(()),
644 FileHandle::Closed => Ok(()),
645 FileHandle::Filter(_) => {
646 entry.handle = FileHandle::Closed;
648 Ok(())
649 }
650 _ => {
651 entry.handle = FileHandle::Closed;
652 Ok(())
653 }
654 }
655 }
656
657 pub fn read_byte(&mut self, entity: EntityId) -> io::Result<Option<u8>> {
659 let entry = &mut self.files[entity.0 as usize];
660 match &mut entry.handle {
661 FileHandle::Real(f) => {
662 let mut buf = [0u8; 1];
663 let n = f.read(&mut buf)?;
664 if n == 0 { Ok(None) } else { Ok(Some(buf[0])) }
665 }
666 FileHandle::Stdin => {
667 if std::io::stdin().is_terminal() {
668 Ok(None) } else {
670 let mut buf = [0u8; 1];
671 let n = io::stdin().read(&mut buf)?;
672 if n == 0 { Ok(None) } else { Ok(Some(buf[0])) }
673 }
674 }
675 FileHandle::StringSource { data, pos } => {
676 if *pos < data.len() {
677 let b = data[*pos];
678 *pos += 1;
679 Ok(Some(b))
680 } else {
681 Ok(None)
682 }
683 }
684 FileHandle::Filter(_) => {
685 self.read_byte_filter(entity)
687 }
688 FileHandle::Closed => Ok(None), _ => Err(io::Error::other("not readable")),
690 }
691 }
692
693 fn read_byte_filter(&mut self, entity: EntityId) -> io::Result<Option<u8>> {
695 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 a filter"));
701 }
702 };
703
704 if let Some(b) = state.putback.pop() {
706 state.bytes_read += 1;
707 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
708 return Ok(Some(b));
709 }
710
711 if state.output_pos < state.output_buf.len() {
713 let b = state.output_buf[state.output_pos];
714 state.output_pos += 1;
715 state.bytes_read += 1;
716 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
717 return Ok(Some(b));
718 }
719
720 if state.eof {
722 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
723 return Ok(None);
724 }
725
726 self.refill_filter(&mut state)?;
728
729 let result = if state.output_pos < state.output_buf.len() {
730 let b = state.output_buf[state.output_pos];
731 state.output_pos += 1;
732 state.bytes_read += 1;
733 Ok(Some(b))
734 } else {
735 Ok(None)
736 };
737
738 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
739 result
740 }
741
742 pub fn read_into(&mut self, entity: EntityId, buf: &mut [u8]) -> io::Result<usize> {
744 let entry = &mut self.files[entity.0 as usize];
745 match &mut entry.handle {
746 FileHandle::Real(f) => f.read(buf),
747 FileHandle::Stdin => {
748 if std::io::stdin().is_terminal() {
751 Ok(0)
752 } else {
753 io::stdin().read(buf)
754 }
755 }
756 FileHandle::StringSource { data, pos } => {
757 let remaining = data.len() - *pos;
758 let n = buf.len().min(remaining);
759 buf[..n].copy_from_slice(&data[*pos..*pos + n]);
760 *pos += n;
761 Ok(n)
762 }
763 FileHandle::Filter(_) => {
764 let mut count = 0;
766 for slot in buf.iter_mut() {
767 match self.read_byte(entity)? {
768 Some(b) => {
769 *slot = b;
770 count += 1;
771 }
772 None => break,
773 }
774 }
775 Ok(count)
776 }
777 FileHandle::Closed => Err(io::Error::other("file closed")),
778 _ => Err(io::Error::other("not readable")),
779 }
780 }
781
782 pub fn write_byte(&mut self, entity: EntityId, byte: u8) -> io::Result<()> {
784 self.write_from(entity, &[byte])
785 }
786
787 pub fn write_from(&mut self, entity: EntityId, buf: &[u8]) -> io::Result<()> {
789 let is_encode = matches!(
791 &self.files[entity.0 as usize].handle,
792 FileHandle::Filter(state) if state.kind.is_encode()
793 );
794 if is_encode {
795 return self.encode_write(entity, buf);
796 }
797 let entry = &mut self.files[entity.0 as usize];
798 match &mut entry.handle {
799 FileHandle::Real(f) => f.get_mut().write_all(buf),
800 FileHandle::Stdout => io::stdout().write_all(buf),
801 FileHandle::Stderr => io::stderr().write_all(buf),
802 FileHandle::Closed => Err(io::Error::other("file closed")),
803 _ => Err(io::Error::other("not writable")),
804 }
805 }
806
807 fn encode_write(&mut self, entity: EntityId, data: &[u8]) -> io::Result<()> {
809 let entry = &mut self.files[entity.0 as usize];
811 let mut state = match std::mem::replace(&mut entry.handle, FileHandle::Closed) {
812 FileHandle::Filter(s) => s,
813 other => {
814 entry.handle = other;
815 return Err(io::Error::other("not an encode filter"));
816 }
817 };
818
819 let target = state.source;
820 let result = match &mut state.kind {
821 FilterKind::ASCIIHexEncode => {
822 let mut hex = Vec::with_capacity(data.len() * 2);
824 for &b in data {
825 hex.push(b"0123456789ABCDEF"[(b >> 4) as usize]);
826 hex.push(b"0123456789ABCDEF"[(b & 0xF) as usize]);
827 }
828 self.write_from(target, &hex)
829 }
830 FilterKind::ASCII85Encode { buf, col } => {
831 let mut encoded = Vec::new();
832 for &byte in data {
833 buf.push(byte);
834 if buf.len() == 4 {
835 let val = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
836 if val == 0 {
837 encoded.push(b'z');
838 *col += 1;
839 } else {
840 let mut chars = [0u8; 5];
841 let mut v = val;
842 for c in chars.iter_mut().rev() {
843 *c = (v % 85) as u8 + b'!';
844 v /= 85;
845 }
846 encoded.extend_from_slice(&chars);
847 *col += 5;
848 }
849 buf.clear();
850 if *col >= 75 {
851 encoded.push(b'\n');
852 *col = 0;
853 }
854 }
855 }
856 if encoded.is_empty() {
857 Ok(())
858 } else {
859 self.write_from(target, &encoded)
860 }
861 }
862 FilterKind::RunLengthEncode {
863 pending,
864 run_byte,
865 run_count,
866 } => {
867 for &b in data {
869 if let Some(rb) = *run_byte {
870 if b == rb {
871 *run_count += 1;
872 if *run_count >= 128 {
873 let lit = rle_emit_literals(pending);
875 if !lit.is_empty() {
876 self.write_from(target, &lit)?;
877 pending.clear();
878 }
879 let rep = rle_emit_repeat(rb, 128);
880 self.write_from(target, &rep)?;
881 *run_byte = None;
882 *run_count = 0;
883 }
884 } else {
885 if *run_count >= 3 {
887 let lit = rle_emit_literals(pending);
889 if !lit.is_empty() {
890 self.write_from(target, &lit)?;
891 pending.clear();
892 }
893 let rep = rle_emit_repeat(rb, *run_count);
894 self.write_from(target, &rep)?;
895 } else {
896 for _ in 0..*run_count {
898 pending.push(rb);
899 }
900 if pending.len() >= 128 {
901 let lit = rle_emit_literals(pending);
902 self.write_from(target, &lit)?;
903 pending.clear();
904 }
905 }
906 *run_byte = Some(b);
907 *run_count = 1;
908 }
909 } else {
910 *run_byte = Some(b);
912 *run_count = 1;
913 }
914 }
915 Ok(())
916 }
917 FilterKind::FlateEncode {
918 compressor,
919 predictor,
920 row_width,
921 bpp,
922 encode_buf,
923 prev_row,
924 ..
925 } => {
926 if *predictor <= 1 {
927 flate_compress_data(compressor, data, |chunk| self.write_from(target, chunk))
929 } else {
930 encode_buf.extend_from_slice(data);
932 let rw = *row_width;
933 let pred = *predictor;
934 let bp = *bpp;
935 while encode_buf.len() >= rw {
936 let row: Vec<u8> = encode_buf.drain(..rw).collect();
937 let encoded = if pred >= 10 {
938 encode_png_row(&row, bp)
939 } else {
940 encode_tiff_row(&row, bp)
941 };
942 prev_row.copy_from_slice(&row);
943 flate_compress_data(compressor, &encoded, |chunk| {
944 self.write_from(target, chunk)
945 })?;
946 }
947 Ok(())
948 }
949 }
950 FilterKind::LZWEncode { encoder } => {
951 let mut out = vec![0u8; data.len() * 2 + 64];
952 let result = encoder.encode_bytes(data, &mut out);
953 if result.consumed_out > 0 {
954 self.write_from(target, &out[..result.consumed_out])?;
955 }
956 Ok(())
957 }
958 FilterKind::NullEncode => self.write_from(target, data),
959 FilterKind::DCTEncode { buf, .. } => {
960 buf.extend_from_slice(data);
964 Ok(())
965 }
966 _ => Err(io::Error::other("not an encode filter")),
967 };
968
969 self.files[entity.0 as usize].handle = FileHandle::Filter(state);
971 result
972 }
973
974 fn close_encode_filter(&mut self, entity: EntityId) -> io::Result<()> {
976 let entry = &mut self.files[entity.0 as usize];
978 let mut state = match std::mem::replace(&mut entry.handle, FileHandle::Closed) {
979 FileHandle::Filter(s) => s,
980 other => {
981 entry.handle = other;
982 return Ok(());
983 }
984 };
985
986 let target = state.source;
987 match &mut state.kind {
988 FilterKind::ASCIIHexEncode => {
989 self.write_from(target, b">")?;
990 }
991 FilterKind::ASCII85Encode { buf, .. } => {
992 if !buf.is_empty() {
994 let n = buf.len();
995 while buf.len() < 4 {
997 buf.push(0);
998 }
999 let val = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
1000 let mut chars = [0u8; 5];
1001 let mut v = val;
1002 for c in chars.iter_mut().rev() {
1003 *c = (v % 85) as u8 + b'!';
1004 v /= 85;
1005 }
1006 self.write_from(target, &chars[..n + 1])?;
1008 }
1009 self.write_from(target, b"~>")?;
1010 }
1011 FilterKind::RunLengthEncode {
1012 pending,
1013 run_byte,
1014 run_count,
1015 } => {
1016 if let Some(rb) = *run_byte {
1018 if *run_count >= 3 {
1019 let lit = rle_emit_literals(pending);
1020 if !lit.is_empty() {
1021 self.write_from(target, &lit)?;
1022 }
1023 let rep = rle_emit_repeat(rb, *run_count);
1024 self.write_from(target, &rep)?;
1025 } else {
1026 for _ in 0..*run_count {
1027 pending.push(rb);
1028 }
1029 let lit = rle_emit_literals(pending);
1030 if !lit.is_empty() {
1031 self.write_from(target, &lit)?;
1032 }
1033 }
1034 } else if !pending.is_empty() {
1035 let lit = rle_emit_literals(pending);
1036 self.write_from(target, &lit)?;
1037 }
1038 self.write_from(target, &[128])?;
1040 }
1041 FilterKind::FlateEncode {
1042 compressor,
1043 predictor,
1044 row_width,
1045 bpp,
1046 encode_buf,
1047 ..
1048 } => {
1049 if *predictor > 1 && !encode_buf.is_empty() {
1051 let rw = *row_width;
1052 let pred = *predictor;
1053 let bp = *bpp;
1054 encode_buf.resize(rw, 0);
1056 let row: Vec<u8> = std::mem::take(encode_buf);
1057 let encoded = if pred >= 10 {
1058 encode_png_row(&row, bp)
1059 } else {
1060 encode_tiff_row(&row, bp)
1061 };
1062 flate_compress_data(compressor, &encoded, |chunk| {
1063 self.write_from(target, chunk)
1064 })?;
1065 }
1066 let mut out = vec![0u8; 256];
1068 loop {
1069 let before_out = compressor.total_out() as usize;
1070 let status = compressor
1071 .compress(&[], &mut out, flate2::FlushCompress::Finish)
1072 .map_err(|e| io::Error::other(e.to_string()))?;
1073 let produced = compressor.total_out() as usize - before_out;
1074 if produced > 0 {
1075 self.write_from(target, &out[..produced])?;
1076 }
1077 if matches!(status, flate2::Status::StreamEnd) {
1078 break;
1079 }
1080 }
1081 }
1082 FilterKind::LZWEncode { encoder } => {
1083 encoder.finish();
1085 let mut out = vec![0u8; 256];
1086 loop {
1087 let result = encoder.encode_bytes(&[], &mut out);
1088 if result.consumed_out > 0 {
1089 self.write_from(target, &out[..result.consumed_out])?;
1090 }
1091 if result.consumed_out == 0 {
1092 break;
1093 }
1094 }
1095 }
1096 FilterKind::NullEncode => {}
1097 FilterKind::DCTEncode {
1098 buf,
1099 columns,
1100 rows,
1101 colors,
1102 quality,
1103 color_transform,
1104 } => {
1105 let w = *columns as u16;
1106 let h = *rows as u16;
1107 let nc = *colors as u8;
1108 let q = *quality;
1109 let _ct = *color_transform;
1110
1111 let color_type = match nc {
1113 1 => jpeg_encoder::ColorType::Luma,
1114 3 => jpeg_encoder::ColorType::Rgb,
1115 4 => jpeg_encoder::ColorType::Cmyk,
1116 _ => jpeg_encoder::ColorType::Rgb,
1117 };
1118
1119 let expected_len = w as usize * h as usize * nc as usize;
1120 buf.resize(expected_len, 0);
1122
1123 let mut jpeg_data = Vec::new();
1124 let encoder = jpeg_encoder::Encoder::new(&mut jpeg_data, q);
1125 encoder
1126 .encode(buf, w, h, color_type)
1127 .map_err(|e| io::Error::other(format!("JPEG encode error: {e}")))?;
1128 self.write_from(target, &jpeg_data)?;
1129 }
1130 _ => {}
1131 }
1132
1133 self.close(target)?;
1135
1136 Ok(())
1138 }
1139
1140 pub fn readline(&mut self, entity: EntityId, buf: &mut [u8]) -> io::Result<(usize, bool)> {
1142 let mut count = 0;
1143 let mut hit_newline = false;
1144 loop {
1145 if count >= buf.len() {
1146 break;
1147 }
1148 match self.read_byte(entity)? {
1149 None => break,
1150 Some(b'\n') => {
1151 hit_newline = true;
1152 break;
1153 }
1154 Some(b'\r') => {
1155 hit_newline = true;
1156 match self.read_byte(entity)? {
1158 Some(b'\n') => {} Some(other) => self.putback_bytes(entity, &[other]),
1160 None => {}
1161 }
1162 break;
1163 }
1164 Some(b) => {
1165 buf[count] = b;
1166 count += 1;
1167 }
1168 }
1169 }
1170 Ok((count, hit_newline))
1171 }
1172
1173 pub fn position(&mut self, entity: EntityId) -> io::Result<u64> {
1175 let entry = &mut self.files[entity.0 as usize];
1176 match &mut entry.handle {
1177 FileHandle::Real(f) => f.stream_position(),
1178 FileHandle::StringSource { pos, .. } => Ok(*pos as u64),
1179 FileHandle::Filter(state) => Ok(state.bytes_read),
1180 _ => Err(io::Error::other("not seekable")),
1181 }
1182 }
1183
1184 pub fn set_position(&mut self, entity: EntityId, pos: u64) -> io::Result<()> {
1186 let entry = &mut self.files[entity.0 as usize];
1187 match &mut entry.handle {
1188 FileHandle::Real(f) => {
1189 f.seek(io::SeekFrom::Start(pos))?;
1190 Ok(())
1191 }
1192 FileHandle::StringSource { data, pos: p } => {
1193 *p = (pos as usize).min(data.len());
1194 Ok(())
1195 }
1196 _ => Err(io::Error::other("not seekable")),
1197 }
1198 }
1199
1200 pub fn flush(&mut self, entity: EntityId) -> io::Result<()> {
1202 let entry = &self.files[entity.0 as usize];
1203 match &entry.handle {
1204 FileHandle::Real(_) => {
1205 let entry = &mut self.files[entity.0 as usize];
1206 if entry.mode.starts_with('r') {
1207 entry.handle = FileHandle::Closed;
1209 } else if let FileHandle::Real(f) = &mut entry.handle {
1210 f.get_mut().flush()?;
1211 }
1212 }
1213 FileHandle::Stdout => io::stdout().flush()?,
1214 FileHandle::Stderr => io::stderr().flush()?,
1215 FileHandle::Filter(_) => {
1216 let mut buf = [0u8; 4096];
1220 loop {
1221 match self.read_into(entity, &mut buf) {
1222 Ok(0) => break,
1223 Ok(_) => continue,
1224 Err(_) => break,
1225 }
1226 }
1227 }
1228 FileHandle::StringSource { .. } => {
1229 let entry = &mut self.files[entity.0 as usize];
1231 if let FileHandle::StringSource { data, pos } = &mut entry.handle {
1232 *pos = data.len();
1233 }
1234 }
1235 _ => {}
1236 }
1237 Ok(())
1238 }
1239
1240 pub fn is_open(&self, entity: EntityId) -> bool {
1242 if (entity.0 as usize) >= self.files.len() {
1243 return false;
1244 }
1245 !matches!(self.files[entity.0 as usize].handle, FileHandle::Closed)
1246 }
1247
1248 pub fn is_readable(&self, entity: EntityId) -> bool {
1250 if (entity.0 as usize) >= self.files.len() {
1251 return false;
1252 }
1253 !matches!(
1254 self.files[entity.0 as usize].handle,
1255 FileHandle::Closed | FileHandle::Stdout | FileHandle::Stderr
1256 )
1257 }
1258
1259 pub fn read_n_bytes(&mut self, entity: EntityId, n: usize) -> io::Result<Vec<u8>> {
1261 let mut result = Vec::with_capacity(n);
1262 for _ in 0..n {
1263 match self.read_byte(entity)? {
1264 Some(b) => result.push(b),
1265 None => return Err(io::Error::other("unexpected EOF")),
1266 }
1267 }
1268 Ok(result)
1269 }
1270
1271 pub fn putback_bytes(&mut self, entity: EntityId, bytes: &[u8]) {
1275 let entry = &mut self.files[entity.0 as usize];
1276 match &mut entry.handle {
1277 FileHandle::Filter(state) => {
1278 for &b in bytes.iter().rev() {
1280 state.putback.push(b);
1281 }
1282 }
1283 FileHandle::StringSource { pos, .. } => {
1284 *pos = pos.saturating_sub(bytes.len());
1285 }
1286 FileHandle::Real(f) => {
1287 let _ = f.seek(std::io::SeekFrom::Current(-(bytes.len() as i64)));
1289 }
1290 _ => {}
1291 }
1292 }
1293
1294 pub fn is_seekable(&self, entity: EntityId) -> bool {
1296 matches!(self.files[entity.0 as usize].handle, FileHandle::Real(_))
1297 }
1298
1299 pub fn bytes_available(&mut self, entity: EntityId) -> i32 {
1303 let entry = &mut self.files[entity.0 as usize];
1304 if entry.mode.starts_with('w') || entry.mode.starts_with('a') {
1306 return -1;
1307 }
1308 match &mut entry.handle {
1309 FileHandle::Real(f) => {
1310 if let Ok(cur) = f.stream_position() {
1311 if let Ok(end) = f.seek(io::SeekFrom::End(0)) {
1312 let _ = f.seek(io::SeekFrom::Start(cur));
1313 let remaining = end.saturating_sub(cur);
1314 if remaining == 0 {
1315 -1 } else {
1317 remaining.min(i32::MAX as u64) as i32
1318 }
1319 } else {
1320 -1
1321 }
1322 } else {
1323 -1
1324 }
1325 }
1326 FileHandle::StringSource { data, pos } => {
1327 let remaining = data.len() - *pos;
1328 if remaining == 0 { -1 } else { remaining as i32 }
1329 }
1330 FileHandle::Closed => -1,
1331 _ => -1,
1332 }
1333 }
1334
1335 pub fn name(&self, entity: EntityId) -> &str {
1337 &self.files[entity.0 as usize].name
1338 }
1339
1340 pub fn set_name(&mut self, entity: EntityId, name: String) {
1342 self.files[entity.0 as usize].name = name;
1343 }
1344
1345 pub fn mode(&self, entity: EntityId) -> &str {
1347 &self.files[entity.0 as usize].mode
1348 }
1349
1350 pub fn len(&self) -> usize {
1352 self.files.len()
1353 }
1354
1355 pub fn is_empty(&self) -> bool {
1357 self.files.is_empty()
1358 }
1359
1360 pub fn putback_byte(&mut self, entity: EntityId, byte: u8) {
1362 let entry = &mut self.files[entity.0 as usize];
1363 if let FileHandle::Filter(ref mut state) = entry.handle {
1364 state.putback.push(byte);
1365 }
1366 }
1367
1368 pub fn read_all(&mut self, entity: EntityId) -> io::Result<Vec<u8>> {
1370 let mut data = Vec::new();
1371 while let Some(b) = self.read_byte(entity)? {
1372 data.push(b);
1373 }
1374 Ok(data)
1375 }
1376
1377 fn refill_filter(&mut self, state: &mut FilterState) -> io::Result<()> {
1381 state.output_buf.clear();
1382 state.output_pos = 0;
1383
1384 match &mut state.kind {
1385 FilterKind::ASCIIHexDecode => {
1386 self.refill_ascii_hex(state.source, &mut state.output_buf, &mut state.eof)?;
1387 }
1388 FilterKind::ASCII85Decode { .. } => {
1389 let source = state.source;
1391 self.refill_ascii85(
1392 source,
1393 &mut state.kind,
1394 &mut state.output_buf,
1395 &mut state.eof,
1396 )?;
1397 }
1398 FilterKind::RunLengthDecode { .. } => {
1399 let source = state.source;
1400 self.refill_rle(
1401 source,
1402 &mut state.kind,
1403 &mut state.output_buf,
1404 &mut state.eof,
1405 )?;
1406 }
1407 FilterKind::FlateDecode { .. } => {
1408 let source = state.source;
1409 self.refill_flate(
1410 source,
1411 &mut state.kind,
1412 &mut state.output_buf,
1413 &mut state.eof,
1414 )?;
1415 }
1416 FilterKind::LZWDecode { .. } => {
1417 let source = state.source;
1418 self.refill_lzw(
1419 source,
1420 &mut state.kind,
1421 &mut state.output_buf,
1422 &mut state.eof,
1423 )?;
1424 }
1425 FilterKind::DCTDecode { decoded, .. } => {
1426 if !*decoded {
1427 let source = state.source;
1429 let mut jpeg_data = self.read_all(source)?;
1430 if !jpeg_data.ends_with(&[0xFF, 0xD9]) {
1437 jpeg_data.extend_from_slice(&[0xFF, 0xD9]);
1438 }
1439 let mut decoder = jpeg_decoder::Decoder::new(jpeg_data.as_slice());
1440 let pixels = decoder
1441 .decode()
1442 .map_err(|e| io::Error::other(format!("JPEG decode error: {e}")))?;
1443 state.output_buf = pixels;
1444 state.output_pos = 0;
1445 *decoded = true;
1446 } else {
1447 state.eof = true;
1448 }
1449 }
1450 FilterKind::JBIG2Decode { decoded, .. } => {
1451 if !*decoded {
1452 let source = state.source;
1453 let raw = self.read_all(source)?;
1454 let globals = match &state.kind {
1456 FilterKind::JBIG2Decode { globals, .. } => globals.clone(),
1457 _ => None,
1458 };
1459 let image = hayro_jbig2::decode_embedded(&raw, globals.as_deref())
1460 .map_err(|e| io::Error::other(format!("JBIG2 decode error: {e}")))?;
1461 let row_bytes = (image.width as usize).div_ceil(8);
1466 let mut packed = vec![0xFFu8; row_bytes * image.height as usize];
1467 for y in 0..image.height as usize {
1468 for x in 0..image.width as usize {
1469 if image.data[y * image.width as usize + x] {
1470 packed[y * row_bytes + x / 8] &= !(0x80 >> (x % 8));
1471 }
1472 }
1473 }
1474 state.output_buf = packed;
1475 state.output_pos = 0;
1476 if let FilterKind::JBIG2Decode { decoded, .. } = &mut state.kind {
1477 *decoded = true;
1478 }
1479 } else {
1480 state.eof = true;
1481 }
1482 }
1483 FilterKind::JPXDecode { decoded } => {
1484 if !*decoded {
1485 let source = state.source;
1486 let raw = self.read_all(source)?;
1487 let image = hayro_jpeg2000::Image::new(
1488 &raw,
1489 &hayro_jpeg2000::DecodeSettings::default(),
1490 )
1491 .map_err(|e| io::Error::other(format!("JPXDecode error: {e}")))?;
1492 let pixels = image
1493 .decode()
1494 .map_err(|e| io::Error::other(format!("JPXDecode error: {e}")))?;
1495 state.output_buf = pixels;
1496 state.output_pos = 0;
1497 *decoded = true;
1498 } else {
1499 state.eof = true;
1500 }
1501 }
1502 FilterKind::CCITTFaxDecode { decoded, .. } => {
1503 if !*decoded {
1504 let source = state.source;
1505 let ccitt_data = self.read_all(source)?;
1506 let decoded_bytes = Self::decode_ccittfax(&ccitt_data, &mut state.kind)?;
1507 state.output_buf = decoded_bytes;
1508 state.output_pos = 0;
1509 if let FilterKind::CCITTFaxDecode { decoded, .. } = &mut state.kind {
1511 *decoded = true;
1512 }
1513 } else {
1514 state.eof = true;
1515 }
1516 }
1517 FilterKind::SubFileDecode { .. } => {
1518 let source = state.source;
1519 self.refill_subfile(
1520 source,
1521 &mut state.kind,
1522 &mut state.output_buf,
1523 &mut state.eof,
1524 )?;
1525 }
1526 FilterKind::EexecDecode { .. } => {
1527 let source = state.source;
1528 self.refill_eexec(
1529 source,
1530 &mut state.kind,
1531 &mut state.output_buf,
1532 &mut state.eof,
1533 )?;
1534 }
1535 _ => {
1537 state.eof = true;
1538 }
1539 }
1540 Ok(())
1541 }
1542
1543 fn refill_ascii_hex(
1545 &mut self,
1546 source: EntityId,
1547 out: &mut Vec<u8>,
1548 eof: &mut bool,
1549 ) -> io::Result<()> {
1550 let mut nibble: Option<u8> = None;
1551 let target = 4096;
1552
1553 while out.len() < target {
1554 match self.read_byte(source)? {
1555 None => {
1556 if let Some(high) = nibble.take() {
1558 out.push(high << 4);
1559 }
1560 *eof = true;
1561 return Ok(());
1562 }
1563 Some(b'>') => {
1564 if let Some(high) = nibble.take() {
1566 out.push(high << 4);
1567 }
1568 *eof = true;
1569 return Ok(());
1570 }
1571 Some(b) => {
1572 let nib = match b {
1573 b'0'..=b'9' => Some(b - b'0'),
1574 b'a'..=b'f' => Some(b - b'a' + 10),
1575 b'A'..=b'F' => Some(b - b'A' + 10),
1576 _ => None, };
1578 if let Some(n) = nib {
1579 match nibble.take() {
1580 None => nibble = Some(n),
1581 Some(high) => out.push((high << 4) | n),
1582 }
1583 }
1584 }
1585 }
1586 }
1587 Ok(())
1588 }
1589
1590 fn refill_ascii85(
1592 &mut self,
1593 source: EntityId,
1594 kind: &mut FilterKind,
1595 out: &mut Vec<u8>,
1596 eof: &mut bool,
1597 ) -> io::Result<()> {
1598 let group = match kind {
1599 FilterKind::ASCII85Decode { group } => group,
1600 _ => return Err(io::Error::other("not ASCII85")),
1601 };
1602 let target = 4096;
1603
1604 while out.len() < target {
1605 match self.read_byte(source)? {
1606 None => {
1607 if group.len() >= 2 {
1609 ascii85_decode_partial(group, out);
1610 }
1611 group.clear();
1612 *eof = true;
1613 return Ok(());
1614 }
1615 Some(b'~') => {
1616 let _ = self.read_byte(source)?; if group.len() >= 2 {
1619 ascii85_decode_partial(group, out);
1620 }
1621 group.clear();
1622 *eof = true;
1623 return Ok(());
1624 }
1625 Some(b'z') => {
1626 out.extend_from_slice(&[0, 0, 0, 0]);
1628 }
1629 Some(b) if b.is_ascii_whitespace() => {
1630 }
1632 Some(b) if (b'!'..=b'u').contains(&b) => {
1633 group.push(b - b'!');
1634 if group.len() == 5 {
1635 let val = group[0] as u64 * 85 * 85 * 85 * 85
1637 + group[1] as u64 * 85 * 85 * 85
1638 + group[2] as u64 * 85 * 85
1639 + group[3] as u64 * 85
1640 + group[4] as u64;
1641 out.push((val >> 24) as u8);
1642 out.push((val >> 16) as u8);
1643 out.push((val >> 8) as u8);
1644 out.push(val as u8);
1645 group.clear();
1646 }
1647 }
1648 Some(_) => {
1649 }
1651 }
1652 }
1653 Ok(())
1654 }
1655
1656 fn refill_rle(
1658 &mut self,
1659 source: EntityId,
1660 kind: &mut FilterKind,
1661 out: &mut Vec<u8>,
1662 eof: &mut bool,
1663 ) -> io::Result<()> {
1664 let rle_state = match kind {
1665 FilterKind::RunLengthDecode { state } => state,
1666 _ => return Err(io::Error::other("not RLE")),
1667 };
1668 let target = 4096;
1669
1670 while out.len() < target {
1671 match rle_state {
1672 RleState::Init => {
1673 match self.read_byte(source)? {
1674 None | Some(128) => {
1675 *rle_state = RleState::Eod;
1676 *eof = true;
1677 return Ok(());
1678 }
1679 Some(b) if b < 128 => {
1680 *rle_state = RleState::Literal {
1681 remaining: b as u16 + 1,
1682 };
1683 }
1684 Some(b) => {
1685 let count = 257 - b as u16;
1687 match self.read_byte(source)? {
1688 None => {
1689 *rle_state = RleState::Eod;
1690 *eof = true;
1691 return Ok(());
1692 }
1693 Some(val) => {
1694 *rle_state = RleState::Repeat {
1695 byte: val,
1696 remaining: count,
1697 };
1698 }
1699 }
1700 }
1701 }
1702 }
1703 RleState::Literal { remaining } => {
1704 if *remaining == 0 {
1705 *rle_state = RleState::Init;
1706 continue;
1707 }
1708 match self.read_byte(source)? {
1709 None => {
1710 *rle_state = RleState::Eod;
1711 *eof = true;
1712 return Ok(());
1713 }
1714 Some(b) => {
1715 out.push(b);
1716 *remaining -= 1;
1717 }
1718 }
1719 }
1720 RleState::Repeat { byte, remaining } => {
1721 if *remaining == 0 {
1722 *rle_state = RleState::Init;
1723 continue;
1724 }
1725 out.push(*byte);
1726 *remaining -= 1;
1727 }
1728 RleState::Eod => {
1729 *eof = true;
1730 return Ok(());
1731 }
1732 }
1733 }
1734 Ok(())
1735 }
1736
1737 fn refill_flate(
1739 &mut self,
1740 source: EntityId,
1741 kind: &mut FilterKind,
1742 out: &mut Vec<u8>,
1743 eof: &mut bool,
1744 ) -> io::Result<()> {
1745 let (decompressor, raw_buf, predictor, columns, colors, bpc, prev_row) = match kind {
1746 FilterKind::FlateDecode {
1747 decompressor,
1748 raw_buf,
1749 predictor,
1750 columns,
1751 colors,
1752 bpc,
1753 prev_row,
1754 } => (
1755 decompressor,
1756 raw_buf,
1757 *predictor,
1758 *columns,
1759 *colors,
1760 *bpc,
1761 prev_row,
1762 ),
1763 _ => return Err(io::Error::other("not Flate")),
1764 };
1765
1766 if raw_buf.is_empty() {
1768 let mut chunk = vec![0u8; 8192];
1769 let mut total = 0;
1770 while let Some(b) = self.read_byte(source)? {
1772 chunk[total] = b;
1773 total += 1;
1774 if total >= chunk.len() {
1775 break;
1776 }
1777 }
1778 if total == 0 {
1779 *eof = true;
1780 return Ok(());
1781 }
1782 raw_buf.extend_from_slice(&chunk[..total]);
1783 }
1784
1785 let mut decompressed = vec![0u8; 16384];
1787 let before_in = decompressor.total_in();
1788 let before_out = decompressor.total_out();
1789 let status = decompressor
1790 .decompress(raw_buf, &mut decompressed, flate2::FlushDecompress::None)
1791 .map_err(|e| io::Error::other(format!("flate2 decompress error: {}", e)))?;
1792
1793 let consumed = (decompressor.total_in() - before_in) as usize;
1794 let produced = (decompressor.total_out() - before_out) as usize;
1795
1796 raw_buf.drain(..consumed);
1798
1799 if status == flate2::Status::StreamEnd {
1800 *eof = true;
1801 }
1802
1803 let decompressed = &decompressed[..produced];
1804
1805 if predictor == 1 || predictor == 0 {
1807 out.extend_from_slice(decompressed);
1809 } else if predictor == 2 {
1810 apply_tiff_predictor(decompressed, out, columns, colors, bpc);
1812 } else if (10..=15).contains(&predictor) {
1813 apply_png_predictor(decompressed, out, columns, colors, bpc, prev_row);
1815 } else {
1816 out.extend_from_slice(decompressed);
1817 }
1818
1819 Ok(())
1820 }
1821
1822 fn refill_lzw(
1824 &mut self,
1825 source: EntityId,
1826 kind: &mut FilterKind,
1827 out: &mut Vec<u8>,
1828 eof: &mut bool,
1829 ) -> io::Result<()> {
1830 let (decoder, raw_buf) = match kind {
1831 FilterKind::LZWDecode { decoder, raw_buf } => (decoder, raw_buf),
1832 _ => return Err(io::Error::other("not LZW")),
1833 };
1834
1835 let mut decompressed = vec![0u8; 16384];
1836
1837 loop {
1838 if raw_buf.is_empty() {
1840 let mut chunk = vec![0u8; 8192];
1841 let mut total = 0;
1842 while let Some(b) = self.read_byte(source)? {
1843 chunk[total] = b;
1844 total += 1;
1845 if total >= chunk.len() {
1846 break;
1847 }
1848 }
1849 if total == 0 {
1850 let result = decoder.decode_bytes(&[], &mut decompressed);
1852 if result.consumed_out > 0 {
1853 out.extend_from_slice(&decompressed[..result.consumed_out]);
1854 }
1855 *eof = true;
1856 return Ok(());
1857 }
1858 raw_buf.extend_from_slice(&chunk[..total]);
1859 }
1860
1861 let result = decoder.decode_bytes(raw_buf, &mut decompressed);
1863 let consumed_in = result.consumed_in;
1864 let consumed_out = result.consumed_out;
1865
1866 raw_buf.drain(..consumed_in);
1868
1869 match result.status {
1870 Ok(weezl::LzwStatus::Done) => {
1871 out.extend_from_slice(&decompressed[..consumed_out]);
1872 *eof = true;
1873 return Ok(());
1874 }
1875 Ok(weezl::LzwStatus::NoProgress) => {
1876 if consumed_out > 0 {
1877 out.extend_from_slice(&decompressed[..consumed_out]);
1878 return Ok(());
1879 }
1880 if raw_buf.is_empty() {
1882 continue; }
1884 *eof = true;
1886 return Ok(());
1887 }
1888 Ok(weezl::LzwStatus::Ok) => {
1889 out.extend_from_slice(&decompressed[..consumed_out]);
1890 if consumed_out > 0 {
1891 return Ok(());
1892 }
1893 continue;
1895 }
1896 Err(e) => {
1897 return Err(io::Error::other(format!("LZW decode error: {}", e)));
1898 }
1899 }
1900 }
1901 }
1902
1903 fn refill_subfile(
1905 &mut self,
1906 source: EntityId,
1907 kind: &mut FilterKind,
1908 out: &mut Vec<u8>,
1909 eof: &mut bool,
1910 ) -> io::Result<()> {
1911 let (eod_string, eod_count, bytes_remaining) = match kind {
1912 FilterKind::SubFileDecode {
1913 eod_string,
1914 eod_count,
1915 bytes_remaining,
1916 } => (eod_string, eod_count, bytes_remaining),
1917 _ => return Err(io::Error::other("not SubFile")),
1918 };
1919
1920 if eod_string.is_empty() {
1921 if let Some(remaining) = bytes_remaining {
1922 let target = (*remaining).min(4096) as usize;
1925 for _ in 0..target {
1926 match self.read_byte(source)? {
1927 Some(b) => {
1928 out.push(b);
1929 *remaining -= 1;
1930 }
1931 None => {
1932 *eof = true;
1933 return Ok(());
1934 }
1935 }
1936 }
1937 if *remaining <= 0 {
1938 *eof = true;
1939 }
1940 } else {
1941 for _ in 0..4096 {
1948 match self.read_byte(source)? {
1949 Some(b) => out.push(b),
1950 None => {
1951 *eof = true;
1952 return Ok(());
1953 }
1954 }
1955 }
1956 }
1957 } else {
1958 let eod = eod_string.clone();
1960 let target_count = *eod_count;
1961 let mut match_pos = 0;
1962 let mut found_count = 0;
1963
1964 for _ in 0..4096 {
1965 match self.read_byte(source)? {
1966 None => {
1967 *eof = true;
1968 return Ok(());
1969 }
1970 Some(b) => {
1971 if b == eod[match_pos] {
1972 match_pos += 1;
1973 if match_pos == eod.len() {
1974 match_pos = 0;
1975 if target_count == 0 {
1980 *eof = true;
1981 return Ok(());
1982 }
1983 found_count += 1;
1984 out.extend_from_slice(&eod);
1985 if found_count >= target_count {
1986 *eof = true;
1987 return Ok(());
1988 }
1989 }
1990 } else {
1991 if match_pos > 0 {
1993 out.extend_from_slice(&eod[..match_pos]);
1994 match_pos = 0;
1995 }
1996 out.push(b);
1997 }
1998 }
1999 }
2000 }
2001 }
2002
2003 Ok(())
2004 }
2005
2006 fn decode_ccittfax(data: &[u8], kind: &mut FilterKind) -> io::Result<Vec<u8>> {
2008 let FilterKind::CCITTFaxDecode {
2009 k,
2010 columns,
2011 rows,
2012 end_of_block,
2013 black_is1,
2014 ..
2015 } = kind
2016 else {
2017 return Err(io::Error::other("not a CCITTFaxDecode filter"));
2018 };
2019 let k = *k;
2020 let width = *columns as u16;
2021 let rows_limit = *rows;
2022 let end_of_block = *end_of_block;
2023 let black_is1 = *black_is1;
2024
2025 let row_bytes = (width as usize).div_ceil(8);
2027 let mut output = Vec::new();
2028 let mut line_count: u32 = 0;
2029
2030 let mut process_line = |transitions: &[u16]| {
2032 if !end_of_block && rows_limit > 0 && line_count >= rows_limit {
2034 return;
2035 }
2036
2037 let line = fax::decoder::Line { transitions, width };
2039 let mut row = vec![0u8; row_bytes];
2040 for (i, color) in line.pels().enumerate() {
2041 if i >= width as usize {
2042 break;
2043 }
2044 let is_set = matches!(color, fax::Color::Black);
2047 if is_set {
2048 row[i / 8] |= 0x80 >> (i % 8);
2049 }
2050 }
2051
2052 if !black_is1 {
2057 for byte in &mut row {
2058 *byte = !*byte;
2059 }
2060 }
2061
2062 output.extend_from_slice(&row);
2063 line_count += 1;
2064 };
2065
2066 if k < 0 {
2067 let height = if rows_limit > 0 {
2069 Some(rows_limit as u16)
2070 } else {
2071 None
2072 };
2073 fax::decoder::decode_g4(data.iter().copied(), width, height, |transitions| {
2074 process_line(transitions)
2075 });
2076 } else {
2077 fax::decoder::decode_g3(data.iter().copied(), |transitions| {
2079 process_line(transitions);
2080 });
2081 }
2082
2083 Ok(output)
2084 }
2085
2086 fn refill_eexec(
2090 &mut self,
2091 source: EntityId,
2092 kind: &mut FilterKind,
2093 out: &mut Vec<u8>,
2094 eof: &mut bool,
2095 ) -> io::Result<()> {
2096 let FilterKind::EexecDecode {
2097 r,
2098 is_hex,
2099 skip_count,
2100 hex_leftover,
2101 } = kind
2102 else {
2103 return Ok(());
2104 };
2105
2106 const C1: u16 = 52845;
2107 const C2: u16 = 22719;
2108 const TARGET: usize = 1;
2113
2114 if is_hex.is_none() {
2116 let mut probe = Vec::with_capacity(8);
2117 for _ in 0..8 {
2118 match self.read_byte(source)? {
2119 Some(b) => probe.push(b),
2120 None => break,
2121 }
2122 }
2123 if probe.is_empty() {
2124 *eof = true;
2125 return Ok(());
2126 }
2127 let hex = probe
2128 .iter()
2129 .all(|&b| b.is_ascii_hexdigit() || is_ps_whitespace(b));
2130 *is_hex = Some(hex);
2131
2132 if hex {
2134 let mut hex_digits = Vec::new();
2135 for &b in &probe {
2136 if b.is_ascii_hexdigit() {
2137 hex_digits.push(b);
2138 }
2139 }
2140 let mut i = 0;
2141 while i + 1 < hex_digits.len() {
2142 let cipher = (hex_val(hex_digits[i]) << 4) | hex_val(hex_digits[i + 1]);
2143 let plain = cipher ^ (*r >> 8) as u8;
2144 *r = (cipher as u16)
2145 .wrapping_add(*r)
2146 .wrapping_mul(C1)
2147 .wrapping_add(C2);
2148 if *skip_count < 4 {
2149 *skip_count += 1;
2150 } else {
2151 out.push(plain);
2152 }
2153 i += 2;
2154 }
2155 if i < hex_digits.len() {
2156 *hex_leftover = Some(hex_digits[i]);
2157 }
2158 } else {
2159 for &cipher in &probe {
2160 let plain = cipher ^ (*r >> 8) as u8;
2161 *r = (cipher as u16)
2162 .wrapping_add(*r)
2163 .wrapping_mul(C1)
2164 .wrapping_add(C2);
2165 if *skip_count < 4 {
2166 *skip_count += 1;
2167 } else {
2168 out.push(plain);
2169 }
2170 }
2171 }
2172 }
2173
2174 while out.len() < TARGET {
2176 let cipher_byte = if *is_hex == Some(true) {
2177 let hi = if let Some(h) = hex_leftover.take() {
2179 h
2180 } else {
2181 match read_next_hex_digit(self, source)? {
2182 Some(d) => d,
2183 None => {
2184 *eof = true;
2185 return Ok(());
2186 }
2187 }
2188 };
2189 let lo = read_next_hex_digit(self, source)?.unwrap_or(b'0');
2191 (hex_val(hi) << 4) | hex_val(lo)
2192 } else {
2193 match self.read_byte(source)? {
2195 Some(b) => b,
2196 None => {
2197 *eof = true;
2198 return Ok(());
2199 }
2200 }
2201 };
2202
2203 let plain = cipher_byte ^ (*r >> 8) as u8;
2204 *r = (cipher_byte as u16)
2205 .wrapping_add(*r)
2206 .wrapping_mul(C1)
2207 .wrapping_add(C2);
2208 if *skip_count < 4 {
2209 *skip_count += 1;
2210 } else {
2211 out.push(plain);
2212 }
2213 }
2214
2215 Ok(())
2216 }
2217}
2218
2219fn read_next_hex_digit(store: &mut FileStore, source: EntityId) -> io::Result<Option<u8>> {
2221 loop {
2222 match store.read_byte(source)? {
2223 Some(b) if b.is_ascii_hexdigit() => return Ok(Some(b)),
2224 Some(b) if is_ps_whitespace(b) => continue,
2225 Some(_) | None => return Ok(None),
2226 }
2227 }
2228}
2229
2230fn is_ps_whitespace(b: u8) -> bool {
2232 matches!(b, b'\0' | b'\t' | b'\n' | 0x0C | b'\r' | b' ')
2233}
2234
2235fn hex_val(b: u8) -> u8 {
2237 match b {
2238 b'0'..=b'9' => b - b'0',
2239 b'a'..=b'f' => b - b'a' + 10,
2240 b'A'..=b'F' => b - b'A' + 10,
2241 _ => 0,
2242 }
2243}
2244
2245fn ascii85_decode_partial(group: &[u8], out: &mut Vec<u8>) {
2247 let n = group.len();
2248 if n < 2 {
2249 return;
2250 }
2251 let mut padded = [84u8; 5];
2253 padded[..n].copy_from_slice(group);
2254
2255 let val = padded[0] as u64 * 85 * 85 * 85 * 85
2256 + padded[1] as u64 * 85 * 85 * 85
2257 + padded[2] as u64 * 85 * 85
2258 + padded[3] as u64 * 85
2259 + padded[4] as u64;
2260
2261 let bytes = [
2262 (val >> 24) as u8,
2263 (val >> 16) as u8,
2264 (val >> 8) as u8,
2265 val as u8,
2266 ];
2267 out.extend_from_slice(&bytes[..n - 1]);
2269}
2270
2271fn flate_compress_data(
2273 compressor: &mut flate2::Compress,
2274 data: &[u8],
2275 mut write_fn: impl FnMut(&[u8]) -> io::Result<()>,
2276) -> io::Result<()> {
2277 let mut out = vec![0u8; data.len() + 64];
2278 let mut input_pos = 0;
2279 loop {
2280 let before_in = compressor.total_in() as usize;
2281 let before_out = compressor.total_out() as usize;
2282 let status = compressor
2283 .compress(&data[input_pos..], &mut out, flate2::FlushCompress::None)
2284 .map_err(|e| io::Error::other(e.to_string()))?;
2285 let consumed = compressor.total_in() as usize - before_in;
2286 let produced = compressor.total_out() as usize - before_out;
2287 input_pos += consumed;
2288 if produced > 0 {
2289 write_fn(&out[..produced])?;
2290 }
2291 if input_pos >= data.len() || matches!(status, flate2::Status::StreamEnd) {
2292 break;
2293 }
2294 }
2295 Ok(())
2296}
2297
2298fn encode_png_row(row: &[u8], bpp: usize) -> Vec<u8> {
2300 let mut encoded = Vec::with_capacity(1 + row.len());
2301 encoded.push(1); for i in 0..row.len() {
2303 let left = if i >= bpp { row[i - bpp] } else { 0 };
2304 encoded.push(row[i].wrapping_sub(left));
2305 }
2306 encoded
2307}
2308
2309fn encode_tiff_row(row: &[u8], colors: usize) -> Vec<u8> {
2311 let mut encoded = Vec::from(row);
2312 for i in (colors..encoded.len()).rev() {
2314 encoded[i] = encoded[i].wrapping_sub(encoded[i - colors]);
2315 }
2316 encoded
2317}
2318
2319fn apply_tiff_predictor(data: &[u8], out: &mut Vec<u8>, columns: u32, colors: u32, bpc: u32) {
2321 let bytes_per_pixel = (colors * bpc).div_ceil(8);
2322 let row_bytes = (columns * colors * bpc).div_ceil(8);
2323
2324 for row in data.chunks(row_bytes as usize) {
2325 let mut prev = vec![0u8; bytes_per_pixel as usize];
2326 for (i, &b) in row.iter().enumerate() {
2327 let pi = i % bytes_per_pixel as usize;
2328 let val = b.wrapping_add(prev[pi]);
2329 out.push(val);
2330 prev[pi] = val;
2331 }
2332 }
2333}
2334
2335fn apply_png_predictor(
2337 data: &[u8],
2338 out: &mut Vec<u8>,
2339 columns: u32,
2340 colors: u32,
2341 bpc: u32,
2342 prev_row: &mut Vec<u8>,
2343) {
2344 let bytes_per_pixel = (colors * bpc).div_ceil(8) as usize;
2345 let row_bytes = (columns * colors * bpc).div_ceil(8) as usize;
2346 let stride = row_bytes + 1; if prev_row.is_empty() {
2349 prev_row.resize(row_bytes, 0);
2350 }
2351
2352 let mut pos = 0;
2353 while pos + stride <= data.len() {
2354 let filter_type = data[pos];
2355 let row_data = &data[pos + 1..pos + stride];
2356 let mut decoded_row = vec![0u8; row_bytes];
2357
2358 for i in 0..row_bytes {
2359 let raw = row_data[i];
2360 let a = if i >= bytes_per_pixel {
2361 decoded_row[i - bytes_per_pixel]
2362 } else {
2363 0
2364 };
2365 let b = prev_row[i];
2366 let c = if i >= bytes_per_pixel {
2367 prev_row[i - bytes_per_pixel]
2368 } else {
2369 0
2370 };
2371
2372 decoded_row[i] = match filter_type {
2373 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,
2379 };
2380 }
2381
2382 out.extend_from_slice(&decoded_row);
2383 prev_row.copy_from_slice(&decoded_row);
2384 pos += stride;
2385 }
2386
2387 if pos < data.len() {
2389 out.extend_from_slice(&data[pos..]);
2390 }
2391}
2392
2393fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 {
2395 let p = a as i32 + b as i32 - c as i32;
2396 let pa = (p - a as i32).abs();
2397 let pb = (p - b as i32).abs();
2398 let pc = (p - c as i32).abs();
2399 if pa <= pb && pa <= pc {
2400 a
2401 } else if pb <= pc {
2402 b
2403 } else {
2404 c
2405 }
2406}
2407
2408impl FilterKind {
2409 pub fn ascii_hex_decode() -> Self {
2411 Self::ASCIIHexDecode
2412 }
2413
2414 pub fn ascii85_decode() -> Self {
2416 Self::ASCII85Decode { group: Vec::new() }
2417 }
2418
2419 pub fn run_length_decode() -> Self {
2421 Self::RunLengthDecode {
2422 state: RleState::Init,
2423 }
2424 }
2425
2426 pub fn flate_decode(predictor: u8, columns: u32, colors: u32, bpc: u32) -> Self {
2428 Self::FlateDecode {
2429 decompressor: flate2::Decompress::new(true),
2430 raw_buf: Vec::new(),
2431 predictor,
2432 columns,
2433 colors,
2434 bpc,
2435 prev_row: Vec::new(),
2436 }
2437 }
2438
2439 pub fn lzw_decode(early_change: bool) -> Self {
2441 let decoder = if early_change {
2442 weezl::decode::Decoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8)
2443 } else {
2444 weezl::decode::Decoder::new(weezl::BitOrder::Msb, 8)
2445 };
2446 Self::LZWDecode {
2447 decoder,
2448 raw_buf: Vec::new(),
2449 }
2450 }
2451
2452 pub fn dct_decode(color_transform: Option<bool>) -> Self {
2454 Self::DCTDecode {
2455 decoded: false,
2456 color_transform,
2457 }
2458 }
2459
2460 pub fn jbig2_decode(globals: Option<Vec<u8>>) -> Self {
2465 Self::JBIG2Decode {
2466 decoded: false,
2467 globals,
2468 }
2469 }
2470
2471 pub fn jpx_decode() -> Self {
2473 Self::JPXDecode { decoded: false }
2474 }
2475
2476 pub fn dct_encode(
2478 columns: u32,
2479 rows: u32,
2480 colors: u32,
2481 quality: u8,
2482 color_transform: bool,
2483 ) -> Self {
2484 Self::DCTEncode {
2485 buf: Vec::new(),
2486 columns,
2487 rows,
2488 colors,
2489 quality,
2490 color_transform,
2491 }
2492 }
2493
2494 pub fn sub_file_decode(
2496 eod_string: Vec<u8>,
2497 eod_count: i32,
2498 bytes_remaining: Option<i64>,
2499 ) -> Self {
2500 Self::SubFileDecode {
2501 eod_string,
2502 eod_count,
2503 bytes_remaining,
2504 }
2505 }
2506
2507 pub fn ccittfax_decode(
2509 k: i32,
2510 columns: u32,
2511 rows: u32,
2512 end_of_line: bool,
2513 encoded_byte_align: bool,
2514 end_of_block: bool,
2515 black_is1: bool,
2516 ) -> Self {
2517 Self::CCITTFaxDecode {
2518 decoded: false,
2519 k,
2520 columns,
2521 rows,
2522 end_of_line,
2523 encoded_byte_align,
2524 end_of_block,
2525 black_is1,
2526 }
2527 }
2528
2529 pub fn eexec_decode() -> Self {
2531 Self::EexecDecode {
2532 r: 55665,
2533 is_hex: None,
2534 skip_count: 0,
2535 hex_leftover: None,
2536 }
2537 }
2538
2539 pub fn ascii_hex_encode() -> Self {
2541 Self::ASCIIHexEncode
2542 }
2543
2544 pub fn ascii85_encode() -> Self {
2546 Self::ASCII85Encode {
2547 buf: Vec::with_capacity(4),
2548 col: 0,
2549 }
2550 }
2551
2552 pub fn run_length_encode() -> Self {
2554 Self::RunLengthEncode {
2555 pending: Vec::new(),
2556 run_byte: None,
2557 run_count: 0,
2558 }
2559 }
2560
2561 pub fn flate_encode(predictor: u8, columns: u32, colors: u32, bpc: u32) -> Self {
2563 let row_width = (columns as usize * colors as usize * bpc as usize).div_ceil(8);
2564 let bpp = (colors as usize * bpc as usize).div_ceil(8);
2565 Self::FlateEncode {
2566 compressor: flate2::Compress::new(flate2::Compression::default(), true),
2567 predictor,
2568 columns,
2569 colors,
2570 bpc,
2571 row_width,
2572 bpp: bpp.max(1),
2573 encode_buf: Vec::new(),
2574 prev_row: vec![0u8; row_width],
2575 }
2576 }
2577
2578 pub fn lzw_encode(early_change: bool) -> Self {
2580 let encoder = if early_change {
2581 weezl::encode::Encoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8)
2582 } else {
2583 weezl::encode::Encoder::new(weezl::BitOrder::Msb, 8)
2584 };
2585 Self::LZWEncode { encoder }
2586 }
2587
2588 pub fn null_encode() -> Self {
2590 Self::NullEncode
2591 }
2592
2593 pub fn is_encode(&self) -> bool {
2595 matches!(
2596 self,
2597 Self::ASCIIHexEncode
2598 | Self::ASCII85Encode { .. }
2599 | Self::RunLengthEncode { .. }
2600 | Self::FlateEncode { .. }
2601 | Self::LZWEncode { .. }
2602 | Self::NullEncode
2603 | Self::DCTEncode { .. }
2604 )
2605 }
2606}
2607
2608impl FileStore {
2609 pub fn create_dct_filter(
2611 &mut self,
2612 source: EntityId,
2613 color_transform: Option<bool>,
2614 ) -> EntityId {
2615 self.create_filter(source, FilterKind::dct_decode(color_transform))
2616 }
2617
2618 pub fn create_dct_encode_filter(
2620 &mut self,
2621 target: EntityId,
2622 columns: u32,
2623 rows: u32,
2624 colors: u32,
2625 quality: u8,
2626 color_transform: bool,
2627 ) -> EntityId {
2628 self.create_encode_filter(
2629 target,
2630 FilterKind::dct_encode(columns, rows, colors, quality, color_transform),
2631 )
2632 }
2633}
2634
2635impl Default for FileStore {
2636 fn default() -> Self {
2637 Self::new()
2638 }
2639}
2640
2641#[cfg(test)]
2642mod tests {
2643 use super::*;
2644 use std::io::Write;
2645
2646 fn tmp_path(name: &str) -> String {
2650 std::env::temp_dir()
2651 .join(name)
2652 .to_string_lossy()
2653 .into_owned()
2654 }
2655
2656 #[test]
2657 fn test_prealloc_standard_streams() {
2658 let store = FileStore::new();
2659 assert_eq!(store.len(), 3);
2660 assert!(store.is_open(FILE_STDIN));
2661 assert!(store.is_open(FILE_STDOUT));
2662 assert!(store.is_open(FILE_STDERR));
2663 assert_eq!(store.name(FILE_STDIN), "%stdin");
2664 }
2665
2666 #[test]
2667 fn test_open_special_names() {
2668 let mut store = FileStore::new();
2669 assert_eq!(store.open("%stdin", "r").unwrap(), FILE_STDIN);
2670 assert_eq!(store.open("%stdout", "w").unwrap(), FILE_STDOUT);
2671 assert_eq!(store.open("%stderr", "w").unwrap(), FILE_STDERR);
2672 }
2673
2674 #[test]
2675 fn test_file_round_trip() {
2676 let mut store = FileStore::new();
2677 let path = tmp_path("stet_test_file_store.txt");
2678 let path = path.as_str();
2679
2680 let wid = store.open(path, "w").unwrap();
2682 store.write_from(wid, b"hello\n").unwrap();
2683 store.flush(wid).unwrap();
2684 store.close(wid).unwrap();
2685
2686 let rid = store.open(path, "r").unwrap();
2688 let mut buf = vec![0u8; 6];
2689 let n = store.read_into(rid, &mut buf).unwrap();
2690 assert_eq!(n, 6);
2691 assert_eq!(&buf, b"hello\n");
2692 store.close(rid).unwrap();
2693
2694 std::fs::remove_file(path).ok();
2696 }
2697
2698 #[test]
2699 fn test_readline() {
2700 let mut store = FileStore::new();
2701 let path = tmp_path("stet_test_readline.txt");
2702 let path = path.as_str();
2703
2704 {
2706 let mut f = std::fs::File::create(path).unwrap();
2707 f.write_all(b"line1\nline2\n").unwrap();
2708 }
2709
2710 let id = store.open(path, "r").unwrap();
2711 let mut buf = vec![0u8; 20];
2712 let (n, nl) = store.readline(id, &mut buf).unwrap();
2713 assert_eq!(&buf[..n], b"line1");
2714 assert!(nl);
2715
2716 let (n, nl) = store.readline(id, &mut buf).unwrap();
2717 assert_eq!(&buf[..n], b"line2");
2718 assert!(nl);
2719
2720 store.close(id).unwrap();
2721 std::fs::remove_file(path).ok();
2722 }
2723
2724 #[test]
2725 fn test_file_position() {
2726 let mut store = FileStore::new();
2727 let path = tmp_path("stet_test_filepos.txt");
2728 let path = path.as_str();
2729 {
2730 let mut f = std::fs::File::create(path).unwrap();
2731 f.write_all(b"abcdef").unwrap();
2732 }
2733
2734 let id = store.open(path, "r").unwrap();
2735 assert_eq!(store.position(id).unwrap(), 0);
2736 let mut buf = [0u8; 3];
2737 store.read_into(id, &mut buf).unwrap();
2738 assert_eq!(store.position(id).unwrap(), 3);
2739 store.set_position(id, 0).unwrap();
2740 assert_eq!(store.position(id).unwrap(), 0);
2741 store.close(id).unwrap();
2742 std::fs::remove_file(path).ok();
2743 }
2744
2745 #[test]
2746 fn test_close_and_reopen() {
2747 let mut store = FileStore::new();
2748 let path = tmp_path("stet_test_close.txt");
2749 let path = path.as_str();
2750 let id = store.open(path, "w").unwrap();
2751 store.write_from(id, b"test").unwrap();
2752 store.close(id).unwrap();
2753 assert!(!store.is_open(id));
2754 std::fs::remove_file(path).ok();
2755 }
2756
2757 #[test]
2758 fn test_invalid_mode() {
2759 let mut store = FileStore::new();
2760 assert!(
2761 store
2762 .open(&tmp_path("stet_test_invalid_mode"), "z")
2763 .is_err()
2764 );
2765 }
2766
2767 #[test]
2768 fn test_read_byte() {
2769 let mut store = FileStore::new();
2770 let path = tmp_path("stet_test_readbyte.txt");
2771 let path = path.as_str();
2772 {
2773 let mut f = std::fs::File::create(path).unwrap();
2774 f.write_all(b"AB").unwrap();
2775 }
2776 let id = store.open(path, "r").unwrap();
2777 assert_eq!(store.read_byte(id).unwrap(), Some(b'A'));
2778 assert_eq!(store.read_byte(id).unwrap(), Some(b'B'));
2779 assert_eq!(store.read_byte(id).unwrap(), None);
2780 store.close(id).unwrap();
2781 std::fs::remove_file(path).ok();
2782 }
2783
2784 #[test]
2787 fn test_string_source() {
2788 let mut store = FileStore::new();
2789 let id = store.create_string_source(b"Hello".to_vec());
2790 assert_eq!(store.read_byte(id).unwrap(), Some(b'H'));
2791 assert_eq!(store.read_byte(id).unwrap(), Some(b'e'));
2792 let mut buf = [0u8; 3];
2793 let n = store.read_into(id, &mut buf).unwrap();
2794 assert_eq!(n, 3);
2795 assert_eq!(&buf, b"llo");
2796 assert_eq!(store.read_byte(id).unwrap(), None);
2797 }
2798
2799 #[test]
2800 fn test_string_source_empty() {
2801 let mut store = FileStore::new();
2802 let id = store.create_string_source(Vec::new());
2803 assert_eq!(store.read_byte(id).unwrap(), None);
2804 }
2805
2806 #[test]
2809 fn test_ascii_hex_decode() {
2810 let mut store = FileStore::new();
2811 let src = store.create_string_source(b"48 65 6C 6C 6F>".to_vec());
2812 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2813 let mut result = Vec::new();
2814 loop {
2815 match store.read_byte(filt).unwrap() {
2816 Some(b) => result.push(b),
2817 None => break,
2818 }
2819 }
2820 assert_eq!(&result, b"Hello");
2821 }
2822
2823 #[test]
2824 fn test_ascii_hex_decode_odd_nibble() {
2825 let mut store = FileStore::new();
2826 let src = store.create_string_source(b"4>".to_vec());
2827 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2828 let b = store.read_byte(filt).unwrap().unwrap();
2829 assert_eq!(b, 0x40);
2830 assert_eq!(store.read_byte(filt).unwrap(), None);
2831 }
2832
2833 #[test]
2834 fn test_ascii_hex_decode_whitespace() {
2835 let mut store = FileStore::new();
2836 let src = store.create_string_source(b"4 1\n4 2>".to_vec());
2837 let filt = store.create_filter(src, FilterKind::ASCIIHexDecode);
2838 let mut result = Vec::new();
2839 loop {
2840 match store.read_byte(filt).unwrap() {
2841 Some(b) => result.push(b),
2842 None => break,
2843 }
2844 }
2845 assert_eq!(&result, &[0x41, 0x42]);
2846 }
2847
2848 #[test]
2851 fn test_ascii85_decode() {
2852 let mut store = FileStore::new();
2853 let src = store.create_string_source(b"9jqo^~>".to_vec());
2855 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2856 let mut result = Vec::new();
2857 loop {
2858 match store.read_byte(filt).unwrap() {
2859 Some(b) => result.push(b),
2860 None => break,
2861 }
2862 }
2863 assert_eq!(&result, b"Man ");
2864 }
2865
2866 #[test]
2867 fn test_ascii85_decode_z() {
2868 let mut store = FileStore::new();
2869 let src = store.create_string_source(b"z~>".to_vec());
2870 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2871 let mut result = Vec::new();
2872 loop {
2873 match store.read_byte(filt).unwrap() {
2874 Some(b) => result.push(b),
2875 None => break,
2876 }
2877 }
2878 assert_eq!(&result, &[0, 0, 0, 0]);
2879 }
2880
2881 #[test]
2882 fn test_ascii85_decode_partial() {
2883 let mut store = FileStore::new();
2884 let src = store.create_string_source(b"9j~>".to_vec());
2886 let filt = store.create_filter(src, FilterKind::ASCII85Decode { group: Vec::new() });
2887 let mut result = Vec::new();
2888 loop {
2889 match store.read_byte(filt).unwrap() {
2890 Some(b) => result.push(b),
2891 None => break,
2892 }
2893 }
2894 assert_eq!(result.len(), 1);
2895 }
2896
2897 #[test]
2900 fn test_rle_literal() {
2901 let mut store = FileStore::new();
2902 let src = store.create_string_source(vec![2, b'A', b'B', b'C', 128]);
2904 let filt = store.create_filter(
2905 src,
2906 FilterKind::RunLengthDecode {
2907 state: RleState::Init,
2908 },
2909 );
2910 let mut result = Vec::new();
2911 loop {
2912 match store.read_byte(filt).unwrap() {
2913 Some(b) => result.push(b),
2914 None => break,
2915 }
2916 }
2917 assert_eq!(&result, b"ABC");
2918 }
2919
2920 #[test]
2921 fn test_rle_repeat() {
2922 let mut store = FileStore::new();
2923 let src = store.create_string_source(vec![253, b'X', 128]);
2925 let filt = store.create_filter(
2926 src,
2927 FilterKind::RunLengthDecode {
2928 state: RleState::Init,
2929 },
2930 );
2931 let mut result = Vec::new();
2932 loop {
2933 match store.read_byte(filt).unwrap() {
2934 Some(b) => result.push(b),
2935 None => break,
2936 }
2937 }
2938 assert_eq!(&result, b"XXXX");
2939 }
2940
2941 #[test]
2944 fn test_subfile_byte_count() {
2945 let mut store = FileStore::new();
2946 let src = store.create_string_source(b"Hello, World!".to_vec());
2947 let filt = store.create_filter(
2948 src,
2949 FilterKind::SubFileDecode {
2950 eod_string: Vec::new(),
2951 eod_count: 0,
2952 bytes_remaining: Some(5),
2953 },
2954 );
2955 let mut result = Vec::new();
2956 loop {
2957 match store.read_byte(filt).unwrap() {
2958 Some(b) => result.push(b),
2959 None => break,
2960 }
2961 }
2962 assert_eq!(&result, b"Hello");
2963 }
2964
2965 fn drain(store: &mut FileStore, entity: EntityId) -> Vec<u8> {
2967 let mut out = Vec::new();
2968 while let Some(b) = store.read_byte(entity).unwrap() {
2969 out.push(b);
2970 }
2971 out
2972 }
2973
2974 #[test]
2975 fn test_subfile_passthrough_no_eod_detection() {
2976 let mut store = FileStore::new();
2981 let src = store.create_string_source(b"abcdef".to_vec());
2982 let filt = store.create_filter(src, FilterKind::sub_file_decode(Vec::new(), 0, None));
2983 assert_eq!(&drain(&mut store, filt), b"abcdef");
2984 }
2985
2986 #[test]
2987 fn test_subfile_eod_count_zero_consumes_without_emitting() {
2988 let mut store = FileStore::new();
2991 let src = store.create_string_source(b"abcSTOPdef".to_vec());
2992 let filt = store.create_filter(src, FilterKind::sub_file_decode(b"STOP".to_vec(), 0, None));
2993 assert_eq!(&drain(&mut store, filt), b"abc");
2994 }
2995
2996 #[test]
2997 fn test_subfile_eod_count_one_includes_the_marker() {
2998 let mut store = FileStore::new();
3001 let src = store.create_string_source(b"abcSTOPdef".to_vec());
3002 let filt = store.create_filter(src, FilterKind::sub_file_decode(b"STOP".to_vec(), 1, None));
3003 assert_eq!(&drain(&mut store, filt), b"abcSTOP");
3004 }
3005
3006 #[test]
3009 fn test_flate_decode() {
3010 use flate2::Compression;
3011 use flate2::write::ZlibEncoder;
3012
3013 let original = b"Hello, stet PostScript interpreter! This is a test of FlateDecode.";
3015 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
3016 encoder.write_all(original).unwrap();
3017 let compressed = encoder.finish().unwrap();
3018
3019 let mut store = FileStore::new();
3020 let src = store.create_string_source(compressed);
3021 let filt = store.create_filter(
3022 src,
3023 FilterKind::FlateDecode {
3024 decompressor: flate2::Decompress::new(true),
3025 raw_buf: Vec::new(),
3026 predictor: 1,
3027 columns: 0,
3028 colors: 0,
3029 bpc: 8,
3030 prev_row: Vec::new(),
3031 },
3032 );
3033 let mut result = Vec::new();
3034 loop {
3035 match store.read_byte(filt).unwrap() {
3036 Some(b) => result.push(b),
3037 None => break,
3038 }
3039 }
3040 assert_eq!(&result, original);
3041 }
3042
3043 #[test]
3046 fn test_lzw_decode() {
3047 let original = b"TOBEORNOTTOBEORTOBEORNOT";
3050 let mut encoder = weezl::encode::Encoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
3051 let compressed = encoder.encode(original).unwrap();
3052
3053 let mut store = FileStore::new();
3054 let src = store.create_string_source(compressed);
3055 let filt = store.create_filter(src, FilterKind::lzw_decode(true));
3056 let mut result = Vec::new();
3057 loop {
3058 match store.read_byte(filt).unwrap() {
3059 Some(b) => result.push(b),
3060 None => break,
3061 }
3062 }
3063 assert_eq!(&result, original);
3064 }
3065
3066 #[test]
3067 fn test_lzw_encode_single_byte() {
3068 let mut store = FileStore::new();
3069 let path = tmp_path("stet_test_lzw_single.bin");
3070 let path = path.as_str();
3071
3072 let target = store.open(path, "w").unwrap();
3073 let enc = store.create_encode_filter(target, FilterKind::lzw_encode(true));
3074 store.write_from(enc, b"Q").unwrap();
3075 store.close(enc).unwrap();
3076
3077 let src = store.open(path, "r").unwrap();
3078 let dec = store.create_filter(src, FilterKind::lzw_decode(true));
3079 let mut result = Vec::new();
3080 loop {
3081 match store.read_byte(dec).unwrap() {
3082 Some(b) => result.push(b),
3083 None => break,
3084 }
3085 }
3086 assert_eq!(&result, b"Q");
3087 std::fs::remove_file(path).ok();
3088 }
3089
3090 #[test]
3091 fn test_lzw_encode_roundtrip() {
3092 let mut store = FileStore::new();
3093 let original = b"Hello LZW!";
3094
3095 let path = tmp_path("stet_test_lzw_encode.bin");
3097 let path = path.as_str();
3098 let target = store.open(path, "w").unwrap();
3099 let enc = store.create_encode_filter(target, FilterKind::lzw_encode(true));
3100
3101 store.write_from(enc, original).unwrap();
3103 store.close(enc).unwrap();
3104
3105 let src = store.open(path, "r").unwrap();
3107 let dec = store.create_filter(src, FilterKind::lzw_decode(true));
3108 let mut result = Vec::new();
3109 loop {
3110 match store.read_byte(dec).unwrap() {
3111 Some(b) => result.push(b),
3112 None => break,
3113 }
3114 }
3115 assert_eq!(&result, original);
3116 std::fs::remove_file(path).ok();
3117 }
3118
3119 #[test]
3120 fn test_ascii_hex_encode_roundtrip() {
3121 let mut store = FileStore::new();
3122 let original = b"Hello";
3123 let path = tmp_path("stet_test_hex_encode.bin");
3124 let path = path.as_str();
3125
3126 let target = store.open(path, "w").unwrap();
3127 let enc = store.create_encode_filter(target, FilterKind::ascii_hex_encode());
3128 store.write_from(enc, original).unwrap();
3129 store.close(enc).unwrap();
3130
3131 let src = store.open(path, "r").unwrap();
3132 let dec = store.create_filter(src, FilterKind::ascii_hex_decode());
3133 let mut result = Vec::new();
3134 loop {
3135 match store.read_byte(dec).unwrap() {
3136 Some(b) => result.push(b),
3137 None => break,
3138 }
3139 }
3140 assert_eq!(&result, original);
3141 std::fs::remove_file(path).ok();
3142 }
3143
3144 #[test]
3145 fn test_ascii85_encode_roundtrip() {
3146 let mut store = FileStore::new();
3147 let original = b"Man sure.";
3148 let path = tmp_path("stet_test_a85_encode.bin");
3149 let path = path.as_str();
3150
3151 let target = store.open(path, "w").unwrap();
3152 let enc = store.create_encode_filter(target, FilterKind::ascii85_encode());
3153 store.write_from(enc, original).unwrap();
3154 store.close(enc).unwrap();
3155
3156 let src = store.open(path, "r").unwrap();
3157 let dec = store.create_filter(src, FilterKind::ascii85_decode());
3158 let mut result = Vec::new();
3159 loop {
3160 match store.read_byte(dec).unwrap() {
3161 Some(b) => result.push(b),
3162 None => break,
3163 }
3164 }
3165 assert_eq!(&result, original);
3166 std::fs::remove_file(path).ok();
3167 }
3168
3169 #[test]
3170 fn test_rle_encode_roundtrip() {
3171 let mut store = FileStore::new();
3172 let original = b"AAAAAABCBCBCBC";
3173 let path = tmp_path("stet_test_rle_encode.bin");
3174 let path = path.as_str();
3175
3176 let target = store.open(path, "w").unwrap();
3177 let enc = store.create_encode_filter(target, FilterKind::run_length_encode());
3178 store.write_from(enc, original).unwrap();
3179 store.close(enc).unwrap();
3180
3181 let src = store.open(path, "r").unwrap();
3182 let dec = store.create_filter(src, FilterKind::run_length_decode());
3183 let mut result = Vec::new();
3184 loop {
3185 match store.read_byte(dec).unwrap() {
3186 Some(b) => result.push(b),
3187 None => break,
3188 }
3189 }
3190 assert_eq!(&result, original);
3191 std::fs::remove_file(path).ok();
3192 }
3193
3194 #[test]
3195 fn test_flate_encode_roundtrip() {
3196 let mut store = FileStore::new();
3197 let original = b"Hello Flate compression test data!";
3198 let path = tmp_path("stet_test_flate_encode.bin");
3199 let path = path.as_str();
3200
3201 let target = store.open(path, "w").unwrap();
3202 let enc = store.create_encode_filter(target, FilterKind::flate_encode(1, 1, 1, 8));
3203 store.write_from(enc, original).unwrap();
3204 store.close(enc).unwrap();
3205
3206 let src = store.open(path, "r").unwrap();
3207 let dec = store.create_filter(src, FilterKind::flate_decode(1, 1, 1, 8));
3208 let mut result = Vec::new();
3209 loop {
3210 match store.read_byte(dec).unwrap() {
3211 Some(b) => result.push(b),
3212 None => break,
3213 }
3214 }
3215 assert_eq!(&result, original);
3216 std::fs::remove_file(path).ok();
3217 }
3218
3219 #[test]
3222 fn test_jbig2_decode_constructor() {
3223 let kind = FilterKind::jbig2_decode(None);
3224 match kind {
3225 FilterKind::JBIG2Decode {
3226 decoded: false,
3227 globals: None,
3228 } => {}
3229 _ => panic!("unexpected variant"),
3230 }
3231 let kind = FilterKind::jbig2_decode(Some(vec![1, 2, 3]));
3232 match kind {
3233 FilterKind::JBIG2Decode {
3234 decoded: false,
3235 globals: Some(ref g),
3236 } if g == &[1, 2, 3] => {}
3237 _ => panic!("globals not stored"),
3238 }
3239 }
3240
3241 #[test]
3242 fn test_jpx_decode_constructor() {
3243 let kind = FilterKind::jpx_decode();
3244 match kind {
3245 FilterKind::JPXDecode { decoded: false } => {}
3246 _ => panic!("unexpected variant"),
3247 }
3248 }
3249
3250 #[test]
3251 fn test_jbig2_decode_malformed_returns_ioerror() {
3252 let mut store = FileStore::new();
3257 let src = store.create_string_source(b"not a jbig2 stream".to_vec());
3258 let filt = store.create_filter(src, FilterKind::jbig2_decode(None));
3259 assert!(store.read_byte(filt).is_err());
3260 }
3261
3262 #[test]
3263 fn test_jpx_decode_malformed_returns_ioerror() {
3264 let mut store = FileStore::new();
3265 let src = store.create_string_source(b"not a jpeg2000 stream".to_vec());
3266 let filt = store.create_filter(src, FilterKind::jpx_decode());
3267 assert!(store.read_byte(filt).is_err());
3268 }
3269
3270 #[test]
3277 fn test_dct_decode_without_eoi_marker() {
3278 let pixels: Vec<u8> = (0..16 * 16 * 3).map(|i| (i % 251) as u8).collect();
3279 let mut jpeg = Vec::new();
3280 jpeg_encoder::Encoder::new(&mut jpeg, 80)
3281 .encode(&pixels, 16, 16, jpeg_encoder::ColorType::Rgb)
3282 .expect("encode");
3283 assert!(jpeg.ends_with(&[0xFF, 0xD9]));
3284 jpeg.truncate(jpeg.len() - 2);
3285
3286 let mut store = FileStore::new();
3287 let src = store.create_string_source(jpeg);
3288 let filt = store.create_filter(src, FilterKind::dct_decode(None));
3289 let mut out = vec![0u8; 16 * 16 * 3];
3290 let n = store.read_into(filt, &mut out).expect("decode");
3291 assert_eq!(n, 16 * 16 * 3);
3292 }
3293}