mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* dxf: write group codes, reals and plain text without the formatting machinery
write_ascii and its code page forms wrote every group code through
write!("{:>3}"), every real through a String of its own and every string
character by character. A large drawing writes millions of each. Codes 0 to
9999 and reals are now appended in place, and text with no line break or
backslash that is ASCII (or goes out as UTF-8) is copied as it is. Text for a
code page still takes the long path, since a code page may write an ASCII
character another way. The output is byte for byte what it was.
Ported from storytold/cadcraft#1938 (the crates/dxf part).
* dxf: parse_recovering reads a damaged or truncated ASCII file up to the damage
parse fails a file at the first line that is no group code, and at a last
group code with no value. parse_recovering returns the tags before that point
and the line where reading stopped, so a caller can open what the file still
holds and say where it ends. Reading stops at the damage: lines after it are
not paired up by guesswork. Damage before the first group, a truncated binary
file and the group-code limit are still errors.
section_slices ends a section at EOF as well as ENDSEC, so the EOF of a file
cut inside a section is not one of that section's records.
Ported from storytold/cadcraft#1565 (the crates/dxf part).
---------
Co-authored-by: Francesco BV <francesco.esposito@bvitalia.net>
Co-authored-by: Alex Ortiz <76929676+aljormon84@users.noreply.github.com>
52 lines
2.2 KiB
Rust
52 lines
2.2 KiB
Rust
//! `parse_recovering`: what a damaged or truncated file still holds.
|
|
|
|
use craft_dxf::{DxfError, parse, parse_recovering, section_slices, write_binary};
|
|
|
|
const WHOLE: &str = "0\nSECTION\n2\nENTITIES\n0\nLINE\n8\nA\n0\nENDSEC\n0\nEOF\n";
|
|
|
|
#[test]
|
|
fn an_intact_file_reads_as_parse_reads_it() {
|
|
let (tags, damaged) = parse_recovering(WHOLE.as_bytes()).expect("reads");
|
|
assert_eq!(damaged, None);
|
|
assert_eq!(tags, parse(WHOLE.as_bytes()).expect("reads"));
|
|
// Binary files are read as before.
|
|
let binary = write_binary(&tags, true);
|
|
assert_eq!(parse_recovering(&binary).expect("reads"), (tags, None));
|
|
}
|
|
|
|
#[test]
|
|
fn a_line_that_is_no_group_code_ends_the_reading() {
|
|
let text = "0\nSECTION\n2\nENTITIES\n0\nLINE\n8\nA\n<<garbage>>\nmore\n0\nCIRCLE\n";
|
|
assert!(matches!(parse(text.as_bytes()), Err(DxfError::BadCode { line: 9, .. })));
|
|
let (tags, damaged) = parse_recovering(text.as_bytes()).expect("what came before is kept");
|
|
assert_eq!(damaged, Some(9));
|
|
assert_eq!(tags.len(), 4, "nothing after the damage is guessed at");
|
|
assert_eq!(tags.last().map(|t| (t.code, t.str())), Some((8, "A".to_string())));
|
|
}
|
|
|
|
#[test]
|
|
fn a_file_cut_after_a_group_code_keeps_the_groups_before_it() {
|
|
let text = "0\nSECTION\n2\nENTITIES\n0\nLINE\n8";
|
|
assert!(matches!(parse(text.as_bytes()), Err(DxfError::Eof)));
|
|
let (tags, damaged) = parse_recovering(text.as_bytes()).expect("what came before is kept");
|
|
assert_eq!((tags.len(), damaged), (3, Some(7)));
|
|
// The section it was cut in still has its records.
|
|
let s = section_slices(&tags);
|
|
assert_eq!((s.len(), s[0].name, s[0].tags.len()), (1, "ENTITIES", 1));
|
|
}
|
|
|
|
#[test]
|
|
fn damage_before_the_first_group_is_still_an_error() {
|
|
assert!(matches!(parse_recovering(b"not a drawing\n"), Err(DxfError::BadCode { line: 1, .. })));
|
|
assert!(matches!(parse_recovering(b"0"), Err(DxfError::Eof)));
|
|
assert!(matches!(parse_recovering(b""), Err(DxfError::NotDxf)));
|
|
assert!(matches!(parse_recovering(b"\n\n"), Err(DxfError::NotDxf)));
|
|
}
|
|
|
|
#[test]
|
|
fn a_section_without_endsec_ends_at_eof() {
|
|
let tags = parse(b"0\nSECTION\n2\nENTITIES\n0\nLINE\n0\nEOF\n").expect("reads");
|
|
let s = section_slices(&tags);
|
|
assert_eq!(s[0].tags.len(), 1, "the EOF is not a record of the section");
|
|
}
|