1use crate::ext::io::*;
3use adler::Adler32;
4use anyhow::Result;
5use emote_psb::PsbError;
6use emote_psb::PsbFile;
7use emote_psb::PsbReader;
8use emote_psb::PsbRefs;
9use emote_psb::PsbWriter;
10use emote_psb::VirtualPsb;
11use emote_psb::header::PsbHeader;
12use emote_psb::offsets::{PsbOffsets, PsbResourcesOffset, PsbStringOffset};
13use emote_psb::reader::MdfReader;
14use emote_psb::types::collection::*;
15use emote_psb::types::number::*;
16use emote_psb::types::reference::*;
17use emote_psb::types::string::*;
18use emote_psb::types::*;
19#[cfg(feature = "json")]
20use json::JsonValue;
21#[cfg(feature = "json")]
22use json::number::Number;
23use serde::ser::SerializeStruct;
24use serde::{Deserialize, Serialize};
25use std::cmp::PartialEq;
26use std::collections::{BTreeMap, HashMap};
27use std::io::{Read, Seek, SeekFrom, Write};
28use std::ops::{Index, IndexMut};
29
30#[cfg(feature = "json")]
31fn f32_to_number(x: f32) -> Number {
32 if !x.is_finite() {
33 return Number::from_parts(true, 0, 0);
34 }
35
36 let s = format!("{}", x);
37
38 if s.contains('e') || s.contains('E') {
39 let value = x as f64;
40 return if value >= 0.0 {
41 Number::from(value)
42 } else {
43 Number::from(value)
44 };
45 }
46
47 let positive = !s.starts_with('-');
48 let s = s.trim_start_matches('-');
49
50 let parts: Vec<&str> = s.split('.').collect();
51
52 if parts.len() == 1 {
53 let mantissa: u64 = parts[0].parse().unwrap_or(0);
54 Number::from_parts(positive, mantissa, 0)
55 } else {
56 let int_part = parts[0];
57 let frac_part = parts[1].trim_end_matches('0'); if frac_part.is_empty() {
60 let mantissa: u64 = int_part.parse().unwrap_or(0);
62 Number::from_parts(positive, mantissa, 0)
63 } else {
64 let combined = format!("{}{}", int_part, frac_part);
65 let mantissa: u64 = combined.parse().unwrap_or(0);
66 let exponent: i16 = -(frac_part.len() as i16);
67
68 Number::from_parts(positive, mantissa, exponent)
69 }
70 }
71}
72
73const NONE: PsbValueFixed = PsbValueFixed::None;
74
75#[derive(Debug, Serialize, Deserialize)]
76pub enum PsbValueFixed {
78 None,
80 Null,
82 Bool(bool),
84 Number(PsbNumber),
86 IntArray(PsbUintArray),
88 String(PsbString),
90 List(PsbListFixed),
92 Object(PsbObjectFixed),
94 Resource(PsbResourceRef),
96 ExtraResource(PsbExtraRef),
98 CompilerNumber,
100 CompilerString,
102 CompilerResource,
104 CompilerDecimal,
106 CompilerArray,
108 CompilerBool,
110 CompilerBinaryTree,
112}
113
114impl From<String> for PsbValueFixed {
115 fn from(value: String) -> Self {
116 PsbValueFixed::String(PsbString::from(value))
117 }
118}
119
120impl From<bool> for PsbValueFixed {
121 fn from(value: bool) -> Self {
122 PsbValueFixed::Bool(value)
123 }
124}
125
126impl From<i64> for PsbValueFixed {
127 fn from(value: i64) -> Self {
128 PsbValueFixed::Number(PsbNumber::Integer(value))
129 }
130}
131
132impl From<f64> for PsbValueFixed {
133 fn from(value: f64) -> Self {
134 PsbValueFixed::Number(PsbNumber::Double(value))
135 }
136}
137
138impl From<f32> for PsbValueFixed {
139 fn from(value: f32) -> Self {
140 PsbValueFixed::Number(PsbNumber::Float(value))
141 }
142}
143
144impl From<PsbObjectFixed> for PsbValueFixed {
145 fn from(value: PsbObjectFixed) -> Self {
146 PsbValueFixed::Object(value)
147 }
148}
149
150impl From<PsbListFixed> for PsbValueFixed {
151 fn from(value: PsbListFixed) -> Self {
152 PsbValueFixed::List(value)
153 }
154}
155
156impl From<&[PsbValueFixed]> for PsbValueFixed {
157 fn from(value: &[PsbValueFixed]) -> Self {
158 PsbValueFixed::List(PsbListFixed {
159 values: value.to_vec(),
160 })
161 }
162}
163
164impl PsbValueFixed {
165 pub fn to_psb(self, warn_on_none: bool) -> PsbValue {
167 match self {
168 PsbValueFixed::None => {
169 if warn_on_none {
170 eprintln!("Warning: PSB value is None, output script may broken.");
171 crate::COUNTER.inc_warning();
172 }
173 PsbValue::None
174 }
175 PsbValueFixed::Null => PsbValue::Null,
176 PsbValueFixed::Bool(b) => PsbValue::Bool(b),
177 PsbValueFixed::Number(n) => PsbValue::Number(n),
178 PsbValueFixed::IntArray(arr) => PsbValue::IntArray(arr),
179 PsbValueFixed::String(s) => PsbValue::String(s),
180 PsbValueFixed::List(l) => PsbValue::List(l.to_psb(warn_on_none)),
181 PsbValueFixed::Object(o) => PsbValue::Object(o.to_psb(warn_on_none)),
182 PsbValueFixed::Resource(r) => PsbValue::Resource(r),
183 PsbValueFixed::ExtraResource(er) => PsbValue::ExtraResource(er),
184 PsbValueFixed::CompilerNumber => PsbValue::CompilerNumber,
185 PsbValueFixed::CompilerString => PsbValue::CompilerString,
186 PsbValueFixed::CompilerResource => PsbValue::CompilerResource,
187 PsbValueFixed::CompilerDecimal => PsbValue::CompilerDecimal,
188 PsbValueFixed::CompilerArray => PsbValue::CompilerArray,
189 PsbValueFixed::CompilerBool => PsbValue::CompilerBool,
190 PsbValueFixed::CompilerBinaryTree => PsbValue::CompilerBinaryTree,
191 }
192 }
193
194 pub fn is_list(&self) -> bool {
196 matches!(self, PsbValueFixed::List(_))
197 }
198
199 pub fn is_object(&self) -> bool {
201 matches!(self, PsbValueFixed::Object(_))
202 }
203
204 pub fn is_string_or_null(&self) -> bool {
206 self.is_string() || self.is_null()
207 }
208
209 pub fn is_string(&self) -> bool {
211 matches!(self, PsbValueFixed::String(_))
212 }
213
214 pub fn is_none(&self) -> bool {
216 matches!(self, PsbValueFixed::None)
217 }
218
219 pub fn is_null(&self) -> bool {
221 matches!(self, PsbValueFixed::Null)
222 }
223
224 pub fn find_resource_key<'a>(
226 &'a self,
227 resource_id: u64,
228 now: Vec<&'a str>,
229 ) -> Option<Vec<&'a str>> {
230 match self {
231 PsbValueFixed::List(l) => l.find_resource_key(resource_id, now),
232 PsbValueFixed::Object(o) => o.find_resource_key(resource_id, now),
233 _ => None,
234 }
235 }
236
237 pub fn find_extra_resource_key<'a>(
239 &'a self,
240 extra_resource_id: u64,
241 now: Vec<&'a str>,
242 ) -> Option<Vec<&'a str>> {
243 match self {
244 PsbValueFixed::List(l) => l.find_extra_resource_key(extra_resource_id, now),
245 PsbValueFixed::Object(o) => o.find_extra_resource_key(extra_resource_id, now),
246 _ => None,
247 }
248 }
249
250 pub fn set_i64(&mut self, value: i64) {
252 *self = PsbValueFixed::Number(PsbNumber::Integer(value));
253 }
254
255 pub fn set_obj(&mut self, value: PsbObjectFixed) {
257 *self = PsbValueFixed::Object(value);
258 }
259
260 pub fn set_str(&mut self, value: &str) {
262 match self {
263 PsbValueFixed::String(s) => {
264 let s = s.string_mut();
265 s.clear();
266 s.push_str(value);
267 }
268 _ => {
269 *self = PsbValueFixed::String(PsbString::from(value.to_owned()));
270 }
271 }
272 }
273
274 pub fn set_string(&mut self, value: String) {
276 self.set_str(&value);
277 }
278
279 pub fn as_u8(&self) -> Option<u8> {
281 self.as_i64().map(|n| n.try_into().ok()).flatten()
282 }
283
284 pub fn as_u32(&self) -> Option<u32> {
286 self.as_i64().map(|n| n as u32)
287 }
288
289 pub fn as_i64(&self) -> Option<i64> {
291 match self {
292 PsbValueFixed::Number(n) => match n {
293 PsbNumber::Integer(n) => Some(*n),
294 PsbNumber::Double(n) if n.fract() == 0.0 => Some(*n as i64),
295 PsbNumber::Float(n) if n.fract() == 0.0 => Some(*n as i64),
296 _ => None,
297 },
298 _ => None,
299 }
300 }
301
302 pub fn as_str(&self) -> Option<&str> {
304 match self {
305 PsbValueFixed::String(s) => Some(s.string()),
306 _ => None,
307 }
308 }
309
310 pub fn len(&self) -> usize {
312 match self {
313 PsbValueFixed::List(l) => l.len(),
314 PsbValueFixed::Object(o) => o.values.len(),
315 _ => 0,
316 }
317 }
318
319 pub fn entries(&self) -> ObjectIter<'_> {
321 match self {
322 PsbValueFixed::Object(o) => o.iter(),
323 _ => ObjectIter::empty(),
324 }
325 }
326
327 pub fn entries_mut(&mut self) -> ObjectIterMut<'_> {
329 match self {
330 PsbValueFixed::Object(o) => o.iter_mut(),
331 _ => ObjectIterMut::empty(),
332 }
333 }
334
335 pub fn members(&self) -> ListIter<'_> {
337 match self {
338 PsbValueFixed::List(l) => l.iter(),
339 _ => ListIter::empty(),
340 }
341 }
342
343 pub fn members_mut(&mut self) -> ListIterMut<'_> {
345 match self {
346 PsbValueFixed::List(l) => l.iter_mut(),
347 _ => ListIterMut::empty(),
348 }
349 }
350
351 pub fn push_member<T: Into<PsbValueFixed>>(&mut self, value: T) {
353 match self {
354 PsbValueFixed::List(l) => {
355 l.values.push(value.into());
356 }
357 _ => {
358 *self = PsbValueFixed::List(PsbListFixed {
359 values: vec![value.into()],
360 });
361 }
362 }
363 }
364
365 pub fn clear_members(&mut self) {
367 match self {
368 PsbValueFixed::List(l) => {
369 l.clear();
370 }
371 _ => {
372 *self = PsbValueFixed::List(PsbListFixed { values: vec![] });
373 }
374 }
375 }
376
377 pub fn insert_member<T: Into<PsbValueFixed>>(&mut self, index: usize, value: T) {
380 match self {
381 PsbValueFixed::List(l) => {
382 l.insert(index, value);
383 }
384 _ => {
385 *self = PsbValueFixed::List(PsbListFixed {
386 values: vec![value.into()],
387 });
388 }
389 }
390 }
391
392 pub fn resource_id(&self) -> Option<u64> {
394 match self {
395 PsbValueFixed::Resource(r) => Some(r.resource_ref),
396 _ => None,
397 }
398 }
399
400 pub fn extra_resource_id(&self) -> Option<u64> {
402 match self {
403 PsbValueFixed::ExtraResource(er) => Some(er.extra_resource_ref),
404 _ => None,
405 }
406 }
407
408 #[cfg(feature = "json")]
410 pub fn to_json(&self) -> Option<JsonValue> {
411 match self {
412 PsbValueFixed::Null => Some(JsonValue::Null),
413 PsbValueFixed::Bool(b) => Some(JsonValue::Boolean(*b)),
414 PsbValueFixed::Number(n) => match n {
415 PsbNumber::Integer(i) => Some(JsonValue::Number((*i).into())),
416 PsbNumber::Float(f) => Some(JsonValue::Number(f32_to_number(*f))),
417 PsbNumber::Double(d) => Some(JsonValue::Number((*d).into())),
418 },
419 PsbValueFixed::String(s) => Some(JsonValue::String(s.string().to_owned())),
420 PsbValueFixed::Resource(s) => {
421 Some(JsonValue::String(format!("#resource#{}", s.resource_ref)))
422 }
423 PsbValueFixed::ExtraResource(s) => Some(JsonValue::String(format!(
424 "#resource@{}",
425 s.extra_resource_ref
426 ))),
427 PsbValueFixed::IntArray(arr) => Some(JsonValue::Array(
428 arr.iter().map(|n| JsonValue::Number((*n).into())).collect(),
429 )),
430 PsbValueFixed::List(l) => Some(l.to_json()),
431 PsbValueFixed::Object(o) => Some(o.to_json()),
432 _ => None,
433 }
434 }
435
436 #[cfg(feature = "json")]
438 pub fn from_json(obj: &JsonValue) -> Self {
439 match obj {
440 JsonValue::Null => PsbValueFixed::Null,
441 JsonValue::Boolean(b) => PsbValueFixed::Bool(*b),
442 JsonValue::Number(n) => {
443 let data: f64 = (*n).into();
444 if data.fract() == 0.0 {
445 PsbValueFixed::Number(PsbNumber::Integer(data as i64))
446 } else {
447 PsbValueFixed::Number(PsbNumber::Float(data as f32))
448 }
449 }
450 JsonValue::String(s) => {
451 if s.starts_with("#resource#") {
452 if let Ok(id) = s[10..].parse::<u64>() {
453 return PsbValueFixed::Resource(PsbResourceRef { resource_ref: id });
454 }
455 } else if s.starts_with("#resource@") {
456 if let Ok(id) = s[10..].parse::<u64>() {
457 return PsbValueFixed::ExtraResource(PsbExtraRef {
458 extra_resource_ref: id,
459 });
460 }
461 }
462 PsbValueFixed::String(PsbString::from(s.clone()))
463 }
464 JsonValue::Array(arr) => {
465 let values: Vec<PsbValueFixed> = arr.iter().map(PsbValueFixed::from_json).collect();
466 PsbValueFixed::List(PsbListFixed { values })
467 }
468 JsonValue::Object(obj) => {
469 let mut values = BTreeMap::new();
470 for (key, value) in obj.iter() {
471 values.insert(key.to_owned(), PsbValueFixed::from_json(value));
472 }
473 PsbValueFixed::Object(PsbObjectFixed { values })
474 }
475 JsonValue::Short(n) => {
476 let s = n.as_str();
477 if s.starts_with("#resource#") {
478 if let Ok(id) = s[10..].parse::<u64>() {
479 return PsbValueFixed::Resource(PsbResourceRef { resource_ref: id });
480 }
481 } else if s.starts_with("#resource@") {
482 if let Ok(id) = s[10..].parse::<u64>() {
483 return PsbValueFixed::ExtraResource(PsbExtraRef {
484 extra_resource_ref: id,
485 });
486 }
487 }
488 PsbValueFixed::String(PsbString::from(s.to_owned()))
489 }
490 }
491 }
492}
493
494impl Index<usize> for PsbValueFixed {
495 type Output = PsbValueFixed;
496
497 fn index(&self, index: usize) -> &Self::Output {
498 match self {
499 PsbValueFixed::List(l) => &l[index],
500 _ => &NONE,
501 }
502 }
503}
504
505impl IndexMut<usize> for PsbValueFixed {
506 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
507 match self {
508 PsbValueFixed::List(l) => {
509 if index < l.values.len() {
510 &mut l.values[index]
511 } else {
512 l.values.push(NONE);
513 l.values.last_mut().unwrap()
514 }
515 }
516 _ => {
517 *self = PsbValueFixed::List(PsbListFixed { values: vec![NONE] });
518 self.index_mut(0)
519 }
520 }
521 }
522}
523
524impl<'a> Index<&'a str> for PsbValueFixed {
525 type Output = PsbValueFixed;
526
527 fn index(&self, index: &'a str) -> &Self::Output {
528 match self {
529 PsbValueFixed::Object(o) => &o[index],
530 _ => &NONE,
531 }
532 }
533}
534
535impl<'a> Index<&'a String> for PsbValueFixed {
536 type Output = PsbValueFixed;
537
538 fn index(&self, index: &'a String) -> &Self::Output {
539 self.index(index.as_str())
540 }
541}
542
543impl Index<String> for PsbValueFixed {
544 type Output = PsbValueFixed;
545
546 fn index(&self, index: String) -> &Self::Output {
547 self.index(index.as_str())
548 }
549}
550
551impl IndexMut<&str> for PsbValueFixed {
552 fn index_mut(&mut self, index: &str) -> &mut Self::Output {
553 match self {
554 PsbValueFixed::Object(o) => o.index_mut(index),
555 _ => {
556 *self = PsbValueFixed::Object(PsbObjectFixed {
557 values: BTreeMap::new(),
558 });
559 self.index_mut(index)
560 }
561 }
562 }
563}
564
565impl IndexMut<&String> for PsbValueFixed {
566 fn index_mut(&mut self, index: &String) -> &mut Self::Output {
567 self.index_mut(index.as_str())
568 }
569}
570
571impl IndexMut<String> for PsbValueFixed {
572 fn index_mut(&mut self, index: String) -> &mut Self::Output {
573 self.index_mut(index.as_str())
574 }
575}
576
577impl Clone for PsbValueFixed {
578 fn clone(&self) -> Self {
579 match self {
580 PsbValueFixed::None => PsbValueFixed::None,
581 PsbValueFixed::Null => PsbValueFixed::Null,
582 PsbValueFixed::Bool(b) => PsbValueFixed::Bool(*b),
583 PsbValueFixed::Number(n) => PsbValueFixed::Number(n.clone()),
584 PsbValueFixed::IntArray(arr) => PsbValueFixed::IntArray(arr.clone()),
585 PsbValueFixed::String(s) => PsbValueFixed::String(PsbString::from(s.string().clone())),
586 PsbValueFixed::List(l) => PsbValueFixed::List(l.clone()),
587 PsbValueFixed::Object(o) => PsbValueFixed::Object(o.clone()),
588 PsbValueFixed::Resource(r) => PsbValueFixed::Resource(r.clone()),
589 PsbValueFixed::ExtraResource(er) => PsbValueFixed::ExtraResource(er.clone()),
590 PsbValueFixed::CompilerNumber => PsbValueFixed::CompilerNumber,
591 PsbValueFixed::CompilerString => PsbValueFixed::CompilerString,
592 PsbValueFixed::CompilerResource => PsbValueFixed::CompilerResource,
593 PsbValueFixed::CompilerDecimal => PsbValueFixed::CompilerDecimal,
594 PsbValueFixed::CompilerArray => PsbValueFixed::CompilerArray,
595 PsbValueFixed::CompilerBool => PsbValueFixed::CompilerBool,
596 PsbValueFixed::CompilerBinaryTree => PsbValueFixed::CompilerBinaryTree,
597 }
598 }
599}
600
601impl PartialEq<String> for PsbValueFixed {
602 fn eq(&self, other: &String) -> bool {
603 self == other.as_str()
604 }
605}
606
607impl PartialEq<str> for PsbValueFixed {
608 fn eq(&self, other: &str) -> bool {
609 match self {
610 PsbValueFixed::String(s) => s.string() == other,
611 _ => false,
612 }
613 }
614}
615
616impl<'a> PartialEq<&'a str> for PsbValueFixed {
617 fn eq(&self, other: &&'a str) -> bool {
618 self == *other
619 }
620}
621
622pub trait PsbValueExt {
624 fn to_psb_fixed(self) -> PsbValueFixed;
626}
627
628impl PsbValueExt for PsbValue {
629 fn to_psb_fixed(self) -> PsbValueFixed {
630 match self {
631 PsbValue::None => PsbValueFixed::None,
632 PsbValue::Null => PsbValueFixed::Null,
633 PsbValue::Bool(b) => PsbValueFixed::Bool(b),
634 PsbValue::Number(n) => PsbValueFixed::Number(n),
635 PsbValue::IntArray(arr) => PsbValueFixed::IntArray(arr),
636 PsbValue::String(s) => PsbValueFixed::String(s),
637 PsbValue::List(l) => PsbValueFixed::List(PsbList::to_psb_fixed(l)),
638 PsbValue::Object(o) => PsbValueFixed::Object(PsbObject::to_psb_fixed(o)),
639 PsbValue::Resource(r) => PsbValueFixed::Resource(r),
640 PsbValue::ExtraResource(er) => PsbValueFixed::ExtraResource(er),
641 PsbValue::CompilerNumber => PsbValueFixed::CompilerNumber,
642 PsbValue::CompilerString => PsbValueFixed::CompilerString,
643 PsbValue::CompilerResource => PsbValueFixed::CompilerResource,
644 PsbValue::CompilerDecimal => PsbValueFixed::CompilerDecimal,
645 PsbValue::CompilerArray => PsbValueFixed::CompilerArray,
646 PsbValue::CompilerBool => PsbValueFixed::CompilerBool,
647 PsbValue::CompilerBinaryTree => PsbValueFixed::CompilerBinaryTree,
648 }
649 }
650}
651
652#[derive(Clone, Debug, Serialize, Deserialize)]
653#[serde(transparent)]
654pub struct PsbListFixed {
656 pub values: Vec<PsbValueFixed>,
658}
659
660impl PsbListFixed {
661 pub fn new() -> Self {
662 PsbListFixed { values: vec![] }
663 }
664
665 pub fn to_psb(self, warn_on_none: bool) -> PsbList {
667 let v: Vec<_> = self
668 .values
669 .into_iter()
670 .map(|v| v.to_psb(warn_on_none))
671 .collect();
672 PsbList::from(v)
673 }
674
675 pub fn find_resource_key<'a>(
677 &'a self,
678 resource_id: u64,
679 now: Vec<&'a str>,
680 ) -> Option<Vec<&'a str>> {
681 for value in &self.values {
682 if let Some(key) = value.find_resource_key(resource_id, now.clone()) {
683 return Some(key);
684 }
685 }
686 None
687 }
688
689 pub fn find_extra_resource_key<'a>(
691 &'a self,
692 extra_resource_id: u64,
693 now: Vec<&'a str>,
694 ) -> Option<Vec<&'a str>> {
695 for value in &self.values {
696 if let Some(key) = value.find_extra_resource_key(extra_resource_id, now.clone()) {
697 return Some(key);
698 }
699 }
700 None
701 }
702
703 pub fn iter(&self) -> ListIter<'_> {
705 ListIter {
706 inner: self.values.iter(),
707 }
708 }
709
710 pub fn iter_mut(&mut self) -> ListIterMut<'_> {
712 ListIterMut {
713 inner: self.values.iter_mut(),
714 }
715 }
716
717 pub fn values(&self) -> &Vec<PsbValueFixed> {
719 &self.values
720 }
721
722 pub fn len(&self) -> usize {
724 self.values.len()
725 }
726
727 pub fn clear(&mut self) {
729 self.values.clear();
730 }
731
732 pub fn insert<V: Into<PsbValueFixed>>(&mut self, index: usize, value: V) {
735 if index <= self.values.len() {
736 self.values.insert(index, value.into());
737 } else {
738 self.values.push(value.into());
739 }
740 }
741
742 #[cfg(feature = "json")]
744 pub fn to_json(&self) -> JsonValue {
745 let data: Vec<_> = self.values.iter().filter_map(|v| v.to_json()).collect();
746 JsonValue::Array(data)
747 }
748}
749
750impl Index<usize> for PsbListFixed {
751 type Output = PsbValueFixed;
752
753 fn index(&self, index: usize) -> &Self::Output {
754 self.values.get(index).unwrap_or(&NONE)
755 }
756}
757
758impl IndexMut<usize> for PsbListFixed {
759 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
760 if index < self.values.len() {
761 &mut self.values[index]
762 } else {
763 self.values.push(NONE);
764 self.values.last_mut().unwrap()
765 }
766 }
767}
768
769pub struct ListIter<'a> {
771 inner: std::slice::Iter<'a, PsbValueFixed>,
772}
773
774impl<'a> ListIter<'a> {
775 pub fn empty() -> Self {
777 ListIter {
778 inner: Default::default(),
779 }
780 }
781}
782
783impl<'a> Iterator for ListIter<'a> {
784 type Item = &'a PsbValueFixed;
785
786 #[inline(always)]
787 fn next(&mut self) -> Option<Self::Item> {
788 self.inner.next()
789 }
790}
791
792impl<'a> ExactSizeIterator for ListIter<'a> {
793 fn len(&self) -> usize {
794 self.inner.len()
795 }
796}
797
798impl<'a> DoubleEndedIterator for ListIter<'a> {
799 #[inline(always)]
800 fn next_back(&mut self) -> Option<Self::Item> {
801 self.inner.next_back()
802 }
803}
804
805pub struct ListIterMut<'a> {
807 inner: std::slice::IterMut<'a, PsbValueFixed>,
808}
809
810impl<'a> ListIterMut<'a> {
811 pub fn empty() -> Self {
813 ListIterMut {
814 inner: Default::default(),
815 }
816 }
817}
818
819impl<'a> Iterator for ListIterMut<'a> {
820 type Item = &'a mut PsbValueFixed;
821
822 #[inline(always)]
823 fn next(&mut self) -> Option<Self::Item> {
824 self.inner.next()
825 }
826}
827
828impl<'a> ExactSizeIterator for ListIterMut<'a> {
829 fn len(&self) -> usize {
830 self.inner.len()
831 }
832}
833
834impl<'a> DoubleEndedIterator for ListIterMut<'a> {
835 #[inline(always)]
836 fn next_back(&mut self) -> Option<Self::Item> {
837 self.inner.next_back()
838 }
839}
840
841pub trait PsbListExt {
843 fn to_psb_fixed(self) -> PsbListFixed;
845}
846
847impl PsbListExt for PsbList {
848 fn to_psb_fixed(self) -> PsbListFixed {
849 let values: Vec<_> = self
850 .unwrap()
851 .into_iter()
852 .map(PsbValue::to_psb_fixed)
853 .collect();
854 PsbListFixed { values }
855 }
856}
857
858#[derive(Clone, Debug, Serialize, Deserialize)]
859#[serde(transparent)]
860pub struct PsbObjectFixed {
862 pub values: BTreeMap<String, PsbValueFixed>,
864}
865
866impl PsbObjectFixed {
867 pub fn new() -> Self {
868 Self {
869 values: BTreeMap::new(),
870 }
871 }
872
873 pub fn to_psb(self, warn_on_none: bool) -> PsbObject {
875 let mut hash_map = HashMap::new();
876 for (key, value) in self.values {
877 hash_map.insert(key, value.to_psb(warn_on_none));
878 }
879 PsbObject::from(hash_map)
880 }
881
882 pub fn get_value(&self, key: &str) -> Option<&PsbValueFixed> {
884 self.values.get(key)
885 }
886
887 pub fn find_resource_key<'a>(
889 &'a self,
890 resource_id: u64,
891 now: Vec<&'a str>,
892 ) -> Option<Vec<&'a str>> {
893 for (key, value) in &self.values {
894 let mut now = now.clone();
895 now.push(key);
896 if let Some(id) = value.resource_id() {
897 if id == resource_id {
898 return Some(now);
899 }
900 }
901 if let Some(key) = value.find_resource_key(resource_id, now) {
902 return Some(key);
903 }
904 }
905 None
906 }
907
908 pub fn find_extra_resource_key<'a>(
910 &'a self,
911 extra_resource_id: u64,
912 now: Vec<&'a str>,
913 ) -> Option<Vec<&'a str>> {
914 for (key, value) in &self.values {
915 let mut now = now.clone();
916 now.push(key);
917 if let Some(id) = value.extra_resource_id() {
918 if id == extra_resource_id {
919 return Some(now);
920 }
921 }
922 if let Some(key) = value.find_extra_resource_key(extra_resource_id, now) {
923 return Some(key);
924 }
925 }
926 None
927 }
928
929 pub fn iter(&self) -> ObjectIter<'_> {
931 ObjectIter {
932 inner: self.values.iter(),
933 }
934 }
935
936 pub fn iter_mut(&mut self) -> ObjectIterMut<'_> {
938 ObjectIterMut {
939 inner: self.values.iter_mut(),
940 }
941 }
942
943 #[cfg(feature = "json")]
945 pub fn to_json(&self) -> JsonValue {
946 let mut obj = json::object::Object::new();
947 for (key, value) in &self.values {
948 if let Some(json_value) = value.to_json() {
949 obj.insert(key, json_value);
950 }
951 }
952 JsonValue::Object(obj)
953 }
954
955 #[cfg(feature = "json")]
957 pub fn from_json(obj: &JsonValue) -> Self {
958 let mut values = BTreeMap::new();
959 for (key, value) in obj.entries() {
960 values.insert(key.to_owned(), PsbValueFixed::from_json(value));
961 }
962 PsbObjectFixed { values }
963 }
964}
965
966impl<'a> Index<&'a str> for PsbObjectFixed {
967 type Output = PsbValueFixed;
968
969 fn index(&self, index: &'a str) -> &Self::Output {
970 self.values.get(index).unwrap_or(&NONE)
971 }
972}
973
974impl<'a> Index<&'a String> for PsbObjectFixed {
975 type Output = PsbValueFixed;
976
977 fn index(&self, index: &'a String) -> &Self::Output {
978 self.index(index.as_str())
979 }
980}
981
982impl Index<String> for PsbObjectFixed {
983 type Output = PsbValueFixed;
984
985 fn index(&self, index: String) -> &Self::Output {
986 self.index(index.as_str())
987 }
988}
989
990impl<'a> IndexMut<&'a str> for PsbObjectFixed {
991 fn index_mut(&mut self, index: &'a str) -> &mut Self::Output {
992 self.values.entry(index.to_string()).or_insert(NONE)
993 }
994}
995
996impl<'a> IndexMut<&'a String> for PsbObjectFixed {
997 fn index_mut(&mut self, index: &'a String) -> &mut Self::Output {
998 self.index_mut(index.as_str())
999 }
1000}
1001
1002impl IndexMut<String> for PsbObjectFixed {
1003 fn index_mut(&mut self, index: String) -> &mut Self::Output {
1004 self.values.entry(index).or_insert(NONE)
1005 }
1006}
1007
1008pub trait PsbObjectExt {
1010 fn to_psb_fixed(self) -> PsbObjectFixed;
1012}
1013
1014impl PsbObjectExt for PsbObject {
1015 fn to_psb_fixed(self) -> PsbObjectFixed {
1016 let mut hash_map = BTreeMap::new();
1017 for (key, value) in self.unwrap() {
1018 hash_map.insert(key, PsbValue::to_psb_fixed(value));
1019 }
1020 PsbObjectFixed { values: hash_map }
1021 }
1022}
1023
1024pub struct ObjectIter<'a> {
1026 inner: std::collections::btree_map::Iter<'a, String, PsbValueFixed>,
1027}
1028
1029impl<'a> ObjectIter<'a> {
1030 pub fn empty() -> Self {
1032 ObjectIter {
1033 inner: Default::default(),
1034 }
1035 }
1036}
1037
1038impl<'a> Iterator for ObjectIter<'a> {
1039 type Item = (&'a String, &'a PsbValueFixed);
1040
1041 #[inline(always)]
1042 fn next(&mut self) -> Option<Self::Item> {
1043 self.inner.next()
1044 }
1045}
1046
1047impl<'a> ExactSizeIterator for ObjectIter<'a> {
1048 fn len(&self) -> usize {
1049 self.inner.len()
1050 }
1051}
1052
1053impl<'a> DoubleEndedIterator for ObjectIter<'a> {
1054 #[inline(always)]
1055 fn next_back(&mut self) -> Option<Self::Item> {
1056 self.inner.next_back()
1057 }
1058}
1059
1060pub struct ObjectIterMut<'a> {
1062 inner: std::collections::btree_map::IterMut<'a, String, PsbValueFixed>,
1063}
1064
1065impl<'a> ObjectIterMut<'a> {
1066 pub fn empty() -> Self {
1068 ObjectIterMut {
1069 inner: Default::default(),
1070 }
1071 }
1072}
1073
1074impl<'a> Iterator for ObjectIterMut<'a> {
1075 type Item = (&'a String, &'a mut PsbValueFixed);
1076
1077 #[inline(always)]
1078 fn next(&mut self) -> Option<Self::Item> {
1079 self.inner.next()
1080 }
1081}
1082
1083impl<'a> ExactSizeIterator for ObjectIterMut<'a> {
1084 fn len(&self) -> usize {
1085 self.inner.len()
1086 }
1087}
1088
1089impl<'a> DoubleEndedIterator for ObjectIterMut<'a> {
1090 #[inline(always)]
1091 fn next_back(&mut self) -> Option<Self::Item> {
1092 self.inner.next_back()
1093 }
1094}
1095
1096#[derive(Clone, Debug)]
1098pub struct VirtualPsbFixed {
1099 header: PsbHeader,
1100 resources: Vec<Vec<u8>>,
1101 extra: Vec<Vec<u8>>,
1102 root: PsbObjectFixed,
1103}
1104
1105impl Serialize for VirtualPsbFixed {
1106 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1107 where
1108 S: serde::Serializer,
1109 {
1110 let mut state = serializer.serialize_struct("VirtualPsbFixed", 3)?;
1111 state.serialize_field("version", &self.header.version)?;
1112 state.serialize_field("encryption", &self.header.encryption)?;
1113 state.serialize_field("data", &self.root)?;
1114 state.end()
1115 }
1116}
1117
1118#[derive(Deserialize)]
1119pub struct VirtualPsbFixedData {
1120 version: u16,
1121 encryption: u16,
1122 data: PsbObjectFixed,
1123}
1124
1125impl VirtualPsbFixed {
1126 pub fn new(
1128 header: PsbHeader,
1129 resources: Vec<Vec<u8>>,
1130 extra: Vec<Vec<u8>>,
1131 root: PsbObjectFixed,
1132 ) -> Self {
1133 Self {
1134 header,
1135 resources,
1136 extra,
1137 root,
1138 }
1139 }
1140
1141 pub fn header(&self) -> PsbHeader {
1143 self.header
1144 }
1145
1146 pub fn header_mut(&mut self) -> &mut PsbHeader {
1148 &mut self.header
1149 }
1150
1151 pub fn resources(&self) -> &Vec<Vec<u8>> {
1153 &self.resources
1154 }
1155
1156 pub fn resources_mut(&mut self) -> &mut Vec<Vec<u8>> {
1158 &mut self.resources
1159 }
1160
1161 pub fn extra(&self) -> &Vec<Vec<u8>> {
1163 &self.extra
1164 }
1165
1166 pub fn extra_mut(&mut self) -> &mut Vec<Vec<u8>> {
1168 &mut self.extra
1169 }
1170
1171 pub fn root(&self) -> &PsbObjectFixed {
1173 &self.root
1174 }
1175
1176 pub fn root_mut(&mut self) -> &mut PsbObjectFixed {
1178 &mut self.root
1179 }
1180
1181 pub fn set_root(&mut self, root: PsbObjectFixed) {
1183 self.root = root;
1184 }
1185
1186 pub fn unwrap(self) -> (PsbHeader, Vec<Vec<u8>>, Vec<Vec<u8>>, PsbObjectFixed) {
1188 (self.header, self.resources, self.extra, self.root)
1189 }
1190
1191 pub fn to_psb(self, warn_on_none: bool) -> VirtualPsb {
1193 let (header, resources, extra, root) = self.unwrap();
1194 VirtualPsb::new(header, resources, extra, root.to_psb(warn_on_none))
1195 }
1196
1197 #[cfg(feature = "json")]
1199 pub fn from_json(&mut self, obj: &JsonValue) -> Result<(), anyhow::Error> {
1200 let version = obj["version"]
1201 .as_u16()
1202 .ok_or_else(|| anyhow::anyhow!("Invalid PSB version"))?;
1203 let encryption = obj["encryption"]
1204 .as_u16()
1205 .ok_or_else(|| anyhow::anyhow!("Invalid PSB encryption"))?;
1206 self.header.version = version;
1207 self.header.encryption = encryption;
1208 self.root = PsbObjectFixed::from_json(&obj["data"]);
1209 Ok(())
1210 }
1211
1212 #[cfg(feature = "json")]
1213 pub fn with_json(obj: &JsonValue) -> Result<Self, anyhow::Error> {
1215 let version = obj["version"]
1216 .as_u16()
1217 .ok_or_else(|| anyhow::anyhow!("Invalid PSB version"))?;
1218 let encryption = obj["encryption"]
1219 .as_u16()
1220 .ok_or_else(|| anyhow::anyhow!("Invalid PSB encryption"))?;
1221 let root = PsbObjectFixed::from_json(&obj["data"]);
1222 Ok(Self {
1223 header: PsbHeader {
1224 version,
1225 encryption,
1226 },
1227 resources: Vec::new(),
1228 extra: Vec::new(),
1229 root,
1230 })
1231 }
1232
1233 pub fn set_data(&mut self, data: VirtualPsbFixedData) {
1234 self.header.version = data.version;
1235 self.header.encryption = data.encryption;
1236 self.root = data.data;
1237 }
1238
1239 #[cfg(feature = "json")]
1241 pub fn to_json(&self) -> JsonValue {
1242 json::object! {
1243 "version": self.header.version,
1244 "encryption": self.header.encryption,
1245 "data": self.root.to_json(),
1246 }
1247 }
1248}
1249
1250pub trait VirtualPsbExt {
1252 fn to_psb_fixed(self) -> VirtualPsbFixed;
1254}
1255
1256impl VirtualPsbExt for VirtualPsb {
1257 fn to_psb_fixed(self) -> VirtualPsbFixed {
1258 let (header, resources, extra, root) = self.unwrap();
1259 VirtualPsbFixed::new(header, resources, extra, root.to_psb_fixed())
1260 }
1261}
1262
1263pub trait PsbWriterExt {
1265 fn finish_v4<T: Write + Seek>(self, stream: T) -> std::result::Result<u64, PsbError>;
1267}
1268
1269impl PsbWriterExt for VirtualPsb {
1270 fn finish_v4<T: Write + Seek>(self, mut stream: T) -> std::result::Result<u64, PsbError> {
1271 let file_start = stream.seek(SeekFrom::Current(0))?;
1272
1273 let (header, resources, extra, root) = self.unwrap();
1274
1275 stream.write_u32(PSB_SIGNATURE)?;
1276 header.write_bytes(&mut stream)?;
1277
1278 let offsets_end_pos = stream.seek(SeekFrom::Current(0))? - file_start;
1279 stream.write_u32(0)?;
1280
1281 let offset_start_pos = stream.seek(SeekFrom::Current(0))? - file_start;
1282 let mut offsets = PsbOffsets::default();
1283
1284 offsets.write_bytes(header.version, &mut stream)?;
1285 let offsets_end = stream.seek(SeekFrom::Current(0))? - file_start;
1286
1287 let refs = {
1288 let mut names = Vec::new();
1289 let mut strings = Vec::new();
1290
1291 root.collect_names(&mut names);
1292 root.collect_strings(&mut strings);
1293
1294 names.sort();
1295 strings.sort();
1296
1297 PsbRefs::new(names, strings)
1298 };
1299
1300 offsets.name_offset = (stream.seek(SeekFrom::Current(0))? - file_start) as u32;
1301 PsbWriter::write_names(refs.names(), &mut stream)?;
1302
1303 offsets.entry_point = (stream.seek(SeekFrom::Current(0))? - file_start) as u32;
1304 PsbValue::Object(root).write_bytes_refs(&mut stream, &refs)?;
1305
1306 let (_, string_offsets) = PsbWriter::write_strings(refs.strings(), &mut stream)?;
1307 offsets.strings = string_offsets;
1308
1309 if header.version > 3 {
1312 let (_, extra_offsets) = PsbWriter::write_resources(&extra, &mut stream)?;
1313 offsets.extra = Some(extra_offsets);
1314 }
1315
1316 let (_, res_offsets) = PsbWriter::write_resources(&resources, &mut stream)?;
1317 offsets.resources = res_offsets;
1318
1319 let file_end = stream.seek(SeekFrom::Current(0))?;
1320
1321 stream.seek(SeekFrom::Start(offsets_end_pos))?;
1322 stream.write_u32(offsets_end as u32)?;
1323
1324 if header.version > 2 {
1325 let mut adler = Adler32::new();
1326
1327 adler.write_slice(&(offset_start_pos as u32).to_le_bytes());
1328 adler.write_slice(&offsets.name_offset.to_le_bytes());
1329 adler.write_slice(&offsets.strings.offset_pos.to_le_bytes());
1330 adler.write_slice(&offsets.strings.data_pos.to_le_bytes());
1331 adler.write_slice(&offsets.resources.offset_pos.to_le_bytes());
1332 adler.write_slice(&offsets.resources.lengths_pos.to_le_bytes());
1333 adler.write_slice(&offsets.resources.data_pos.to_le_bytes());
1334 adler.write_slice(&offsets.entry_point.to_le_bytes());
1335
1336 offsets.checksum = Some(adler.checksum());
1337 }
1338
1339 stream.seek(SeekFrom::Start(offset_start_pos))?;
1340 offsets.write_bytes(header.version, &mut stream)?;
1341 stream.seek(SeekFrom::Start(file_end))?;
1342
1343 Ok(file_end - file_start)
1344 }
1345}
1346
1347pub trait PsbReaderExt {
1349 fn open_psb_v2<T: Read + Seek>(stream: T) -> Result<VirtualPsb>;
1351}
1352
1353const LZ4_SIGNATURE: u32 = 0x184D2204;
1354const PSB_SIGNATURE: u32 = emote_psb::PSB_SIGNATURE;
1355const MDF_SIGNATURE: u32 = emote_psb::PSB_MDF_SIGNATURE;
1356const PSB_TYPE_INTEGER_ARRAY_N: u8 = 0x0C;
1357const PSB_TYPE_STRING_N: u8 = 0x14;
1358const PSB_TYPE_RESOURCE_N: u8 = 0x18;
1359const PSB_TYPE_LIST: u8 = 0x20;
1360const PSB_TYPE_OBJECT: u8 = 0x21;
1361const PSB_TYPE_EXTRA_N: u8 = 0x21;
1362
1363fn is_psb_array_type(value: u8) -> bool {
1364 (PSB_TYPE_INTEGER_ARRAY_N + 1..=PSB_TYPE_INTEGER_ARRAY_N + 8).contains(&value)
1365}
1366
1367fn read_int_array<R: Read + Seek>(stream: &mut R) -> Result<Vec<u64>> {
1368 let (_, value) = PsbValue::from_bytes(stream)
1369 .map_err(|e| anyhow::anyhow!("Failed to read PSB array: {:?}", e))?;
1370 match value {
1371 PsbValue::IntArray(arr) => Ok(arr.unwrap()),
1372 _ => Err(anyhow::anyhow!("Expected PSB int array")),
1373 }
1374}
1375
1376fn skip_psb_value<R: Read + Seek>(stream: &mut R) -> Result<u64> {
1377 let start = stream.seek(SeekFrom::Current(0))?;
1378 let value_type = stream.read_u8()?;
1379 match value_type {
1380 PSB_TYPE_LIST => {
1381 let ref_offsets = read_int_array(stream)?;
1382 if ref_offsets.is_empty() {
1383 return Ok(stream.seek(SeekFrom::Current(0))? - start);
1384 }
1385 let mut max_end = 0_u64;
1386 let data_start = stream.seek(SeekFrom::Current(0))?;
1387 for offset in ref_offsets {
1388 stream.seek(SeekFrom::Start(data_start + offset))?;
1389 let read = skip_psb_value(stream)?;
1390 max_end = max_end.max(offset + read);
1391 }
1392 stream.seek(SeekFrom::Start(data_start + max_end))?;
1393 Ok(stream.seek(SeekFrom::Current(0))? - start)
1394 }
1395 PSB_TYPE_OBJECT => {
1396 let _ = read_int_array(stream)?;
1397 let ref_offsets = read_int_array(stream)?;
1398 if ref_offsets.is_empty() {
1399 return Ok(stream.seek(SeekFrom::Current(0))? - start);
1400 }
1401 let mut max_end = 0_u64;
1402 let data_start = stream.seek(SeekFrom::Current(0))?;
1403 for offset in ref_offsets {
1404 stream.seek(SeekFrom::Start(data_start + offset))?;
1405 let read = skip_psb_value(stream)?;
1406 max_end = max_end.max(offset + read);
1407 }
1408 stream.seek(SeekFrom::Start(data_start + max_end))?;
1409 Ok(stream.seek(SeekFrom::Current(0))? - start)
1410 }
1411 _ if (PSB_TYPE_STRING_N + 1..=PSB_TYPE_STRING_N + 4).contains(&value_type)
1413 || (PSB_TYPE_RESOURCE_N + 1..=PSB_TYPE_RESOURCE_N + 4).contains(&value_type)
1414 || (PSB_TYPE_EXTRA_N + 1..=PSB_TYPE_EXTRA_N + 4).contains(&value_type) =>
1415 {
1416 let n = if value_type <= PSB_TYPE_STRING_N + 4 {
1417 value_type - PSB_TYPE_STRING_N
1418 } else if value_type <= PSB_TYPE_RESOURCE_N + 4 {
1419 value_type - PSB_TYPE_RESOURCE_N
1420 } else {
1421 value_type - PSB_TYPE_EXTRA_N
1422 };
1423 stream.seek(SeekFrom::Current(n as i64))?;
1424 Ok(stream.seek(SeekFrom::Current(0))? - start)
1425 }
1426 _ => {
1427 stream.seek(SeekFrom::Start(start))?;
1428 let (read, _) = PsbValue::from_bytes(stream)
1429 .map_err(|e| anyhow::anyhow!("Failed to skip PSB value: {:?}", e))?;
1430 Ok(read)
1431 }
1432 }
1433}
1434
1435fn detect_name_pos(data: &[u8]) -> Option<usize> {
1436 if data.len() < 8 {
1437 return None;
1438 }
1439 let mut name_pos = None;
1440 for i in 0..(data.len() - 7) {
1441 if data[i] == 0x0D || data[i] == 0x0E {
1442 let offset1 = (data[i] - 0x0B) as usize;
1443 if i + offset1 < data.len() {
1444 if data[i + offset1] == 0x0E
1445 && i + 7 < data.len()
1446 && data[i + 4..i + 8] == [1, 0, 0, 0]
1447 {
1448 name_pos = Some(i);
1449 break;
1450 }
1451 if data[i + offset1] == 0x0D
1452 && i + offset1 + 2 < data.len()
1453 && data[i + offset1 + 1..i + offset1 + 3] == [1, 0]
1454 {
1455 name_pos = Some(i);
1456 break;
1457 }
1458 }
1459 }
1460 }
1461 name_pos
1462}
1463
1464fn load_psb_dullahan<R: Read + Seek>(mut stream: R) -> Result<VirtualPsb> {
1465 let mut probe = vec![0_u8; 1024];
1466 stream.seek(SeekFrom::Start(0))?;
1467 let probe_len = stream.read(&mut probe)?;
1468 probe.truncate(probe_len);
1469
1470 let name_pos = detect_name_pos(&probe)
1471 .ok_or_else(|| anyhow::anyhow!("Dullahan fallback: cannot find names segment"))?
1472 as u64;
1473
1474 let version = stream.peek_u16_at(4)?;
1475 let encryption = stream.peek_u16_at(6)?;
1476 let mut header = PsbHeader {
1477 version,
1478 encryption,
1479 };
1480
1481 stream.seek(SeekFrom::Start(name_pos))?;
1482 let (_, names) = PsbReader::read_names(&mut stream)
1483 .map_err(|e| anyhow::anyhow!("Dullahan fallback: failed to read names: {:?}", e))?;
1484
1485 let file_len = stream.stream_length()?;
1486 let mut entry_point = None;
1487 while stream.seek(SeekFrom::Current(0))? < file_len {
1488 let b = stream.read_u8()?;
1489 if b == PSB_TYPE_LIST || b == PSB_TYPE_OBJECT {
1490 entry_point = Some(stream.seek(SeekFrom::Current(-1))? as u32);
1491 break;
1492 }
1493 }
1494 let entry_point = entry_point
1495 .ok_or_else(|| anyhow::anyhow!("Dullahan fallback: cannot find root object/list"))?;
1496
1497 stream.seek(SeekFrom::Start(entry_point as u64))?;
1498 let _ = skip_psb_value(&mut stream)?;
1499
1500 let mut strings_offset_pos = None;
1501 while stream.seek(SeekFrom::Current(0))? < file_len {
1502 let b = stream.read_u8()?;
1503 if is_psb_array_type(b) {
1504 strings_offset_pos = Some(stream.seek(SeekFrom::Current(-1))? as u32);
1505 break;
1506 }
1507 }
1508 let strings_offset_pos = strings_offset_pos
1509 .ok_or_else(|| anyhow::anyhow!("Dullahan fallback: cannot find strings offset table"))?;
1510
1511 stream.seek(SeekFrom::Start(strings_offset_pos as u64))?;
1512 let string_offsets = read_int_array(&mut stream)?;
1513 let strings_data_pos = stream.seek(SeekFrom::Current(0))? as u32;
1514
1515 stream.seek(SeekFrom::Start(strings_offset_pos as u64))?;
1516 let (_, strings) = PsbReader::read_strings(strings_data_pos, &mut stream)
1517 .map_err(|e| anyhow::anyhow!("Dullahan fallback: failed to read strings: {:?}", e))?;
1518
1519 let mut strings_data_end = strings_data_pos as u64;
1520 for (idx, offset) in string_offsets.iter().enumerate() {
1521 if let Some(s) = strings.get(idx) {
1522 strings_data_end = strings_data_end
1523 .max(strings_data_pos as u64 + *offset + s.as_bytes().len() as u64 + 1);
1524 }
1525 }
1526
1527 stream.seek(SeekFrom::Start(strings_data_end.min(file_len)))?;
1528 let mut resource_array_start = None;
1529 while stream.seek(SeekFrom::Current(0))? < file_len {
1530 let b = stream.read_u8()?;
1531 if is_psb_array_type(b) {
1532 resource_array_start = Some(stream.seek(SeekFrom::Current(-1))? as u32);
1533 break;
1534 }
1535 }
1536
1537 let mut resources = PsbResourcesOffset::default();
1538 let mut extra: Option<PsbResourcesOffset> = None;
1539
1540 if let Some(pos1) = resource_array_start {
1541 stream.seek(SeekFrom::Start(pos1 as u64))?;
1542 let array1 = read_int_array(&mut stream)?;
1543 let pos2 = stream.seek(SeekFrom::Current(0))? as u32;
1544 let array2 = read_int_array(&mut stream)?;
1545
1546 let after_array2 = stream.seek(SeekFrom::Current(0))?;
1547 let mut probe_next = 0_u8;
1548 let mut has_next = false;
1549 if after_array2 < file_len {
1550 probe_next = stream.read_u8()?;
1551 stream.seek(SeekFrom::Current(-1))?;
1552 has_next = true;
1553 }
1554
1555 if has_next && (version >= 4 || is_psb_array_type(probe_next)) {
1556 header.version = 4;
1557 let mut extra_table = PsbResourcesOffset {
1558 offset_pos: pos1,
1559 lengths_pos: pos2,
1560 data_pos: after_array2 as u32,
1561 };
1562
1563 if !array1.is_empty() && !array2.is_empty() {
1564 let max_idx = array1
1565 .iter()
1566 .enumerate()
1567 .max_by_key(|(_, offset)| *offset)
1568 .map(|(idx, _)| idx)
1569 .unwrap_or(0);
1570 let should_be_len = array1[max_idx] + array2[max_idx];
1571 let detect_start = after_array2.saturating_add(should_be_len);
1572 let detect_end = (detect_start + 1024).min(file_len);
1573
1574 let mut found = false;
1575 let mut cursor = detect_start;
1576 while cursor < detect_end {
1577 stream.seek(SeekFrom::Start(cursor))?;
1578 let b = stream.read_u8()?;
1579 if !is_psb_array_type(b) {
1580 cursor += 1;
1581 continue;
1582 }
1583
1584 stream.seek(SeekFrom::Start(cursor))?;
1585 if read_int_array(&mut stream).is_ok() {
1586 let off_pos = cursor as u32;
1587 let len_pos = stream.seek(SeekFrom::Current(0))? as u32;
1588 if read_int_array(&mut stream).is_ok() {
1589 extra_table.data_pos = off_pos.saturating_sub(should_be_len as u32);
1590 resources.offset_pos = off_pos;
1591 resources.lengths_pos = len_pos;
1592 resources.data_pos = stream.seek(SeekFrom::Current(0))? as u32;
1593 found = true;
1594 break;
1595 }
1596 }
1597
1598 cursor += 1;
1599 }
1600
1601 if !found {
1602 return Err(anyhow::anyhow!(
1603 "Dullahan fallback: cannot find resource offset/length tables"
1604 ));
1605 }
1606 } else {
1607 stream.seek(SeekFrom::Start(after_array2))?;
1608 while stream.seek(SeekFrom::Current(0))? < file_len {
1609 let b = stream.read_u8()?;
1610 if is_psb_array_type(b) {
1611 stream.seek(SeekFrom::Current(-1))?;
1612 resources.offset_pos = stream.seek(SeekFrom::Current(0))? as u32;
1613 let _ = read_int_array(&mut stream)?;
1614 resources.lengths_pos = stream.seek(SeekFrom::Current(0))? as u32;
1615 let _ = read_int_array(&mut stream)?;
1616 resources.data_pos = stream.seek(SeekFrom::Current(0))? as u32;
1617 break;
1618 }
1619 }
1620 }
1621
1622 extra = Some(extra_table);
1623 } else {
1624 resources.offset_pos = pos1;
1625 resources.lengths_pos = pos2;
1626 resources.data_pos = after_array2 as u32;
1627 }
1628
1629 stream.seek(SeekFrom::Start(resources.offset_pos as u64))?;
1630 let chunk_offsets = read_int_array(&mut stream).unwrap_or_default();
1631 stream.seek(SeekFrom::Start(resources.lengths_pos as u64))?;
1632 let chunk_lengths = read_int_array(&mut stream).unwrap_or_default();
1633 if !chunk_offsets.is_empty() && !chunk_lengths.is_empty() {
1634 let current_pos = resources.data_pos as u64;
1635 if current_pos <= file_len {
1636 let remain_length = file_len - current_pos;
1637 let max_idx = chunk_offsets
1638 .iter()
1639 .enumerate()
1640 .max_by_key(|(_, offset)| *offset)
1641 .map(|(idx, _)| idx)
1642 .unwrap_or(0);
1643 let should_be_len = chunk_offsets[max_idx] + chunk_lengths[max_idx];
1644 let padding = remain_length.saturating_sub(should_be_len);
1645 resources.data_pos = current_pos.saturating_add(padding) as u32;
1646 }
1647 }
1648 }
1649
1650 let refs = PsbRefs::new(names, strings);
1651 let offsets = PsbOffsets {
1652 name_offset: name_pos as u32,
1653 strings: PsbStringOffset {
1654 offset_pos: strings_offset_pos,
1655 data_pos: strings_data_pos,
1656 },
1657 resources,
1658 entry_point,
1659 checksum: Some(0),
1660 extra,
1661 };
1662
1663 stream.seek(SeekFrom::Start(0))?;
1664 let mut file = PsbFile::new(header, refs, offsets, stream);
1665 file.load()
1666 .map_err(|e| anyhow::anyhow!("Dullahan fallback: failed to load PSB: {:?}", e))
1667}
1668
1669impl PsbReaderExt for PsbReader {
1670 fn open_psb_v2<T: Read + Seek>(mut stream: T) -> Result<VirtualPsb> {
1671 let signature = stream.peek_u32_at(0)?;
1672 if signature == LZ4_SIGNATURE {
1673 let mut decoder = lz4::Decoder::new(stream)?;
1674 let mut mem_stream = MemWriter::new();
1675 std::io::copy(&mut decoder, &mut mem_stream)?;
1676 return Self::open_psb_v2(MemReader::new(mem_stream.into_inner()));
1677 }
1678 if signature == MDF_SIGNATURE {
1679 let mut file = MdfReader::open_mdf(stream)
1680 .map_err(|e| anyhow::anyhow!("Failed to open MDF/PSB: {:?}", e))?;
1681 return file
1682 .load()
1683 .map_err(|e| anyhow::anyhow!("Failed to load MDF/PSB: {:?}", e));
1684 }
1685 if signature != PSB_SIGNATURE {
1686 return Err(anyhow::anyhow!("Failed to open PSB: invalid signature"));
1687 }
1688 let normal_file = PsbReader::open_psb(&mut stream);
1689 match normal_file {
1690 Ok(mut file) => file
1691 .load()
1692 .map_err(|e| anyhow::anyhow!("Failed to load PSB: {:?}", e)),
1693 Err(err) => {
1694 stream.seek(SeekFrom::Start(0))?;
1695 let encryption = stream.peek_u16_at(6).unwrap_or(0);
1696 if encryption != 0 {
1697 load_psb_dullahan(&mut stream).map_err(|fallback_err| {
1698 anyhow::anyhow!(
1699 "Failed to open PSB: {:?}; fallback failed: {}",
1700 err,
1701 fallback_err
1702 )
1703 })
1704 } else {
1705 Err(anyhow::anyhow!("Failed to open PSB: {:?}", err))
1706 }
1707 }
1708 }
1709 }
1710}
1711
1712#[cfg(feature = "json")]
1713#[test]
1714fn test_f32_to_json() {
1715 let num = PsbValueFixed::Number(PsbNumber::Float(3.03));
1716 let json_value = num.to_json().unwrap();
1717 assert_eq!(json_value.to_string(), "3.03");
1718 let num = PsbValueFixed::Number(PsbNumber::Double(3.03));
1719 let json_value = num.to_json().unwrap();
1720 assert_eq!(json_value.to_string(), "3.03");
1721}