.ai import: data with no end outside a section does not hide a later section's end

When the scan for swatch names searched data outside a section and found no `~>`, it stopped searching for the end of all later data. Data in a later section then was not skipped, so a `(` on a `%_` line of it opened a string that ran past the section's end marker, and a color named after the section did not reserve its name. The scan now records the search that found nothing per section's end marker, so a search in another section still stops at that section's markers.
This commit is contained in:
dotCooCoo
2026-11-07 05:15:06 +07:00
committed by bflatastic
parent 3e1893d399
commit a17907ee7d
2 changed files with 25 additions and 4 deletions
+6 -4
View File
@@ -1143,8 +1143,9 @@ pub(super) struct Dictionaries<'s> {
name: Option<&'s [u8]>,
/// Whether the string just before the token taken is a key that ASCII85 data follows.
string_key: bool,
/// The rest of the data has no `~>` or marker to stop at, so they aren't searched for again.
no_end: bool,
/// The end markers of the sections being scanned (`None`: no section) where the rest of the data
/// had no `~>` or marker to stop at, so they aren't searched for again in those sections.
no_end: Vec<Option<String>>,
}
/// Where the ASCII85 data at the start of `rest` stops: just past its `~>`, or at the comment that
@@ -1176,10 +1177,11 @@ impl<'s> Dictionaries<'s> {
/// Take `tok`, the token `lex` just gave, and skip the ASCII85 data that follows it, up to where
/// [`data_end`] stops for `section`, so the scan still finds that section's markers.
pub(super) fn pass(&mut self, tok: &super::Tok<'s>, lex: &mut super::Lexer<'s>, section: Option<(&str, &str)>) {
if self.data_follows(tok) && !self.no_end {
let end = section.map(|(_, end)| end);
if self.data_follows(tok) && !self.no_end.iter().any(|e| e.as_deref() == end) {
match data_end(lex.rest(), section) {
Some(stop) => lex.seek(lex.offset() + stop),
None => self.no_end = true,
None => self.no_end.push(end.map(str::to_owned)),
}
}
}
+19
View File
@@ -4632,6 +4632,25 @@ fn swatch_names_are_found_past_data_in_versioned_content_that_does_not_end() {
}
}
/// A search for where data stops that found nothing outside a section doesn't stop a later
/// section's data at that section's end, so the named color after it still takes its name first.
/// The `/Binary` holds a group, where the reader doesn't take what follows its key as data.
#[test]
fn swatch_names_are_found_past_data_in_a_section_after_a_search_outside_sections_found_nothing() {
let sea = format!("0 1 1 0 (Sea) 0 x\n{}f\n", rect_path(0.0, 0.0, 5.0, 5.0));
let before = "/Binary :\nu\n/ASCII85Decode ,\nU\n;\n";
for section in [
"%AI17_Begin_Content_if_version_gt:24 4\n%AI17_Alternate_Content\n/Binary : /ASCII85Decode ,\n%_(]<[%\n%AI17_End_Versioned_Content\n",
"%AI11_BeginTextDocument\n/AI11TextDocument : /ASCII85Decode ,\n%_(]<[%\n%AI11_EndTextDocument\n",
] {
let art_text = format!("{before}{section}{sea}");
let body = format!("{}{}", DOTS.replace("(Dots)", "(Sea\\n1)"), layer(&art_text));
let d = read(stream(&body).as_bytes()).unwrap().doc;
let names: Vec<&str> = d.patterns.iter().map(|p| p.name.as_str()).collect();
assert_eq!(names, ["Sea 2"], "{art_text}");
}
}
/// The names the swatches take are found past the same data: a named color after it still takes
/// its name first, and the pattern named after it is numbered.
#[test]