1use crate::binary::{Reader, Writer};
18use crate::error::{Error, Result, bail};
19
20pub const TYPES_0100: [&str; 22] = [
22 "null",
23 "Byte",
24 "SByte",
25 "UInt16",
26 "Int16",
27 "UInt32",
28 "Int32",
29 "Single",
30 "Double",
31 "String",
32 "Float2",
33 "Float3",
34 "Quat",
35 "Matrix44",
36 "Single[]",
37 "Byte[]",
38 "Int32[]",
39 "String[]",
40 "Float2[]",
41 "Float3[]",
42 "Quat[]",
43 "Matrix44[]",
44];
45
46pub const TYPES_0110: [&str; 22] = [
48 "null",
49 "Byte",
50 "SByte",
51 "UInt16",
52 "Int16",
53 "UInt32",
54 "Int32",
55 "Single",
56 "Double",
57 "String",
58 "Double2",
59 "Double3",
60 "Quat",
61 "Matrix44",
62 "Double[]",
63 "Byte[]",
64 "Int32[]",
65 "String[]",
66 "Double2[]",
67 "Double3[]",
68 "Quat[]",
69 "Matrix44[]",
70];
71
72const MAGIC: &[u8; 4] = b"cmt ";
73const BINARY: &[u8; 4] = b"binc";
74const NODE_HEADER: u32 = 16;
76
77#[derive(Debug, Clone, PartialEq, serde::Serialize)]
80pub enum Value {
81 Null,
83 Byte(u8),
85 SByte(i8),
87 UInt16(u16),
89 Int16(i16),
91 UInt32(u32),
93 Int32(i32),
95 Single(f32),
97 Double(f64),
99 String(String),
101 Float2([f32; 2]),
103 Float3([f32; 3]),
105 Double2([f64; 2]),
107 Double3([f64; 3]),
109 SingleArray(Vec<f32>),
111 DoubleArray(Vec<f64>),
113 ByteArray(Vec<u8>),
115 Int32Array(Vec<i32>),
117 StringArray(Vec<String>),
119 Float2Array(Vec<[f32; 2]>),
121 Float3Array(Vec<[f32; 3]>),
123 Double2Array(Vec<[f64; 2]>),
125 Double3Array(Vec<[f64; 3]>),
127}
128
129impl Value {
130 pub fn type_name(&self) -> &'static str {
132 match self {
133 Value::Null => "null",
134 Value::Byte(_) => "Byte",
135 Value::SByte(_) => "SByte",
136 Value::UInt16(_) => "UInt16",
137 Value::Int16(_) => "Int16",
138 Value::UInt32(_) => "UInt32",
139 Value::Int32(_) => "Int32",
140 Value::Single(_) => "Single",
141 Value::Double(_) => "Double",
142 Value::String(_) => "String",
143 Value::Float2(_) => "Float2",
144 Value::Float3(_) => "Float3",
145 Value::Double2(_) => "Double2",
146 Value::Double3(_) => "Double3",
147 Value::SingleArray(_) => "Single[]",
148 Value::DoubleArray(_) => "Double[]",
149 Value::ByteArray(_) => "Byte[]",
150 Value::Int32Array(_) => "Int32[]",
151 Value::StringArray(_) => "String[]",
152 Value::Float2Array(_) => "Float2[]",
153 Value::Float3Array(_) => "Float3[]",
154 Value::Double2Array(_) => "Double2[]",
155 Value::Double3Array(_) => "Double3[]",
156 }
157 }
158
159 pub fn as_f64(&self) -> Option<f64> {
161 Some(match self {
162 Value::Byte(v) => *v as f64,
163 Value::SByte(v) => *v as f64,
164 Value::UInt16(v) => *v as f64,
165 Value::Int16(v) => *v as f64,
166 Value::UInt32(v) => *v as f64,
167 Value::Int32(v) => *v as f64,
168 Value::Single(v) => *v as f64,
169 Value::Double(v) => *v,
170 _ => return None,
171 })
172 }
173
174 pub fn as_pair(&self) -> Option<[f64; 2]> {
176 match self {
177 Value::Float2([x, y]) => Some([*x as f64, *y as f64]),
178 Value::Double2(pair) => Some(*pair),
179 _ => None,
180 }
181 }
182
183 pub fn as_numbers(&self) -> Option<Vec<f64>> {
185 match self {
186 Value::SingleArray(v) => Some(v.iter().map(|x| *x as f64).collect()),
187 Value::DoubleArray(v) => Some(v.clone()),
188 Value::ByteArray(v) => Some(v.iter().map(|x| *x as f64).collect()),
189 Value::Int32Array(v) => Some(v.iter().map(|x| *x as f64).collect()),
190 _ => None,
191 }
192 }
193
194 pub fn as_strings(&self) -> Option<&[String]> {
196 match self {
197 Value::StringArray(v) => Some(v),
198 _ => None,
199 }
200 }
201
202 pub fn as_str(&self) -> Option<&str> {
204 match self {
205 Value::String(v) => Some(v),
206 _ => None,
207 }
208 }
209
210 fn strings(&self) -> Vec<&str> {
212 match self {
213 Value::String(v) => vec![v.as_str()],
214 Value::StringArray(v) => v.iter().map(String::as_str).collect(),
215 _ => Vec::new(),
216 }
217 }
218}
219
220#[derive(Debug, Clone, PartialEq, serde::Serialize)]
222pub struct Node {
223 pub name: String,
225 pub value: Value,
227 pub attributes: Vec<(String, String)>,
229 pub children: Vec<Node>,
231}
232
233impl Node {
234 pub fn new(name: impl Into<String>, value: Value) -> Self {
236 Node { name: name.into(), value, attributes: Vec::new(), children: Vec::new() }
237 }
238
239 pub fn attribute(&self, name: &str) -> Option<&str> {
241 self.attributes.iter().find(|(key, _)| key == name).map(|(_, value)| value.as_str())
242 }
243
244 pub fn child(&self, name: &str) -> Option<&Node> {
246 self.children.iter().find(|child| child.name == name)
247 }
248
249 pub fn child_mut(&mut self, name: &str) -> Option<&mut Node> {
251 self.children.iter_mut().find(|child| child.name == name)
252 }
253
254 pub fn find(&self, path: &[&str]) -> Option<&Node> {
256 path.iter().try_fold(self, |node, name| node.child(name))
257 }
258
259 pub fn find_mut(&mut self, path: &[&str]) -> Option<&mut Node> {
261 path.iter().try_fold(self, |node, name| node.child_mut(name))
262 }
263
264 pub fn dump(&self) -> String {
266 let mut out = String::new();
267 self.dump_into(0, &mut out);
268 out
269 }
270
271 fn dump_into(&self, depth: usize, out: &mut String) {
272 use std::fmt::Write;
273 let _ = write!(out, "{}{}", " ".repeat(depth), self.name);
274 if self.value != Value::Null {
275 let _ = write!(out, " : {} = {}", self.value.type_name(), value_text(&self.value));
276 }
277 if !self.attributes.is_empty() {
278 let attributes: Vec<String> = self.attributes.iter().map(|(k, v)| format!("{k}={v:?}")).collect();
279 let _ = write!(out, " [{}]", attributes.join(" "));
280 }
281 out.push('\n');
282 for child in &self.children {
283 child.dump_into(depth + 1, out);
284 }
285 }
286}
287
288fn value_text(value: &Value) -> String {
289 match value {
290 Value::String(v) => format!("{v:?}"),
291 Value::Byte(v) => v.to_string(),
292 Value::SByte(v) => v.to_string(),
293 Value::UInt16(v) => v.to_string(),
294 Value::Int16(v) => v.to_string(),
295 Value::UInt32(v) => v.to_string(),
296 Value::Int32(v) => v.to_string(),
297 Value::Single(v) => v.to_string(),
298 Value::Double(v) => v.to_string(),
299 other => serde_json::to_value(other)
300 .ok()
301 .and_then(|json| json.as_object().and_then(|o| o.values().next().cloned()))
302 .map(|inner| inner.to_string())
303 .unwrap_or_default(),
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, serde::Serialize)]
309pub struct Document {
310 pub version: String,
312 pub root: Node,
314}
315
316impl Document {
317 pub fn parse(data: &[u8]) -> Result<Self> {
319 let mut reader = Reader::new(data);
320 if reader.bytes(4)? != MAGIC {
321 bail!("Not a cmt document");
322 }
323 let version = String::from_utf8_lossy(reader.bytes(4)?).into_owned();
324 if version != "0100" && version != "0110" {
325 bail!("Unknown cmt version {version:?}");
326 }
327 if reader.bytes(4)? != BINARY {
328 bail!("cmt document is not binary");
329 }
330 let crc = reader.le_u32()?;
331 if crc != crc32(&data[16..]) {
332 bail!("cmt document checksum does not match");
333 }
334 let count = reader.le_u32()? as usize;
335 let mut strings = Vec::with_capacity(count.min(data.len()));
336 for _ in 0..count {
337 let length = reader.u8()? as usize;
338 let text =
339 std::str::from_utf8(reader.bytes(length)?).map_err(|_| Error::format("cmt string is not UTF-8"))?;
340 strings.push(text.to_owned());
341 }
342 let types = types(&version);
343 if strings.len() < types.len() || strings.iter().zip(types).any(|(a, b)| a != b) {
344 bail!("cmt string table does not start with the {version} type names");
345 }
346 let parser = Parser { strings: &strings, headers: version == "0110" };
347 let root = parser.node(&mut reader, 0)?;
348 if !reader.is_empty() {
349 bail!("{} bytes after the cmt root node", reader.remaining());
350 }
351 Ok(Document { version, root })
352 }
353
354 pub fn to_bytes(&self) -> Result<Vec<u8>> {
356 let types = types(&self.version);
357 let mut strings: Vec<String> = types.iter().map(|t| (*t).to_owned()).collect();
358 collect_strings(&self.root, &mut strings);
359 let index = |text: &str| -> u32 { strings.iter().position(|s| s == text).expect("collected") as u32 };
360 let mut body = Writer::new();
361 body.le_u32(strings.len() as u32);
362 for text in &strings {
363 let length = u8::try_from(text.len()).map_err(|_| Error::format("cmt string longer than 255 bytes"))?;
364 body.u8(length).bytes(text.as_bytes());
365 }
366 write_node(&self.root, &mut body, &index, types, self.version == "0110")?;
367 let body = body.into_inner();
368 let mut out = Writer::new();
369 out.bytes(MAGIC).bytes(self.version.as_bytes()).bytes(BINARY).le_u32(crc32(&body)).bytes(&body);
370 Ok(out.into_inner())
371 }
372
373 pub fn action_clip(&self) -> Option<&Node> {
375 self.root.find(&["General", "ActionNodeClip"])
376 }
377
378 pub fn action_clip_mut(&mut self) -> Option<&mut Node> {
380 self.root.find_mut(&["General", "ActionNodeClip"])
381 }
382}
383
384fn types(version: &str) -> &'static [&'static str; 22] {
385 if version == "0110" { &TYPES_0110 } else { &TYPES_0100 }
386}
387
388fn collect_strings(node: &Node, strings: &mut Vec<String>) {
389 let mut add = |text: &str| {
390 if !strings.iter().any(|s| s == text) {
391 strings.push(text.to_owned());
392 }
393 };
394 add(&node.name);
395 for text in node.value.strings() {
396 add(text);
397 }
398 for (name, value) in &node.attributes {
399 add(name);
400 add(value);
401 }
402 for child in &node.children {
403 collect_strings(child, strings);
404 }
405}
406
407struct Parser<'a> {
408 strings: &'a [String],
409 headers: bool,
410}
411
412impl Parser<'_> {
413 fn string(&self, index: u32) -> Result<String> {
414 self.strings.get(index as usize).cloned().ok_or_else(|| Error::format(format!("cmt string {index} missing")))
415 }
416
417 fn node(&self, reader: &mut Reader, depth: usize) -> Result<Node> {
418 if depth > 64 {
419 bail!("cmt tree too deep");
420 }
421 let start = reader.position();
422 let offsets = if self.headers {
423 let first = reader.le_u32()?;
424 if first != NODE_HEADER {
425 bail!("cmt node header {first}, expected {NODE_HEADER}");
426 }
427 Some((reader.le_u32()? as usize, reader.le_u32()? as usize))
428 } else {
429 None
430 };
431 let name = self.string(reader.le_u32()?)?;
432 let type_index = reader.le_u32()? as usize;
433 let type_name =
434 *TYPES_0100.get(type_index).ok_or_else(|| Error::format(format!("cmt type {type_index} unknown")))?;
435 let value = self.value(reader, type_index, type_name)?;
436 if let Some((attributes, _)) = offsets
437 && reader.position() != start + attributes
438 {
439 bail!("cmt node {name:?}: attributes at {}, header says {attributes}", reader.position() - start);
440 }
441 let count = reader.le_u32()? as usize;
442 let mut attribute_list = Vec::with_capacity(count.min(reader.remaining() / 8));
443 for _ in 0..count {
444 attribute_list.push((self.string(reader.le_u32()?)?, self.string(reader.le_u32()?)?));
445 }
446 if let Some((_, children)) = offsets
447 && reader.position() != start + children
448 {
449 bail!("cmt node {name:?}: children at {}, header says {children}", reader.position() - start);
450 }
451 let count = reader.le_u32()? as usize;
452 let mut children = Vec::with_capacity(count.min(reader.remaining() / 12));
453 for _ in 0..count {
454 children.push(self.node(reader, depth + 1)?);
455 }
456 Ok(Node { name, value, attributes: attribute_list, children })
457 }
458
459 fn value(&self, reader: &mut Reader, type_index: usize, name0100: &str) -> Result<Value> {
460 let double = self.headers;
463 let pair = |r: &mut Reader| -> Result<[f64; 2]> { Ok([r.le_f64()?, r.le_f64()?]) };
464 let triple = |r: &mut Reader| -> Result<[f64; 3]> { Ok([r.le_f64()?, r.le_f64()?, r.le_f64()?]) };
465 let fpair = |r: &mut Reader| -> Result<[f32; 2]> { Ok([r.le_f32()?, r.le_f32()?]) };
466 let ftriple = |r: &mut Reader| -> Result<[f32; 3]> { Ok([r.le_f32()?, r.le_f32()?, r.le_f32()?]) };
467 let count = |r: &mut Reader, size: usize| -> Result<usize> {
468 let n = r.le_u32()? as usize;
469 if n.saturating_mul(size) > r.remaining() {
470 bail!("cmt array of {n} does not fit");
471 }
472 Ok(n)
473 };
474 Ok(match type_index {
475 0 => Value::Null,
476 1 => Value::Byte(reader.u8()?),
477 2 => Value::SByte(reader.u8()? as i8),
478 3 => Value::UInt16(reader.le_u16()?),
479 4 => Value::Int16(reader.le_u16()? as i16),
480 5 => Value::UInt32(reader.le_u32()?),
481 6 => Value::Int32(reader.le_i32()?),
482 7 => Value::Single(reader.le_f32()?),
483 8 => Value::Double(reader.le_f64()?),
484 9 => Value::String(self.string(reader.le_u32()?)?),
485 10 if double => Value::Double2(pair(reader)?),
486 10 => Value::Float2(fpair(reader)?),
487 11 if double => Value::Double3(triple(reader)?),
488 11 => Value::Float3(ftriple(reader)?),
489 14 if double => {
490 let n = count(reader, 8)?;
491 Value::DoubleArray((0..n).map(|_| reader.le_f64()).collect::<Result<_>>()?)
492 }
493 14 => {
494 let n = count(reader, 4)?;
495 Value::SingleArray((0..n).map(|_| reader.le_f32()).collect::<Result<_>>()?)
496 }
497 15 => {
498 let n = count(reader, 1)?;
499 Value::ByteArray(reader.bytes(n)?.to_vec())
500 }
501 16 => {
502 let n = count(reader, 4)?;
503 Value::Int32Array((0..n).map(|_| reader.le_i32()).collect::<Result<_>>()?)
504 }
505 17 => {
506 let n = count(reader, 4)?;
507 Value::StringArray((0..n).map(|_| self.string(reader.le_u32()?)).collect::<Result<_>>()?)
508 }
509 18 if double => {
510 let n = count(reader, 16)?;
511 Value::Double2Array((0..n).map(|_| pair(reader)).collect::<Result<_>>()?)
512 }
513 18 => {
514 let n = count(reader, 8)?;
515 Value::Float2Array((0..n).map(|_| fpair(reader)).collect::<Result<_>>()?)
516 }
517 19 if double => {
518 let n = count(reader, 24)?;
519 Value::Double3Array((0..n).map(|_| triple(reader)).collect::<Result<_>>()?)
520 }
521 19 => {
522 let n = count(reader, 12)?;
523 Value::Float3Array((0..n).map(|_| ftriple(reader)).collect::<Result<_>>()?)
524 }
525 _ => bail!("cmt value type {name0100} is not supported"),
526 })
527 }
528}
529
530fn write_node(
531 node: &Node,
532 out: &mut Writer,
533 index: &dyn Fn(&str) -> u32,
534 types: &[&str; 22],
535 headers: bool,
536) -> Result<()> {
537 let type_name = node.value.type_name();
538 let type_index = types
539 .iter()
540 .position(|t| *t == type_name)
541 .ok_or_else(|| Error::format(format!("cmt type {type_name} does not exist in this version")))?;
542 let mut value = Writer::new();
543 match &node.value {
544 Value::Null => {}
545 Value::Byte(v) => {
546 value.u8(*v);
547 }
548 Value::SByte(v) => {
549 value.u8(*v as u8);
550 }
551 Value::UInt16(v) => {
552 value.le_u16(*v);
553 }
554 Value::Int16(v) => {
555 value.le_u16(*v as u16);
556 }
557 Value::UInt32(v) => {
558 value.le_u32(*v);
559 }
560 Value::Int32(v) => {
561 value.le_i32(*v);
562 }
563 Value::Single(v) => {
564 value.le_f32(*v);
565 }
566 Value::Double(v) => {
567 value.le_f64(*v);
568 }
569 Value::String(v) => {
570 value.le_u32(index(v));
571 }
572 Value::Float2(v) => v.iter().for_each(|x| {
573 value.le_f32(*x);
574 }),
575 Value::Float3(v) => v.iter().for_each(|x| {
576 value.le_f32(*x);
577 }),
578 Value::Double2(v) => v.iter().for_each(|x| {
579 value.le_f64(*x);
580 }),
581 Value::Double3(v) => v.iter().for_each(|x| {
582 value.le_f64(*x);
583 }),
584 Value::SingleArray(v) => {
585 value.le_u32(v.len() as u32);
586 v.iter().for_each(|x| {
587 value.le_f32(*x);
588 });
589 }
590 Value::DoubleArray(v) => {
591 value.le_u32(v.len() as u32);
592 v.iter().for_each(|x| {
593 value.le_f64(*x);
594 });
595 }
596 Value::ByteArray(v) => {
597 value.le_u32(v.len() as u32).bytes(v);
598 }
599 Value::Int32Array(v) => {
600 value.le_u32(v.len() as u32);
601 v.iter().for_each(|x| {
602 value.le_i32(*x);
603 });
604 }
605 Value::StringArray(v) => {
606 value.le_u32(v.len() as u32);
607 v.iter().for_each(|x| {
608 value.le_u32(index(x));
609 });
610 }
611 Value::Float2Array(v) => {
612 value.le_u32(v.len() as u32);
613 v.iter().flatten().for_each(|x| {
614 value.le_f32(*x);
615 });
616 }
617 Value::Float3Array(v) => {
618 value.le_u32(v.len() as u32);
619 v.iter().flatten().for_each(|x| {
620 value.le_f32(*x);
621 });
622 }
623 Value::Double2Array(v) => {
624 value.le_u32(v.len() as u32);
625 v.iter().flatten().for_each(|x| {
626 value.le_f64(*x);
627 });
628 }
629 Value::Double3Array(v) => {
630 value.le_u32(v.len() as u32);
631 v.iter().flatten().for_each(|x| {
632 value.le_f64(*x);
633 });
634 }
635 }
636 let value = value.into_inner();
637 if headers {
638 let attributes = 12 + 8 + value.len();
639 let children = attributes + 4 + 8 * node.attributes.len();
640 out.le_u32(NODE_HEADER).le_u32(attributes as u32).le_u32(children as u32);
641 }
642 out.le_u32(index(&node.name)).le_u32(type_index as u32).bytes(&value);
643 out.le_u32(node.attributes.len() as u32);
644 for (name, value) in &node.attributes {
645 out.le_u32(index(name)).le_u32(index(value));
646 }
647 out.le_u32(node.children.len() as u32);
648 for child in &node.children {
649 write_node(child, out, index, types, headers)?;
650 }
651 Ok(())
652}
653
654pub fn crc32(data: &[u8]) -> u32 {
656 let mut crc = flate2::Crc::new();
657 crc.update(data);
658 crc.sum()
659}
660
661pub fn unpack(payload: &[u8]) -> Result<Vec<u8>> {
665 let mut reader = Reader::new(payload);
666 let rest = reader.be_u64()?;
667 let length = reader.le_u32()? as usize;
668 if rest as usize != payload.len() - 8 || length != payload.len() - 12 {
669 bail!("cmt chunk lengths {rest}/{length} do not match its size {}", payload.len());
670 }
671 let mut out = Vec::new();
672 std::io::Read::read_to_end(&mut flate2::read::ZlibDecoder::new(&payload[12..]), &mut out)?;
673 Ok(out)
674}
675
676pub fn pack(document: &[u8]) -> Result<Vec<u8>> {
678 let stream = crate::zlib::compress(document)?;
679 let mut out = Writer::new();
680 out.be_u64(stream.len() as u64 + 4).le_u32(stream.len() as u32).bytes(&stream);
681 Ok(out.into_inner())
682}
683
684#[cfg(test)]
685mod tests {
686 use super::*;
687
688 fn sample(version: &str) -> Document {
689 let double = version == "0110";
690 let numbers = |v: &[f64]| {
691 if double {
692 Value::DoubleArray(v.to_vec())
693 } else {
694 Value::SingleArray(v.iter().map(|x| *x as f32).collect())
695 }
696 };
697 let mut curve = Node::new("FCurve", Value::Null);
698 curve.attributes.push(("Type".into(), "Opacity".into()));
699 curve.children = vec![
700 Node::new("Frame", numbers(&[10.0, 90.0])),
701 Node::new("Value", numbers(&[89.84375, 30.078125])),
702 Node::new("Interp", Value::StringArray(vec!["Constant".into(), "Default".into()])),
703 Node::new("ReviseConstant", Value::ByteArray(vec![1, 1])),
704 ];
705 let mut param = Node::new("Param", Value::Double(30.0));
706 param.attributes.push(("Name".into(), "Opacity".into()));
707 let mut anim = Node::new("AnimInfo", Value::Null);
708 anim.children = vec![param, curve];
709 let mut clip = Node::new("ActionNodeClip", Value::Null);
710 clip.attributes.push(("Name".into(), String::new()));
711 let mut time = Node::new("TimeClip", Value::Null);
712 time.children = vec![Node::new("Start", Value::Double(10.0)), Node::new("End", Value::Double(145.0))];
713 clip.children = vec![time, Node::new("Blend", Value::Byte(0)), anim];
714 let mut general = Node::new("General", Value::Null);
715 general.attributes.push(("Version".into(), if double { "2.1.0" } else { "2.0.0" }.into()));
716 general.children = vec![clip];
717 let mut info = Node::new("Version-Information", Value::Null);
718 info.children = vec![
719 Node::new("Software", Value::String("CLIP STUDIO".into())),
720 Node::new("Version", Value::String("2.1.0".into())),
721 ];
722 let mut root = Node::new("celsysdocument", Value::Null);
723 root.attributes.push(("version".into(), "1.0.0".into()));
724 root.children = vec![info, general];
725 Document { version: version.into(), root }
726 }
727
728 #[test]
729 fn both_versions_round_trip() {
730 for version in ["0100", "0110"] {
731 let document = sample(version);
732 let bytes = document.to_bytes().unwrap();
733 assert_eq!(&bytes[..8], format!("cmt {version}").as_bytes());
734 let parsed = Document::parse(&bytes).unwrap();
735 assert_eq!(parsed, document);
736 assert_eq!(parsed.to_bytes().unwrap(), bytes);
737 let clip = parsed.action_clip().unwrap();
738 assert_eq!(clip.find(&["TimeClip", "End"]).unwrap().value.as_f64(), Some(145.0));
739 }
740 }
741
742 #[test]
743 fn version_0110_has_node_headers() {
744 let bytes = sample("0110").to_bytes().unwrap();
745 let count = u32::from_le_bytes(bytes[16..20].try_into().unwrap()) as usize;
746 let mut at = 20;
747 for _ in 0..count {
748 at += 1 + bytes[at] as usize;
749 }
750 let words: Vec<u32> =
752 (0..3).map(|i| u32::from_le_bytes(bytes[at + 4 * i..at + 4 * i + 4].try_into().unwrap())).collect();
753 assert_eq!(words, [16, 20, 32]);
754 }
755
756 #[test]
757 fn string_table_follows_first_use() {
758 let bytes = sample("0100").to_bytes().unwrap();
759 let mut reader = Reader::new(&bytes[16..]);
760 let count = reader.le_u32().unwrap() as usize;
761 let strings: Vec<String> = (0..count)
762 .map(|_| {
763 let n = reader.u8().unwrap() as usize;
764 String::from_utf8(reader.bytes(n).unwrap().to_vec()).unwrap()
765 })
766 .collect();
767 assert_eq!(
768 &strings[22..28],
769 ["celsysdocument", "version", "1.0.0", "Version-Information", "Software", "CLIP STUDIO"]
770 );
771 }
772
773 #[test]
774 fn checksum_and_packing_are_checked() {
775 let mut bytes = sample("0110").to_bytes().unwrap();
776 let packed = pack(&bytes).unwrap();
777 assert_eq!(unpack(&packed).unwrap(), bytes);
778 *bytes.last_mut().unwrap() ^= 1;
779 assert!(Document::parse(&bytes).is_err());
780 }
781}