forked from 1b-agent/fieldcraft-upstream
geometry: read tagged meshes through the VFS, refuse singular transforms, share the model's coordinate limit (#6)
read_3mf_file reads through solidcraft_io::vfs like open_design_file (regular files only, browser files too), so the engine drops its own capped reader and EngineError::File. A build item whose transform flattens its object is an error, and coordinates use modelcraft_model::MAX_COORD (1e9) instead of a looser limit of their own. Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
7 files changed
+44
-27
No files matched your search
@@ -1,10 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use modelcraft_geometry::tagged_mesh::{self, MAX_FILE_BYTES};
|
||||
use modelcraft_geometry::tagged_mesh;
|
||||
use modelcraft_geometry::{Shape, open_design_file};
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use super::read_capped;
|
||||
use crate::{CommandSpec, EngineError, Result, Session};
|
||||
|
||||
pub const OPEN: CommandSpec = CommandSpec {
|
||||
@@ -93,7 +92,7 @@ fn import_mesh(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
.and_then(Value::as_str)
|
||||
.filter(|x| !x.trim().is_empty() && x.len() < 4096)
|
||||
.ok_or_else(|| EngineError::Params("`path` must name a .3mf file".into()))?;
|
||||
let surfaces = tagged_mesh::read_3mf(&read_capped(path, MAX_FILE_BYTES)?)?;
|
||||
let surfaces = tagged_mesh::read_3mf_file(path)?;
|
||||
let first = s.surfaces.len();
|
||||
let added: Vec<Value> = surfaces
|
||||
.iter()
|
||||
@@ -139,7 +138,15 @@ mod tests {
|
||||
assert_eq!(s.surfaces[0].mesh.tri_face, vec![0, 1, 1, 1]);
|
||||
assert_eq!(s.journal.len(), 1);
|
||||
|
||||
for p in [json!({"path": junk.to_str().unwrap()}), json!({"path": dir.join("missing.3mf").to_str().unwrap()}), json!({"path": ""})] {
|
||||
let hostile = [
|
||||
json!({"path": junk.to_str().unwrap()}),
|
||||
json!({"path": dir.join("missing.3mf").to_str().unwrap()}),
|
||||
json!({"path": dir.to_str().unwrap()}),
|
||||
json!({"path": "/dev/zero"}),
|
||||
json!({"path": ""}),
|
||||
json!({"path": "x".repeat(5000)}),
|
||||
];
|
||||
for p in hostile {
|
||||
assert!(s.execute("geometry.import.mesh", &p).is_err(), "{p}");
|
||||
}
|
||||
assert_eq!(s.surfaces.len(), 1);
|
||||
|
||||
@@ -38,17 +38,3 @@ pub(crate) fn xyz(p: &Value, key: &str) -> Result<[f64; 3]> {
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// A file's bytes, refusing anything over `cap`.
|
||||
pub(crate) fn read_capped(path: &str, cap: usize) -> Result<Vec<u8>> {
|
||||
use std::io::Read;
|
||||
let err = |e: std::io::Error| EngineError::File(format!("{path}: {e}"));
|
||||
let f = std::fs::File::open(path).map_err(err)?;
|
||||
let len = f.metadata().map(|m| m.len()).unwrap_or(0);
|
||||
let mut bytes = Vec::with_capacity(usize::try_from(len).unwrap_or(0).min(cap));
|
||||
f.take(cap as u64 + 1).read_to_end(&mut bytes).map_err(err)?;
|
||||
if bytes.len() > cap {
|
||||
return Err(EngineError::File(format!("{path}: larger than {} MB", cap >> 20)));
|
||||
}
|
||||
Ok(bytes)
|
||||
}
|
||||
Reference in new issue
Block a user