1use std::fmt;
40
41#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct EngineDataError(pub String);
44
45impl fmt::Display for EngineDataError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "{}", self.0)
48 }
49}
50
51impl std::error::Error for EngineDataError {}
52
53#[derive(Debug, Clone, PartialEq)]
55pub enum EngineValue {
56 Null,
58 Number(f64),
60 Bool(bool),
62 Str(String),
64 Array(Vec<EngineValue>),
66 Dict(Vec<(String, EngineValue)>),
68}
69
70impl EngineValue {
71 pub fn is_object(&self) -> bool {
72 matches!(self, EngineValue::Dict(_) | EngineValue::Array(_) | EngineValue::Null)
75 }
76}
77
78fn is_whitespace(char: u8) -> bool {
80 char == 32 || char == 10 || char == 13 || char == 9
81}
82
83fn is_number(char: u8) -> bool {
85 (48..=57).contains(&char) || char == 46 || char == 45
86}
87
88enum StackItem {
90 Value(EngineValue),
91 Key(String),
92}
93
94pub fn parse_engine_data(data: &[u8]) -> Result<EngineValue, EngineDataError> {
96 let mut index: usize = 0;
97
98 fn skip_whitespace(data: &[u8], index: &mut usize) {
101 while *index < data.len() && is_whitespace(data[*index]) {
102 *index += 1;
103 }
104 }
105
106 fn get_text_byte(data: &[u8], index: &mut usize) -> u8 {
107 let mut byte = data[*index];
108 *index += 1;
109
110 if byte == 92 {
111 byte = data[*index];
113 *index += 1;
114 }
115
116 byte
117 }
118
119 fn get_text(data: &[u8], index: &mut usize) -> Result<String, EngineDataError> {
120 let mut units: Vec<u16> = Vec::new();
121
122 if data[*index] == 41 {
123 *index += 1;
125 return Ok(String::new());
126 }
127
128 if data.get(*index) != Some(&0xFE) || data.get(*index + 1) != Some(&0xFF) {
130 return Err(EngineDataError("Invalid utf-16 BOM".to_string()));
131 }
132
133 *index += 2;
134
135 while *index < data.len() && data[*index] != 41 {
138 let high = get_text_byte(data, index) as u16;
140 let low = get_text_byte(data, index) as u16;
141 let char = (high << 8) | low;
142 units.push(char);
143 }
144
145 *index += 1;
146 Ok(String::from_utf16_lossy(&units))
147 }
148
149 let mut root: Option<EngineValue> = None;
155 let mut stack: Vec<StackItem> = Vec::new();
156
157 fn set_dict(map: &mut Vec<(String, EngineValue)>, key: &str, value: EngineValue) {
158 if let Some(slot) = map.iter_mut().find(|(k, _)| k == key) {
161 slot.1 = value;
162 } else {
163 map.push((key.to_string(), value));
164 }
165 }
166
167 fn push_value(
169 stack: &mut Vec<StackItem>,
170 _root: &mut Option<EngineValue>,
171 value: EngineValue,
172 ) -> Result<(), EngineDataError> {
173 let top = stack.last().ok_or_else(|| EngineDataError("Invalid data".to_string()))?;
174
175 match top {
176 StackItem::Key(_) => {
177 let key = match stack.pop().unwrap() {
179 StackItem::Key(k) => k,
180 _ => unreachable!(),
181 };
182 match stack.last_mut() {
183 Some(StackItem::Value(EngineValue::Dict(map))) => {
184 set_dict(map, &key, value);
185 Ok(())
186 }
187 _ => Err(EngineDataError("Invalid data".to_string())),
188 }
189 }
190 StackItem::Value(EngineValue::Array(_)) => {
191 if let Some(StackItem::Value(EngineValue::Array(arr))) = stack.last_mut() {
192 arr.push(value);
193 }
194 Ok(())
195 }
196 _ => Err(EngineDataError("Invalid data".to_string())),
197 }
198 }
199
200 fn push_container(
203 stack: &mut Vec<StackItem>,
204 _root: &mut Option<EngineValue>,
205 value: EngineValue,
206 ) {
207 stack.push(StackItem::Value(value));
208 }
209
210 fn push_property(
212 stack: &mut Vec<StackItem>,
213 root: &mut Option<EngineValue>,
214 name: &str,
215 ) -> Result<(), EngineDataError> {
216 if stack.is_empty() {
217 push_container(stack, root, EngineValue::Dict(Vec::new()));
218 }
219
220 match stack.last() {
221 Some(StackItem::Key(_)) => {
222 if name == "nil" {
224 push_value(stack, root, EngineValue::Null)
225 } else {
226 push_value(stack, root, EngineValue::Str(format!("/{}", name)))
227 }
228 }
229 Some(StackItem::Value(_)) => {
230 stack.push(StackItem::Key(name.to_string()));
232 Ok(())
233 }
234 None => Err(EngineDataError("Invalid data".to_string())),
235 }
236 }
237
238 fn pop(
241 stack: &mut Vec<StackItem>,
242 root: &mut Option<EngineValue>,
243 ) -> Result<(), EngineDataError> {
244 let item = stack.pop().ok_or_else(|| EngineDataError("Invalid data".to_string()))?;
245 let value = match item {
246 StackItem::Value(v) => v,
247 StackItem::Key(_) => return Err(EngineDataError("Invalid data".to_string())),
248 };
249
250 if stack.is_empty() {
251 *root = Some(value);
252 Ok(())
253 } else {
254 push_value(stack, root, value)
255 }
256 }
257
258 skip_whitespace(data, &mut index);
259
260 let mut data_length = data.len();
261
262 while data_length > 0 && data[data_length - 1] == 0 {
263 data_length -= 1; }
265
266 while index < data_length {
267 let i = index;
268 let char = data[i];
269
270 if char == 60 && data.get(i + 1) == Some(&60) {
271 index += 2;
273 push_container(&mut stack, &mut root, EngineValue::Dict(Vec::new()));
274 } else if char == 62 && data.get(i + 1) == Some(&62) {
275 index += 2;
277 pop(&mut stack, &mut root)?;
278 } else if char == 47 {
279 index += 1;
281 let start = index;
282
283 while index < data.len() && !is_whitespace(data[index]) {
284 index += 1;
285 }
286
287 let mut name = String::new();
288 for j in start..index {
289 name.push(data[j] as char);
290 }
291
292 push_property(&mut stack, &mut root, &name)?;
293 } else if char == 40 {
294 index += 1;
296 let text = get_text(data, &mut index)?;
297 push_value(&mut stack, &mut root, EngineValue::Str(text))?;
298 } else if char == 91 {
299 index += 1;
301 push_container(&mut stack, &mut root, EngineValue::Array(Vec::new()));
302 } else if char == 93 {
303 index += 1;
305 pop(&mut stack, &mut root)?;
306 } else if char == 110
307 && data.get(i + 1) == Some(&117)
308 && data.get(i + 2) == Some(&108)
309 && data.get(i + 3) == Some(&108)
310 {
311 index += 4;
313 push_value(&mut stack, &mut root, EngineValue::Null)?;
314 } else if char == 116
315 && data.get(i + 1) == Some(&114)
316 && data.get(i + 2) == Some(&117)
317 && data.get(i + 3) == Some(&101)
318 {
319 index += 4;
321 push_value(&mut stack, &mut root, EngineValue::Bool(true))?;
322 } else if char == 102
323 && data.get(i + 1) == Some(&97)
324 && data.get(i + 2) == Some(&108)
325 && data.get(i + 3) == Some(&115)
326 && data.get(i + 4) == Some(&101)
327 {
328 index += 5;
330 push_value(&mut stack, &mut root, EngineValue::Bool(false))?;
331 } else if is_number(char) {
332 let mut value = String::new();
333
334 while index < data.len() && is_number(data[index]) {
335 value.push(data[index] as char);
336 index += 1;
337 }
338
339 let parsed = parse_float(&value);
340 push_value(&mut stack, &mut root, EngineValue::Number(parsed))?;
341 } else {
342 index += 1;
343 eprintln!(
345 "Invalid token '{}' ({}) at {}",
346 char as char, char, index
347 );
348 }
349
350 skip_whitespace(data, &mut index);
351 }
352
353 if root.is_none() {
357 if let Some(StackItem::Value(v)) = stack.into_iter().next() {
358 root = Some(v);
359 }
360 }
361
362 Ok(root.unwrap_or(EngineValue::Null))
363}
364
365fn parse_float(value: &str) -> f64 {
367 let s = value.trim_start();
368 let mut end = 0;
370 let bytes = s.as_bytes();
371 let mut seen_dot = false;
372 let mut i = 0;
373 if i < bytes.len() && (bytes[i] == b'+' || bytes[i] == b'-') {
374 i += 1;
375 }
376 while i < bytes.len() {
377 let c = bytes[i];
378 if c.is_ascii_digit() {
379 end = i + 1;
380 i += 1;
381 } else if c == b'.' && !seen_dot {
382 seen_dot = true;
383 i += 1;
384 } else {
385 break;
386 }
387 }
388 if end == 0 {
389 f64::NAN
390 } else {
391 s[..end].parse::<f64>().unwrap_or(f64::NAN)
392 }
393}
394
395const FLOAT_KEYS: &[&str] = &[
396 "Axis", "XY", "Zone", "WordSpacing", "FirstLineIndent", "GlyphSpacing", "StartIndent",
397 "EndIndent", "SpaceBefore", "SpaceAfter", "LetterSpacing", "Values", "GridSize",
398 "GridLeading", "PointBase", "BoxBounds", "TransformPoint0", "TransformPoint1",
399 "TransformPoint2", "FontSize", "Leading", "HorizontalScale", "VerticalScale",
400 "BaselineShift", "Tsume", "OutlineWidth", "AutoLeading",
401];
402
403const INT_ARRAYS: &[&str] = &["RunLengthArray"];
404
405fn serialize_int(value: f64) -> String {
407 js_number_to_string(value)
409}
410
411fn serialize_float(value: f64) -> String {
413 let mut s = format!("{:.5}", value);
414
415 s = replace_trailing_zeros(&s);
417 s = replace_leading_zero_dot(&s);
419 s = replace_neg_zero_dot(&s);
421
422 s
423}
424
425fn replace_trailing_zeros(s: &str) -> String {
429 let bytes = s.as_bytes();
430 let n = bytes.len();
431 for p in 0..n {
432 if bytes[p].is_ascii_digit() && p + 1 < n && bytes[p + 1..].iter().all(|&c| c == b'0') {
433 return s[..=p].to_string();
434 }
435 }
436 s.to_string()
437}
438
439fn replace_leading_zero_dot(s: &str) -> String {
441 let bytes = s.as_bytes();
442 let mut i = 0;
443 while i < bytes.len() && bytes[i] == b'0' {
444 i += 1;
445 }
446 if i >= 1
448 && i + 1 < bytes.len()
449 && bytes[i] == b'.'
450 && (b'1'..=b'9').contains(&bytes[i + 1])
451 {
452 format!(".{}", &s[i + 1..])
453 } else {
454 s.to_string()
455 }
456}
457
458fn replace_neg_zero_dot(s: &str) -> String {
460 let bytes = s.as_bytes();
461 if bytes.first() != Some(&b'-') {
462 return s.to_string();
463 }
464 let mut i = 1;
465 while i < bytes.len() && bytes[i] == b'0' {
466 i += 1;
467 }
468 if i >= 2
470 && i + 2 < bytes.len()
471 && bytes[i] == b'.'
472 && bytes[i + 1] == b'0'
473 && bytes[i + 2].is_ascii_digit()
474 {
475 format!("-.0{}", &s[i + 2..])
476 } else {
477 s.to_string()
478 }
479}
480
481fn serialize_number(value: f64, key: Option<&str>) -> String {
483 let is_float = key.map(|k| FLOAT_KEYS.contains(&k)).unwrap_or(false) || (to_int32(value) as f64) != value;
485 if is_float {
486 serialize_float(value)
487 } else {
488 serialize_int(value)
489 }
490}
491
492fn to_int32(value: f64) -> i32 {
494 if !value.is_finite() {
495 return 0;
496 }
497 let n = value.trunc();
498 let m = n.rem_euclid(4294967296.0); let u = m as u64 as u32;
500 u as i32
501}
502
503fn js_number_to_string(value: f64) -> String {
505 if value == value.trunc() && value.is_finite() && value.abs() < 1e21 {
506 format!("{}", value as i64)
508 } else {
509 let s = format!("{}", value);
512 s
513 }
514}
515
516fn get_keys(map: &[(String, EngineValue)]) -> Vec<String> {
518 let mut keys: Vec<String> = map.iter().map(|(k, _)| k.clone()).collect();
519
520 if keys.iter().any(|k| k == "98") {
522 if let Some(pos) = keys.iter().position(|k| k == "99") {
523 let removed = keys.remove(pos);
524 keys.insert(0, removed);
525 }
526 else if !keys.is_empty() {
528 let removed = keys.remove(keys.len() - 1);
529 keys.insert(0, removed);
530 }
531 }
532
533 if let Some(pos) = keys.iter().position(|k| k == "99") {
535 let removed = keys.remove(pos);
536 keys.insert(0, removed);
537 }
538
539 keys
540}
541
542pub fn serialize_engine_data(data: &EngineValue, condensed: bool) -> Vec<u8> {
544 let mut buffer: Vec<u8> = Vec::with_capacity(1024);
545 let mut indent: usize = 0;
546
547 serialize_engine_data_inner(data, condensed, &mut buffer, &mut indent);
548
549 buffer
550}
551
552fn write_str(buffer: &mut Vec<u8>, value: &str) {
553 for unit in value.encode_utf16() {
557 buffer.push((unit & 0xff) as u8);
558 }
559}
560
561fn write_indent(buffer: &mut Vec<u8>, condensed: bool, indent: usize) {
562 if condensed {
563 write_str(buffer, " ");
564 } else {
565 for _ in 0..indent {
566 write_str(buffer, "\t");
567 }
568 }
569}
570
571fn write_string_byte(buffer: &mut Vec<u8>, value: u8) {
572 if value == 40 || value == 41 || value == 92 {
573 buffer.push(92); }
576 buffer.push(value);
577}
578
579fn serialize_engine_data_inner(
580 data: &EngineValue,
581 condensed: bool,
582 buffer: &mut Vec<u8>,
583 indent: &mut usize,
584) {
585 if condensed {
586 if let EngineValue::Dict(map) = data {
587 for key in get_keys(map) {
588 let value = map.iter().find(|(k, _)| *k == key).map(|(_, v)| v).unwrap();
589 write_property(&key, value, condensed, buffer, indent);
590 }
591 }
592 else if let EngineValue::Array(arr) = data {
597 for (i, value) in arr.iter().enumerate() {
599 let key = i.to_string();
600 write_property(&key, value, condensed, buffer, indent);
601 }
602 }
603 } else {
604 write_str(buffer, "\n\n");
605 write_value(data, None, false, condensed, buffer, indent);
606 }
607}
608
609fn write_property(
610 key: &str,
611 value: &EngineValue,
612 condensed: bool,
613 buffer: &mut Vec<u8>,
614 indent: &mut usize,
615) {
616 write_indent(buffer, condensed, *indent);
617 write_str(buffer, &format!("/{}", key));
618 write_value(value, Some(key), true, condensed, buffer, indent);
619 if !condensed {
620 write_str(buffer, "\n");
621 }
622}
623
624fn write_value(
625 value: &EngineValue,
626 key: Option<&str>,
627 in_property: bool,
628 condensed: bool,
629 buffer: &mut Vec<u8>,
630 indent: &mut usize,
631) {
632 fn write_prefix(in_property: bool, condensed: bool, buffer: &mut Vec<u8>, indent: usize) {
634 if in_property {
635 write_str(buffer, " ");
636 } else {
637 write_indent(buffer, condensed, indent);
638 }
639 }
640
641 match value {
642 EngineValue::Null => {
643 write_prefix(in_property, condensed, buffer, *indent);
644 write_str(buffer, if condensed { "/nil" } else { "null" });
645 }
646 EngineValue::Number(n) => {
647 write_prefix(in_property, condensed, buffer, *indent);
648 write_str(buffer, &serialize_number(*n, key));
649 }
650 EngineValue::Bool(b) => {
651 write_prefix(in_property, condensed, buffer, *indent);
652 write_str(buffer, if *b { "true" } else { "false" });
653 }
654 EngineValue::Str(s) => {
655 write_prefix(in_property, condensed, buffer, *indent);
656
657 let is_name = (key == Some("99") || key == Some("98")) && s.starts_with('/');
658 if is_name {
659 write_str(buffer, s);
660 } else {
661 write_str(buffer, "(");
662 buffer.push(0xfe);
663 buffer.push(0xff);
664
665 for code in s.encode_utf16() {
666 write_string_byte(buffer, ((code >> 8) & 0xff) as u8);
667 write_string_byte(buffer, (code & 0xff) as u8);
668 }
669
670 write_str(buffer, ")");
671 }
672 }
673 EngineValue::Array(arr) => {
674 write_prefix(in_property, condensed, buffer, *indent);
675
676 let all_numbers = arr.iter().all(|x| matches!(x, EngineValue::Number(_)));
677 if all_numbers {
678 write_str(buffer, "[");
679
680 let int_array = key.map(|k| INT_ARRAYS.contains(&k)).unwrap_or(false);
681
682 for x in arr {
683 if let EngineValue::Number(n) = x {
684 write_str(buffer, " ");
685 let s = if int_array {
686 serialize_number(*n, None)
687 } else {
688 serialize_float(*n)
689 };
690 write_str(buffer, &s);
691 }
692 }
693
694 write_str(buffer, " ]");
695 } else {
696 write_str(buffer, "[");
697 if !condensed {
698 write_str(buffer, "\n");
699 }
700
701 for x in arr {
702 write_value(x, key, false, condensed, buffer, indent);
703 if !condensed {
704 write_str(buffer, "\n");
705 }
706 }
707
708 write_indent(buffer, condensed, *indent);
709 write_str(buffer, "]");
710 }
711 }
712 EngineValue::Dict(map) => {
713 if in_property && !condensed {
714 write_str(buffer, "\n");
715 }
716
717 write_indent(buffer, condensed, *indent);
718 write_str(buffer, "<<");
719
720 if !condensed {
721 write_str(buffer, "\n");
722 }
723
724 *indent += 1;
725
726 for k in get_keys(map) {
727 let v = map.iter().find(|(kk, _)| *kk == k).map(|(_, v)| v).unwrap();
728 write_property(&k, v, condensed, buffer, indent);
729 }
730
731 *indent -= 1;
732 write_indent(buffer, condensed, *indent);
733 write_str(buffer, ">>");
734 }
735 }
736}
737
738#[cfg(test)]
739mod tests {
740 use super::*;
741
742 fn dict(pairs: Vec<(&str, EngineValue)>) -> EngineValue {
743 EngineValue::Dict(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
744 }
745
746 fn sample() -> EngineValue {
747 dict(vec![
748 (
749 "EngineDict",
750 dict(vec![
751 (
752 "Editor",
753 dict(vec![("Text", EngineValue::Str("Привет ❤".to_string()))]),
754 ),
755 (
756 "RunLengthArray",
757 EngineValue::Array(vec![
758 EngineValue::Number(3.0),
759 EngineValue::Number(5.0),
760 ]),
761 ),
762 (
763 "Values",
764 EngineValue::Array(vec![
765 EngineValue::Number(0.0),
766 EngineValue::Number(0.5),
767 EngineValue::Number(1.0),
768 ]),
769 ),
770 ("FontSize", EngineValue::Number(12.0)),
771 ("AntiAlias", EngineValue::Number(4.0)),
772 ("UseFractionalGlyphWidths", EngineValue::Bool(true)),
773 ("Nothing", EngineValue::Null),
774 ]),
775 ),
776 (
777 "ResourceDict",
778 dict(vec![(
779 "Nested",
780 dict(vec![("Flag", EngineValue::Bool(false))]),
781 )]),
782 ),
783 ])
784 }
785
786 #[test]
787 fn round_trip_full() {
788 let value = sample();
789 let bytes = serialize_engine_data(&value, false);
790 let parsed = parse_engine_data(&bytes).unwrap();
791 assert_eq!(parsed, value);
792 }
793
794 #[test]
795 fn round_trip_condensed() {
796 let value = sample();
797 let bytes = serialize_engine_data(&value, true);
798 let parsed = parse_engine_data(&bytes).unwrap();
799 assert_eq!(parsed, value);
800 }
801
802 #[test]
803 fn condensed_byte_exact() {
804 let value = dict(vec![
806 ("A", EngineValue::Number(1.0)),
807 ("B", EngineValue::Bool(true)),
808 ("C", EngineValue::Number(12.0)),
809 ("D", EngineValue::Null),
810 ]);
811 let bytes = serialize_engine_data(&value, true);
812 let expected = b" /A 1 /B true /C 12 /D /nil".to_vec();
814 assert_eq!(bytes, expected);
815 }
816
817 #[test]
818 fn condensed_string_byte_exact() {
819 let value = dict(vec![("T", EngineValue::Str("AB".to_string()))]);
821 let bytes = serialize_engine_data(&value, true);
822 let mut expected: Vec<u8> = Vec::new();
823 expected.extend_from_slice(b" /T (");
824 expected.push(0xfe);
825 expected.push(0xff);
826 expected.extend_from_slice(&[0x00, b'A', 0x00, b'B']);
827 expected.push(b')');
828 assert_eq!(bytes, expected);
829 }
830
831 #[test]
832 fn condensed_string_escapes() {
833 let value = dict(vec![("T", EngineValue::Str("()\\".to_string()))]);
835 let bytes = serialize_engine_data(&value, true);
836 let mut expected: Vec<u8> = Vec::new();
837 expected.extend_from_slice(b" /T (");
838 expected.push(0xfe);
839 expected.push(0xff);
840 expected.extend_from_slice(&[0x00, 0x5c, 0x28]); expected.extend_from_slice(&[0x00, 0x5c, 0x29]); expected.extend_from_slice(&[0x00, 0x5c, 0x5c]); expected.push(b')');
845 assert_eq!(bytes, expected);
846 }
847
848 #[test]
849 fn non_condensed_byte_exact() {
850 let value = dict(vec![
852 ("A", EngineValue::Number(1.0)),
853 ("B", dict(vec![("C", EngineValue::Number(2.0))])),
854 ]);
855 let bytes = serialize_engine_data(&value, false);
856 let expected = "\n\n<<\n\t/A 1\n\t/B\n\t<<\n\t\t/C 2\n\t>>\n>>";
858 assert_eq!(String::from_utf8(bytes).unwrap(), expected);
859 }
860
861 #[test]
862 fn float_formatting() {
863 assert_eq!(serialize_float(0.5), ".5");
864 assert_eq!(serialize_float(1.0), "1.0");
865 assert_eq!(serialize_float(12.25), "12.25");
866 assert_eq!(serialize_float(-0.05), "-.05");
867 assert_eq!(serialize_float(100.0), "100.0");
868 }
869
870 #[test]
871 fn number_int_vs_float() {
872 assert_eq!(serialize_number(12.0, Some("FontSize")), "12.0");
874 assert_eq!(serialize_number(12.0, Some("AntiAlias")), "12");
876 assert_eq!(serialize_number(0.5, None), ".5");
878 }
879
880 #[test]
881 fn get_keys_99_first() {
882 let map = vec![
883 ("0".to_string(), EngineValue::Number(1.0)),
884 ("99".to_string(), EngineValue::Str("/Type".to_string())),
885 ("1".to_string(), EngineValue::Number(2.0)),
886 ];
887 assert_eq!(get_keys(&map), vec!["99", "0", "1"]);
888 }
889}