1mod class_index_map;
2mod enum_access;
3mod map;
4pub mod parser;
5mod seq;
6
7use crate::{lib::*, tri};
8
9use self::class_index_map::ClassIndexMapDeserializer;
10use self::enum_access::EnumDeserializer;
11use self::map::MapDeserializer;
12use self::parser::{
13 comment_multispace0,
14 tag::{attr_string, end_tag},
15 type_kind::{
16 boolean, matrix3, matrix4, pointer, qstransform, quaternion, real, rotation, string,
17 transform, vector4,
18 },
19};
20use self::seq::SeqDeserializer;
21use crate::errors::{
22 de::{Error, Result},
23 readable::ReadableError,
24};
25use havok_serde::de::{self, Deserialize, ReadEnumSize, Visitor};
26use havok_types::*;
27use parser::tag::{class_start_tag, start_tag};
28use winnow::Parser;
29use winnow::ascii::{dec_int, dec_uint};
30use winnow::combinator::opt;
31
32#[derive(Debug)]
35pub struct XmlDeserializer<'de> {
36 input: &'de str,
39
40 original: &'de str,
42
43 class_index: Option<usize>,
49
50 in_struct: bool,
59}
60
61impl<'de> XmlDeserializer<'de> {
62 #[allow(clippy::should_implement_trait)]
64 #[inline]
65 pub const fn from_str(input: &'de str) -> Self {
66 XmlDeserializer {
67 input,
68 original: input,
69 class_index: None,
70 in_struct: false,
71 }
72 }
73}
74
75#[inline]
80pub fn from_partial_str<'a, T>(s: &'a str) -> Result<T>
81where
82 T: Deserialize<'a>,
83{
84 from_partial_str_with_opt(XmlDeserializer::from_str(s))
85}
86
87pub fn from_partial_str_with_opt<'a, T>(de: XmlDeserializer<'a>) -> Result<T>
92where
93 T: Deserialize<'a>,
94{
95 let mut deserializer = de;
96 let t = tri!(T::deserialize(&mut deserializer));
97
98 if deserializer.input.is_empty() {
99 Ok(t)
100 } else {
101 Err(Error::TrailingCharacters {
102 remain: deserializer.input.to_string(),
103 })
104 }
105}
106
107#[inline]
112pub fn from_str<'a, T>(s: &'a str) -> Result<T>
113where
114 T: Deserialize<'a>,
115{
116 from_str_with_opt(XmlDeserializer::from_str(s))
117}
118
119pub fn from_str_with_opt<'a, T>(de: XmlDeserializer<'a>) -> Result<T>
124where
125 T: Deserialize<'a>,
126{
127 let mut de = de;
128
129 tri!(
130 de.parse_next(opt(winnow::token::take_until(
131 0..,
132 "<hksection name=\"__data__\">"
133 )))
134 .map_err(|err| de.to_readable_err(err))
135 );
136 tri!(
137 de.parse_next(winnow::token::take_until(0.., "<hkobject"))
138 .map_err(|err| de.to_readable_err(err))
139 );
140 let t = tri!(T::deserialize(&mut de).map_err(|err| de.to_readable_err(err)));
141 tri!(
142 de.parse_next(opt(end_tag("hksection")))
143 .map_err(|err| de.to_readable_err(err))
144 );
145 tri!(
146 de.parse_next(opt(end_tag("hkpackfile")))
147 .map_err(|err| de.to_readable_err(err))
148 );
149
150 if de.input.is_empty() {
151 Ok(t)
152 } else {
153 Err(de.to_readable_err(Error::TrailingCharacters {
154 remain: de.input.to_string(),
155 }))
156 }
157}
158
159pub fn from_str_peek<'a, T>(s: &'a str) -> Result<(&'a str, T)>
167where
168 T: Deserialize<'a>,
169{
170 let mut deserializer = XmlDeserializer::from_str(s);
171 let t = T::deserialize(&mut deserializer)?;
172 Ok((deserializer.input, t))
173}
174
175impl<'de> XmlDeserializer<'de> {
179 fn parse_next<O>(
183 &mut self,
184 mut parser: impl Parser<&'de str, O, winnow::error::ContextError>,
185 ) -> Result<O> {
186 let res = parser
187 .parse_next(&mut self.input)
188 .map_err(|err| Error::ContextError { err })?;
189 Ok(res)
190 }
191
192 fn parse_peek<O>(
196 &self,
197 mut parser: impl Parser<&'de str, O, winnow::error::ContextError>,
198 ) -> Result<O> {
199 let (_, res) = parser
200 .parse_peek(self.input)
201 .map_err(|err| Error::ContextError { err })?;
202 Ok(res)
203 }
204
205 #[cold]
210 fn to_readable_err(&self, err: Error) -> Error {
211 let readable = match err {
212 Error::ContextError { err } => ReadableError::from_context(
213 err,
214 self.original,
215 self.original.len() - self.input.len(),
216 ),
217 Error::ReadableError { source } => source,
218 err => ReadableError::from_display(
219 err,
220 self.original,
221 self.original.len() - self.input.len(),
222 ),
223 };
224
225 Error::ReadableError { source: readable }
226 }
227}
228
229impl<'de> de::Deserializer<'de> for &mut XmlDeserializer<'de> {
233 type Error = Error;
234
235 fn deserialize_identifier<V>(
242 self,
243 _size: ReadEnumSize,
244 visitor: V,
245 ) -> Result<V::Value, Self::Error>
246 where
247 V: Visitor<'de>,
248 {
249 let s = tri!(self.parse_next(string)); visitor.visit_stringptr(StringPtr::from_option(Some(s)))
251 }
252
253 #[inline]
255 fn deserialize_key<V>(self, visitor: V) -> Result<V::Value, Self::Error>
256 where
257 V: Visitor<'de>,
258 {
259 let key = tri!(self.parse_next(attr_string));
260 #[cfg(feature = "tracing")]
261 tracing::debug!(key);
262
263 visitor.visit_key(key)
264 }
265
266 #[inline]
267 fn deserialize_class_index<V>(self, visitor: V) -> Result<V::Value, Self::Error>
268 where
269 V: Visitor<'de>,
270 {
271 visitor.visit_class_index(ClassIndexMapDeserializer::new(self))
272 }
273
274 #[inline]
275 fn deserialize_void<V>(self, visitor: V) -> Result<V::Value, Self::Error>
276 where
277 V: Visitor<'de>,
278 {
279 visitor.visit_void(())
280 }
281
282 fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
283 where
284 V: Visitor<'de>,
285 {
286 visitor.visit_bool(tri!(self.parse_next(boolean)))
287 }
288
289 fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
290 where
291 V: Visitor<'de>,
292 {
293 let ch = self.input.chars().next().ok_or(Error::Eof)?;
294 self.input = &self.input[ch.len_utf8()..];
295 visitor.visit_char(ch)
296 }
297
298 fn deserialize_int8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
299 where
300 V: Visitor<'de>,
301 {
302 visitor.visit_int8(tri!(self.parse_next(dec_int)))
303 }
304
305 fn deserialize_uint8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
306 where
307 V: Visitor<'de>,
308 {
309 visitor.visit_uint8(tri!(self.parse_next(dec_uint)))
310 }
311
312 fn deserialize_int16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
313 where
314 V: Visitor<'de>,
315 {
316 visitor.visit_int16(tri!(self.parse_next(dec_int)))
317 }
318
319 fn deserialize_uint16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
320 where
321 V: Visitor<'de>,
322 {
323 visitor.visit_uint16(tri!(self.parse_next(dec_uint)))
324 }
325
326 fn deserialize_int32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
327 where
328 V: Visitor<'de>,
329 {
330 visitor.visit_int32(tri!(self.parse_next(dec_int)))
331 }
332
333 fn deserialize_uint32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
334 where
335 V: Visitor<'de>,
336 {
337 visitor.visit_uint32(tri!(self.parse_next(dec_uint)))
338 }
339
340 fn deserialize_int64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
341 where
342 V: Visitor<'de>,
343 {
344 visitor.visit_int64(tri!(self.parse_next(dec_int)))
345 }
346
347 fn deserialize_uint64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
348 where
349 V: Visitor<'de>,
350 {
351 visitor.visit_uint64(tri!(self.parse_next(dec_uint)))
352 }
353
354 fn deserialize_real<V>(self, visitor: V) -> Result<V::Value, Self::Error>
355 where
356 V: Visitor<'de>,
357 {
358 visitor.visit_real(tri!(self.parse_next(real)))
359 }
360
361 fn deserialize_vector4<V>(self, visitor: V) -> Result<V::Value, Self::Error>
362 where
363 V: Visitor<'de>,
364 {
365 visitor.visit_vector4(tri!(self.parse_next(vector4)))
366 }
367
368 fn deserialize_quaternion<V>(self, visitor: V) -> Result<V::Value, Self::Error>
369 where
370 V: Visitor<'de>,
371 {
372 visitor.visit_quaternion(tri!(self.parse_next(quaternion)))
373 }
374
375 fn deserialize_matrix3<V>(self, visitor: V) -> Result<V::Value, Self::Error>
376 where
377 V: Visitor<'de>,
378 {
379 visitor.visit_matrix3(tri!(self.parse_next(matrix3)))
380 }
381
382 fn deserialize_rotation<V>(self, visitor: V) -> Result<V::Value, Self::Error>
383 where
384 V: Visitor<'de>,
385 {
386 visitor.visit_rotation(tri!(self.parse_next(rotation)))
387 }
388
389 fn deserialize_qstransform<V>(self, visitor: V) -> Result<V::Value, Self::Error>
390 where
391 V: Visitor<'de>,
392 {
393 visitor.visit_qstransform(tri!(self.parse_next(qstransform)))
394 }
395
396 fn deserialize_matrix4<V>(self, visitor: V) -> Result<V::Value, Self::Error>
397 where
398 V: Visitor<'de>,
399 {
400 visitor.visit_matrix4(tri!(self.parse_next(matrix4)))
401 }
402
403 fn deserialize_transform<V>(self, visitor: V) -> Result<V::Value, Self::Error>
404 where
405 V: Visitor<'de>,
406 {
407 visitor.visit_transform(tri!(self.parse_next(transform)))
408 }
409
410 fn deserialize_pointer<V>(self, visitor: V) -> Result<V::Value, Self::Error>
411 where
412 V: Visitor<'de>,
413 {
414 visitor.visit_pointer(tri!(self.parse_next(pointer)))
415 }
416
417 fn deserialize_array<V>(self, visitor: V) -> Result<V::Value, Self::Error>
418 where
419 V: Visitor<'de>,
420 {
421 tri!(self.parse_next(comment_multispace0));
422 visitor.visit_array(SeqDeserializer::new(self))
423 }
424
425 #[inline]
426 fn deserialize_fixed_array<V>(self, visitor: V) -> Result<V::Value, Self::Error>
427 where
428 V: Visitor<'de>,
429 {
430 self.deserialize_array(visitor)
431 }
432
433 #[inline]
434 fn deserialize_class_index_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
435 where
436 V: Visitor<'de>,
437 {
438 self.deserialize_array(visitor)
439 }
440
441 #[inline]
442 fn deserialize_enum<V>(
443 self,
444 _name: &'static str,
445 _variants: &'static [&'static str],
446 visitor: V,
447 ) -> Result<V::Value, Self::Error>
448 where
449 V: Visitor<'de>,
450 {
451 visitor.visit_enum(EnumDeserializer::new(self))
452 }
453
454 fn deserialize_struct<V>(
465 self,
466 name: &'static str,
467 _fields: &'static [&'static str], visitor: V,
469 ) -> Result<V::Value, Self::Error>
470 where
471 V: Visitor<'de>,
472 {
473 let ptr_name = if self.in_struct {
474 #[cfg(feature = "tracing")]
475 tracing::trace!("Parsed class=\"{name}\": <hkobject>");
476 tri!(self.parse_next(start_tag("hkobject")));
478 None
479 } else {
480 let (ptr_name, class_name, _signature) = tri!(self.parse_next(class_start_tag));
481 #[cfg(feature = "tracing")]
482 tracing::trace!(
483 "Parsed: <hkobject name=\"{ptr_name}\" class=\"{class_name}\" signature=\"{_signature}\">"
484 );
485
486 if name != class_name {
487 return Err(Error::MismatchClassName {
488 actual: name,
489 expected: class_name.to_string(),
490 });
491 };
492 self.in_struct = true;
493 self.class_index = Some(ptr_name.get()); Some(ptr_name)
495 };
496 #[cfg(feature = "tracing")]
497 tracing::trace!("fields: {_fields:?}");
498
499 let value = tri!(visitor.visit_struct(MapDeserializer::new(self, ptr_name, name,)));
500 tri!(self.parse_next(end_tag("hkobject")));
501 Ok(value)
502 }
503
504 fn deserialize_variant<V>(self, visitor: V) -> Result<V::Value, Self::Error>
506 where
507 V: Visitor<'de>,
508 {
509 visitor.visit_pointer(tri!(self.parse_next(pointer)))
510 }
511
512 fn deserialize_cstring<V>(self, visitor: V) -> Result<V::Value, Self::Error>
513 where
514 V: Visitor<'de>,
515 {
516 let s = tri!(self.parse_next(string)); let s = if s == "\u{2400}" { None } else { Some(s) }; visitor.visit_cstring(CString::from_option(s))
519 }
520
521 #[inline]
522 fn deserialize_ulong<V>(self, visitor: V) -> Result<V::Value, Self::Error>
523 where
524 V: Visitor<'de>,
525 {
526 self.deserialize_uint64(visitor)
527 }
528
529 fn deserialize_flags<V>(self, _size: ReadEnumSize, visitor: V) -> Result<V::Value, Self::Error>
530 where
531 V: Visitor<'de>,
532 {
533 let s = tri!(self.parse_next(string));
534 visitor.visit_stringptr(StringPtr::from_option(Some(s)))
536 }
537
538 fn deserialize_half<V>(self, visitor: V) -> Result<V::Value, Self::Error>
539 where
540 V: Visitor<'de>,
541 {
542 let float = tri!(self.parse_next(real));
543 visitor.visit_half(f16::from_f32(float))
544 }
545
546 fn deserialize_stringptr<V>(self, visitor: V) -> Result<V::Value, Self::Error>
547 where
548 V: Visitor<'de>,
549 {
550 let s = tri!(self.parse_next(string)); let s = if s == "\u{2400}" { None } else { Some(s) }; visitor.visit_stringptr(StringPtr::from_option(s))
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559 use crate::tests::ClassMap;
560 use pretty_assertions::assert_eq;
561
562 fn partial_parse_assert<'a, T>(s: &'a str, expected: T)
563 where
564 T: Deserialize<'a> + PartialEq + fmt::Debug,
565 {
566 match from_partial_str::<T>(s) {
567 Ok(res) => assert_eq!(res, expected),
568 Err(err) => {
569 tracing::error!(?err);
570 panic!("{err}")
571 }
572 }
573 }
574
575 fn parse_peek_assert<'a, T>(s: &'a str, expected: (&str, T))
576 where
577 T: Deserialize<'a> + PartialEq + fmt::Debug,
578 {
579 match from_str_peek::<T>(s) {
580 Ok(res) => assert_eq!(res, expected),
581 Err(err) => {
582 tracing::error!(?err);
583 panic!("{err}")
584 }
585 }
586 }
587
588 #[test]
589 fn test_deserialize_primitive() {
590 use havok_classes::EventMode;
591 use havok_classes::hkClassMember_::FlagValues;
592
593 parse_peek_assert(
594 "ALIGN_8|ALiGN_16|SERIALIZE_IGNORED</hkparam>",
595 (
596 "</hkparam>",
597 FlagValues::ALIGN_8 | FlagValues::ALIGN_16 | FlagValues::SERIALIZE_IGNORED,
598 ),
599 );
600
601 parse_peek_assert(
602 "EVENT_MODE_DEFAULT</hkparam>",
603 ("</hkparam>", EventMode::EVENT_MODE_DEFAULT),
604 );
605
606 use havok_classes::RoleFlags;
608 const REMAIN_BITS: i16 = 0xFFFFF300_u32 as i16; parse_peek_assert(
610 "FLAG_HIDDEN|FLAG_NORMALIZED|FLAG_NONE|0xfffff300</hkparam>",
611 (
612 "</hkparam>",
613 RoleFlags::FLAG_HIDDEN
614 | RoleFlags::FLAG_NORMALIZED
615 | RoleFlags::FLAG_NONE
616 | RoleFlags::from_bits_retain(REMAIN_BITS),
617 ),
618 );
619 }
620
621 #[test]
622 fn test_deserialize_string() {
623 partial_parse_assert::<Vec<StringPtr>>(
624 r#"
625 <hkcstring>Hello</hkcstring>
626 <hkcstring>World</hkcstring>
627 <hkcstring></hkcstring>
628 "#,
629 vec!["Hello".into(), "World".into(), "".into()],
630 );
631 }
632
633 #[test]
634 fn test_deserialize_primitive_vec() {
635 partial_parse_assert(
636 r#"
637 <!-- Hi? -->
638 <!-- Hi? -->
639 true
640
641 <!-- Hi? -->
642 false
643 <!-- Hi?2 -->
644 "#,
645 vec![true, false],
646 );
647
648 partial_parse_assert(
649 r#"
650 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
651 16 17 18 19 20
652"#,
653 (0..21).collect::<Vec<i32>>(),
654 );
655 }
656
657 #[test]
658 fn test_deserialize_math_vec() {
659 #[rustfmt::skip]
660 partial_parse_assert(
661 r#" <!-- comment -->
662
663 (-0.000000 0.000000 -0.000000 1.000000 )
664<!-- comment -->
665
666 ( 0.000000 0.000000 -0.000000 1.000000 )
667
668 <!-- COmment -->
669
670( -0.000000 0.000000 -0.000000 1.000000 )
671 <!-- comment -->
672"#,
673 vec![
674 Vector4 { x: -0.0, y: 0.0, z: -0.0, w: 1.0, },
675 Vector4 { x: 0.0, y: 0.0, z: -0.0, w: 1.0, },
676 Vector4 { x: -0.0, y: 0.0, z: -0.0, w: 1.0, },
677 ],
678 );
679 }
680
681 #[test]
682 fn test_deserialize_primitive_array() {
683 partial_parse_assert::<[char; 0]>("", []);
684 }
685
686 #[test]
687 fn should_skip_class() {
688 use havok_classes::{hkBaseObject, hkReferencedObject};
689 partial_parse_assert(
690 r##"
691<hkobject name="#01000" class="hkReferencedObject" signature="0xea7f1d08">
692 <!-- memSizeAndFlags SERIALIZE_IGNORED -->
693 <!-- referenceCount SERIALIZE_IGNORED -->
694</hkobject>
695 "##,
696 hkReferencedObject {
697 __ptr: Some(Pointer::new(1000)),
698 parent: hkBaseObject { __ptr: None },
699 m_memSizeAndFlags: 0,
700 m_referenceCount: 0,
701 },
702 );
703 }
704
705 #[test]
706 fn test_hka_skeleton_invalid_lock_translation() {
707 use havok_classes::hkaSkeleton;
708
709 let xml = r###"
710 <hkobject name="#0122" class="hkaSkeleton" signature="0x366e8220">
711 <hkparam name="name">NPC Root [Root]</hkparam>
712 <hkparam name="parentIndices" numelements="52">-1 0 1</hkparam>
713 <hkparam name="bones" numelements="52">
714 <hkobject>
715 <hkparam name="name">NPC Root [Root]</hkparam>
716 <hkparam name="lockTranslation">fals</hkparam>
717 </hkobject>
718 </hkparam>
719 </hkobject>
720 "###;
721
722 assert!(from_str::<hkaSkeleton>(xml).is_err());
723 }
724
725 #[test]
726 fn test_hka_skeleton_valid() {
727 use havok_classes::{hkBaseObject, hkReferencedObject, hkaBone, hkaSkeleton};
728
729 let xml = r###"
730 <hkobject name="#0122" class="hkaSkeleton" signature="0x366e8220">
731 <hkparam name="name">NPC Root [Root]</hkparam>
732 <hkparam name="parentIndices" numelements="0" />
733 <hkparam name="bones" numelements="52">
734 <hkobject>
735 <hkparam name="name">NPC Root [Root]</hkparam>
736 <hkparam name="lockTranslation">false</hkparam>
737 </hkobject>
738 </hkparam>
739 </hkobject>
740 "###;
741
742 assert_eq!(
743 from_str::<hkaSkeleton>(xml),
744 Ok(hkaSkeleton {
745 __ptr: Some(Pointer::new(122)),
746 parent: hkReferencedObject {
747 __ptr: None,
748 parent: hkBaseObject { __ptr: None },
749 m_memSizeAndFlags: 0,
750 m_referenceCount: 0,
751 },
752 m_name: StringPtr::from_str("NPC Root [Root]"),
753 m_parentIndices: vec![],
754 m_bones: vec![hkaBone {
755 __ptr: None,
756 m_name: StringPtr::from_str("NPC Root [Root]"),
757 m_lockTranslation: false,
758 }],
759 m_referencePose: vec![],
760 m_referenceFloats: vec![],
761 m_floatSlots: vec![],
762 m_localFrames: vec![],
763 }),
764 );
765 }
766
767 #[test]
768 fn test_hk_root_level_container_valid() {
769 use havok_classes::{hkRootLevelContainer, hkRootLevelContainerNamedVariant};
770
771 let xml = r###"
772 <hkobject name="#0008" class="hkRootLevelContainer" signature="0x2772c11e">
773 <hkparam name="namedVariants" numelements="1">
774 <hkobject>
775 <hkparam name="name">hkbProjectData</hkparam>
776 <hkparam name="className">hkbProjectData</hkparam>
777 <hkparam name="variant">#0010</hkparam>
778 </hkobject>
779 </hkparam>
780 </hkobject>
781 "###;
782
783 assert_eq!(
784 from_str::<hkRootLevelContainer>(xml),
785 Ok(hkRootLevelContainer {
786 __ptr: Some(8.into()),
787 m_namedVariants: vec![hkRootLevelContainerNamedVariant {
788 __ptr: None,
789 m_name: "hkbProjectData".into(),
790 m_className: "hkbProjectData".into(),
791 m_variant: Pointer::new(10),
792 }],
793 })
794 );
795 }
796
797 #[test]
798 fn should_deserialize_classes_from_xml() {
799 use crate::tests::mocks::new_defaultmale;
800 use havok_classes::Classes;
801
802 fn from_file<'a, T>(xml: &'a str) -> T
803 where
804 T: Deserialize<'a>,
805 {
806 match from_str::<T>(xml) {
807 Ok(res) => res,
808 Err(err) => {
809 tracing::error!("{err}");
810 panic!("{err}")
811 }
812 }
813 }
814
815 let xml = include_str!("../../../../docs/handson_hex_dump/defaultmale/defaultmale_x86.xml");
816 tracing::debug!("{:#?}", from_file::<Vec<Classes>>(xml));
817
818 let actual = from_file::<ClassMap>(xml);
819 let expected = new_defaultmale();
820 assert_eq!(actual, expected);
821 }
822}