1mod error;
31
32#[cfg(test)]
33mod tests;
34
35pub use error::{Error, ParseError};
36
37use byteorder::{ReadBytesExt, WriteBytesExt, LE};
38use std::{
39 borrow::Cow,
40 io::{Read, Seek, Write},
41};
42
43use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
44
45type TResult<T> = Result<T, Error>;
46
47trait Readable<R: Read + Seek, V> {
48 fn read(reader: &mut Context<R, V>) -> TResult<Self>
49 where
50 Self: Sized;
51}
52trait Writable<W, V> {
53 fn write(&self, writer: &mut Context<W, V>) -> TResult<()>;
54}
55
56struct SeekReader<R: Read> {
57 reader: R,
58 read_bytes: usize,
59}
60
61impl<R: Read> SeekReader<R> {
62 fn new(reader: R) -> Self {
63 Self {
64 reader,
65 read_bytes: 0,
66 }
67 }
68}
69impl<R: Read> Seek for SeekReader<R> {
70 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
71 match pos {
72 std::io::SeekFrom::Current(0) => Ok(self.read_bytes as u64),
73 _ => unimplemented!(),
74 }
75 }
76}
77impl<R: Read> Read for SeekReader<R> {
78 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
79 self.reader.read(buf).inspect(|s| self.read_bytes += s)
80 }
81}
82
83fn read_optional_uuid<R: Read + Seek, V>(
84 reader: &mut Context<R, V>,
85) -> TResult<Option<uuid::Uuid>> {
86 Ok(if reader.read_u8()? > 0 {
87 Some(uuid::Uuid::read(reader)?)
88 } else {
89 None
90 })
91}
92fn write_optional_uuid<W: Write, V>(
93 writer: &mut Context<W, V>,
94 id: Option<uuid::Uuid>,
95) -> TResult<()> {
96 if let Some(id) = id {
97 writer.write_u8(1)?;
98 id.write(writer)?;
99 } else {
100 writer.write_u8(0)?;
101 }
102 Ok(())
103}
104
105fn read_string<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<String> {
106 let len = reader.read_i32::<LE>()?;
107 if len < 0 {
108 let chars = read_array((-len) as u32, reader, |r| Ok(r.read_u16::<LE>()?))?;
109 let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
110 Ok(String::from_utf16(&chars[..length]).unwrap())
111 } else {
112 let mut chars = vec![0; len as usize];
113 reader.read_exact(&mut chars)?;
114 let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
115 Ok(String::from_utf8_lossy(&chars[..length]).into_owned())
116 }
117}
118fn write_string<W: Write, V>(writer: &mut Context<W, V>, string: &str) -> TResult<()> {
119 if string.is_empty() {
120 writer.write_u32::<LE>(0)?;
121 } else {
122 write_string_trailing(writer, string, None)?;
123 }
124 Ok(())
125}
126
127fn read_string_trailing<R: Read + Seek, V>(
128 reader: &mut Context<R, V>,
129) -> TResult<(String, Vec<u8>)> {
130 let len = reader.read_i32::<LE>()?;
131 if len < 0 {
132 let bytes = (-len) as usize * 2;
133 let mut chars = vec![];
134 let mut rest = vec![];
135 let mut read = 0;
136 while read < bytes {
137 let next = reader.read_u16::<LE>()?;
138 read += 2;
139 if next == 0 {
140 rest.extend(next.to_le_bytes());
141 break;
142 } else {
143 chars.push(next);
144 }
145 }
146 while read < bytes {
147 rest.push(reader.read_u8()?);
148 read += 1;
149 }
150 Ok((String::from_utf16(&chars).unwrap(), rest))
151 } else {
152 let bytes = len as usize;
153 let mut chars = vec![];
154 let mut rest = vec![];
155 let mut read = 0;
156 while read < bytes {
157 let next = reader.read_u8()?;
158 read += 1;
159 if next == 0 {
160 rest.push(next);
161 break;
162 } else {
163 chars.push(next);
164 }
165 }
166 while read < bytes {
167 rest.push(reader.read_u8()?);
168 read += 1;
169 }
170 Ok((String::from_utf8(chars).unwrap(), rest))
171 }
172}
173fn write_string_trailing<W: Write, V>(
174 writer: &mut Context<W, V>,
175 string: &str,
176 trailing: Option<&[u8]>,
177) -> TResult<()> {
178 if string.is_empty() || string.is_ascii() {
179 writer.write_u32::<LE>((string.len() + trailing.map(|t| t.len()).unwrap_or(1)) as u32)?;
180 writer.write_all(string.as_bytes())?;
181 writer.write_all(trailing.unwrap_or(&[0]))?;
182 } else {
183 let chars: Vec<u16> = string.encode_utf16().collect();
184 writer.write_i32::<LE>(
185 -((chars.len() + trailing.map(|t| t.len()).unwrap_or(2) / 2) as i32),
186 )?;
187 for c in chars {
188 writer.write_u16::<LE>(c)?;
189 }
190 writer.write_all(trailing.unwrap_or(&[0, 0]))?;
191 }
192 Ok(())
193}
194
195#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub struct PropertyKey(pub u32, pub String);
197impl From<String> for PropertyKey {
198 fn from(value: String) -> Self {
199 Self(0, value)
200 }
201}
202impl From<&str> for PropertyKey {
203 fn from(value: &str) -> Self {
204 Self(0, value.to_string())
205 }
206}
207
208struct PropertyKeyVisitor;
209impl Visitor<'_> for PropertyKeyVisitor {
210 type Value = PropertyKey;
211 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
212 formatter.write_str(
213 "a property key in the form of key name and index seperated by '_' e.g. property_2",
214 )
215 }
216 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
217 where
218 E: serde::de::Error,
219 {
220 let (name_str, index_str) = value
221 .rsplit_once('_')
222 .ok_or_else(|| serde::de::Error::custom("property key does not contain a '_'"))?;
223 let index: u32 = index_str.parse().map_err(serde::de::Error::custom)?;
224
225 Ok(PropertyKey(index, name_str.to_string()))
226 }
227}
228impl<'de> Deserialize<'de> for PropertyKey {
229 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
230 where
231 D: Deserializer<'de>,
232 {
233 deserializer.deserialize_str(PropertyKeyVisitor)
234 }
235}
236impl Serialize for PropertyKey {
237 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238 where
239 S: Serializer,
240 {
241 serializer.serialize_str(&format!("{}_{}", self.1, self.0))
242 }
243}
244
245#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
246pub struct Properties(pub indexmap::IndexMap<PropertyKey, Property>);
247impl Properties {
248 fn insert(&mut self, k: impl Into<PropertyKey>, v: Property) -> Option<Property> {
249 self.0.insert(k.into(), v)
250 }
251}
252impl<K> std::ops::Index<K> for Properties
253where
254 K: Into<PropertyKey>,
255{
256 type Output = Property;
257 fn index(&self, index: K) -> &Self::Output {
258 self.0.index(&index.into())
259 }
260}
261impl<K> std::ops::IndexMut<K> for Properties
262where
263 K: Into<PropertyKey>,
264{
265 fn index_mut(&mut self, index: K) -> &mut Property {
266 self.0.index_mut(&index.into())
267 }
268}
269impl<'a> IntoIterator for &'a Properties {
270 type Item = <&'a indexmap::IndexMap<PropertyKey, Property> as IntoIterator>::Item;
271 type IntoIter = <&'a indexmap::IndexMap<PropertyKey, Property> as IntoIterator>::IntoIter;
272 fn into_iter(self) -> Self::IntoIter {
273 self.0.iter()
274 }
275}
276
277fn read_properties_until_none<R: Read + Seek, V: VersionInfo>(
278 reader: &mut Context<R, V>,
279) -> TResult<Properties> {
280 let mut properties = Properties::default();
281 while let Some((name, prop)) = read_property(reader)? {
282 properties.insert(name, prop);
283 }
284 Ok(properties)
285}
286fn write_properties_none_terminated<W: Write, V: VersionInfo>(
287 writer: &mut Context<W, V>,
288 properties: &Properties,
289) -> TResult<()> {
290 for p in properties {
291 write_property(p, writer)?;
292 }
293 write_string(writer, "None")?;
294 Ok(())
295}
296
297fn read_property<R: Read + Seek, V: VersionInfo>(
298 reader: &mut Context<R, V>,
299) -> TResult<Option<(PropertyKey, Property)>> {
300 if let Some(tag) = PropertyTagFull::read(reader)? {
301 let value = reader.with_scope(&tag.name, |reader| Property::read(reader, tag.clone()))?;
302 Ok(Some((PropertyKey(tag.index, tag.name.to_string()), value)))
303 } else {
304 Ok(None)
305 }
306}
307fn write_property<W: Write, V: VersionInfo>(
308 prop: (&PropertyKey, &Property),
309 writer: &mut Context<W, V>,
310) -> TResult<()> {
311 let mut tag = prop
312 .1
313 .tag
314 .clone()
315 .into_full(&prop.0 .1, 0, prop.0 .0, prop.1);
316 let mut buf = vec![];
317 let size = writer.with_stream(&mut buf, |writer| prop.1.write(writer, &tag))? as u32;
318 tag.size = size;
319
320 tag.write(writer)?;
321 writer.write_all(&buf[..])?;
322 Ok(())
323}
324
325fn read_array<T, F, R: Read + Seek, V>(
326 length: u32,
327 reader: &mut Context<R, V>,
328 f: F,
329) -> TResult<Vec<T>>
330where
331 F: Fn(&mut Context<R, V>) -> TResult<T>,
332{
333 (0..length).map(|_| f(reader)).collect()
334}
335
336#[rustfmt::skip]
337impl<R: Read + Seek, V> Readable<R, V> for uuid::Uuid {
338 fn read(reader: &mut Context<R, V>) -> TResult<uuid::Uuid> {
339 let mut b = [0; 16];
340 reader.read_exact(&mut b)?;
341 Ok(uuid::Uuid::from_bytes([
342 b[0x3], b[0x2], b[0x1], b[0x0],
343 b[0x7], b[0x6], b[0x5], b[0x4],
344 b[0xb], b[0xa], b[0x9], b[0x8],
345 b[0xf], b[0xe], b[0xd], b[0xc],
346 ]))
347 }
348}
349#[rustfmt::skip]
350impl<W: Write, V> Writable<W, V> for uuid::Uuid {
351 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
352 let b = self.as_bytes();
353 writer.write_all(&[
354 b[0x3], b[0x2], b[0x1], b[0x0],
355 b[0x7], b[0x6], b[0x5], b[0x4],
356 b[0xb], b[0xa], b[0x9], b[0x8],
357 b[0xf], b[0xe], b[0xd], b[0xc],
358 ])?;
359 Ok(())
360 }
361}
362
363#[derive(Debug, Default, Clone)]
365pub struct Types {
366 types: std::collections::HashMap<String, StructType>,
367}
368impl Types {
369 pub fn new() -> Self {
371 Self::default()
372 }
373 pub fn add(&mut self, path: String, t: StructType) {
375 self.types.insert(path, t);
378 }
379}
380
381#[derive(Debug)]
382enum Scope<'p, 'n> {
383 Root,
384 Node {
385 parent: &'p Scope<'p, 'p>,
386 name: &'n str,
387 },
388}
389
390impl Scope<'_, '_> {
391 fn path(&self) -> String {
392 match self {
393 Self::Root => "".into(),
394 Self::Node { parent, name } => {
395 format!("{}.{}", parent.path(), name)
396 }
397 }
398 }
399}
400
401#[derive(Debug)]
402struct Context<'stream, 'version, 'types, 'scope, S, V> {
403 stream: &'stream mut S,
404 state: ContextState<'version, 'types, 'scope, V>,
405}
406#[derive(Debug)]
407struct ContextState<'version, 'types, 'scope, V> {
408 version: &'version V,
409 types: &'types Types,
410 scope: &'scope Scope<'scope, 'scope>,
411 log: bool,
412}
413impl<R: Read, V> Read for Context<'_, '_, '_, '_, R, V> {
414 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
415 self.stream.read(buf)
416 }
417}
418impl<S: Seek, V> Seek for Context<'_, '_, '_, '_, S, V> {
419 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
420 self.stream.seek(pos)
421 }
422}
423impl<W: Write, V> Write for Context<'_, '_, '_, '_, W, V> {
424 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
425 self.stream.write(buf)
426 }
427 fn flush(&mut self) -> std::io::Result<()> {
428 self.stream.flush()
429 }
430}
431
432impl<'stream, 'scope, S> Context<'stream, '_, '_, 'scope, S, ()> {
433 fn run<F, T>(stream: &'stream mut S, f: F) -> T
434 where
435 F: FnOnce(&mut Context<'stream, '_, '_, 'scope, S, ()>) -> T,
436 {
437 f(&mut Context::<'stream, '_, '_, 'scope> {
438 stream,
439 state: ContextState {
440 version: &(),
441 types: &Types::new(),
442 scope: &Scope::Root,
443 log: false,
444 },
445 })
446 }
447}
448impl<'types, S, V> Context<'_, '_, 'types, '_, S, V> {
449 fn with_scope<'name, F, T>(&mut self, name: &'name str, f: F) -> T
450 where
451 F: FnOnce(&mut Context<'_, '_, 'types, '_, S, V>) -> T,
452 {
453 f(&mut Context {
454 stream: self.stream,
455 state: ContextState {
456 scope: &Scope::Node {
457 name,
458 parent: self.state.scope,
459 },
460 ..self.state
461 },
462 })
463 }
464 fn with_version<'h, F, T, V2>(&mut self, version: &'h V2, f: F) -> T
465 where
466 F: FnOnce(&mut Context<'_, '_, 'types, '_, S, V2>) -> T,
467 {
468 f(&mut Context {
469 stream: self.stream,
470 state: ContextState {
471 version,
472 types: self.state.types,
473 scope: self.state.scope,
474 log: self.state.log,
475 },
476 })
477 }
478 fn with_stream<'s, F, T, S2>(&mut self, stream: &'s mut S2, f: F) -> T
479 where
480 F: FnOnce(&mut Context<'_, '_, 'types, '_, S2, V>) -> T,
481 {
482 f(&mut Context {
483 stream,
484 state: ContextState { ..self.state },
485 })
486 }
487 fn path(&self) -> String {
488 self.state.scope.path()
489 }
490 fn get_type(&self) -> Option<&'types StructType> {
491 self.state.types.types.get(&self.path())
492 }
493 fn version(&self) -> &V {
494 self.state.version
495 }
496 fn log(&self) -> bool {
497 self.state.log
498 }
499}
500impl<'types, R: Read + Seek, V> Context<'_, '_, 'types, '_, R, V> {
501 fn get_type_or<'t>(&mut self, t: &'t StructType) -> TResult<&'t StructType>
502 where
503 'types: 't,
504 {
505 let offset = self.stream.stream_position()?;
506 Ok(self.get_type().unwrap_or_else(|| {
507 if self.log() {
508 eprintln!(
509 "offset {}: StructType for \"{}\" unspecified, assuming {:?}",
510 offset,
511 self.path(),
512 t
513 );
514 }
515 t
516 }))
517 }
518}
519
520#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
521struct PropertyTagFull<'a> {
522 name: Cow<'a, str>,
523 id: Option<uuid::Uuid>,
524 size: u32,
525 index: u32,
526 data: PropertyTagDataFull,
527}
528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
529enum PropertyTagDataFull {
530 Array(std::boxed::Box<PropertyTagDataFull>),
531 Struct {
532 struct_type: StructType,
533 id: uuid::Uuid,
534 },
535 Set {
536 key_type: std::boxed::Box<PropertyTagDataFull>,
537 },
538 Map {
539 key_type: std::boxed::Box<PropertyTagDataFull>,
540 value_type: std::boxed::Box<PropertyTagDataFull>,
541 },
542 Byte(Option<String>),
543 Enum(String, Option<String>),
544 Bool(bool),
545 Other(PropertyType),
546}
547#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
548pub struct PropertyTagPartial {
549 #[serde(skip_serializing_if = "Option::is_none")]
550 pub id: Option<uuid::Uuid>,
551 pub data: PropertyTagDataPartial,
552}
553#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
554pub enum PropertyTagDataPartial {
555 Array(std::boxed::Box<PropertyTagDataPartial>),
556 Struct {
557 struct_type: StructType,
558 id: uuid::Uuid,
559 },
560 Set {
561 key_type: std::boxed::Box<PropertyTagDataPartial>,
562 },
563 Map {
564 key_type: std::boxed::Box<PropertyTagDataPartial>,
565 value_type: std::boxed::Box<PropertyTagDataPartial>,
566 },
567 Byte(Option<String>),
568 Enum(String, Option<String>),
569 Other(PropertyType),
570}
571impl PropertyTagDataFull {
572 fn into_partial(self) -> PropertyTagDataPartial {
573 match self {
574 Self::Array(inner) => PropertyTagDataPartial::Array(inner.into_partial().into()),
575 Self::Struct { struct_type, id } => PropertyTagDataPartial::Struct { struct_type, id },
576 Self::Set { key_type } => PropertyTagDataPartial::Set {
577 key_type: key_type.into_partial().into(),
578 },
579 Self::Map {
580 key_type,
581 value_type,
582 } => PropertyTagDataPartial::Map {
583 key_type: key_type.into_partial().into(),
584 value_type: value_type.into_partial().into(),
585 },
586 Self::Byte(a) => PropertyTagDataPartial::Byte(a),
587 Self::Enum(a, b) => PropertyTagDataPartial::Enum(a, b),
588 Self::Bool(_) => PropertyTagDataPartial::Other(PropertyType::BoolProperty),
589 Self::Other(t) => PropertyTagDataPartial::Other(t),
590 }
591 }
592}
593impl PropertyTagDataPartial {
594 fn into_full(self, prop: &Property) -> PropertyTagDataFull {
595 match self {
596 Self::Array(inner) => PropertyTagDataFull::Array(inner.into_full(prop).into()),
597 Self::Struct { struct_type, id } => PropertyTagDataFull::Struct { struct_type, id },
598 Self::Set { key_type } => PropertyTagDataFull::Set {
599 key_type: key_type.into_full(prop).into(),
600 },
601 Self::Map {
602 key_type,
603 value_type,
604 } => PropertyTagDataFull::Map {
605 key_type: key_type.into_full(prop).into(),
606 value_type: value_type.into_full(prop).into(),
607 },
608 Self::Byte(a) => PropertyTagDataFull::Byte(a),
609 Self::Enum(a, b) => PropertyTagDataFull::Enum(a, b),
610 Self::Other(PropertyType::BoolProperty) => {
611 PropertyTagDataFull::Bool(match prop.inner {
612 PropertyInner::Bool(value) => value,
613 _ => false,
614 })
615 }
616 Self::Other(t) => PropertyTagDataFull::Other(t),
617 }
618 }
619}
620
621impl PropertyTagDataFull {
622 fn basic_type(&self) -> PropertyType {
623 match self {
624 Self::Array(_) => PropertyType::ArrayProperty,
625 Self::Struct { .. } => PropertyType::StructProperty,
626 Self::Set { .. } => PropertyType::SetProperty,
627 Self::Map { .. } => PropertyType::MapProperty,
628 Self::Byte(_) => PropertyType::ByteProperty,
629 Self::Enum(_, _) => PropertyType::EnumProperty,
630 Self::Bool(_) => PropertyType::BoolProperty,
631 Self::Other(property_type) => *property_type,
632 }
633 }
634 fn from_type(inner_type: PropertyType, struct_type: Option<StructType>) -> Self {
635 match inner_type {
636 PropertyType::BoolProperty => Self::Bool(false),
637 PropertyType::ByteProperty => Self::Byte(None),
638 PropertyType::EnumProperty => Self::Enum("".to_string(), None),
639 PropertyType::ArrayProperty => unreachable!("array of array is invalid"),
640 PropertyType::SetProperty => unreachable!("array of set is invalid"),
641 PropertyType::MapProperty => unreachable!("array of map is invalid"),
642 PropertyType::StructProperty => Self::Struct {
643 struct_type: struct_type.unwrap_or(StructType::Struct(None)),
644 id: Default::default(),
645 },
646 other => Self::Other(other),
647 }
648 }
649}
650bitflags::bitflags! {
651 #[derive(Debug, Clone, Copy)]
652 struct EPropertyTagFlags : u8 {
653 const None = 0x00;
654 const HasArrayIndex = 0x01;
655 const HasPropertyGuid = 0x02;
656 const HasPropertyExtensions = 0x04;
657 const HasBinaryOrNativeSerialize = 0x08;
658 const BoolTrue = 0x10;
659 }
660}
661impl PropertyTagPartial {
662 fn into_full<'a>(
663 self,
664 name: &'a str,
665 size: u32,
666 index: u32,
667 prop: &Property,
668 ) -> PropertyTagFull<'a> {
669 PropertyTagFull {
670 name: name.into(),
671 id: self.id,
672 size,
673 index,
674 data: self.data.into_full(prop),
675 }
676 }
677}
678impl PropertyTagFull<'_> {
679 fn into_full(self) -> PropertyTagPartial {
680 PropertyTagPartial {
681 id: self.id,
682 data: self.data.into_partial(),
683 }
684 }
685 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Option<Self>> {
686 let name = read_string(reader)?;
687 if name == "None" {
688 return Ok(None);
689 }
690 if reader.version().property_tag() {
691 let data = read_type(reader)?;
692
693 let mut tag = Self {
694 name: name.into(),
695 size: 0,
696 index: 0,
697 id: None,
698 data,
699 };
700
701 #[derive(Default, Debug)]
702 struct Node {
703 name: String,
704 inner_count: u32,
705 }
706 fn read_node<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Node> {
707 Ok(Node {
708 name: read_string(reader)?,
709 inner_count: reader.read_u32::<LE>()?,
710 })
711 }
712 fn read_path<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<String> {
713 let name = read_node(reader)?;
714 assert_eq!(1, name.inner_count);
715 let package = read_node(reader)?;
716 assert_eq!(0, package.inner_count);
717 Ok(format!("{}.{}", package.name, name.name))
718 }
719 fn read_type<R: Read + Seek, V>(
720 reader: &mut Context<R, V>,
721 ) -> TResult<PropertyTagDataFull> {
722 let node = read_node(reader)?;
723 Ok(match node.name.as_str() {
724 "ArrayProperty" => PropertyTagDataFull::Array(read_type(reader)?.into()),
725 "StructProperty" => {
726 let struct_type = StructType::from_full(&read_path(reader)?);
727 let id = match node.inner_count {
728 1 => Default::default(),
729 2 => uuid::Uuid::parse_str(&read_node(reader)?.name)?,
730 _ => unimplemented!(),
731 };
732 PropertyTagDataFull::Struct { struct_type, id }
733 }
734 "SetProperty" => PropertyTagDataFull::Set {
735 key_type: read_type(reader)?.into(),
736 },
737 "MapProperty" => PropertyTagDataFull::Map {
738 key_type: read_type(reader)?.into(),
739 value_type: read_type(reader)?.into(),
740 },
741 "ByteProperty" => {
742 let inner = match node.inner_count {
743 0 => None,
744 1 => Some(read_path(reader)?),
745 _ => unimplemented!(),
746 };
747 PropertyTagDataFull::Byte(inner)
748 }
749 "EnumProperty" => {
750 assert_eq!(2, node.inner_count);
751 let inner = read_path(reader)?;
752 let container = read_node(reader)?;
753 assert_eq!(0, container.inner_count);
754 PropertyTagDataFull::Enum(inner, Some(container.name.to_owned()))
755 }
756 "BoolProperty" => PropertyTagDataFull::Bool(false),
757 other => {
758 assert_eq!(0, node.inner_count);
759 PropertyTagDataFull::Other(PropertyType::try_from(other)?)
760 }
761 })
762 }
763
764 tag.size = reader.read_u32::<LE>()?;
765
766 let flags = EPropertyTagFlags::from_bits(reader.read_u8()?)
767 .ok_or_else(|| error::Error::Other("unknown EPropertyTagFlags bits".into()))?;
768
769 if flags.contains(EPropertyTagFlags::BoolTrue) {
770 if let PropertyTagDataFull::Bool(value) = &mut tag.data {
771 *value = true
772 }
773 }
774 if flags.contains(EPropertyTagFlags::HasArrayIndex) {
775 tag.index = reader.read_u32::<LE>()?;
776 }
777 if flags.contains(EPropertyTagFlags::HasPropertyGuid) {
778 tag.id = Some(uuid::Uuid::read(reader)?);
779 }
780 if flags.contains(EPropertyTagFlags::HasPropertyExtensions) {
781 unimplemented!();
782 }
783
784 Ok(Some(tag))
785 } else {
786 reader.with_scope(&name.clone(), |reader| {
787 let type_ = PropertyType::read(reader)?;
788 let size = reader.read_u32::<LE>()?;
789 let index = reader.read_u32::<LE>()?;
790 let data = match type_ {
791 PropertyType::BoolProperty => {
792 let value = reader.read_u8()? > 0;
793 PropertyTagDataFull::Bool(value)
794 }
795 PropertyType::IntProperty
796 | PropertyType::Int8Property
797 | PropertyType::Int16Property
798 | PropertyType::Int64Property
799 | PropertyType::UInt8Property
800 | PropertyType::UInt16Property
801 | PropertyType::UInt32Property
802 | PropertyType::UInt64Property
803 | PropertyType::FloatProperty
804 | PropertyType::DoubleProperty
805 | PropertyType::StrProperty
806 | PropertyType::ObjectProperty
807 | PropertyType::FieldPathProperty
808 | PropertyType::SoftObjectProperty
809 | PropertyType::NameProperty
810 | PropertyType::TextProperty
811 | PropertyType::DelegateProperty
812 | PropertyType::MulticastDelegateProperty
813 | PropertyType::MulticastInlineDelegateProperty
814 | PropertyType::MulticastSparseDelegateProperty => {
815 PropertyTagDataFull::Other(type_)
816 }
817 PropertyType::ByteProperty => {
818 let enum_type = read_string(reader)?;
819 PropertyTagDataFull::Byte((enum_type != "None").then_some(enum_type))
820 }
821 PropertyType::EnumProperty => {
822 let enum_type = read_string(reader)?;
823 PropertyTagDataFull::Enum(enum_type, None)
824 }
825 PropertyType::ArrayProperty => {
826 let inner_type = PropertyType::read(reader)?;
827
828 PropertyTagDataFull::Array(std::boxed::Box::new(
829 PropertyTagDataFull::from_type(inner_type, None),
830 ))
831 }
832 PropertyType::SetProperty => {
833 let key_type = PropertyType::read(reader)?;
834 let key_struct_type = match key_type {
835 PropertyType::StructProperty => {
836 Some(reader.get_type_or(&StructType::Guid)?.clone())
837 }
838 _ => None,
839 };
840
841 let key_type =
842 PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
843 .into();
844
845 PropertyTagDataFull::Set { key_type }
846 }
847 PropertyType::MapProperty => {
848 let key_type = PropertyType::read(reader)?;
849 let key_struct_type = match key_type {
850 PropertyType::StructProperty => Some(
851 reader
852 .with_scope("Key", |r| r.get_type_or(&StructType::Guid))?
853 .clone(),
854 ),
855 _ => None,
856 };
857 let value_type = PropertyType::read(reader)?;
858 let value_struct_type = match value_type {
859 PropertyType::StructProperty => Some(
860 reader
861 .with_scope("Value", |r| {
862 r.get_type_or(&StructType::Struct(None))
863 })?
864 .clone(),
865 ),
866 _ => None,
867 };
868
869 let key_type =
870 PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
871 .into();
872 let value_type =
873 PropertyTagDataFull::from_type(value_type, value_struct_type.clone())
874 .into();
875
876 PropertyTagDataFull::Map {
877 key_type,
878 value_type,
879 }
880 }
881 PropertyType::StructProperty => {
882 let struct_type = StructType::read(reader)?;
883 let struct_id = uuid::Uuid::read(reader)?;
884 PropertyTagDataFull::Struct {
885 struct_type,
886 id: struct_id,
887 }
888 }
889 };
890 let id = if reader.version().property_guid() {
891 read_optional_uuid(reader)?
892 } else {
893 None
894 };
895 Ok(Some(Self {
896 name: name.into(),
897 size,
898 index,
899 id,
900 data,
901 }))
902 })
903 }
904 }
905 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
906 write_string(writer, &self.name)?;
907
908 if writer.version().property_tag() {
909 fn write_node<W: Write, V>(
910 writer: &mut Context<W, V>,
911 name: &str,
912 inner_count: u32,
913 ) -> TResult<()> {
914 write_string(writer, name)?;
915 writer.write_u32::<LE>(inner_count)?;
916 Ok(())
917 }
918 fn write_full_type<W: Write, V>(
919 writer: &mut Context<W, V>,
920 full_type: &str,
921 ) -> TResult<()> {
922 let (a, b) = full_type.split_once('.').unwrap(); write_node(writer, b, 1)?;
924 write_node(writer, a, 0)?;
925 Ok(())
926 }
927 fn write_nodes<W: Write, V>(
928 writer: &mut Context<W, V>,
929 flags: &mut EPropertyTagFlags,
930 data: &PropertyTagDataFull,
931 ) -> TResult<()> {
932 match data {
933 PropertyTagDataFull::Array(inner) => {
934 write_node(writer, "ArrayProperty", 1)?;
935 write_nodes(writer, flags, inner)?;
936 }
937 PropertyTagDataFull::Struct { struct_type, id } => {
938 write_node(writer, "StructProperty", if id.is_nil() { 1 } else { 2 })?;
939 match struct_type {
940 StructType::Struct(Some(_)) => {}
941 _ => *flags |= EPropertyTagFlags::HasBinaryOrNativeSerialize,
942 }
943 write_full_type(writer, struct_type.full_str())?;
944
945 if !id.is_nil() {
946 write_node(writer, &id.to_string(), 0)?;
947 }
948 }
949 PropertyTagDataFull::Set { key_type } => {
950 write_node(writer, "SetProperty", 1)?;
951 write_nodes(writer, flags, key_type)?;
952 }
953 PropertyTagDataFull::Map {
954 key_type,
955 value_type,
956 } => {
957 write_node(writer, "MapProperty", 2)?;
958 write_nodes(writer, flags, key_type)?;
959 write_nodes(writer, flags, value_type)?;
960 }
961 PropertyTagDataFull::Byte(enum_type) => {
962 write_node(
963 writer,
964 "ByteProperty",
965 if enum_type.is_some() { 1 } else { 0 },
966 )?;
967 if let Some(enum_type) = enum_type {
968 write_full_type(writer, enum_type)?;
969 }
970 }
971 PropertyTagDataFull::Enum(enum_type, container) => {
972 write_node(writer, "EnumProperty", 2)?;
973 write_full_type(writer, enum_type)?;
974 write_node(writer, container.as_ref().unwrap(), 0)?;
975 }
976 PropertyTagDataFull::Bool(value) => {
977 if *value {
978 *flags |= EPropertyTagFlags::BoolTrue;
979 }
980 write_node(writer, "BoolProperty", 0)?;
981 }
982 PropertyTagDataFull::Other(property_type) => {
983 write_node(writer, property_type.get_name(), 0)?;
984 }
985 }
986 Ok(())
987 }
988
989 let mut flags = EPropertyTagFlags::empty();
990 write_nodes(writer, &mut flags, &self.data)?;
991
992 writer.write_u32::<LE>(self.size)?;
993
994 if self.id.is_some() {
995 flags |= EPropertyTagFlags::HasPropertyGuid;
996 }
997
998 writer.write_u8(flags.bits())?;
999 } else {
1000 self.data.basic_type().write(writer)?;
1001 writer.write_u32::<LE>(self.size)?;
1002 writer.write_u32::<LE>(self.index)?;
1003 match &self.data {
1004 PropertyTagDataFull::Array(inner_type) => {
1005 inner_type.basic_type().write(writer)?;
1006 }
1007 PropertyTagDataFull::Struct { struct_type, id } => {
1008 struct_type.write(writer)?;
1009 id.write(writer)?;
1010 }
1011 PropertyTagDataFull::Set { key_type, .. } => {
1012 key_type.basic_type().write(writer)?;
1013 }
1014 PropertyTagDataFull::Map {
1015 key_type,
1016 value_type,
1017 ..
1018 } => {
1019 key_type.basic_type().write(writer)?;
1020 value_type.basic_type().write(writer)?;
1021 }
1022 PropertyTagDataFull::Byte(enum_type) => {
1023 write_string(writer, enum_type.as_deref().unwrap_or("None"))?;
1024 }
1025 PropertyTagDataFull::Enum(enum_type, _) => {
1026 write_string(writer, enum_type)?;
1027 }
1028 PropertyTagDataFull::Bool(value) => {
1029 writer.write_u8(*value as u8)?;
1030 }
1031 PropertyTagDataFull::Other(_) => {}
1032 }
1033 if writer.version().property_guid() {
1034 write_optional_uuid(writer, self.id)?;
1035 }
1036 }
1037 Ok(())
1038 }
1039}
1040
1041#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1042pub enum PropertyType {
1043 IntProperty,
1044 Int8Property,
1045 Int16Property,
1046 Int64Property,
1047 UInt8Property,
1048 UInt16Property,
1049 UInt32Property,
1050 UInt64Property,
1051 FloatProperty,
1052 DoubleProperty,
1053 BoolProperty,
1054 ByteProperty,
1055 EnumProperty,
1056 ArrayProperty,
1057 ObjectProperty,
1058 StrProperty,
1059 FieldPathProperty,
1060 SoftObjectProperty,
1061 NameProperty,
1062 TextProperty,
1063 DelegateProperty,
1064 MulticastDelegateProperty,
1065 MulticastInlineDelegateProperty,
1066 MulticastSparseDelegateProperty,
1067 SetProperty,
1068 MapProperty,
1069 StructProperty,
1070}
1071impl PropertyType {
1072 fn get_name(&self) -> &str {
1073 match &self {
1074 PropertyType::Int8Property => "Int8Property",
1075 PropertyType::Int16Property => "Int16Property",
1076 PropertyType::IntProperty => "IntProperty",
1077 PropertyType::Int64Property => "Int64Property",
1078 PropertyType::UInt8Property => "UInt8Property",
1079 PropertyType::UInt16Property => "UInt16Property",
1080 PropertyType::UInt32Property => "UInt32Property",
1081 PropertyType::UInt64Property => "UInt64Property",
1082 PropertyType::FloatProperty => "FloatProperty",
1083 PropertyType::DoubleProperty => "DoubleProperty",
1084 PropertyType::BoolProperty => "BoolProperty",
1085 PropertyType::ByteProperty => "ByteProperty",
1086 PropertyType::EnumProperty => "EnumProperty",
1087 PropertyType::ArrayProperty => "ArrayProperty",
1088 PropertyType::ObjectProperty => "ObjectProperty",
1089 PropertyType::StrProperty => "StrProperty",
1090 PropertyType::FieldPathProperty => "FieldPathProperty",
1091 PropertyType::SoftObjectProperty => "SoftObjectProperty",
1092 PropertyType::NameProperty => "NameProperty",
1093 PropertyType::TextProperty => "TextProperty",
1094 PropertyType::DelegateProperty => "DelegateProperty",
1095 PropertyType::MulticastDelegateProperty => "MulticastDelegateProperty",
1096 PropertyType::MulticastInlineDelegateProperty => "MulticastInlineDelegateProperty",
1097 PropertyType::MulticastSparseDelegateProperty => "MulticastSparseDelegateProperty",
1098 PropertyType::SetProperty => "SetProperty",
1099 PropertyType::MapProperty => "MapProperty",
1100 PropertyType::StructProperty => "StructProperty",
1101 }
1102 }
1103 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1104 Self::try_from(&read_string(reader)?)
1105 }
1106 fn try_from(name: &str) -> TResult<Self> {
1107 match name {
1108 "Int8Property" => Ok(PropertyType::Int8Property),
1109 "Int16Property" => Ok(PropertyType::Int16Property),
1110 "IntProperty" => Ok(PropertyType::IntProperty),
1111 "Int64Property" => Ok(PropertyType::Int64Property),
1112 "UInt8Property" => Ok(PropertyType::UInt8Property),
1113 "UInt16Property" => Ok(PropertyType::UInt16Property),
1114 "UInt32Property" => Ok(PropertyType::UInt32Property),
1115 "UInt64Property" => Ok(PropertyType::UInt64Property),
1116 "FloatProperty" => Ok(PropertyType::FloatProperty),
1117 "DoubleProperty" => Ok(PropertyType::DoubleProperty),
1118 "BoolProperty" => Ok(PropertyType::BoolProperty),
1119 "ByteProperty" => Ok(PropertyType::ByteProperty),
1120 "EnumProperty" => Ok(PropertyType::EnumProperty),
1121 "ArrayProperty" => Ok(PropertyType::ArrayProperty),
1122 "ObjectProperty" => Ok(PropertyType::ObjectProperty),
1123 "StrProperty" => Ok(PropertyType::StrProperty),
1124 "FieldPathProperty" => Ok(PropertyType::FieldPathProperty),
1125 "SoftObjectProperty" => Ok(PropertyType::SoftObjectProperty),
1126 "NameProperty" => Ok(PropertyType::NameProperty),
1127 "TextProperty" => Ok(PropertyType::TextProperty),
1128 "DelegateProperty" => Ok(PropertyType::DelegateProperty),
1129 "MulticastDelegateProperty" => Ok(PropertyType::MulticastDelegateProperty),
1130 "MulticastInlineDelegateProperty" => Ok(PropertyType::MulticastInlineDelegateProperty),
1131 "MulticastSparseDelegateProperty" => Ok(PropertyType::MulticastSparseDelegateProperty),
1132 "SetProperty" => Ok(PropertyType::SetProperty),
1133 "MapProperty" => Ok(PropertyType::MapProperty),
1134 "StructProperty" => Ok(PropertyType::StructProperty),
1135 _ => Err(Error::UnknownPropertyType(format!("{name:?}"))),
1136 }
1137 }
1138 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1139 write_string(writer, self.get_name())?;
1140 Ok(())
1141 }
1142}
1143
1144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1145pub enum StructType {
1146 Guid,
1147 DateTime,
1148 Timespan,
1149 Vector2D,
1150 Vector,
1151 IntVector,
1152 Box,
1153 IntPoint,
1154 Quat,
1155 Rotator,
1156 LinearColor,
1157 Color,
1158 SoftObjectPath,
1159 GameplayTagContainer,
1160 UniqueNetIdRepl,
1161 Struct(Option<String>),
1162}
1163impl From<&str> for StructType {
1164 fn from(t: &str) -> Self {
1165 match t {
1166 "Guid" => StructType::Guid,
1167 "DateTime" => StructType::DateTime,
1168 "Timespan" => StructType::Timespan,
1169 "Vector2D" => StructType::Vector2D,
1170 "Vector" => StructType::Vector,
1171 "IntVector" => StructType::IntVector,
1172 "Box" => StructType::Box,
1173 "IntPoint" => StructType::IntPoint,
1174 "Quat" => StructType::Quat,
1175 "Rotator" => StructType::Rotator,
1176 "LinearColor" => StructType::LinearColor,
1177 "Color" => StructType::Color,
1178 "SoftObjectPath" => StructType::SoftObjectPath,
1179 "GameplayTagContainer" => StructType::GameplayTagContainer,
1180 "UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1181 "Struct" => StructType::Struct(None),
1182 _ => StructType::Struct(Some(t.to_owned())),
1183 }
1184 }
1185}
1186impl From<String> for StructType {
1187 fn from(t: String) -> Self {
1188 match t.as_str() {
1189 "Guid" => StructType::Guid,
1190 "DateTime" => StructType::DateTime,
1191 "Timespan" => StructType::Timespan,
1192 "Vector2D" => StructType::Vector2D,
1193 "Vector" => StructType::Vector,
1194 "IntVector" => StructType::IntVector,
1195 "Box" => StructType::Box,
1196 "IntPoint" => StructType::IntPoint,
1197 "Quat" => StructType::Quat,
1198 "Rotator" => StructType::Rotator,
1199 "LinearColor" => StructType::LinearColor,
1200 "Color" => StructType::Color,
1201 "SoftObjectPath" => StructType::SoftObjectPath,
1202 "GameplayTagContainer" => StructType::GameplayTagContainer,
1203 "UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1204 "Struct" => StructType::Struct(None),
1205 _ => StructType::Struct(Some(t)),
1206 }
1207 }
1208}
1209impl StructType {
1210 fn from_full(t: &str) -> Self {
1211 match t {
1212 "/Script/CoreUObject.Guid" => StructType::Guid,
1213 "/Script/CoreUObject.DateTime" => StructType::DateTime,
1214 "/Script/CoreUObject.Timespan" => StructType::Timespan,
1215 "/Script/CureUObject.Vector2D" => StructType::Vector2D,
1216 "/Script/CoreUObject.Vector" => StructType::Vector,
1217 "/Script/CureUObject.IntVector" => StructType::IntVector,
1218 "/Script/CoreUObject.Box" => StructType::Box,
1219 "/Script/CoreUObject.IntPoint" => StructType::IntPoint,
1220 "/Script/CoreUObject.Quat" => StructType::Quat,
1221 "/Script/CoreUObject.Rotator" => StructType::Rotator,
1222 "/Script/CoreUObject.LinearColor" => StructType::LinearColor,
1223 "/Script/CoreUObject.Color" => StructType::Color,
1224 "/Script/CoreUObject.SoftObjectPath" => StructType::SoftObjectPath,
1225 "/Script/GameplayTags.GameplayTagContainer" => StructType::GameplayTagContainer,
1226 "/Script/Engine.UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1227 "/Script/CoreUObject.Struct" => StructType::Struct(None),
1228 _ => StructType::Struct(Some(t.to_owned())),
1229 }
1230 }
1231 fn full_str(&self) -> &str {
1232 match self {
1233 StructType::Guid => "/Script/CoreUObject.Guid",
1234 StructType::DateTime => "/Script/CoreUObject.DateTime",
1235 StructType::Timespan => "/Script/CoreUObject.Timespan",
1236 StructType::Vector2D => "/Script/CoreUObject.Vector2D",
1237 StructType::Vector => "/Script/CoreUObject.Vector",
1238 StructType::IntVector => "/Script/CoreUObject.IntVector",
1239 StructType::Box => "/Script/CoreUObject.Box",
1240 StructType::IntPoint => "/Script/CoreUObject.IntPoint",
1241 StructType::Quat => "/Script/CoreUObject.Quat",
1242 StructType::Rotator => "/Script/CoreUObject.Rotator",
1243 StructType::LinearColor => "/Script/CoreUObject.LinearColor",
1244 StructType::Color => "/Script/CoreUObject.Color",
1245 StructType::SoftObjectPath => "/Script/CoreUObject.SoftObjectPath",
1246 StructType::GameplayTagContainer => "/Script/GameplayTags.GameplayTagContainer",
1247 StructType::UniqueNetIdRepl => "/Script/Engine.UniqueNetIdRepl",
1248 StructType::Struct(Some(t)) => t,
1249 _ => unreachable!(),
1250 }
1251 }
1252 fn as_str(&self) -> &str {
1253 match self {
1254 StructType::Guid => "Guid",
1255 StructType::DateTime => "DateTime",
1256 StructType::Timespan => "Timespan",
1257 StructType::Vector2D => "Vector2D",
1258 StructType::Vector => "Vector",
1259 StructType::IntVector => "IntVector",
1260 StructType::Box => "Box",
1261 StructType::IntPoint => "IntPoint",
1262 StructType::Quat => "Quat",
1263 StructType::Rotator => "Rotator",
1264 StructType::LinearColor => "LinearColor",
1265 StructType::Color => "Color",
1266 StructType::SoftObjectPath => "SoftObjectPath",
1267 StructType::GameplayTagContainer => "GameplayTagContainer",
1268 StructType::UniqueNetIdRepl => "UniqueNetIdRepl",
1269 StructType::Struct(Some(t)) => t,
1270 _ => unreachable!(),
1271 }
1272 }
1273 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1274 Ok(read_string(reader)?.into())
1275 }
1276 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1277 write_string(writer, self.as_str())?;
1278 Ok(())
1279 }
1280}
1281
1282type DateTime = u64;
1283type Timespan = i64;
1284type Int8 = i8;
1285type Int16 = i16;
1286type Int = i32;
1287type Int64 = i64;
1288type UInt8 = u8;
1289type UInt16 = u16;
1290type UInt32 = u32;
1291type UInt64 = u64;
1292type Float = f32;
1293type Double = f64;
1294type Bool = bool;
1295type Enum = String;
1296
1297#[derive(Debug, PartialEq, Serialize, Deserialize)]
1298pub struct MapEntry {
1299 pub key: PropertyValue,
1300 pub value: PropertyValue,
1301}
1302impl MapEntry {
1303 fn read<R: Read + Seek, V: VersionInfo>(
1304 reader: &mut Context<R, V>,
1305 key_type: &PropertyTagDataFull,
1306 value_type: &PropertyTagDataFull,
1307 ) -> TResult<MapEntry> {
1308 let key = PropertyValue::read(reader, key_type)?;
1309 let value = PropertyValue::read(reader, value_type)?;
1310 Ok(Self { key, value })
1311 }
1312 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1313 self.key.write(writer)?;
1314 self.value.write(writer)?;
1315 Ok(())
1316 }
1317}
1318
1319#[derive(Debug, PartialEq, Serialize, Deserialize)]
1320pub struct FieldPath {
1321 path: Vec<String>,
1322 owner: String,
1323}
1324impl FieldPath {
1325 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1326 Ok(Self {
1327 path: read_array(reader.read_u32::<LE>()?, reader, read_string)?,
1328 owner: read_string(reader)?,
1329 })
1330 }
1331 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1332 writer.write_u32::<LE>(self.path.len() as u32)?;
1333 for p in &self.path {
1334 write_string(writer, p)?;
1335 }
1336 write_string(writer, &self.owner)?;
1337 Ok(())
1338 }
1339}
1340
1341#[derive(Debug, PartialEq, Serialize, Deserialize)]
1342pub struct Delegate {
1343 name: String,
1344 path: String,
1345}
1346impl Delegate {
1347 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1348 Ok(Self {
1349 name: read_string(reader)?,
1350 path: read_string(reader)?,
1351 })
1352 }
1353 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1354 write_string(writer, &self.name)?;
1355 write_string(writer, &self.path)?;
1356 Ok(())
1357 }
1358}
1359
1360#[derive(Debug, PartialEq, Serialize, Deserialize)]
1361pub struct MulticastDelegate(Vec<Delegate>);
1362impl MulticastDelegate {
1363 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1364 Ok(Self(read_array(
1365 reader.read_u32::<LE>()?,
1366 reader,
1367 Delegate::read,
1368 )?))
1369 }
1370 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1371 writer.write_u32::<LE>(self.0.len() as u32)?;
1372 for entry in &self.0 {
1373 entry.write(writer)?;
1374 }
1375 Ok(())
1376 }
1377}
1378
1379#[derive(Debug, PartialEq, Serialize, Deserialize)]
1380pub struct MulticastInlineDelegate(Vec<Delegate>);
1381impl MulticastInlineDelegate {
1382 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1383 Ok(Self(read_array(
1384 reader.read_u32::<LE>()?,
1385 reader,
1386 Delegate::read,
1387 )?))
1388 }
1389 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1390 writer.write_u32::<LE>(self.0.len() as u32)?;
1391 for entry in &self.0 {
1392 entry.write(writer)?;
1393 }
1394 Ok(())
1395 }
1396}
1397
1398#[derive(Debug, PartialEq, Serialize, Deserialize)]
1399pub struct MulticastSparseDelegate(Vec<Delegate>);
1400impl MulticastSparseDelegate {
1401 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1402 Ok(Self(read_array(
1403 reader.read_u32::<LE>()?,
1404 reader,
1405 Delegate::read,
1406 )?))
1407 }
1408 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1409 writer.write_u32::<LE>(self.0.len() as u32)?;
1410 for entry in &self.0 {
1411 entry.write(writer)?;
1412 }
1413 Ok(())
1414 }
1415}
1416
1417#[derive(Debug, PartialEq, Serialize, Deserialize)]
1418pub struct LinearColor {
1419 pub r: f32,
1420 pub g: f32,
1421 pub b: f32,
1422 pub a: f32,
1423}
1424impl LinearColor {
1425 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1426 Ok(Self {
1427 r: reader.read_f32::<LE>()?,
1428 g: reader.read_f32::<LE>()?,
1429 b: reader.read_f32::<LE>()?,
1430 a: reader.read_f32::<LE>()?,
1431 })
1432 }
1433 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1434 writer.write_f32::<LE>(self.r)?;
1435 writer.write_f32::<LE>(self.g)?;
1436 writer.write_f32::<LE>(self.b)?;
1437 writer.write_f32::<LE>(self.a)?;
1438 Ok(())
1439 }
1440}
1441#[derive(Debug, PartialEq, Serialize, Deserialize)]
1442pub struct Quat {
1443 pub x: f64,
1444 pub y: f64,
1445 pub z: f64,
1446 pub w: f64,
1447}
1448impl Quat {
1449 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1450 if reader.version().large_world_coordinates() {
1451 Ok(Self {
1452 x: reader.read_f64::<LE>()?,
1453 y: reader.read_f64::<LE>()?,
1454 z: reader.read_f64::<LE>()?,
1455 w: reader.read_f64::<LE>()?,
1456 })
1457 } else {
1458 Ok(Self {
1459 x: reader.read_f32::<LE>()? as f64,
1460 y: reader.read_f32::<LE>()? as f64,
1461 z: reader.read_f32::<LE>()? as f64,
1462 w: reader.read_f32::<LE>()? as f64,
1463 })
1464 }
1465 }
1466 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1467 if writer.version().large_world_coordinates() {
1468 writer.write_f64::<LE>(self.x)?;
1469 writer.write_f64::<LE>(self.y)?;
1470 writer.write_f64::<LE>(self.z)?;
1471 writer.write_f64::<LE>(self.w)?;
1472 } else {
1473 writer.write_f32::<LE>(self.x as f32)?;
1474 writer.write_f32::<LE>(self.y as f32)?;
1475 writer.write_f32::<LE>(self.z as f32)?;
1476 writer.write_f32::<LE>(self.w as f32)?;
1477 }
1478 Ok(())
1479 }
1480}
1481#[derive(Debug, PartialEq, Serialize, Deserialize)]
1482pub struct Rotator {
1483 pub x: f64,
1484 pub y: f64,
1485 pub z: f64,
1486}
1487impl Rotator {
1488 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1489 if reader.version().large_world_coordinates() {
1490 Ok(Self {
1491 x: reader.read_f64::<LE>()?,
1492 y: reader.read_f64::<LE>()?,
1493 z: reader.read_f64::<LE>()?,
1494 })
1495 } else {
1496 Ok(Self {
1497 x: reader.read_f32::<LE>()? as f64,
1498 y: reader.read_f32::<LE>()? as f64,
1499 z: reader.read_f32::<LE>()? as f64,
1500 })
1501 }
1502 }
1503 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1504 if writer.version().large_world_coordinates() {
1505 writer.write_f64::<LE>(self.x)?;
1506 writer.write_f64::<LE>(self.y)?;
1507 writer.write_f64::<LE>(self.z)?;
1508 } else {
1509 writer.write_f32::<LE>(self.x as f32)?;
1510 writer.write_f32::<LE>(self.y as f32)?;
1511 writer.write_f32::<LE>(self.z as f32)?;
1512 }
1513 Ok(())
1514 }
1515}
1516#[derive(Debug, PartialEq, Serialize, Deserialize)]
1517pub struct Color {
1518 pub r: u8,
1519 pub g: u8,
1520 pub b: u8,
1521 pub a: u8,
1522}
1523impl Color {
1524 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1525 Ok(Self {
1526 r: reader.read_u8()?,
1527 g: reader.read_u8()?,
1528 b: reader.read_u8()?,
1529 a: reader.read_u8()?,
1530 })
1531 }
1532 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1533 writer.write_u8(self.r)?;
1534 writer.write_u8(self.g)?;
1535 writer.write_u8(self.b)?;
1536 writer.write_u8(self.a)?;
1537 Ok(())
1538 }
1539}
1540#[derive(Debug, PartialEq, Serialize, Deserialize)]
1541pub struct Vector {
1542 pub x: f64,
1543 pub y: f64,
1544 pub z: f64,
1545}
1546impl Vector {
1547 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1548 if reader.version().large_world_coordinates() {
1549 Ok(Self {
1550 x: reader.read_f64::<LE>()?,
1551 y: reader.read_f64::<LE>()?,
1552 z: reader.read_f64::<LE>()?,
1553 })
1554 } else {
1555 Ok(Self {
1556 x: reader.read_f32::<LE>()? as f64,
1557 y: reader.read_f32::<LE>()? as f64,
1558 z: reader.read_f32::<LE>()? as f64,
1559 })
1560 }
1561 }
1562 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1563 if writer.version().large_world_coordinates() {
1564 writer.write_f64::<LE>(self.x)?;
1565 writer.write_f64::<LE>(self.y)?;
1566 writer.write_f64::<LE>(self.z)?;
1567 } else {
1568 writer.write_f32::<LE>(self.x as f32)?;
1569 writer.write_f32::<LE>(self.y as f32)?;
1570 writer.write_f32::<LE>(self.z as f32)?;
1571 }
1572 Ok(())
1573 }
1574}
1575#[derive(Debug, PartialEq, Serialize, Deserialize)]
1576pub struct Vector2D {
1577 pub x: f64,
1578 pub y: f64,
1579}
1580impl Vector2D {
1581 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1582 if reader.version().large_world_coordinates() {
1583 Ok(Self {
1584 x: reader.read_f64::<LE>()?,
1585 y: reader.read_f64::<LE>()?,
1586 })
1587 } else {
1588 Ok(Self {
1589 x: reader.read_f32::<LE>()? as f64,
1590 y: reader.read_f32::<LE>()? as f64,
1591 })
1592 }
1593 }
1594 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1595 if writer.version().large_world_coordinates() {
1596 writer.write_f64::<LE>(self.x)?;
1597 writer.write_f64::<LE>(self.y)?;
1598 } else {
1599 writer.write_f32::<LE>(self.x as f32)?;
1600 writer.write_f32::<LE>(self.y as f32)?;
1601 }
1602 Ok(())
1603 }
1604}
1605#[derive(Debug, PartialEq, Serialize, Deserialize)]
1606pub struct IntVector {
1607 pub x: i32,
1608 pub y: i32,
1609 pub z: i32,
1610}
1611impl IntVector {
1612 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1613 Ok(Self {
1614 x: reader.read_i32::<LE>()?,
1615 y: reader.read_i32::<LE>()?,
1616 z: reader.read_i32::<LE>()?,
1617 })
1618 }
1619 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1620 writer.write_i32::<LE>(self.x)?;
1621 writer.write_i32::<LE>(self.y)?;
1622 writer.write_i32::<LE>(self.z)?;
1623 Ok(())
1624 }
1625}
1626#[derive(Debug, PartialEq, Serialize, Deserialize)]
1627pub struct Box {
1628 pub min: Vector,
1629 pub max: Vector,
1630 pub is_valid: bool,
1631}
1632impl Box {
1633 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1634 Ok(Self {
1635 min: Vector::read(reader)?,
1636 max: Vector::read(reader)?,
1637 is_valid: reader.read_u8()? > 0,
1638 })
1639 }
1640 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1641 self.min.write(writer)?;
1642 self.max.write(writer)?;
1643 writer.write_u8(self.is_valid as u8)?;
1644 Ok(())
1645 }
1646}
1647#[derive(Debug, PartialEq, Serialize, Deserialize)]
1648pub struct IntPoint {
1649 pub x: i32,
1650 pub y: i32,
1651}
1652impl IntPoint {
1653 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1654 Ok(Self {
1655 x: reader.read_i32::<LE>()?,
1656 y: reader.read_i32::<LE>()?,
1657 })
1658 }
1659 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1660 writer.write_i32::<LE>(self.x)?;
1661 writer.write_i32::<LE>(self.y)?;
1662 Ok(())
1663 }
1664}
1665
1666#[derive(Debug, PartialEq, Serialize, Deserialize)]
1667pub enum SoftObjectPath {
1668 Old {
1669 asset_path_name: String,
1670 sub_path_string: String,
1671 },
1672 New {
1673 asset_path_name: String,
1674 package_name: String,
1675 asset_name: String,
1676 },
1677}
1678impl SoftObjectPath {
1679 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1680 Ok(if reader.version().remove_asset_path_fnames() {
1681 Self::New {
1682 asset_path_name: read_string(reader)?,
1683 package_name: read_string(reader)?,
1684 asset_name: read_string(reader)?,
1685 }
1686 } else {
1687 Self::Old {
1688 asset_path_name: read_string(reader)?,
1689 sub_path_string: read_string(reader)?,
1690 }
1691 })
1692 }
1693 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1694 match self {
1695 Self::Old {
1696 asset_path_name,
1697 sub_path_string,
1698 } => {
1699 write_string(writer, asset_path_name)?;
1700 write_string(writer, sub_path_string)?;
1701 }
1702 Self::New {
1703 asset_path_name,
1704 package_name,
1705 asset_name,
1706 } => {
1707 write_string(writer, asset_path_name)?;
1708 write_string(writer, package_name)?;
1709 write_string(writer, asset_name)?;
1710 }
1711 }
1712 Ok(())
1713 }
1714}
1715
1716#[derive(Debug, PartialEq, Serialize, Deserialize)]
1717pub struct GameplayTag {
1718 pub name: String,
1719}
1720impl GameplayTag {
1721 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1722 Ok(Self {
1723 name: read_string(reader)?,
1724 })
1725 }
1726 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1727 write_string(writer, &self.name)?;
1728 Ok(())
1729 }
1730}
1731
1732#[derive(Debug, PartialEq, Serialize, Deserialize)]
1733pub struct GameplayTagContainer {
1734 pub gameplay_tags: Vec<GameplayTag>,
1735}
1736impl GameplayTagContainer {
1737 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1738 Ok(Self {
1739 gameplay_tags: read_array(reader.read_u32::<LE>()?, reader, GameplayTag::read)?,
1740 })
1741 }
1742 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1743 writer.write_u32::<LE>(self.gameplay_tags.len() as u32)?;
1744 for entry in &self.gameplay_tags {
1745 entry.write(writer)?;
1746 }
1747 Ok(())
1748 }
1749}
1750
1751#[derive(Debug, PartialEq, Serialize, Deserialize)]
1752pub struct UniqueNetIdRepl {
1753 pub inner: Option<UniqueNetIdReplInner>,
1754}
1755#[derive(Debug, PartialEq, Serialize, Deserialize)]
1756pub struct UniqueNetIdReplInner {
1757 pub size: std::num::NonZeroU32,
1758 pub type_: String,
1759 pub contents: String,
1760}
1761impl UniqueNetIdRepl {
1762 fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1763 let size = reader.read_u32::<LE>()?;
1764 let inner = if let Ok(size) = size.try_into() {
1765 Some(UniqueNetIdReplInner {
1766 size,
1767 type_: read_string(reader)?,
1768 contents: read_string(reader)?,
1769 })
1770 } else {
1771 None
1772 };
1773 Ok(Self { inner })
1774 }
1775 fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1776 match &self.inner {
1777 Some(inner) => {
1778 writer.write_u32::<LE>(inner.size.into())?;
1779 write_string(writer, &inner.type_)?;
1780 write_string(writer, &inner.contents)?;
1781 }
1782 None => writer.write_u32::<LE>(0)?,
1783 }
1784 Ok(())
1785 }
1786}
1787
1788#[derive(Debug, PartialEq, Serialize, Deserialize)]
1789pub struct FFormatArgumentData {
1790 name: String,
1791 value: FFormatArgumentDataValue,
1792}
1793impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentData {
1794 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1795 Ok(Self {
1796 name: read_string(reader)?,
1797 value: FFormatArgumentDataValue::read(reader)?,
1798 })
1799 }
1800}
1801impl<W: Write, V> Writable<W, V> for FFormatArgumentData {
1802 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1803 write_string(writer, &self.name)?;
1804 self.value.write(writer)?;
1805 Ok(())
1806 }
1807}
1808#[derive(Debug, PartialEq, Serialize, Deserialize)]
1811pub enum FFormatArgumentDataValue {
1812 Int(i32),
1813 UInt(u32),
1814 Float(f32),
1815 Double(f64),
1816 Text(std::boxed::Box<Text>),
1817 Gender(u64),
1818}
1819impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentDataValue {
1820 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1821 let type_ = reader.read_u8()?;
1822 match type_ {
1823 0 => Ok(Self::Int(reader.read_i32::<LE>()?)),
1824 1 => Ok(Self::UInt(reader.read_u32::<LE>()?)),
1825 2 => Ok(Self::Float(reader.read_f32::<LE>()?)),
1826 3 => Ok(Self::Double(reader.read_f64::<LE>()?)),
1827 4 => Ok(Self::Text(std::boxed::Box::new(Text::read(reader)?))),
1828 5 => Ok(Self::Gender(reader.read_u64::<LE>()?)),
1829 _ => Err(Error::Other(format!(
1830 "unimplemented variant for FFormatArgumentDataValue 0x{type_:x}"
1831 ))),
1832 }
1833 }
1834}
1835impl<W: Write, V> Writable<W, V> for FFormatArgumentDataValue {
1836 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1837 match self {
1838 Self::Int(value) => {
1839 writer.write_u8(0)?;
1840 writer.write_i32::<LE>(*value)?;
1841 }
1842 Self::UInt(value) => {
1843 writer.write_u8(1)?;
1844 writer.write_u32::<LE>(*value)?;
1845 }
1846 Self::Float(value) => {
1847 writer.write_u8(2)?;
1848 writer.write_f32::<LE>(*value)?;
1849 }
1850 Self::Double(value) => {
1851 writer.write_u8(3)?;
1852 writer.write_f64::<LE>(*value)?;
1853 }
1854 Self::Text(value) => {
1855 writer.write_u8(4)?;
1856 value.write(writer)?;
1857 }
1858 Self::Gender(value) => {
1859 writer.write_u8(5)?;
1860 writer.write_u64::<LE>(*value)?;
1861 }
1862 };
1863 Ok(())
1864 }
1865}
1866
1867#[derive(Debug, PartialEq, Serialize, Deserialize)]
1868pub enum FFormatArgumentValue {
1869 Int(i64),
1870 UInt(u64),
1871 Float(f32),
1872 Double(f64),
1873 Text(std::boxed::Box<Text>),
1874 Gender(u64),
1875}
1876
1877impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentValue {
1878 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1879 let type_ = reader.read_u8()?;
1880 match type_ {
1881 0 => Ok(Self::Int(reader.read_i64::<LE>()?)),
1882 1 => Ok(Self::UInt(reader.read_u64::<LE>()?)),
1883 2 => Ok(Self::Float(reader.read_f32::<LE>()?)),
1884 3 => Ok(Self::Double(reader.read_f64::<LE>()?)),
1885 4 => Ok(Self::Text(std::boxed::Box::new(Text::read(reader)?))),
1886 5 => Ok(Self::Gender(reader.read_u64::<LE>()?)),
1887 _ => Err(Error::Other(format!(
1888 "unimplemented variant for FFormatArgumentValue 0x{type_:x}"
1889 ))),
1890 }
1891 }
1892}
1893impl<W: Write, V> Writable<W, V> for FFormatArgumentValue {
1894 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1895 match self {
1896 Self::Int(value) => {
1897 writer.write_u8(0)?;
1898 writer.write_i64::<LE>(*value)?;
1899 }
1900 Self::UInt(value) => {
1901 writer.write_u8(1)?;
1902 writer.write_u64::<LE>(*value)?;
1903 }
1904 Self::Float(value) => {
1905 writer.write_u8(2)?;
1906 writer.write_f32::<LE>(*value)?;
1907 }
1908 Self::Double(value) => {
1909 writer.write_u8(3)?;
1910 writer.write_f64::<LE>(*value)?;
1911 }
1912 Self::Text(value) => {
1913 writer.write_u8(4)?;
1914 value.write(writer)?;
1915 }
1916 Self::Gender(value) => {
1917 writer.write_u8(5)?;
1918 writer.write_u64::<LE>(*value)?;
1919 }
1920 };
1921 Ok(())
1922 }
1923}
1924
1925#[derive(Debug, PartialEq, Serialize, Deserialize)]
1926pub struct FNumberFormattingOptions {
1927 always_sign: bool,
1928 use_grouping: bool,
1929 rounding_mode: i8, minimum_integral_digits: i32,
1931 maximum_integral_digits: i32,
1932 minimum_fractional_digits: i32,
1933 maximum_fractional_digits: i32,
1934}
1935impl<R: Read + Seek, V> Readable<R, V> for FNumberFormattingOptions {
1936 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1937 Ok(Self {
1938 always_sign: reader.read_u32::<LE>()? != 0,
1939 use_grouping: reader.read_u32::<LE>()? != 0,
1940 rounding_mode: reader.read_i8()?,
1941 minimum_integral_digits: reader.read_i32::<LE>()?,
1942 maximum_integral_digits: reader.read_i32::<LE>()?,
1943 minimum_fractional_digits: reader.read_i32::<LE>()?,
1944 maximum_fractional_digits: reader.read_i32::<LE>()?,
1945 })
1946 }
1947}
1948impl<W: Write, V> Writable<W, V> for FNumberFormattingOptions {
1949 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1950 writer.write_u32::<LE>(self.always_sign as u32)?;
1951 writer.write_u32::<LE>(self.use_grouping as u32)?;
1952 writer.write_i8(self.rounding_mode)?;
1953 writer.write_i32::<LE>(self.minimum_integral_digits)?;
1954 writer.write_i32::<LE>(self.maximum_integral_digits)?;
1955 writer.write_i32::<LE>(self.minimum_fractional_digits)?;
1956 writer.write_i32::<LE>(self.maximum_fractional_digits)?;
1957 Ok(())
1958 }
1959}
1960
1961#[derive(Debug, PartialEq, Serialize, Deserialize)]
1962pub struct Text {
1963 flags: u32,
1964 variant: TextVariant,
1965}
1966#[derive(Debug, PartialEq, Serialize, Deserialize)]
1967pub enum TextVariant {
1968 None {
1970 culture_invariant: Option<String>,
1971 },
1972 Base {
1974 namespace: (String, Vec<u8>),
1975 key: String,
1976 source_string: String,
1977 },
1978 ArgumentFormat {
1980 format_text: std::boxed::Box<Text>,
1982 arguments: Vec<FFormatArgumentData>,
1983 },
1984 AsNumber {
1986 source_value: FFormatArgumentValue,
1987 format_options: Option<FNumberFormattingOptions>,
1988 culture_name: String,
1989 },
1990 AsDate {
1992 source_date_time: DateTime,
1993 date_style: i8, time_zone: String,
1995 culture_name: String,
1996 },
1997 StringTableEntry {
1998 table: String,
2000 key: String,
2001 },
2002}
2003
2004impl<R: Read + Seek, V> Readable<R, V> for Text {
2005 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2006 let flags = reader.read_u32::<LE>()?;
2007 let text_history_type = reader.read_i8()?;
2008 let variant = match text_history_type {
2009 -0x1 => Ok(TextVariant::None {
2010 culture_invariant: (reader.read_u32::<LE>()? != 0) .then(|| read_string(reader))
2012 .transpose()?,
2013 }),
2014 0x0 => Ok(TextVariant::Base {
2015 namespace: read_string_trailing(reader)?,
2016 key: read_string(reader)?,
2017 source_string: read_string(reader)?,
2018 }),
2019 0x3 => Ok(TextVariant::ArgumentFormat {
2020 format_text: std::boxed::Box::new(Text::read(reader)?),
2021 arguments: read_array(reader.read_u32::<LE>()?, reader, FFormatArgumentData::read)?,
2022 }),
2023 0x4 => Ok(TextVariant::AsNumber {
2024 source_value: FFormatArgumentValue::read(reader)?,
2025 format_options:
2026 (reader.read_u32::<LE>()? != 0) .then(|| FNumberFormattingOptions::read(reader))
2028 .transpose()?,
2029 culture_name: read_string(reader)?,
2030 }),
2031 0x7 => Ok(TextVariant::AsDate {
2032 source_date_time: reader.read_u64::<LE>()?,
2033 date_style: reader.read_i8()?,
2034 time_zone: read_string(reader)?,
2035 culture_name: read_string(reader)?,
2036 }),
2037 0xb => Ok({
2038 TextVariant::StringTableEntry {
2039 table: read_string(reader)?,
2040 key: read_string(reader)?,
2041 }
2042 }),
2043 _ => Err(Error::Other(format!(
2044 "unimplemented variant for FTextHistory 0x{text_history_type:x}"
2045 ))),
2046 }?;
2047 Ok(Self { flags, variant })
2048 }
2049}
2050impl<W: Write, V> Writable<W, V> for Text {
2051 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
2052 writer.write_u32::<LE>(self.flags)?;
2053 match &self.variant {
2054 TextVariant::None { culture_invariant } => {
2055 writer.write_i8(-0x1)?;
2056 writer.write_u32::<LE>(culture_invariant.is_some() as u32)?;
2057 if let Some(culture_invariant) = culture_invariant {
2058 write_string(writer, culture_invariant)?;
2059 }
2060 }
2061 TextVariant::Base {
2062 namespace,
2063 key,
2064 source_string,
2065 } => {
2066 writer.write_i8(0x0)?;
2067 write_string_trailing(writer, &namespace.0, Some(&namespace.1))?;
2071 write_string(writer, key)?;
2072 write_string(writer, source_string)?;
2073 }
2074 TextVariant::ArgumentFormat {
2075 format_text,
2076 arguments,
2077 } => {
2078 writer.write_i8(0x3)?;
2079 format_text.write(writer)?;
2080 writer.write_u32::<LE>(arguments.len() as u32)?;
2081 for a in arguments {
2082 a.write(writer)?;
2083 }
2084 }
2085 TextVariant::AsNumber {
2086 source_value,
2087 format_options,
2088 culture_name,
2089 } => {
2090 writer.write_i8(0x4)?;
2091 source_value.write(writer)?;
2092 writer.write_u32::<LE>(format_options.is_some() as u32)?;
2093 if let Some(format_options) = format_options {
2094 format_options.write(writer)?;
2095 }
2096 write_string(writer, culture_name)?;
2097 }
2098 TextVariant::AsDate {
2099 source_date_time,
2100 date_style,
2101 time_zone,
2102 culture_name,
2103 } => {
2104 writer.write_i8(0x7)?;
2105 writer.write_u64::<LE>(*source_date_time)?;
2106 writer.write_i8(*date_style)?;
2107 write_string(writer, time_zone)?;
2108 write_string(writer, culture_name)?;
2109 }
2110 TextVariant::StringTableEntry { table, key } => {
2111 writer.write_i8(0xb)?;
2112 write_string(writer, table)?;
2113 write_string(writer, key)?;
2114 }
2115 }
2116 Ok(())
2117 }
2118}
2119
2120#[derive(Debug, PartialEq, Serialize, Deserialize)]
2122pub enum Byte {
2123 Byte(u8),
2124 Label(String),
2125}
2126#[derive(Debug, PartialEq, Serialize, Deserialize)]
2128pub enum ByteArray {
2129 Byte(Vec<u8>),
2130 Label(Vec<String>),
2131}
2132
2133#[derive(Debug, PartialEq, Serialize, Deserialize)]
2134pub enum PropertyValue {
2135 Int(Int),
2136 Int8(Int8),
2137 Int16(Int16),
2138 Int64(Int64),
2139 UInt16(UInt16),
2140 UInt32(UInt32),
2141 Float(Float),
2142 Double(Double),
2143 Bool(Bool),
2144 Byte(Byte),
2145 Enum(Enum),
2146 Name(String),
2147 Str(String),
2148 SoftObject(SoftObjectPath),
2149 SoftObjectPath(SoftObjectPath),
2150 Object(String),
2151 Struct(StructValue),
2152}
2153
2154#[derive(Debug, PartialEq, Serialize, Deserialize)]
2155pub enum StructValue {
2156 Guid(uuid::Uuid),
2157 DateTime(DateTime),
2158 Timespan(Timespan),
2159 Vector2D(Vector2D),
2160 Vector(Vector),
2161 IntVector(IntVector),
2162 Box(Box),
2163 IntPoint(IntPoint),
2164 Quat(Quat),
2165 LinearColor(LinearColor),
2166 Color(Color),
2167 Rotator(Rotator),
2168 SoftObjectPath(SoftObjectPath),
2169 GameplayTagContainer(GameplayTagContainer),
2170 UniqueNetIdRepl(UniqueNetIdRepl),
2171 Struct(Properties),
2173}
2174
2175#[derive(Debug, PartialEq, Serialize, Deserialize)]
2177pub enum ValueVec {
2178 Int8(Vec<Int8>),
2179 Int16(Vec<Int16>),
2180 Int(Vec<Int>),
2181 Int64(Vec<Int64>),
2182 UInt8(Vec<UInt8>),
2183 UInt16(Vec<UInt16>),
2184 UInt32(Vec<UInt32>),
2185 UInt64(Vec<UInt64>),
2186 Float(Vec<Float>),
2187 Double(Vec<Double>),
2188 Bool(Vec<bool>),
2189 Byte(ByteArray),
2190 Enum(Vec<Enum>),
2191 Str(Vec<String>),
2192 Text(Vec<Text>),
2193 SoftObject(Vec<(String, String)>),
2194 Name(Vec<String>),
2195 Object(Vec<String>),
2196 Box(Vec<Box>),
2197}
2198
2199#[derive(Debug, PartialEq, Serialize, Deserialize)]
2201pub enum ValueArray {
2202 Base(ValueVec),
2203 Struct {
2204 type_: PropertyType,
2205 struct_type: StructType,
2206 id: Option<uuid::Uuid>,
2207 value: Vec<StructValue>,
2208 },
2209}
2210#[derive(Debug, PartialEq, Serialize, Deserialize)]
2212pub enum ValueSet {
2213 Base(ValueVec),
2214 Struct(Vec<StructValue>),
2215}
2216
2217impl PropertyValue {
2218 fn read<R: Read + Seek, V: VersionInfo>(
2219 reader: &mut Context<R, V>,
2220 t: &PropertyTagDataFull,
2221 ) -> TResult<PropertyValue> {
2222 Ok(match t {
2223 PropertyTagDataFull::Array(_) => unreachable!(),
2224 PropertyTagDataFull::Struct { struct_type, .. } => {
2225 PropertyValue::Struct(StructValue::read(reader, struct_type)?)
2226 }
2227 PropertyTagDataFull::Set { .. } => unreachable!(),
2228 PropertyTagDataFull::Map { .. } => unreachable!(),
2229 PropertyTagDataFull::Byte(_) => PropertyValue::Byte(Byte::Label(read_string(reader)?)),
2230 PropertyTagDataFull::Enum(_, _) => PropertyValue::Enum(read_string(reader)?),
2231 PropertyTagDataFull::Bool(_) => PropertyValue::Bool(reader.read_u8()? > 0),
2232 PropertyTagDataFull::Other(property_type) => match property_type {
2233 PropertyType::IntProperty => PropertyValue::Int(reader.read_i32::<LE>()?),
2234 PropertyType::Int8Property => PropertyValue::Int8(reader.read_i8()?),
2235 PropertyType::Int16Property => PropertyValue::Int16(reader.read_i16::<LE>()?),
2236 PropertyType::Int64Property => PropertyValue::Int64(reader.read_i64::<LE>()?),
2237 PropertyType::UInt16Property => PropertyValue::UInt16(reader.read_u16::<LE>()?),
2238 PropertyType::UInt32Property => PropertyValue::UInt32(reader.read_u32::<LE>()?),
2239 PropertyType::FloatProperty => PropertyValue::Float(reader.read_f32::<LE>()?),
2240 PropertyType::DoubleProperty => PropertyValue::Double(reader.read_f64::<LE>()?),
2241 PropertyType::NameProperty => PropertyValue::Name(read_string(reader)?),
2242 PropertyType::StrProperty => PropertyValue::Str(read_string(reader)?),
2243 PropertyType::SoftObjectProperty => {
2244 PropertyValue::SoftObject(SoftObjectPath::read(reader)?)
2245 }
2246 PropertyType::ObjectProperty => PropertyValue::Object(read_string(reader)?),
2247 _ => return Err(Error::Other(format!("unimplemented property {t:?}"))),
2248 },
2249 })
2250 }
2251 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2252 match &self {
2253 PropertyValue::Int(v) => writer.write_i32::<LE>(*v)?,
2254 PropertyValue::Int8(v) => writer.write_i8(*v)?,
2255 PropertyValue::Int16(v) => writer.write_i16::<LE>(*v)?,
2256 PropertyValue::Int64(v) => writer.write_i64::<LE>(*v)?,
2257 PropertyValue::UInt16(v) => writer.write_u16::<LE>(*v)?,
2258 PropertyValue::UInt32(v) => writer.write_u32::<LE>(*v)?,
2259 PropertyValue::Float(v) => writer.write_f32::<LE>(*v)?,
2260 PropertyValue::Double(v) => writer.write_f64::<LE>(*v)?,
2261 PropertyValue::Bool(v) => writer.write_u8(u8::from(*v))?,
2262 PropertyValue::Name(v) => write_string(writer, v)?,
2263 PropertyValue::Str(v) => write_string(writer, v)?,
2264 PropertyValue::SoftObject(v) => v.write(writer)?,
2265 PropertyValue::SoftObjectPath(v) => v.write(writer)?,
2266 PropertyValue::Object(v) => write_string(writer, v)?,
2267 PropertyValue::Byte(v) => match v {
2268 Byte::Byte(b) => writer.write_u8(*b)?,
2269 Byte::Label(l) => write_string(writer, l)?,
2270 },
2271 PropertyValue::Enum(v) => write_string(writer, v)?,
2272 PropertyValue::Struct(v) => v.write(writer)?,
2273 };
2274 Ok(())
2275 }
2276}
2277impl StructValue {
2278 fn read<R: Read + Seek, V: VersionInfo>(
2279 reader: &mut Context<R, V>,
2280 t: &StructType,
2281 ) -> TResult<StructValue> {
2282 Ok(match t {
2283 StructType::Guid => StructValue::Guid(uuid::Uuid::read(reader)?),
2284 StructType::DateTime => StructValue::DateTime(reader.read_u64::<LE>()?),
2285 StructType::Timespan => StructValue::Timespan(reader.read_i64::<LE>()?),
2286 StructType::Vector2D => StructValue::Vector2D(Vector2D::read(reader)?),
2287 StructType::Vector => StructValue::Vector(Vector::read(reader)?),
2288 StructType::IntVector => StructValue::IntVector(IntVector::read(reader)?),
2289 StructType::Box => StructValue::Box(Box::read(reader)?),
2290 StructType::IntPoint => StructValue::IntPoint(IntPoint::read(reader)?),
2291 StructType::Quat => StructValue::Quat(Quat::read(reader)?),
2292 StructType::LinearColor => StructValue::LinearColor(LinearColor::read(reader)?),
2293 StructType::Color => StructValue::Color(Color::read(reader)?),
2294 StructType::Rotator => StructValue::Rotator(Rotator::read(reader)?),
2295 StructType::SoftObjectPath => {
2296 StructValue::SoftObjectPath(SoftObjectPath::read(reader)?)
2297 }
2298 StructType::GameplayTagContainer => {
2299 StructValue::GameplayTagContainer(GameplayTagContainer::read(reader)?)
2300 }
2301 StructType::UniqueNetIdRepl => {
2302 StructValue::UniqueNetIdRepl(UniqueNetIdRepl::read(reader)?)
2303 }
2304
2305 StructType::Struct(_) => StructValue::Struct(read_properties_until_none(reader)?),
2306 })
2307 }
2308 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2309 match self {
2310 StructValue::Guid(v) => v.write(writer)?,
2311 StructValue::DateTime(v) => writer.write_u64::<LE>(*v)?,
2312 StructValue::Timespan(v) => writer.write_i64::<LE>(*v)?,
2313 StructValue::Vector2D(v) => v.write(writer)?,
2314 StructValue::Vector(v) => v.write(writer)?,
2315 StructValue::IntVector(v) => v.write(writer)?,
2316 StructValue::Box(v) => v.write(writer)?,
2317 StructValue::IntPoint(v) => v.write(writer)?,
2318 StructValue::Quat(v) => v.write(writer)?,
2319 StructValue::LinearColor(v) => v.write(writer)?,
2320 StructValue::Color(v) => v.write(writer)?,
2321 StructValue::Rotator(v) => v.write(writer)?,
2322 StructValue::SoftObjectPath(v) => v.write(writer)?,
2323 StructValue::GameplayTagContainer(v) => v.write(writer)?,
2324 StructValue::UniqueNetIdRepl(v) => v.write(writer)?,
2325 StructValue::Struct(v) => write_properties_none_terminated(writer, v)?,
2326 }
2327 Ok(())
2328 }
2329}
2330impl ValueVec {
2331 fn read<R: Read + Seek, V>(
2332 reader: &mut Context<R, V>,
2333 t: &PropertyType,
2334 size: u32,
2335 count: u32,
2336 ) -> TResult<ValueVec> {
2337 Ok(match t {
2338 PropertyType::IntProperty => {
2339 ValueVec::Int(read_array(count, reader, |r| Ok(r.read_i32::<LE>()?))?)
2340 }
2341 PropertyType::Int16Property => {
2342 ValueVec::Int16(read_array(count, reader, |r| Ok(r.read_i16::<LE>()?))?)
2343 }
2344 PropertyType::Int64Property => {
2345 ValueVec::Int64(read_array(count, reader, |r| Ok(r.read_i64::<LE>()?))?)
2346 }
2347 PropertyType::UInt16Property => {
2348 ValueVec::UInt16(read_array(count, reader, |r| Ok(r.read_u16::<LE>()?))?)
2349 }
2350 PropertyType::UInt32Property => {
2351 ValueVec::UInt32(read_array(count, reader, |r| Ok(r.read_u32::<LE>()?))?)
2352 }
2353 PropertyType::FloatProperty => {
2354 ValueVec::Float(read_array(count, reader, |r| Ok(r.read_f32::<LE>()?))?)
2355 }
2356 PropertyType::DoubleProperty => {
2357 ValueVec::Double(read_array(count, reader, |r| Ok(r.read_f64::<LE>()?))?)
2358 }
2359 PropertyType::BoolProperty => {
2360 ValueVec::Bool(read_array(count, reader, |r| Ok(r.read_u8()? > 0))?)
2361 }
2362 PropertyType::ByteProperty => {
2363 if size == count {
2364 ValueVec::Byte(ByteArray::Byte(read_array(count, reader, |r| {
2365 Ok(r.read_u8()?)
2366 })?))
2367 } else {
2368 ValueVec::Byte(ByteArray::Label(read_array(count, reader, |r| {
2369 read_string(r)
2370 })?))
2371 }
2372 }
2373 PropertyType::EnumProperty => {
2374 ValueVec::Enum(read_array(count, reader, |r| read_string(r))?)
2375 }
2376 PropertyType::StrProperty => ValueVec::Str(read_array(count, reader, read_string)?),
2377 PropertyType::TextProperty => ValueVec::Text(read_array(count, reader, Text::read)?),
2378 PropertyType::SoftObjectProperty => {
2379 ValueVec::SoftObject(read_array(count, reader, |r| {
2380 Ok((read_string(r)?, read_string(r)?))
2381 })?)
2382 }
2383 PropertyType::NameProperty => ValueVec::Name(read_array(count, reader, read_string)?),
2384 PropertyType::ObjectProperty => {
2385 ValueVec::Object(read_array(count, reader, read_string)?)
2386 }
2387 _ => return Err(Error::UnknownVecType(format!("{t:?}"))),
2388 })
2389 }
2390 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2391 match &self {
2392 ValueVec::Int8(v) => {
2393 writer.write_u32::<LE>(v.len() as u32)?;
2394 for i in v {
2395 writer.write_i8(*i)?;
2396 }
2397 }
2398 ValueVec::Int16(v) => {
2399 writer.write_u32::<LE>(v.len() as u32)?;
2400 for i in v {
2401 writer.write_i16::<LE>(*i)?;
2402 }
2403 }
2404 ValueVec::Int(v) => {
2405 writer.write_u32::<LE>(v.len() as u32)?;
2406 for i in v {
2407 writer.write_i32::<LE>(*i)?;
2408 }
2409 }
2410 ValueVec::Int64(v) => {
2411 writer.write_u32::<LE>(v.len() as u32)?;
2412 for i in v {
2413 writer.write_i64::<LE>(*i)?;
2414 }
2415 }
2416 ValueVec::UInt8(v) => {
2417 writer.write_u32::<LE>(v.len() as u32)?;
2418 for i in v {
2419 writer.write_u8(*i)?;
2420 }
2421 }
2422 ValueVec::UInt16(v) => {
2423 writer.write_u32::<LE>(v.len() as u32)?;
2424 for i in v {
2425 writer.write_u16::<LE>(*i)?;
2426 }
2427 }
2428 ValueVec::UInt32(v) => {
2429 writer.write_u32::<LE>(v.len() as u32)?;
2430 for i in v {
2431 writer.write_u32::<LE>(*i)?;
2432 }
2433 }
2434 ValueVec::UInt64(v) => {
2435 writer.write_u32::<LE>(v.len() as u32)?;
2436 for i in v {
2437 writer.write_u64::<LE>(*i)?;
2438 }
2439 }
2440 ValueVec::Float(v) => {
2441 writer.write_u32::<LE>(v.len() as u32)?;
2442 for i in v {
2443 writer.write_f32::<LE>(*i)?;
2444 }
2445 }
2446 ValueVec::Double(v) => {
2447 writer.write_u32::<LE>(v.len() as u32)?;
2448 for i in v {
2449 writer.write_f64::<LE>(*i)?;
2450 }
2451 }
2452 ValueVec::Bool(v) => {
2453 writer.write_u32::<LE>(v.len() as u32)?;
2454 for b in v {
2455 writer.write_u8(*b as u8)?;
2456 }
2457 }
2458 ValueVec::Byte(v) => match v {
2459 ByteArray::Byte(b) => {
2460 writer.write_u32::<LE>(b.len() as u32)?;
2461 for b in b {
2462 writer.write_u8(*b)?;
2463 }
2464 }
2465 ByteArray::Label(l) => {
2466 writer.write_u32::<LE>(l.len() as u32)?;
2467 for l in l {
2468 write_string(writer, l)?;
2469 }
2470 }
2471 },
2472 ValueVec::Enum(v) => {
2473 writer.write_u32::<LE>(v.len() as u32)?;
2474 for i in v {
2475 write_string(writer, i)?;
2476 }
2477 }
2478 ValueVec::Str(v) | ValueVec::Object(v) | ValueVec::Name(v) => {
2479 writer.write_u32::<LE>(v.len() as u32)?;
2480 for i in v {
2481 write_string(writer, i)?;
2482 }
2483 }
2484 ValueVec::Text(v) => {
2485 writer.write_u32::<LE>(v.len() as u32)?;
2486 for i in v {
2487 i.write(writer)?;
2488 }
2489 }
2490 ValueVec::SoftObject(v) => {
2491 writer.write_u32::<LE>(v.len() as u32)?;
2492 for (a, b) in v {
2493 write_string(writer, a)?;
2494 write_string(writer, b)?;
2495 }
2496 }
2497 ValueVec::Box(v) => {
2498 writer.write_u32::<LE>(v.len() as u32)?;
2499 for i in v {
2500 i.write(writer)?;
2501 }
2502 }
2503 }
2504 Ok(())
2505 }
2506}
2507impl ValueArray {
2508 fn read<R: Read + Seek, V: VersionInfo>(
2509 reader: &mut Context<R, V>,
2510 tag: PropertyTagDataFull,
2511 size: u32,
2512 ) -> TResult<ValueArray> {
2513 let count = reader.read_u32::<LE>()?;
2514 Ok(match tag {
2515 PropertyTagDataFull::Struct { struct_type, id } => {
2516 let (struct_type, id) = if !reader.version().property_tag() {
2517 if reader.version().array_inner_tag() {
2518 let tag = PropertyTagFull::read(reader)?.unwrap();
2519 match tag.data {
2520 PropertyTagDataFull::Struct { struct_type, id } => (struct_type, id),
2521 _ => {
2522 return Err(Error::Other(format!(
2523 "expected StructProperty tag, found {tag:?}"
2524 )))
2525 }
2526 }
2527 } else {
2528 (StructType::Struct(None), Default::default())
2531 }
2532 } else {
2533 (struct_type, id)
2534 };
2535
2536 let mut value = vec![];
2537 for _ in 0..count {
2538 value.push(StructValue::read(reader, &struct_type)?);
2539 }
2540 ValueArray::Struct {
2541 type_: PropertyType::StructProperty,
2542 struct_type,
2543 id: Some(id),
2544 value,
2545 }
2546 }
2547 _ => ValueArray::Base(ValueVec::read(reader, &tag.basic_type(), size, count)?),
2548 })
2549 }
2550 fn write<W: Write, V: VersionInfo>(
2551 &self,
2552 writer: &mut Context<W, V>,
2553 tag: &PropertyTagFull,
2554 ) -> TResult<()> {
2555 match &self {
2556 ValueArray::Struct {
2557 type_,
2558 struct_type,
2559 id,
2560 value,
2561 } => {
2562 writer.write_u32::<LE>(value.len() as u32)?;
2563
2564 let mut buf = vec![];
2565 for v in value {
2566 writer.with_stream(&mut buf, |writer| v.write(writer))?;
2567 }
2568
2569 if !writer.version().property_tag() && writer.version().array_inner_tag() {
2570 write_string(writer, &tag.name)?;
2571 type_.write(writer)?;
2572 writer.write_u32::<LE>(buf.len() as u32)?;
2573 writer.write_u32::<LE>(0)?;
2574 struct_type.write(writer)?;
2575 if let Some(id) = id {
2576 id.write(writer)?;
2577 }
2578 writer.write_u8(0)?;
2579 }
2580 writer.write_all(&buf)?;
2581 }
2582 ValueArray::Base(vec) => {
2583 vec.write(writer)?;
2584 }
2585 }
2586 Ok(())
2587 }
2588}
2589impl ValueSet {
2590 fn read<R: Read + Seek, V: VersionInfo>(
2591 reader: &mut Context<R, V>,
2592 t: &PropertyTagDataFull,
2593 size: u32,
2594 ) -> TResult<ValueSet> {
2595 let count = reader.read_u32::<LE>()?;
2596 Ok(match t {
2597 PropertyTagDataFull::Struct { struct_type, .. } => {
2598 ValueSet::Struct(read_array(count, reader, |r| {
2599 StructValue::read(r, struct_type)
2600 })?)
2601 }
2602 _ => ValueSet::Base(ValueVec::read(reader, &t.basic_type(), size, count)?),
2603 })
2604 }
2605 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2606 match &self {
2607 ValueSet::Struct(value) => {
2608 writer.write_u32::<LE>(value.len() as u32)?;
2609 for v in value {
2610 v.write(writer)?;
2611 }
2612 }
2613 ValueSet::Base(vec) => {
2614 vec.write(writer)?;
2615 }
2616 }
2617 Ok(())
2618 }
2619}
2620
2621#[derive(Debug, PartialEq, Serialize, Deserialize)]
2623pub struct Property {
2624 pub tag: PropertyTagPartial,
2625 #[serde(flatten)]
2626 pub inner: PropertyInner,
2627}
2628
2629#[derive(Debug, PartialEq, Serialize, Deserialize)]
2631pub enum PropertyInner {
2632 Int8(Int8),
2633 Int16(Int16),
2634 Int(Int),
2635 Int64(Int64),
2636 UInt8(UInt8),
2637 UInt16(UInt16),
2638 UInt32(UInt32),
2639 UInt64(UInt64),
2640 Float(Float),
2641 Double(Double),
2642 Bool(Bool),
2643 Byte(Byte),
2644 Enum(Enum),
2645 Str(String),
2646 FieldPath(FieldPath),
2647 SoftObject(SoftObjectPath),
2648 Name(String),
2649 Object(String),
2650 Text(Text),
2651 Delegate(Delegate),
2652 MulticastDelegate(MulticastDelegate),
2653 MulticastInlineDelegate(MulticastInlineDelegate),
2654 MulticastSparseDelegate(MulticastSparseDelegate),
2655 Set(ValueSet),
2656 Map(Vec<MapEntry>),
2657 Struct(StructValue),
2658 Array(ValueArray),
2659}
2660
2661impl Property {
2662 fn read<R: Read + Seek, V: VersionInfo>(
2663 reader: &mut Context<R, V>,
2664 tag: PropertyTagFull,
2665 ) -> TResult<Property> {
2666 let inner = match &tag.data {
2667 PropertyTagDataFull::Bool(value) => PropertyInner::Bool(*value),
2668 PropertyTagDataFull::Byte(ref enum_type) => {
2669 let value = if enum_type.is_none() {
2670 Byte::Byte(reader.read_u8()?)
2671 } else {
2672 Byte::Label(read_string(reader)?)
2673 };
2674 PropertyInner::Byte(value)
2675 }
2676 PropertyTagDataFull::Enum { .. } => PropertyInner::Enum(read_string(reader)?),
2677 PropertyTagDataFull::Set { key_type } => {
2678 reader.read_u32::<LE>()?;
2679 PropertyInner::Set(ValueSet::read(reader, key_type, tag.size - 8)?)
2680 }
2681 PropertyTagDataFull::Map {
2682 key_type,
2683 value_type,
2684 } => {
2685 reader.read_u32::<LE>()?;
2686 let count = reader.read_u32::<LE>()?;
2687 let mut value = vec![];
2688
2689 for _ in 0..count {
2690 value.push(MapEntry::read(reader, key_type, value_type)?)
2691 }
2692
2693 PropertyInner::Map(value)
2694 }
2695 PropertyTagDataFull::Struct { struct_type, .. } => {
2696 PropertyInner::Struct(StructValue::read(reader, struct_type)?)
2697 }
2698 PropertyTagDataFull::Array(data) => {
2699 PropertyInner::Array(ValueArray::read(reader, *data.clone(), tag.size - 4)?)
2700 }
2701 PropertyTagDataFull::Other(t) => match t {
2702 PropertyType::BoolProperty
2703 | PropertyType::ByteProperty
2704 | PropertyType::EnumProperty
2705 | PropertyType::SetProperty
2706 | PropertyType::MapProperty
2707 | PropertyType::StructProperty
2708 | PropertyType::ArrayProperty => unreachable!(),
2709 PropertyType::Int8Property => PropertyInner::Int8(reader.read_i8()?),
2710 PropertyType::Int16Property => PropertyInner::Int16(reader.read_i16::<LE>()?),
2711 PropertyType::IntProperty => PropertyInner::Int(reader.read_i32::<LE>()?),
2712 PropertyType::Int64Property => PropertyInner::Int64(reader.read_i64::<LE>()?),
2713 PropertyType::UInt8Property => PropertyInner::UInt8(reader.read_u8()?),
2714 PropertyType::UInt16Property => PropertyInner::UInt16(reader.read_u16::<LE>()?),
2715 PropertyType::UInt32Property => PropertyInner::UInt32(reader.read_u32::<LE>()?),
2716 PropertyType::UInt64Property => PropertyInner::UInt64(reader.read_u64::<LE>()?),
2717 PropertyType::FloatProperty => PropertyInner::Float(reader.read_f32::<LE>()?),
2718 PropertyType::DoubleProperty => PropertyInner::Double(reader.read_f64::<LE>()?),
2719 PropertyType::NameProperty => PropertyInner::Name(read_string(reader)?),
2720 PropertyType::StrProperty => PropertyInner::Str(read_string(reader)?),
2721 PropertyType::FieldPathProperty => {
2722 PropertyInner::FieldPath(FieldPath::read(reader)?)
2723 }
2724 PropertyType::SoftObjectProperty => {
2725 PropertyInner::SoftObject(SoftObjectPath::read(reader)?)
2726 }
2727 PropertyType::ObjectProperty => PropertyInner::Object(read_string(reader)?),
2728 PropertyType::TextProperty => PropertyInner::Text(Text::read(reader)?),
2729 PropertyType::DelegateProperty => PropertyInner::Delegate(Delegate::read(reader)?),
2730 PropertyType::MulticastDelegateProperty => {
2731 PropertyInner::MulticastDelegate(MulticastDelegate::read(reader)?)
2732 }
2733 PropertyType::MulticastInlineDelegateProperty => {
2734 PropertyInner::MulticastInlineDelegate(MulticastInlineDelegate::read(reader)?)
2735 }
2736 PropertyType::MulticastSparseDelegateProperty => {
2737 PropertyInner::MulticastSparseDelegate(MulticastSparseDelegate::read(reader)?)
2738 }
2739 },
2740 };
2741 Ok(Property {
2742 tag: tag.into_full(),
2743 inner,
2744 })
2745 }
2746 fn write<W: Write, V: VersionInfo>(
2747 &self,
2748 writer: &mut Context<W, V>,
2749 tag: &PropertyTagFull,
2750 ) -> TResult<usize> {
2751 Ok(match &self.inner {
2752 PropertyInner::Int8(value) => {
2753 writer.write_i8(*value)?;
2754 1
2755 }
2756 PropertyInner::Int16(value) => {
2757 writer.write_i16::<LE>(*value)?;
2758 2
2759 }
2760 PropertyInner::Int(value) => {
2761 writer.write_i32::<LE>(*value)?;
2762 4
2763 }
2764 PropertyInner::Int64(value) => {
2765 writer.write_i64::<LE>(*value)?;
2766 8
2767 }
2768 PropertyInner::UInt8(value) => {
2769 writer.write_u8(*value)?;
2770 1
2771 }
2772 PropertyInner::UInt16(value) => {
2773 writer.write_u16::<LE>(*value)?;
2774 2
2775 }
2776 PropertyInner::UInt32(value) => {
2777 writer.write_u32::<LE>(*value)?;
2778 4
2779 }
2780 PropertyInner::UInt64(value) => {
2781 writer.write_u64::<LE>(*value)?;
2782 8
2783 }
2784 PropertyInner::Float(value) => {
2785 writer.write_f32::<LE>(*value)?;
2786 4
2787 }
2788 PropertyInner::Double(value) => {
2789 writer.write_f64::<LE>(*value)?;
2790 8
2791 }
2792 PropertyInner::Bool(_) => 0,
2793 PropertyInner::Byte(value) => match value {
2794 Byte::Byte(b) => {
2795 writer.write_u8(*b)?;
2796 1
2797 }
2798 Byte::Label(l) => {
2799 write_string(writer, l)?;
2800 l.len() + 5
2801 }
2802 },
2803 PropertyInner::Enum(value) => {
2804 write_string(writer, value)?;
2805 value.len() + 5
2806 }
2807 PropertyInner::Name(value) => {
2808 let mut buf = vec![];
2809 writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2810 writer.write_all(&buf)?;
2811 buf.len()
2812 }
2813 PropertyInner::Str(value) => {
2814 let mut buf = vec![];
2815 writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2816 writer.write_all(&buf)?;
2817 buf.len()
2818 }
2819 PropertyInner::FieldPath(value) => {
2820 let mut buf = vec![];
2821 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2822 writer.write_all(&buf)?;
2823 buf.len()
2824 }
2825 PropertyInner::SoftObject(value) => {
2826 let mut buf = vec![];
2827 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2828 writer.write_all(&buf)?;
2829 buf.len()
2830 }
2831 PropertyInner::Object(value) => {
2832 let mut buf = vec![];
2833 writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2834 writer.write_all(&buf)?;
2835 buf.len()
2836 }
2837 PropertyInner::Text(value) => {
2838 let mut buf = vec![];
2839 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2840 writer.write_all(&buf)?;
2841 buf.len()
2842 }
2843 PropertyInner::Delegate(value) => {
2844 let mut buf = vec![];
2845 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2846 writer.write_all(&buf)?;
2847 buf.len()
2848 }
2849 PropertyInner::MulticastDelegate(value) => {
2850 let mut buf = vec![];
2851 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2852 writer.write_all(&buf)?;
2853 buf.len()
2854 }
2855 PropertyInner::MulticastInlineDelegate(value) => {
2856 let mut buf = vec![];
2857 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2858 writer.write_all(&buf)?;
2859 buf.len()
2860 }
2861 PropertyInner::MulticastSparseDelegate(value) => {
2862 let mut buf = vec![];
2863 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2864 writer.write_all(&buf)?;
2865 buf.len()
2866 }
2867 PropertyInner::Set(value) => {
2868 let mut buf = vec![];
2869 buf.write_u32::<LE>(0)?;
2870 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2871 writer.write_all(&buf)?;
2872 buf.len()
2873 }
2874 PropertyInner::Map(value) => {
2875 let mut buf = vec![];
2876 buf.write_u32::<LE>(0)?;
2877 buf.write_u32::<LE>(value.len() as u32)?;
2878 for v in value {
2879 writer.with_stream(&mut buf, |writer| v.write(writer))?;
2880 }
2881 writer.write_all(&buf)?;
2882 buf.len()
2883 }
2884 PropertyInner::Struct(value) => {
2885 let mut buf = vec![];
2886 writer.with_stream(&mut buf, |writer| value.write(writer))?;
2887 writer.write_all(&buf)?;
2888 buf.len()
2889 }
2890 PropertyInner::Array(value) => {
2891 let mut buf = vec![];
2892 writer.with_stream(&mut buf, |writer| value.write(writer, tag))?;
2893 writer.write_all(&buf)?;
2894 buf.len()
2895 }
2896 })
2897 }
2898}
2899
2900#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2901pub struct CustomFormatData {
2902 pub id: uuid::Uuid,
2903 pub value: i32,
2904}
2905impl<R: Read + Seek, V> Readable<R, V> for CustomFormatData {
2906 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2907 Ok(CustomFormatData {
2908 id: uuid::Uuid::read(reader)?,
2909 value: reader.read_i32::<LE>()?,
2910 })
2911 }
2912}
2913impl<W: Write, V> Writable<W, V> for CustomFormatData {
2914 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
2915 self.id.write(writer)?;
2916 writer.write_i32::<LE>(self.value)?;
2917 Ok(())
2918 }
2919}
2920
2921#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2922pub struct PackageVersion {
2923 ue4: u32,
2924 ue5: Option<u32>,
2925}
2926
2927pub trait VersionInfo {
2928 fn large_world_coordinates(&self) -> bool;
2929 fn property_tag(&self) -> bool;
2930 fn property_guid(&self) -> bool;
2931 fn array_inner_tag(&self) -> bool;
2932 fn remove_asset_path_fnames(&self) -> bool;
2933}
2934
2935#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2936pub struct Header {
2937 pub magic: u32,
2938 pub save_game_version: u32,
2939 pub package_version: PackageVersion,
2940 pub engine_version_major: u16,
2941 pub engine_version_minor: u16,
2942 pub engine_version_patch: u16,
2943 pub engine_version_build: u32,
2944 pub engine_version: String,
2945 pub custom_version: Option<(u32, Vec<CustomFormatData>)>,
2946}
2947impl VersionInfo for Header {
2948 fn large_world_coordinates(&self) -> bool {
2949 self.engine_version_major >= 5
2950 }
2951 fn property_tag(&self) -> bool {
2952 (self.engine_version_major, self.engine_version_minor) >= (5, 4)
2954 }
2955 fn property_guid(&self) -> bool {
2956 (self.engine_version_major, self.engine_version_minor) >= (4, 12)
2957 }
2960 fn array_inner_tag(&self) -> bool {
2961 (self.engine_version_major, self.engine_version_minor) >= (4, 12)
2963 }
2964 fn remove_asset_path_fnames(&self) -> bool {
2965 self.package_version
2966 .ue5
2967 .map(|ue5| ue5 >= 1007) .unwrap_or_default()
2969 }
2970}
2971impl<R: Read + Seek, V> Readable<R, V> for Header {
2972 fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2973 let magic = reader.read_u32::<LE>()?;
2974 if reader.log() && magic != u32::from_le_bytes(*b"GVAS") {
2975 eprintln!(
2976 "Found non-standard magic: {:02x?} ({}) expected: GVAS, continuing to parse...",
2977 &magic.to_le_bytes(),
2978 String::from_utf8_lossy(&magic.to_le_bytes())
2979 );
2980 }
2981 let save_game_version = reader.read_u32::<LE>()?;
2982 let package_version = PackageVersion {
2983 ue4: reader.read_u32::<LE>()?,
2984 ue5: (save_game_version >= 3 && save_game_version != 34) .then(|| reader.read_u32::<LE>())
2986 .transpose()?,
2987 };
2988 let engine_version_major = reader.read_u16::<LE>()?;
2989 let engine_version_minor = reader.read_u16::<LE>()?;
2990 let engine_version_patch = reader.read_u16::<LE>()?;
2991 let engine_version_build = reader.read_u32::<LE>()?;
2992 let engine_version = read_string(reader)?;
2993 let custom_version = if (engine_version_major, engine_version_minor) >= (4, 12) {
2994 Some((
2995 reader.read_u32::<LE>()?,
2996 read_array(reader.read_u32::<LE>()?, reader, CustomFormatData::read)?,
2997 ))
2998 } else {
2999 None
3000 };
3001 Ok(Header {
3002 magic,
3003 save_game_version,
3004 package_version,
3005 engine_version_major,
3006 engine_version_minor,
3007 engine_version_patch,
3008 engine_version_build,
3009 engine_version,
3010 custom_version,
3011 })
3012 }
3013}
3014impl<W: Write, V> Writable<W, V> for Header {
3015 fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
3016 writer.write_u32::<LE>(self.magic)?;
3017 writer.write_u32::<LE>(self.save_game_version)?;
3018 writer.write_u32::<LE>(self.package_version.ue4)?;
3019 if let Some(ue5) = self.package_version.ue5 {
3020 writer.write_u32::<LE>(ue5)?;
3021 }
3022 writer.write_u16::<LE>(self.engine_version_major)?;
3023 writer.write_u16::<LE>(self.engine_version_minor)?;
3024 writer.write_u16::<LE>(self.engine_version_patch)?;
3025 writer.write_u32::<LE>(self.engine_version_build)?;
3026 write_string(writer, &self.engine_version)?;
3027 if let Some((custom_format_version, custom_format)) = &self.custom_version {
3028 writer.write_u32::<LE>(*custom_format_version)?;
3029 writer.write_u32::<LE>(custom_format.len() as u32)?;
3030 for cf in custom_format {
3031 cf.write(writer)?;
3032 }
3033 }
3034 Ok(())
3035 }
3036}
3037
3038#[derive(Debug, PartialEq, Serialize, Deserialize)]
3040pub struct Root {
3041 pub save_game_type: String,
3042 pub properties: Properties,
3043}
3044impl Root {
3045 fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
3046 let save_game_type = read_string(reader)?;
3047 if reader.version().property_tag() {
3048 reader.read_u8()?;
3049 }
3050 let properties = read_properties_until_none(reader)?;
3051 Ok(Self {
3052 save_game_type,
3053 properties,
3054 })
3055 }
3056 fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
3057 write_string(writer, &self.save_game_type)?;
3058 if writer.version().property_tag() {
3059 writer.write_u8(0)?;
3060 }
3061 write_properties_none_terminated(writer, &self.properties)?;
3062 Ok(())
3063 }
3064}
3065
3066#[derive(Debug, PartialEq, Serialize, Deserialize)]
3067pub struct Save {
3068 pub header: Header,
3069 pub root: Root,
3070 pub extra: Vec<u8>,
3071}
3072impl Save {
3073 pub fn read<R: Read>(reader: &mut R) -> Result<Self, ParseError> {
3075 Self::read_with_types(reader, &Types::new())
3076 }
3077 pub fn read_with_types<R: Read>(reader: &mut R, types: &Types) -> Result<Self, ParseError> {
3079 SaveReader::new().types(types).read(reader)
3080 }
3081 pub fn write<W: Write>(&self, writer: &mut W) -> TResult<()> {
3082 Context::run(writer, |writer| {
3083 writer.with_version(&self.header, |writer| {
3084 self.header.write(writer)?;
3085 self.root.write(writer)?;
3086 writer.write_all(&self.extra)?;
3087 Ok(())
3088 })
3089 })
3090 }
3091}
3092
3093pub struct SaveReader<'types> {
3094 log: bool,
3095 types: Option<&'types Types>,
3096}
3097impl Default for SaveReader<'_> {
3098 fn default() -> Self {
3099 Self::new()
3100 }
3101}
3102impl<'types> SaveReader<'types> {
3103 pub fn new() -> Self {
3104 Self {
3105 log: false,
3106 types: None,
3107 }
3108 }
3109 pub fn log(mut self, log: bool) -> Self {
3110 self.log = log;
3111 self
3112 }
3113 pub fn types(mut self, types: &'types Types) -> Self {
3114 self.types = Some(types);
3115 self
3116 }
3117 pub fn read<S: Read>(self, stream: S) -> Result<Save, ParseError> {
3118 let tmp = Types::new();
3119 let types = self.types.unwrap_or(&tmp);
3120
3121 let mut stream = SeekReader::new(stream);
3122 let mut reader = Context {
3123 stream: &mut stream,
3124 state: ContextState {
3125 version: &(),
3126 types,
3127 scope: &Scope::Root,
3128 log: self.log,
3129 },
3130 };
3131
3132 || -> TResult<Save> {
3133 let header = Header::read(&mut reader)?;
3134 let (root, extra) = reader.with_version(&header, |reader| -> TResult<_> {
3135 let root = Root::read(reader)?;
3136 let extra = {
3137 let mut buf = vec![];
3138 reader.read_to_end(&mut buf)?;
3139 if reader.log() && buf != [0; 4] {
3140 eprintln!(
3141 "{} extra bytes. Save may not have been parsed completely.",
3142 buf.len()
3143 );
3144 }
3145 buf
3146 };
3147 Ok((root, extra))
3148 })?;
3149 Ok(Save {
3150 header,
3151 root,
3152 extra,
3153 })
3154 }()
3155 .map_err(|e| error::ParseError {
3156 offset: reader.stream_position().unwrap() as usize, error: e,
3158 })
3159 }
3160}