1use crate::{lib::*, tri};
3
4use crate::errors::ser::{Error, Result};
5use havok_serde::ser::{
6 Serialize, SerializeFlags, SerializeSeq, SerializeStruct, Serializer, TypeSize,
7};
8use havok_types::variant::Variant;
9use havok_types::{
10 CString, Matrix3, Matrix4, Pointer, QsTransform, Quaternion, Rotation, Signature, StringPtr,
11 Transform, Ulong, Vector4, f16,
12};
13
14#[derive(Debug)]
15pub struct XmlSerializer {
16 output: String,
18 indent: &'static str,
20 depth: usize,
22 start_root: Option<&'static str>,
29 end_root: Option<&'static str>,
35}
36
37impl Default for XmlSerializer {
38 fn default() -> Self {
39 Self {
40 output: String::new(),
41 indent: "\t",
42 depth: 0,
43 start_root: Some(
44 r###"<?xml version="1.0" encoding="ascii"?>
45<hkpackfile classversion="8" contentsversion="hk_2010.2.0-r1" toplevelobject=""###,
46 ),
47 end_root: Some("</hkpackfile>\n"),
48 }
49 }
50}
51
52#[inline]
57pub fn to_string<T>(value: &T, top_ptr: usize) -> Result<String>
58where
59 T: Serialize,
60{
61 to_string_with_opt(value, top_ptr, XmlSerializer::default())
62}
63
64pub fn to_string_with_opt<T>(value: &T, top_ptr: usize, ser: XmlSerializer) -> Result<String>
72where
73 T: Serialize,
74{
75 let mut serializer = ser;
76
77 if let Some(start_root) = serializer.start_root {
78 serializer.output += start_root;
79 serializer.output += &Pointer::new(top_ptr).to_string();
80 serializer.output += "\">\n\n";
81 serializer.increment_depth();
82 serializer.indent();
83 serializer.output += "<hksection name=\"__data__\">\n";
84 serializer.increment_depth();
85 };
86
87 tri!(value.serialize(&mut serializer));
88
89 if let Some(end_root) = serializer.end_root {
90 serializer.decrement_depth();
91 serializer.output += "\n";
92 serializer.indent();
93 serializer.output += "</hksection>";
94 serializer.decrement_depth();
95 serializer.output += "\n\n";
96 serializer.output += end_root;
97 };
98 Ok(serializer.output)
99}
100
101impl Serializer for &mut XmlSerializer {
102 type Ok = ();
103 type Error = Error;
104
105 type SerializeSeq = Self;
106 type SerializeStruct = Self;
107 type SerializeFlags = Self;
108
109 #[inline]
110 fn serialize_void(self, _: ()) -> Result<Self::Ok> {
111 Ok(())
112 }
113
114 #[inline]
115 fn serialize_bool(self, v: bool) -> Result<Self::Ok> {
116 self.output += if v { "true" } else { "false" };
117 Ok(())
118 }
119
120 #[inline]
121 fn serialize_char(self, v: char) -> Result<Self::Ok> {
122 self.output.push(v);
123 Ok(())
124 }
125
126 #[inline]
127 fn serialize_int8(self, v: i8) -> Result<Self::Ok> {
128 self.serialize_int64(v as i64)
129 }
130
131 #[inline]
132 fn serialize_uint8(self, v: u8) -> Result<Self::Ok> {
133 self.serialize_uint64(v as u64)
134 }
135
136 #[inline]
137 fn serialize_int16(self, v: i16) -> Result<Self::Ok> {
138 self.serialize_int64(v as i64)
139 }
140
141 #[inline]
142 fn serialize_uint16(self, v: u16) -> Result<Self::Ok> {
143 self.serialize_uint64(v as u64)
144 }
145
146 #[inline]
147 fn serialize_int32(self, v: i32) -> Result<Self::Ok> {
148 self.serialize_int64(v as i64)
149 }
150
151 #[inline]
152 fn serialize_uint32(self, v: u32) -> Result<Self::Ok> {
153 self.serialize_uint64(v as u64)
154 }
155
156 #[inline]
157 fn serialize_int64(self, v: i64) -> Result<Self::Ok> {
158 self.output += &v.to_string();
159 Ok(())
160 }
161
162 #[inline]
163 fn serialize_uint64(self, v: u64) -> Result<Self::Ok> {
164 self.output += &v.to_string();
165 Ok(())
166 }
167
168 #[inline]
169 fn serialize_real(self, v: f32) -> Result<Self::Ok> {
170 self.output += &format!("{v:.06}");
171 Ok(())
172 }
173
174 #[inline]
175 fn serialize_vector4(self, v: &Vector4) -> Result<Self::Ok> {
176 self.output += &v.to_string();
177 Ok(())
178 }
179
180 #[inline]
181 fn serialize_quaternion(self, v: &Quaternion) -> Result<Self::Ok> {
182 self.output += &v.to_string();
183 Ok(())
184 }
185
186 #[inline]
187 fn serialize_matrix3(self, v: &Matrix3) -> Result<Self::Ok> {
188 self.output += &v.to_string();
189 Ok(())
190 }
191
192 #[inline]
193 fn serialize_rotation(self, v: &Rotation) -> Result<Self::Ok> {
194 self.output += &v.to_string();
195 Ok(())
196 }
197
198 #[inline]
199 fn serialize_qstransform(self, v: &QsTransform) -> Result<Self::Ok> {
200 self.output += &v.to_string();
201 Ok(())
202 }
203
204 #[inline]
205 fn serialize_matrix4(self, v: &Matrix4) -> Result<Self::Ok> {
206 self.output += &v.to_string();
207 Ok(())
208 }
209
210 #[inline]
211 fn serialize_transform(self, v: &Transform) -> Result<Self::Ok> {
212 self.output += &v.to_string();
213 Ok(())
214 }
215
216 #[inline]
217 fn serialize_pointer(self, v: Pointer) -> Result<Self::Ok> {
218 if v.get() == 0 {
219 self.output += "null"; } else {
221 self.output += &v.to_string();
222 }
223 Ok(())
224 }
225
226 #[inline]
227 fn serialize_array(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
228 Ok(self)
229 }
230
231 fn serialize_struct(
242 self,
243 name: &'static str,
244 class_meta: Option<(Pointer, Signature)>,
245 _sizes: (u64, u64),
246 ) -> Result<Self::SerializeStruct> {
247 if let Some((ptr_name, sig)) = class_meta {
248 self.output += "\n";
249 self.indent();
250 self.output +=
251 &format!("<hkobject name=\"{ptr_name}\" class=\"{name}\" signature=\"{sig}\">\n");
252 } else {
253 if !self.output.ends_with('\n') {
258 self.output += "\n";
259 self.increment_depth();
260 };
261 self.indent();
262 self.output += "<hkobject>\n"; }
264
265 self.increment_depth(); Ok(self)
267 }
268
269 #[inline]
271 fn serialize_variant(self, v: &Variant) -> Result<Self::Ok> {
272 tri!(self.serialize_pointer(v.object));
273 self.serialize_pointer(v.class)
274 }
275
276 #[inline]
277 fn serialize_cstring(self, v: &CString) -> Result<Self::Ok> {
278 if let Some(s) = v.get_ref() {
279 self.output += &html_escape::encode_text(s);
280 } else {
281 self.output += "␀";
283 };
284 Ok(())
285 }
286
287 #[inline]
288 fn serialize_ulong(self, v: Ulong) -> Result<Self::Ok> {
289 self.output += &v.to_string();
290 Ok(())
291 }
292
293 #[inline]
294 fn serialize_enum_flags(self) -> Result<Self::SerializeFlags> {
295 Ok(self)
296 }
297
298 #[inline]
299 fn serialize_half(self, v: f16) -> Result<Self::Ok> {
300 self.output += &format!("{v:.06}");
301 Ok(())
302 }
303
304 #[inline]
305 fn serialize_stringptr(self, v: &StringPtr) -> Result<Self::Ok> {
306 if let Some(s) = v.get_ref() {
307 self.output += &html_escape::encode_text(s);
308 } else {
309 self.output += "␀";
311 };
312 Ok(())
313 }
314}
315
316impl XmlSerializer {
317 #[inline]
319 fn indent(&mut self) {
320 match self.depth {
321 0 => (), 1 => self.output += self.indent, _ => self.output += &self.indent.repeat(self.depth), }
326 }
327
328 #[inline]
330 const fn increment_depth(&mut self) {
331 self.depth += 1;
332 }
333
334 #[inline]
336 const fn decrement_depth(&mut self) {
337 self.depth -= 1;
338 }
339}
340
341impl SerializeSeq for &mut XmlSerializer {
342 type Ok = ();
343 type Error = Error;
344
345 fn serialize_primitive_element<T>(
355 &mut self,
356 value: &T,
357 index: usize,
358 len: usize,
359 ) -> Result<(), Self::Error>
360 where
361 T: ?Sized + havok_serde::ser::Serialize,
362 {
363 if index == 0 {
364 self.indent();
365 };
366 tri!(value.serialize(&mut **self));
367
368 if index + 1 == len {
369 self.output.push('\n');
372 return Ok(());
373 } else if (index + 1) % 16 == 0 {
374 self.output.push('\n'); self.indent();
376 } else {
377 self.output.push(' '); }
379 Ok(())
380 }
381
382 #[inline]
383 fn serialize_class_element<T>(&mut self, value: &T) -> Result<()>
384 where
385 T: ?Sized + Serialize,
386 {
387 tri!(value.serialize(&mut **self));
388 self.output += "\n";
389 Ok(())
390 }
391
392 fn serialize_math_element<T>(&mut self, value: &T) -> Result<()>
393 where
394 T: ?Sized + Serialize,
395 {
396 self.indent();
397 tri!(value.serialize(&mut **self));
398 self.output += "\n";
399 Ok(())
400 }
401
402 fn serialize_cstring_element(&mut self, value: &CString) -> Result<()> {
408 self.indent();
409 self.output += "<hkcstring>";
410 tri!(value.serialize(&mut **self));
411 self.output += "</hkcstring>\n";
412 Ok(())
413 }
414
415 fn serialize_stringptr_element(&mut self, value: &StringPtr) -> Result<()> {
421 self.indent();
422 self.output += "<hkcstring>";
423 tri!(value.serialize(&mut **self));
424 self.output += "</hkcstring>\n";
425 Ok(())
426 }
427
428 #[inline]
429 fn end(self) -> Result<()> {
430 Ok(())
431 }
432}
433
434impl SerializeStruct for &mut XmlSerializer {
435 type Ok = ();
436 type Error = Error;
437
438 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
444 where
445 T: ?Sized + Serialize,
446 {
447 self.indent();
448 self.output += "<hkparam name=\"";
449 self.output += key;
450 self.output += "\">";
451
452 tri!(value.serialize(&mut **self));
453
454 if self.output.ends_with("</hkobject>") {
457 self.output += "\n";
458 self.decrement_depth();
459 self.indent();
460 };
461 self.output += "</hkparam>\n";
462 Ok(())
463 }
464
465 #[inline]
466 fn serialize_fixed_array_field<V, T>(
467 &mut self,
468 key: &'static str,
469 value: V,
470 size: TypeSize,
471 ) -> std::result::Result<(), Self::Error>
472 where
473 V: AsRef<[T]> + Serialize,
474 T: Serialize,
475 {
476 SerializeStruct::serialize_array_field(self, key, value, size)
477 }
478
479 fn serialize_array_field<V, T>(
506 &mut self,
507 key: &'static str,
508 value: V,
509 _size: TypeSize,
510 ) -> Result<()>
511 where
512 V: AsRef<[T]> + Serialize,
513 T: Serialize,
514 {
515 self.indent();
516 self.output += "<hkparam name=\"";
517 self.output += key;
518
519 let array = value.as_ref();
520 if array.is_empty() {
521 self.output += "\" numelements=\"0\"></hkparam>\n";
522 return Ok(());
523 };
524
525 let len = array.len();
526 self.output += &format!("\" numelements=\"{len}\">\n");
527 self.increment_depth();
528 tri!(value.serialize(&mut **self));
529 self.decrement_depth();
530 self.indent();
531 self.output += "</hkparam>\n";
532 Ok(())
533 }
534
535 #[inline]
542 fn skip_field<T>(&mut self, key: &'static str, _: &T) -> Result<()>
543 where
544 T: ?Sized + Serialize,
545 {
546 self.indent();
547 self.output += &format!("<!-- {key} SERIALIZE_IGNORED -->\n");
548 Ok(())
549 }
550
551 #[inline]
552 fn end(self) -> Result<()> {
553 self.decrement_depth();
554 self.indent();
555 self.output += "</hkobject>";
556 Ok(())
557 }
558}
559
560impl SerializeFlags for &mut XmlSerializer {
561 type Ok = ();
562 type Error = Error;
563
564 #[inline]
566 fn serialize_empty_bit(&mut self) -> Result<(), Self::Error> {
567 self.output += "0";
568 Ok(())
569 }
570
571 #[inline]
572 fn serialize_field<T>(&mut self, key: &str, _value: &T) -> Result<(), Self::Error>
573 where
574 T: ?Sized + Serialize,
575 {
576 if !self.output.ends_with('>') {
579 self.output += "|";
580 }
581 self.output += key;
582
583 Ok(())
584 }
585
586 #[inline]
587 fn end(self) -> Result<Self::Ok, Self::Error> {
588 Ok(())
589 }
590}
591
592#[cfg(test)]
593mod tests {
594 use super::*;
595 use crate::{HavokSort as _, tests::mocks::new_defaultmale};
596 use pretty_assertions::assert_eq;
597
598 #[ignore = "No error on local PC Windows, but for some reason error occurs on GitHub Actions Windows"]
599 #[test]
600 fn test_serialize_defaultmale() -> Result<()> {
601 let mut classes = new_defaultmale();
602 let top_ptr = classes.sort_for_xml()?; let actual = tri!(to_string(&classes, top_ptr));
605 let expected =
606 include_str!("../../../../docs/handson_hex_dump/defaultmale/defaultmale_x86.xml");
607
608 assert_eq!(actual, expected);
609 Ok(())
610 }
611}