Skip to content

Commit 7a71016

Browse files
committed
Implement remaining FTextHistory variants
fixes #92
1 parent ab53b2c commit 7a71016

1 file changed

Lines changed: 284 additions & 9 deletions

File tree

uesave/src/lib.rs

Lines changed: 284 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3403,6 +3403,71 @@ pub struct Text {
34033403
flags: u32,
34043404
variant: TextVariant,
34053405
}
3406+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3407+
#[repr(i8)]
3408+
pub enum EDateTimeStyle {
3409+
Default = 0,
3410+
Short = 1,
3411+
Medium = 2,
3412+
Long = 3,
3413+
Full = 4,
3414+
Custom = 5,
3415+
}
3416+
impl EDateTimeStyle {
3417+
fn from_i8(value: i8) -> Result<Self> {
3418+
Ok(match value {
3419+
0 => Self::Default,
3420+
1 => Self::Short,
3421+
2 => Self::Medium,
3422+
3 => Self::Long,
3423+
4 => Self::Full,
3424+
5 => Self::Custom,
3425+
_ => {
3426+
return Err(Error::Other(format!("unknown EDateTimeStyle 0x{value:x}")));
3427+
}
3428+
})
3429+
}
3430+
}
3431+
3432+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
3433+
#[repr(u8)]
3434+
pub enum ETextTransformType {
3435+
ToLower = 0,
3436+
ToUpper = 1,
3437+
}
3438+
impl ETextTransformType {
3439+
fn from_u8(value: u8) -> Result<Self> {
3440+
Ok(match value {
3441+
0 => Self::ToLower,
3442+
1 => Self::ToUpper,
3443+
_ => {
3444+
return Err(Error::Other(format!(
3445+
"unknown ETextTransformType 0x{value:x}"
3446+
)));
3447+
}
3448+
})
3449+
}
3450+
}
3451+
3452+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
3453+
pub struct FFormatNamedArgument {
3454+
name: String,
3455+
value: FFormatArgumentValue,
3456+
}
3457+
impl FFormatNamedArgument {
3458+
fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
3459+
Ok(Self {
3460+
name: ar.read_string()?,
3461+
value: FFormatArgumentValue::read(ar)?,
3462+
})
3463+
}
3464+
fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
3465+
ar.write_string(&self.name)?;
3466+
self.value.write(ar)?;
3467+
Ok(())
3468+
}
3469+
}
3470+
34063471
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
34073472
pub enum TextVariant {
34083473
// -0x1
@@ -3415,6 +3480,16 @@ pub enum TextVariant {
34153480
key: String,
34163481
source_string: String,
34173482
},
3483+
// 0x1
3484+
NamedFormat {
3485+
format_text: std::boxed::Box<Text>,
3486+
arguments: Vec<FFormatNamedArgument>,
3487+
},
3488+
// 0x2
3489+
OrderedFormat {
3490+
format_text: std::boxed::Box<Text>,
3491+
arguments: Vec<FFormatArgumentValue>,
3492+
},
34183493
// 0x3
34193494
ArgumentFormat {
34203495
// aka ArgumentDataFormat
@@ -3427,18 +3502,58 @@ pub enum TextVariant {
34273502
format_options: Option<FNumberFormattingOptions>,
34283503
culture_name: String,
34293504
},
3505+
// 0x5
3506+
AsPercent {
3507+
source_value: FFormatArgumentValue,
3508+
format_options: Option<FNumberFormattingOptions>,
3509+
culture_name: String,
3510+
},
3511+
// 0x6
3512+
AsCurrency {
3513+
currency_code: String,
3514+
source_value: FFormatArgumentValue,
3515+
format_options: Option<FNumberFormattingOptions>,
3516+
culture_name: String,
3517+
},
34303518
// 0x7
34313519
AsDate {
34323520
source_date_time: DateTime,
3433-
date_style: i8, // TODO EDateTimeStyle::Type
3521+
date_style: EDateTimeStyle,
3522+
time_zone: String,
3523+
culture_name: String,
3524+
},
3525+
// 0x8
3526+
AsTime {
3527+
source_date_time: DateTime,
3528+
time_style: EDateTimeStyle,
34343529
time_zone: String,
34353530
culture_name: String,
34363531
},
3532+
// 0x9
3533+
AsDateTime {
3534+
source_date_time: DateTime,
3535+
date_style: EDateTimeStyle,
3536+
time_style: EDateTimeStyle,
3537+
/// Only present when `date_style` is `EDateTimeStyle::Custom`.
3538+
custom_pattern: Option<String>,
3539+
time_zone: String,
3540+
culture_name: String,
3541+
},
3542+
// 0xa
3543+
Transform {
3544+
source_text: std::boxed::Box<Text>,
3545+
transform_type: ETextTransformType,
3546+
},
3547+
// 0xb
34373548
StringTableEntry {
3438-
// 0xb
34393549
table: String,
34403550
key: String,
34413551
},
3552+
// 0xc
3553+
TextGenerator {
3554+
generator_type_id: String,
3555+
generator_contents: Vec<u8>,
3556+
},
34423557
}
34433558

34443559
impl Text {
@@ -3457,6 +3572,14 @@ impl Text {
34573572
key: read_string(ar)?,
34583573
source_string: read_string(ar)?,
34593574
}),
3575+
0x1 => Ok(TextVariant::NamedFormat {
3576+
format_text: std::boxed::Box::new(Text::read(ar)?),
3577+
arguments: read_array(ar.read_u32::<LE>()?, ar, FFormatNamedArgument::read)?,
3578+
}),
3579+
0x2 => Ok(TextVariant::OrderedFormat {
3580+
format_text: std::boxed::Box::new(Text::read(ar)?),
3581+
arguments: read_array(ar.read_u32::<LE>()?, ar, FFormatArgumentValue::read)?,
3582+
}),
34603583
0x3 => Ok(TextVariant::ArgumentFormat {
34613584
format_text: std::boxed::Box::new(Text::read(ar)?),
34623585
arguments: read_array(ar.read_u32::<LE>()?, ar, FFormatArgumentData::read)?,
@@ -3468,17 +3591,67 @@ impl Text {
34683591
.transpose()?,
34693592
culture_name: ar.read_string()?,
34703593
}),
3594+
0x5 => Ok(TextVariant::AsPercent {
3595+
source_value: FFormatArgumentValue::read(ar)?,
3596+
format_options: (ar.read_u32::<LE>()? != 0) // bHasFormatOptions
3597+
.then(|| FNumberFormattingOptions::read(ar))
3598+
.transpose()?,
3599+
culture_name: ar.read_string()?,
3600+
}),
3601+
0x6 => Ok(TextVariant::AsCurrency {
3602+
currency_code: ar.read_string()?,
3603+
source_value: FFormatArgumentValue::read(ar)?,
3604+
format_options: (ar.read_u32::<LE>()? != 0) // bHasFormatOptions
3605+
.then(|| FNumberFormattingOptions::read(ar))
3606+
.transpose()?,
3607+
culture_name: ar.read_string()?,
3608+
}),
34713609
0x7 => Ok(TextVariant::AsDate {
34723610
source_date_time: ar.read_u64::<LE>()?,
3473-
date_style: ar.read_i8()?,
3611+
date_style: EDateTimeStyle::from_i8(ar.read_i8()?)?,
34743612
time_zone: ar.read_string()?,
34753613
culture_name: ar.read_string()?,
34763614
}),
3477-
0xb => Ok({
3478-
TextVariant::StringTableEntry {
3479-
table: ar.read_string()?,
3480-
key: read_string(ar)?,
3481-
}
3615+
0x8 => Ok(TextVariant::AsTime {
3616+
source_date_time: ar.read_u64::<LE>()?,
3617+
time_style: EDateTimeStyle::from_i8(ar.read_i8()?)?,
3618+
time_zone: ar.read_string()?,
3619+
culture_name: ar.read_string()?,
3620+
}),
3621+
0x9 => {
3622+
let source_date_time = ar.read_u64::<LE>()?;
3623+
let date_style = EDateTimeStyle::from_i8(ar.read_i8()?)?;
3624+
let time_style = EDateTimeStyle::from_i8(ar.read_i8()?)?;
3625+
let custom_pattern = if date_style == EDateTimeStyle::Custom {
3626+
Some(ar.read_string()?)
3627+
} else {
3628+
None
3629+
};
3630+
Ok(TextVariant::AsDateTime {
3631+
source_date_time,
3632+
date_style,
3633+
time_style,
3634+
custom_pattern,
3635+
time_zone: ar.read_string()?,
3636+
culture_name: ar.read_string()?,
3637+
})
3638+
}
3639+
0xa => Ok(TextVariant::Transform {
3640+
source_text: std::boxed::Box::new(Text::read(ar)?),
3641+
transform_type: ETextTransformType::from_u8(ar.read_u8()?)?,
3642+
}),
3643+
0xb => Ok(TextVariant::StringTableEntry {
3644+
table: ar.read_string()?,
3645+
key: read_string(ar)?,
3646+
}),
3647+
0xc => Ok(TextVariant::TextGenerator {
3648+
generator_type_id: ar.read_string()?,
3649+
generator_contents: {
3650+
let len = ar.read_u32::<LE>()? as usize;
3651+
let mut bytes = vec![0; len];
3652+
ar.read_exact(&mut bytes)?;
3653+
bytes
3654+
},
34823655
}),
34833656
_ => Err(Error::Other(format!(
34843657
"unimplemented variant for FTextHistory 0x{text_history_type:x}"
@@ -3511,6 +3684,28 @@ impl Text {
35113684
write_string(ar, key)?;
35123685
write_string(ar, source_string)?;
35133686
}
3687+
TextVariant::NamedFormat {
3688+
format_text,
3689+
arguments,
3690+
} => {
3691+
ar.write_i8(0x1)?;
3692+
format_text.write(ar)?;
3693+
ar.write_u32::<LE>(arguments.len() as u32)?;
3694+
for a in arguments {
3695+
a.write(ar)?;
3696+
}
3697+
}
3698+
TextVariant::OrderedFormat {
3699+
format_text,
3700+
arguments,
3701+
} => {
3702+
ar.write_i8(0x2)?;
3703+
format_text.write(ar)?;
3704+
ar.write_u32::<LE>(arguments.len() as u32)?;
3705+
for a in arguments {
3706+
a.write(ar)?;
3707+
}
3708+
}
35143709
TextVariant::ArgumentFormat {
35153710
format_text,
35163711
arguments,
@@ -3535,6 +3730,34 @@ impl Text {
35353730
}
35363731
ar.write_string(culture_name)?;
35373732
}
3733+
TextVariant::AsPercent {
3734+
source_value,
3735+
format_options,
3736+
culture_name,
3737+
} => {
3738+
ar.write_i8(0x5)?;
3739+
source_value.write(ar)?;
3740+
ar.write_u32::<LE>(format_options.is_some() as u32)?;
3741+
if let Some(format_options) = format_options {
3742+
format_options.write(ar)?;
3743+
}
3744+
ar.write_string(culture_name)?;
3745+
}
3746+
TextVariant::AsCurrency {
3747+
currency_code,
3748+
source_value,
3749+
format_options,
3750+
culture_name,
3751+
} => {
3752+
ar.write_i8(0x6)?;
3753+
ar.write_string(currency_code)?;
3754+
source_value.write(ar)?;
3755+
ar.write_u32::<LE>(format_options.is_some() as u32)?;
3756+
if let Some(format_options) = format_options {
3757+
format_options.write(ar)?;
3758+
}
3759+
ar.write_string(culture_name)?;
3760+
}
35383761
TextVariant::AsDate {
35393762
source_date_time,
35403763
date_style,
@@ -3543,15 +3766,67 @@ impl Text {
35433766
} => {
35443767
ar.write_i8(0x7)?;
35453768
ar.write_u64::<LE>(*source_date_time)?;
3546-
ar.write_i8(*date_style)?;
3769+
ar.write_i8(*date_style as i8)?;
35473770
ar.write_string(time_zone)?;
35483771
ar.write_string(culture_name)?;
35493772
}
3773+
TextVariant::AsTime {
3774+
source_date_time,
3775+
time_style,
3776+
time_zone,
3777+
culture_name,
3778+
} => {
3779+
ar.write_i8(0x8)?;
3780+
ar.write_u64::<LE>(*source_date_time)?;
3781+
ar.write_i8(*time_style as i8)?;
3782+
ar.write_string(time_zone)?;
3783+
ar.write_string(culture_name)?;
3784+
}
3785+
TextVariant::AsDateTime {
3786+
source_date_time,
3787+
date_style,
3788+
time_style,
3789+
custom_pattern,
3790+
time_zone,
3791+
culture_name,
3792+
} => {
3793+
ar.write_i8(0x9)?;
3794+
ar.write_u64::<LE>(*source_date_time)?;
3795+
ar.write_i8(*date_style as i8)?;
3796+
ar.write_i8(*time_style as i8)?;
3797+
if *date_style == EDateTimeStyle::Custom {
3798+
let pattern = custom_pattern.as_deref().ok_or_else(|| {
3799+
Error::Other(
3800+
"AsDateTime with Custom date_style requires custom_pattern".to_string(),
3801+
)
3802+
})?;
3803+
ar.write_string(pattern)?;
3804+
}
3805+
ar.write_string(time_zone)?;
3806+
ar.write_string(culture_name)?;
3807+
}
3808+
TextVariant::Transform {
3809+
source_text,
3810+
transform_type,
3811+
} => {
3812+
ar.write_i8(0xa)?;
3813+
source_text.write(ar)?;
3814+
ar.write_u8(*transform_type as u8)?;
3815+
}
35503816
TextVariant::StringTableEntry { table, key } => {
35513817
ar.write_i8(0xb)?;
35523818
ar.write_string(table)?;
35533819
write_string(ar, key)?;
35543820
}
3821+
TextVariant::TextGenerator {
3822+
generator_type_id,
3823+
generator_contents,
3824+
} => {
3825+
ar.write_i8(0xc)?;
3826+
ar.write_string(generator_type_id)?;
3827+
ar.write_u32::<LE>(generator_contents.len() as u32)?;
3828+
ar.write_all(generator_contents)?;
3829+
}
35553830
}
35563831
Ok(())
35573832
}

0 commit comments

Comments
 (0)