mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 19:57:05 -06:00
EPS import: bound what hostile editing data can cost, and say when it can't be read
- a story is read once however many text objects name it; the text objects, their pairs with the page's type, the pieces of a line and a story's size are capped, and over a cap the layers aren't used - the ASCII85 of the text document is bounded before it is decoded - joining the pieces of lines that interleave no longer removes the wrong pieces - a run length too large for the text saturates instead of overflowing - a dictionary left open at the end of a layer, and layers nested deeper than are read, make the file one that comes in as its page (they were silently dropped) - a file whose editing data can't be decoded says so, and the notes about art that was too much or too far away count as losses, so writing over the source asks first - the private data of a .ai is inflated under a cap of its own (the PDF reader's decoder has none) - the other writers (PDF, selection, office, print) ask before replacing a source that lost things, and a recovered copy remembers that Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
e622b87ca2
commit
8fe0fd8394
@@ -169,6 +169,9 @@ pub(crate) fn isolated(doc: &Document, ids: &[NodeId], name: &str) -> Option<(Do
|
||||
/// template layers are guides, not artwork, and are left out.
|
||||
pub(super) fn export_selection(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "document.exportSelection";
|
||||
if let Some(path) = str_param(p, "path") {
|
||||
super::check_not_lossy_overwrite(s.doc()?, path, p, C)?;
|
||||
}
|
||||
let path = str_param(p, "path");
|
||||
let f = writable(C, str_param(p, "format"), path)?;
|
||||
let expanded = expand_presets(s, C, p)?;
|
||||
@@ -184,6 +187,9 @@ pub(super) fn export_selection(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
/// `transparent`.
|
||||
pub(super) fn export_for_office(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "document.exportForOffice";
|
||||
if let Some(path) = str_param(p, "path") {
|
||||
super::check_not_lossy_overwrite(s.doc()?, path, p, C)?;
|
||||
}
|
||||
let path = str_param(p, "path");
|
||||
let ppi = f64_or(p, "ppi", 150.0);
|
||||
let doc = &s.doc()?.doc;
|
||||
|
||||
@@ -356,6 +356,9 @@ fn without_non_printing(layers: &[Arc<Node>]) -> Option<Vec<Arc<Node>>> {
|
||||
}
|
||||
|
||||
fn export_pdf(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(path) = str_param(p, "path") {
|
||||
super::check_not_lossy_overwrite(s.doc()?, path, p, C)?;
|
||||
}
|
||||
let expanded = expand_preset(s, C, p)?;
|
||||
let p = &*expanded;
|
||||
let (bytes, warnings) = encode(C, &s.doc()?.doc, p)?;
|
||||
|
||||
@@ -109,6 +109,9 @@ fn to_postscript(p: &Value) -> Result<bool> {
|
||||
}
|
||||
|
||||
fn print(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(path) = str_param(p, "path") {
|
||||
super::fileio::check_not_lossy_overwrite(s.doc()?, path, p, PRINT)?;
|
||||
}
|
||||
let postscript = to_postscript(p)?;
|
||||
let doc = &s.doc()?.doc;
|
||||
let mut set = settings(PRINT, doc, p)?;
|
||||
|
||||
@@ -523,6 +523,10 @@ struct Meta {
|
||||
format: String,
|
||||
/// When the copy was written (Unix seconds; none without a clock).
|
||||
saved: Option<i64>,
|
||||
/// The file it was read from when that import left things out of the document, and what
|
||||
/// (see [`crate::DocState::import_losses`]): a restored copy still refuses to replace it.
|
||||
imported_from: Option<String>,
|
||||
import_losses: Vec<String>,
|
||||
}
|
||||
|
||||
fn read_meta(store: &dyn RecoveryStore, file: &str) -> Meta {
|
||||
@@ -651,7 +655,14 @@ pub fn jobs(s: &mut Session, store: &Arc<dyn RecoveryStore>) -> Result<(Vec<Reco
|
||||
modified: None,
|
||||
};
|
||||
let save = fileio::job_for(s, st, plan)?;
|
||||
let meta = Meta { title: title.clone(), path: st.path.clone(), format: st.format.to_string(), saved };
|
||||
let meta = Meta {
|
||||
title: title.clone(),
|
||||
path: st.path.clone(),
|
||||
format: st.format.to_string(),
|
||||
saved,
|
||||
imported_from: st.imported_from.clone(),
|
||||
import_losses: st.import_losses.clone(),
|
||||
};
|
||||
out.push(RecoveryJob { uid: st.uid, file, title, meta, save });
|
||||
}
|
||||
Ok((out, skipped))
|
||||
@@ -839,6 +850,8 @@ fn restore_one(s: &mut Session, store: &Arc<dyn RecoveryStore>, file: &str) -> R
|
||||
let index = s.add_document(doc, meta.path.clone());
|
||||
let st = s.doc_mut()?;
|
||||
st.recovered = true;
|
||||
st.imported_from = meta.imported_from.clone();
|
||||
st.import_losses = meta.import_losses.clone();
|
||||
st.format = SAVE_FORMATS.iter().copied().find(|f| *f == meta.format).unwrap_or("vectorcraft");
|
||||
st.mark_unsaved();
|
||||
// The copy stays until the document is saved or closed.
|
||||
|
||||
Reference in New Issue
Block a user