mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 12:24:54 +00:00
HP-GL: a .plt file needs at least one instruction the reader knows
A file read as HP-GL by its extension that holds only instructions of another set (`GC5;`) is now refused as "not an HP-GL file" instead of opening as an empty plot. At least one of the instructions the check reads must be one the reader knows.
This commit is contained in:
@@ -71,16 +71,18 @@ pub fn is_hpgl(bytes: &[u8]) -> bool {
|
||||
|
||||
/// Does `bytes` hold HP-GL instructions as [`is_hpgl`] checks? When `strict` is false, any of them
|
||||
/// may come first: a file picked by its extension may start with one a plot file seldom starts
|
||||
/// with (`SI`, `DI`).
|
||||
/// with (`SI`, `DI`). Either way, at least one of the instructions checked must be one the reader
|
||||
/// knows.
|
||||
fn holds_instructions(bytes: &[u8], strict: bool) -> bool {
|
||||
let mut lex = Lexer::new(bytes);
|
||||
let mut terminator = lex::ETX;
|
||||
let mut first = 0;
|
||||
let mut any_known = false;
|
||||
for n in 0..8 {
|
||||
if n > 0 && lex.pos() > first + 4096 {
|
||||
return true;
|
||||
return any_known;
|
||||
}
|
||||
let Some(op) = lex.op(true) else { return n > 0 && lex.done() };
|
||||
let Some(op) = lex.op(true) else { return n > 0 && any_known && lex.done() };
|
||||
if n == 0 {
|
||||
first = lex.pos();
|
||||
}
|
||||
@@ -88,6 +90,7 @@ fn holds_instructions(bytes: &[u8], strict: bool) -> bool {
|
||||
return false;
|
||||
}
|
||||
let known = PLAYED.contains(&op) || IGNORED.contains(&op);
|
||||
any_known |= known;
|
||||
match &op {
|
||||
b"CO" => {
|
||||
if !lex.comment() {
|
||||
@@ -114,11 +117,12 @@ fn holds_instructions(bytes: &[u8], strict: bool) -> bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
any_known
|
||||
}
|
||||
|
||||
/// Read an HP-GL file. It may start with any instruction the reader knows, or one of another set
|
||||
/// that a semicolon ends; the rest of [`is_hpgl`]'s check applies.
|
||||
/// that a semicolon ends; the rest of [`is_hpgl`]'s check applies, and at least one instruction the
|
||||
/// reader knows must be among those it checks.
|
||||
pub fn import(bytes: &[u8]) -> Result<Imported, String> {
|
||||
if !holds_instructions(bytes, false) {
|
||||
return Err("not an HP-GL file".into());
|
||||
|
||||
@@ -451,6 +451,11 @@ fn a_plot_file_may_start_with_any_instruction() {
|
||||
for f in [&b"GC5"[..], b"SIhello world", b"set terminal png\n"] {
|
||||
assert_eq!(import(f).err().as_deref(), Some("not an HP-GL file"), "{:?}", String::from_utf8_lossy(f));
|
||||
}
|
||||
// Instructions of another set alone, however many or long, are not taken for HP-GL.
|
||||
let long = [&b"GC"[..], "1".repeat(5000).as_bytes(), b";ZZ1;"].concat();
|
||||
for f in [&b"GC5;"[..], b"GC5;ZZ1;", b"GC5;ZZ1;YY2;XX3;WW4;VV5;UU6;TT7;", &long] {
|
||||
assert_eq!(import(f).err().as_deref(), Some("not an HP-GL file"), "{:?}", String::from_utf8_lossy(f));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user