mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 09:59:47 -06:00
Pending filters read the file they were made over
A filter over `currentfile` waits until it is first read, and it took its data from whichever file was running by then. One made over the program's own file and first read inside a file run with `cvx exec` read that file instead, and one made over a file being run, first read in a file that one runs, read the inner file. The pending stream now records the file it was made over (a chained filter inherits it), and `materialize` decodes from that file.
This commit is contained in:
@@ -1,15 +1,19 @@
|
|||||||
use super::ops::MAX_DATA;
|
use super::ops::MAX_DATA;
|
||||||
use super::{
|
use super::{
|
||||||
DecodeSettings, Decoder, DecoderContext, DictRef, EncodingMode, ImageBlob, Key, Obj, PsError, Rc, Res, find, hex_decode, jpeg_components, ps,
|
DecodeSettings, Decoder, DecoderContext, DictRef, EncodingMode, ImageBlob, Key, Obj, PsError, Rc, RefCell, Res, find, hex_decode,
|
||||||
ps_err,
|
jpeg_components, ps, ps_err,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A file object: the program itself, or data a filter decoded.
|
/// A file object: the program itself, or data a filter decoded.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Stream {
|
pub(crate) enum Stream {
|
||||||
Current,
|
Current,
|
||||||
/// Filters over the program's own data, decoded when first read.
|
/// Filters over the data the program reads, decoded when first read, from the file they were
|
||||||
Pending(Vec<Filter>),
|
/// made over: a file being run (`from`), or else the program's own file.
|
||||||
|
Pending {
|
||||||
|
chain: Vec<Filter>,
|
||||||
|
from: Option<Rc<RefCell<Stream>>>,
|
||||||
|
},
|
||||||
Buf {
|
Buf {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ impl Interp<'_> {
|
|||||||
let n = match &*f.borrow() {
|
let n = match &*f.borrow() {
|
||||||
Stream::Current => self.lex.rest().len(),
|
Stream::Current => self.lex.rest().len(),
|
||||||
Stream::Buf { data, pos, .. } => data.len().saturating_sub(*pos),
|
Stream::Buf { data, pos, .. } => data.len().saturating_sub(*pos),
|
||||||
Stream::Pending(_) => 0,
|
Stream::Pending { .. } => 0,
|
||||||
};
|
};
|
||||||
self.push(Obj::Int(n as i64))?;
|
self.push(Obj::Int(n as i64))?;
|
||||||
}
|
}
|
||||||
@@ -189,7 +189,7 @@ impl Interp<'_> {
|
|||||||
*pos += rest.len() - lex.data().len();
|
*pos += rest.len() - lex.data().len();
|
||||||
(o, lex.immediate)
|
(o, lex.immediate)
|
||||||
}
|
}
|
||||||
Stream::Pending(_) => (None, false),
|
Stream::Pending { .. } => (None, false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ impl Interp<'_> {
|
|||||||
*pos = end;
|
*pos = end;
|
||||||
data.get(start..end).unwrap_or_default().to_vec()
|
data.get(start..end).unwrap_or_default().to_vec()
|
||||||
}
|
}
|
||||||
Stream::Pending(_) => vec![],
|
Stream::Pending { .. } => vec![],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +229,7 @@ impl Interp<'_> {
|
|||||||
*pos += 1;
|
*pos += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stream::Pending(_) => {}
|
Stream::Pending { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,28 +284,28 @@ impl Interp<'_> {
|
|||||||
let spec = Filter { name, sub, predictor, fax };
|
let spec = Filter { name, sub, predictor, fax };
|
||||||
let stream = match self.pop()? {
|
let stream = match self.pop()? {
|
||||||
Obj::File { stream: f, .. } => {
|
Obj::File { stream: f, .. } => {
|
||||||
// A filter over the file being run reads it, as one over the program's own file
|
// A filter over the program's own file or the file being run waits until it is
|
||||||
// does, from where the program is when the filter is first read.
|
// first read, and keeps which of them it reads, wherever the program runs by then.
|
||||||
let running = self.running.last().is_some_and(|r| Rc::ptr_eq(r, &f));
|
let running = self.running.last().is_some_and(|r| Rc::ptr_eq(r, &f));
|
||||||
match &*f.borrow() {
|
match &*f.borrow() {
|
||||||
Stream::Buf { data, pos, .. } if !running => self.alloc(data.len().saturating_sub(*pos))?,
|
Stream::Buf { data, pos, .. } if !running => self.alloc(data.len().saturating_sub(*pos))?,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let chain = match &*f.borrow() {
|
let pending = match &*f.borrow() {
|
||||||
Stream::Current => Some(vec![]),
|
Stream::Current => Some((vec![], None)),
|
||||||
Stream::Buf { .. } if running => Some(vec![]),
|
Stream::Buf { .. } if running => Some((vec![], Some(f.clone()))),
|
||||||
Stream::Pending(c) => Some(c.clone()),
|
Stream::Pending { chain, from } => Some((chain.clone(), from.clone())),
|
||||||
Stream::Buf { .. } => None,
|
Stream::Buf { .. } => None,
|
||||||
};
|
};
|
||||||
match chain {
|
match pending {
|
||||||
Some(mut c) => {
|
Some((mut chain, from)) => {
|
||||||
// The new filter reads a pending one's data: it has none left of its own
|
// The new filter reads a pending one's data: it has none left of its own
|
||||||
// (`flushfile` on it skips nothing more).
|
// (`flushfile` on it skips nothing more).
|
||||||
if !c.is_empty() {
|
if !chain.is_empty() {
|
||||||
*f.borrow_mut() = Stream::Buf { data: vec![], pos: 0, rgb: None };
|
*f.borrow_mut() = Stream::Buf { data: vec![], pos: 0, rgb: None };
|
||||||
}
|
}
|
||||||
c.push(spec);
|
chain.push(spec);
|
||||||
Stream::Pending(c)
|
Stream::Pending { chain, from }
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let mut b = f.borrow_mut();
|
let mut b = f.borrow_mut();
|
||||||
@@ -348,18 +348,18 @@ impl Interp<'_> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decode the filters a file waits to run over the program's data, from where it is now: the
|
/// Decode the filters a file waits to run over the data the program reads, from where it is
|
||||||
/// file being run, or the program's own file.
|
/// now in the file they were made over: a file being run, or the program's own file.
|
||||||
pub(in super::super) fn materialize(&mut self, f: &Rc<RefCell<Stream>>) -> Res {
|
pub(in super::super) fn materialize(&mut self, f: &Rc<RefCell<Stream>>) -> Res {
|
||||||
let chain = match &*f.borrow() {
|
let (chain, from) = match &*f.borrow() {
|
||||||
Stream::Pending(c) => c.clone(),
|
Stream::Pending { chain, from } => (chain.clone(), from.clone()),
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
let mut buf: Option<(Vec<u8>, Option<u8>)> = None;
|
let mut buf: Option<(Vec<u8>, Option<u8>)> = None;
|
||||||
for spec in &chain {
|
for spec in &chain {
|
||||||
buf = Some(match buf.take() {
|
buf = Some(match buf.take() {
|
||||||
None => {
|
None => {
|
||||||
let (data, rgb) = match self.running.last() {
|
let (data, rgb) = match &from {
|
||||||
Some(r) => {
|
Some(r) => {
|
||||||
let mut b = r.borrow_mut();
|
let mut b = r.borrow_mut();
|
||||||
let Stream::Buf { data, pos, .. } = &mut *b else { return io("filter") };
|
let Stream::Buf { data, pos, .. } = &mut *b else { return io("filter") };
|
||||||
|
|||||||
@@ -106,6 +106,31 @@ fn image_data_comes_from_the_file_being_run() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A filter waits until it is first read, then reads the file it was made over, wherever the
|
||||||
|
/// program runs by then: one over the program's own file, read in a file being run, and one over
|
||||||
|
/// a file being run, read in a file that one runs.
|
||||||
|
#[test]
|
||||||
|
fn filters_read_the_file_they_were_made_over() {
|
||||||
|
super::tests::check(
|
||||||
|
"/f currentfile /ASCIIHexDecode filter def\n\
|
||||||
|
currentfile 0 (endstream) /SubFileDecode filter cvx exec\n\
|
||||||
|
/s f 3 string readstring pop def\n\
|
||||||
|
endstream\n\
|
||||||
|
616263>\n\
|
||||||
|
s (abc) eq",
|
||||||
|
);
|
||||||
|
super::tests::check(
|
||||||
|
"currentfile 0 (endstream) /SubFileDecode filter cvx exec\n\
|
||||||
|
/g currentfile /ASCIIHexDecode filter def\n\
|
||||||
|
currentfile 0 (endinner) /SubFileDecode filter cvx exec\n\
|
||||||
|
/t g 3 string readstring pop def\n\
|
||||||
|
endinner\n\
|
||||||
|
78797A>\n\
|
||||||
|
endstream\n\
|
||||||
|
t (xyz) eq",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// CMYK samples keep their ink amounts in a CMYK TIFF: in the operand and dictionary forms, from
|
/// CMYK samples keep their ink amounts in a CMYK TIFF: in the operand and dictionary forms, from
|
||||||
/// hex and binary data, from one source or one a component, at 4, 8 and 16 bits, read through
|
/// hex and binary data, from one source or one a component, at 4, 8 and 16 bits, read through
|
||||||
/// the Decode array. Gray and RGB images stay PNGs.
|
/// the Decode array. Gray and RGB images stay PNGs.
|
||||||
|
|||||||
Reference in New Issue
Block a user