Merge pull request #6002 from mockydevs/fix/eps-cvi-radix

EPS import: cvi and cvr read radix numbers (eps2write spot colours with spaces)
This commit is contained in:
BFlat
2026-11-07 09:35:34 +08:00
committed by GitHub
3 changed files with 27 additions and 4 deletions
+14 -3
View File
@@ -12,7 +12,7 @@ use vectorcraft_geom::Affine;
use super::data::Stream;
use super::graphics::{GState, Out};
use super::lex::{IMMEDIATE, Lexer};
use super::lex::{IMMEDIATE, Lexer, number};
use super::obj::{Dict, DictRef, Key, Obj, Op, PsError, Res, Shared, ps_err};
/// Most operations one file may run.
@@ -775,7 +775,7 @@ impl<'a> Interp<'a> {
},
Cvi => {
let v = match self.pop()? {
Obj::Str(s) => String::from_utf8_lossy(&s.borrow()).trim().parse::<f64>().map_err(|_| PsError::Ps("typecheck", String::new()))?,
Obj::Str(s) => string_number(&s.borrow())?,
o => o.as_num().ok_or(PsError::Ps("typecheck", String::new()))?,
};
if !(v.is_finite() && v.abs() < 9e15) {
@@ -785,7 +785,7 @@ impl<'a> Interp<'a> {
}
Cvr => {
let v = match self.pop()? {
Obj::Str(s) => String::from_utf8_lossy(&s.borrow()).trim().parse::<f64>().map_err(|_| PsError::Ps("typecheck", String::new()))?,
Obj::Str(s) => string_number(&s.borrow())?,
o => o.as_num().ok_or(PsError::Ps("typecheck", String::new()))?,
};
self.push_num(v)?;
@@ -1471,6 +1471,17 @@ impl<'a> Interp<'a> {
}
/// An array or string index.
/// The number a string holds by the PostScript syntax (`cvi`, `cvr`: PLRM 3rd ed., chapter 8),
/// radix numbers such as `16#20` included.
fn string_number(s: &[u8]) -> Res<f64> {
let text = String::from_utf8_lossy(s);
match number(text.trim_matches(|c: char| c.is_ascii_whitespace() || c == '\0')) {
Some(Obj::Int(i)) => Ok(i as f64),
Some(Obj::Real(r)) => Ok(r),
_ => ps_err("typecheck", ""),
}
}
fn index(k: &Obj) -> Res<usize> {
match *k {
Obj::Int(i) if i >= 0 => Ok(i as usize),
+1 -1
View File
@@ -276,7 +276,7 @@ pub(crate) fn hex_decode(body: &[u8]) -> Option<Vec<u8>> {
}
/// A number token (`12`, `-3.5`, `.5`, `1e-3`, `16#ff`), or `None`.
fn number(w: &str) -> Option<Obj> {
pub(crate) fn number(w: &str) -> Option<Obj> {
let first = w.bytes().next()?;
if !(first.is_ascii_digit() || matches!(first, b'+' | b'-' | b'.')) {
return None;
+12
View File
@@ -1022,6 +1022,18 @@ fn known_answers_false_for_keys_no_dictionary_holds() {
check("{ 1 dict null known } stopped");
}
/// `cvi` and `cvr` read a string as the PostScript syntax reads a number (PLRM 3rd ed., chapter
/// 8), radix numbers included: prologs turn a name's `#20` escape back into its character with
/// `(16#20) cvi`.
#[test]
fn cvi_and_cvr_read_radix_numbers() {
check("(16#20) cvi 32 eq (8#17) cvi 15 eq and ( 2#101 ) cvi 5 eq and (36#Z) cvi 35 eq and");
check("(16#ff) cvr 255 eq (3.7) cvi 3 eq and (-2.5e1) cvr -25 eq and (12) cvr 12 eq and");
check("{ (16#zz) cvi } stopped { (inf) cvr } stopped and { (16#-1) cvi } stopped and { () cvi } stopped and");
// A name's escapes, as a prolog undoes them for a spot colour named `PANTONE 300 C`.
check("(PANTONE#20300) dup 7 3 getinterval (16#--) dup 3 4 -1 roll 1 2 getinterval putinterval cvi 32 eq exch pop");
}
#[test]
fn dictstack_and_internaldict_answer() {
check("10 array dictstack length countdictstack eq");