mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-05 18:19:57 +00:00
Apply review fixes
- crates/format/src/lib.rs
This commit is contained in:
1 parent
bef505efd6
commit
f67f052b7f
1 file changed
+13
-10
+13
-10
@@ -180,9 +180,8 @@ const MAX_ENTRIES: usize = 100_000;
|
||||
|
||||
/// How much a `.designcraft` archive may expand to when read. The sizes an archive claims are
|
||||
/// not trusted, so deflated entries are capped; a *stored* entry can't expand (its size is its
|
||||
/// bytes in the archive, which is already in memory, and all stored entries together can't
|
||||
/// exceed the archive), so a placed image — stored as is by [`save`] — opens whatever its size
|
||||
/// and counts for nothing against the budget. Saving has no cap, and this keeps every saved
|
||||
/// bytes in the archive, which is already in memory, and all stored entries read together are held to the archive's own size), so a placed image — stored as is by [`save`] — opens whatever its size
|
||||
/// and doesn't count against the budget. Saving has no cap, and this keeps every saved
|
||||
/// document openable (#2166).
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Limits {
|
||||
@@ -201,11 +200,11 @@ impl Limits {
|
||||
/// Read entry `name` of `z`, or `None` when it is missing or unreadable. Refuses a deflated entry
|
||||
/// that expands past `limit` bytes or past what is `left` of the archive's budget, without
|
||||
/// decompressing more than that: the sizes the archive claims are not trusted. A stored entry
|
||||
/// is read at its size in the archive and leaves the budget alone.
|
||||
fn read_entry(z: &mut zip::ZipArchive<Cursor<&[u8]>>, name: &str, limit: u64, left: &mut u64) -> Result<Option<Vec<u8>>, FormatError> {
|
||||
/// is read at its size in the archive and charged to `stored_left`, the archive's own size.
|
||||
fn read_entry(z: &mut zip::ZipArchive<Cursor<&[u8]>>, name: &str, limit: u64, left: &mut u64, stored_left: &mut u64) -> Result<Option<Vec<u8>>, FormatError> {
|
||||
let Ok(f) = z.by_name(name) else { return Ok(None) };
|
||||
let stored = f.compression() == zip::CompressionMethod::Stored;
|
||||
let limit = if stored { f.compressed_size() } else { limit.min(*left) };
|
||||
let limit = if stored { f.compressed_size().min(*stored_left) } else { limit.min(*left) };
|
||||
let too_big = || FormatError::Io(format!("{name} is larger than the {limit}-byte limit (or the archive expands past its {}-byte budget)", *left));
|
||||
if f.size() > limit {
|
||||
return Err(too_big());
|
||||
@@ -218,7 +217,9 @@ fn read_entry(z: &mut zip::ZipArchive<Cursor<&[u8]>>, name: &str, limit: u64, le
|
||||
if n > limit {
|
||||
return Err(too_big());
|
||||
}
|
||||
if !stored {
|
||||
if stored {
|
||||
*stored_left = stored_left.saturating_sub(n);
|
||||
} else {
|
||||
*left = left.saturating_sub(n);
|
||||
}
|
||||
Ok(Some(v))
|
||||
@@ -234,14 +235,16 @@ fn load_zip_within(bytes: &[u8], limits: Limits) -> Result<Document, FormatError
|
||||
return Err(FormatError::NotOurs(format!("{} entries (at most {MAX_ENTRIES})", z.len())));
|
||||
}
|
||||
let mut left = limits.total;
|
||||
let version = read_entry(&mut z, "meta.json", limits.json, &mut left)?
|
||||
// Stored entries can't expand, but a crafted zip can point several at the same bytes: together they get the archive's own size.
|
||||
let mut stored_left = bytes.len() as u64;
|
||||
let version = read_entry(&mut z, "meta.json", limits.json, &mut left, &mut stored_left)?
|
||||
.and_then(|meta| serde_json::from_slice::<Value>(&meta).ok())
|
||||
.and_then(|m| m.get("version").and_then(Value::as_u64))
|
||||
.unwrap_or(1);
|
||||
if version > u64::from(VERSION) {
|
||||
return Err(FormatError::TooNew(version));
|
||||
}
|
||||
let json = read_entry(&mut z, "document.json", limits.json, &mut left)?.ok_or_else(|| FormatError::NotOurs("missing document.json".into()))?;
|
||||
let json = read_entry(&mut z, "document.json", limits.json, &mut left, &mut stored_left)?.ok_or_else(|| FormatError::NotOurs("missing document.json".into()))?;
|
||||
let mut v: Value = serde_json::from_slice(&json).map_err(|e| FormatError::NotOurs(e.to_string()))?;
|
||||
upgrade_json(&mut v);
|
||||
let mut doc: Document = serde_json::from_value(v).map_err(|e| FormatError::NotOurs(e.to_string()))?;
|
||||
@@ -257,7 +260,7 @@ fn load_zip_within(bytes: &[u8], limits: Limits) -> Result<Document, FormatError
|
||||
if !doc.assets.contains_key(&AssetId(id)) {
|
||||
continue;
|
||||
}
|
||||
if let (Some(data), Some(a)) = (read_entry(&mut z, &name, limits.asset, &mut left)?, doc.assets.get_mut(&AssetId(id))) {
|
||||
if let (Some(data), Some(a)) = (read_entry(&mut z, &name, limits.asset, &mut left, &mut stored_left)?, doc.assets.get_mut(&AssetId(id))) {
|
||||
let same = loaded.entry(fingerprint.hash_one(data.as_slice())).or_default();
|
||||
let data = match same.iter().find(|d| ***d == data) {
|
||||
Some(d) => d.clone(),
|
||||
|
||||
Reference in new issue
Block a user