Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,42 @@
|
||||
/// Returns `true` if `bytes` is a PNG whose `tEXt` metadata contains `Software: Figma`.
|
||||
///
|
||||
/// Figma exports PNGs with a `tEXt` chunk where the keyword is `Software` and the value
|
||||
/// is `Figma`. We scan the raw chunk stream for this marker without pulling in an image
|
||||
/// parsing library, keeping the check lightweight.
|
||||
const PNG_SIGNATURE: &[u8] = b"\x89PNG\r\n\x1a\n";
|
||||
|
||||
pub fn is_figma_png(bytes: &[u8]) -> bool {
|
||||
if !bytes.starts_with(PNG_SIGNATURE) {
|
||||
return false;
|
||||
}
|
||||
let mut offset = 8usize;
|
||||
while offset + 12 <= bytes.len() {
|
||||
let length = u32::from_be_bytes([
|
||||
bytes[offset],
|
||||
bytes[offset + 1],
|
||||
bytes[offset + 2],
|
||||
bytes[offset + 3],
|
||||
]) as usize;
|
||||
let type_start = offset + 4;
|
||||
let data_start = type_start + 4;
|
||||
let Some(data_end) = data_start.checked_add(length) else {
|
||||
break;
|
||||
};
|
||||
if data_end + 4 > bytes.len() {
|
||||
break;
|
||||
}
|
||||
// tEXt chunk: data is `keyword\0text`
|
||||
if &bytes[type_start..data_start] == b"tEXt"
|
||||
&& bytes[data_start..data_end].starts_with(b"Software\x00Figma")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Advance past: length(4) + type(4) + data(length) + CRC(4)
|
||||
offset = data_end + 4;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "is_figma_png_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,85 @@
|
||||
use super::is_figma_png;
|
||||
|
||||
fn build_png_with_text_chunk(keyword: &[u8], text: &[u8]) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(b"\x89PNG\r\n\x1a\n");
|
||||
let data: Vec<u8> = keyword.iter().chain(b"\x00").chain(text).copied().collect();
|
||||
let length = data.len() as u32;
|
||||
bytes.extend_from_slice(&length.to_be_bytes());
|
||||
bytes.extend_from_slice(b"tEXt");
|
||||
bytes.extend_from_slice(&data);
|
||||
bytes.extend_from_slice(&[0u8; 4]); // fake CRC
|
||||
bytes
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_true_for_figma_export_png() {
|
||||
let bytes = include_bytes!("figma-export.png");
|
||||
assert!(is_figma_png(bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_for_non_figma_png() {
|
||||
let bytes = include_bytes!("non-figma-export.png");
|
||||
assert!(!is_figma_png(bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_for_empty_bytes() {
|
||||
assert!(!is_figma_png(&[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_for_invalid_png_signature() {
|
||||
let mut bytes = b"\x00PNG\r\n\x1a\n".to_vec();
|
||||
bytes.extend_from_slice(&[0u8; 12]);
|
||||
assert!(!is_figma_png(&bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_true_for_crafted_png_with_software_figma() {
|
||||
let bytes = build_png_with_text_chunk(b"Software", b"Figma");
|
||||
assert!(is_figma_png(&bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_when_text_chunk_keyword_is_not_software() {
|
||||
let bytes = build_png_with_text_chunk(b"Author", b"Figma");
|
||||
assert!(!is_figma_png(&bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_when_software_value_is_not_figma() {
|
||||
let bytes = build_png_with_text_chunk(b"Software", b"Sketch");
|
||||
assert!(!is_figma_png(&bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_true_when_figma_text_chunk_follows_another_chunk() {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(b"\x89PNG\r\n\x1a\n");
|
||||
// A preceding chunk (e.g. tIME)
|
||||
let preceding = b"dummy data";
|
||||
bytes.extend_from_slice(&(preceding.len() as u32).to_be_bytes());
|
||||
bytes.extend_from_slice(b"tIME");
|
||||
bytes.extend_from_slice(preceding);
|
||||
bytes.extend_from_slice(&[0u8; 4]); // fake CRC
|
||||
// tEXt chunk with Software: Figma
|
||||
let text_data = b"Software\x00Figma";
|
||||
bytes.extend_from_slice(&(text_data.len() as u32).to_be_bytes());
|
||||
bytes.extend_from_slice(b"tEXt");
|
||||
bytes.extend_from_slice(text_data);
|
||||
bytes.extend_from_slice(&[0u8; 4]); // fake CRC
|
||||
assert!(is_figma_png(&bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_false_for_truncated_chunk_data() {
|
||||
let mut bytes = Vec::new();
|
||||
bytes.extend_from_slice(b"\x89PNG\r\n\x1a\n");
|
||||
// Declare length as 100 but provide fewer bytes
|
||||
bytes.extend_from_slice(&100u32.to_be_bytes());
|
||||
bytes.extend_from_slice(b"tEXt");
|
||||
bytes.extend_from_slice(b"Software\x00Figma"); // only 15 bytes, not 100
|
||||
assert!(!is_figma_png(&bytes));
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
mod is_figma_png;
|
||||
|
||||
pub use is_figma_png::is_figma_png;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Reference in New Issue
Block a user