• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PredatorCZ / RevilLib / 164

13 Nov 2025 11:19PM UTC coverage: 11.207% (+0.02%) from 11.187%
164

push

github

PredatorCZ
refactor mtf textures

0 of 114 new or added lines in 1 file covered. (0.0%)

802 existing lines in 3 files now uncovered.

757 of 6755 relevant lines covered (11.21%)

6709.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.26
/src/xfs.cpp
1
/*  Revil Format Library
2
    Copyright(C) 2021-2023 Lukas Cone
3

4
    This program is free software : you can redistribute it and / or modify
5
    it under the terms of the GNU General Public License as published by
6
    the Free Software Foundation, either version 3 of the License, or
7
    (at your option) any later version.
8

9
    This program is distributed in the hope that it will be useful,
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
12
    GNU General Public License for more details.
13

14
    You should have received a copy of the GNU General Public License
15
    along with this program.If not, see <https://www.gnu.org/licenses/>.
16
*/
17

18
#include "revil/xfs.hpp"
19
#include "pugixml.hpp"
20
#include "revil/hashreg.hpp"
21
#include "spike/io/binreader.hpp"
22
#include "spike/io/binwritter.hpp"
23
#include "spike/reflect/reflector.hpp"
24
#include "spike/reflect/reflector_xml.hpp"
25
#include "spike/type/bitfield.hpp"
26
#include "spike/type/matrix44.hpp"
27
#include "spike/type/vectors_simd.hpp"
28
#include <algorithm>
29
#include <deque>
30
#include <vector>
31

32
#include "shift_jis.inl"
33

34
// #define XFS_DEBUG
35

36
/*
37
lp pc: 4
38
lp ps3: 5
39
lp2 pc: 8
40
*/
41

42
using namespace revil;
43

44
struct XFSClassMember;
45

46
MAKE_ENUM(ENUMSCOPE(class XFSType : uint8, XFSType), //
1✔
47
          EMEMBER(invalid_),                         //
48
          EMEMBER(class_),                           //
49
          EMEMBER(classref_),                        //
50
          EMEMBER(bool_),                            //
51
          EMEMBER(u8_),                              //
52
          EMEMBER(u16_),                             //
53
          EMEMBER(u32_),                             //
54
          EMEMBER(u64_),                             //
55
          EMEMBER(s8_),                              //
56
          EMEMBER(s16_),                             //
57
          EMEMBER(s32_),                             //
58
          EMEMBER(s64_),                             //
59
          EMEMBER(f32_),                             //
60
          EMEMBERVAL(string_, 14),                   //
61
          EMEMBER(color_),                           //
62
          EMEMBER(point_),                           //
63
          EMEMBER(size_),                            //
64
          EMEMBER(rect_),                            // 8+ rectangle?
65
          EMEMBER(_matrix_),                         //
66
          EMEMBER(vector4_),                         //
67
          EMEMBER(_vector4_),                        // colour
68
          EMEMBERVAL(string2_, 32),                  //
69
          EMEMBERVAL(vector2_, 34),                  //
70
          EMEMBER(vector3_),                         //
71
          EMEMBERVAL(_resource_, 0x80)               // 8+, custom?
72
);
73

74
struct XFSSizeAndFlag {
75
  using Size = BitMemberDecl<0, 15>;
76
  using Unk = BitMemberDecl<1, 1>;
77
  using type = BitFieldType<uint16, Size, Unk>;
78
  type data;
79

80
  const type *operator->() const { return &data; }
81
};
82

83
struct XFSClassInfo {
84
  using NumMembers = BitMemberDecl<0, 15>;
85
  using Unk = BitMemberDecl<1, 17>;
86
  using type = BitFieldType<uint32, NumMembers, Unk>;
87
  type data;
88

89
  const type *operator->() const { return &data; }
90
};
91

92
struct XFSMeta {
93
  using Active = BitMemberDecl<0, 1>;
94
  using LayoutIndex = BitMemberDecl<1, 15>;
95
  using MetaIndex = BitMemberDecl<2, 16>;
96
  using type = BitFieldType<uint32, Active, LayoutIndex, MetaIndex>;
97
  type data;
98

99
  const type *operator->() const { return &data; }
100
};
101

102
struct XFSHeaderBase {
103
  uint32 id;
104
  uint16 version;
105
  uint16 unk; // class version?
106

UNCOV
107
  void SwapEndian() {
×
108
    FByteswapper(id);
×
109
    FByteswapper(version);
×
110
    FByteswapper(unk);
×
111
  }
112
};
113

114
struct XFSHeaderV1 : XFSHeaderBase {
115
  uint32 numLayouts;
116
  uint32 dataStart;
117

118
  void SwapEndian() {
UNCOV
119
    FByteswapper(numLayouts);
×
120
    FByteswapper(dataStart);
×
121
  }
122
};
123

124
struct XFSHeaderV2 : XFSHeaderBase {
125
  uint64 unk0; // num members/strings?
126
  uint32 numLayouts;
127
  uint32 dataStart;
128
};
129

UNCOV
130
template <class PadType> struct XFSClassMemberRaw {
×
131
  std::string memberName;
132
  XFSType type;
133
  uint8 flags; // alignment flags??
134
  XFSSizeAndFlag memberSize;
135
  PadType null[4];
136

UNCOV
137
  void Read(BinReaderRef_e rd) {
×
138
    uint32 memNameOffset;
UNCOV
139
    rd.Read(memNameOffset);
×
140
    rd.Read(type);
×
141
    rd.Read(flags);
×
142
    rd.Read(memberSize.data);
×
143
    rd.Read(null);
×
144
    rd.Push();
UNCOV
145
    rd.Seek(memNameOffset);
×
146
    rd.ReadString(memberName);
×
147
    memberName = sj2utf8(memberName);
×
148
    rd.Pop();
149
  }
UNCOV
150
};
×
151

UNCOV
152
template <class PtrType, bool PSN> struct XFSClassMemberV2 {
×
153
  std::string memberName;
×
154
  XFSType type;
×
155
  uint8 flags; // alignment flags??
×
156
  uint16 memberSize;
×
157
  PtrType null[4 * (PSN + 1)];
UNCOV
158

×
159
  void Read(BinReaderRef_e rd) {
×
160
    PtrType memNameOffset;
×
161
    rd.Read(memNameOffset);
162
    rd.Read(type);
UNCOV
163
    rd.Read(flags);
×
164
    rd.Read(memberSize);
UNCOV
165
    // Padding
×
166
    if constexpr (sizeof(PtrType) == 8) {
×
167
      rd.Skip(4);
×
168
    }
×
169
    rd.Read(null);
×
170
    rd.Push();
UNCOV
171
    rd.Seek(memNameOffset);
×
172
    rd.ReadString(memberName);
×
173
    memberName = sj2utf8(memberName);
×
174
    rd.Pop();
175
  }
176
};
177

UNCOV
178
template <class PadType> struct XFSClass {
×
179
  uint32 hash;
180
  XFSClassInfo info;
181
  std::vector<XFSClassMemberRaw<PadType>> members;
182

183
  void Read(BinReaderRef_e rd) {
184
    rd.Read(hash);
UNCOV
185
    rd.Read(info.data);
×
186
    rd.ReadContainer(members, info->Get<XFSClassInfo::NumMembers>());
UNCOV
187
  }
×
188
};
×
189

×
190
template <class PtrType, bool PSN> struct XFSClassV2 {
×
191
  uint32 hash;
192
  std::vector<XFSClassMemberV2<PtrType, PSN>> members;
193

194
  void Read(BinReaderRef_e rd) {
UNCOV
195
    rd.Read(hash);
×
196

UNCOV
197
    // Padding
×
198
    if constexpr (sizeof(PtrType) == 8) {
×
199
      rd.Skip(4);
×
200
    }
201

UNCOV
202
    rd.ReadContainer<PtrType>(members);
×
203
  }
UNCOV
204
};
×
205

×
206
struct XFSClassMember {
×
207
  std::string name;
×
208
  XFSType type;
209
  uint8 flags;
210
  uint16 size;
211

UNCOV
212
  XFSClassMember() = default;
×
213
  template <class pad_type>
UNCOV
214
  XFSClassMember(XFSClassMemberRaw<pad_type> &&raw)
×
215
      : name(std::move(raw.memberName)), type(raw.type), flags(raw.flags),
×
216
        size(raw.memberSize->template Get<XFSSizeAndFlag::Size>()) {
×
217
    if (raw.memberSize->template Get<XFSSizeAndFlag::Unk>()) {
218
      throw std::runtime_error("Some bullshit");
UNCOV
219
    }
×
220
  }
UNCOV
221

×
222
  template <class pad_type, bool psn>
×
223
  XFSClassMember(XFSClassMemberV2<pad_type, psn> &&raw)
×
224
      : name(std::move(raw.memberName)), type(raw.type), flags(raw.flags),
×
225
        size(raw.memberSize) {}
226
};
227

228
REFLECT(CLASS(XFSClassMember), MEMBER(name), MEMBER(type), MEMBER(flags));
UNCOV
229

×
230
struct XFSClassDesc {
UNCOV
231
  uint32 hash;
×
232
  std::string_view className;
×
233
  std::vector<XFSClassMember> members;
×
234

235
  XFSClassDesc() = default;
UNCOV
236
  template <class pad_type>
×
237
  XFSClassDesc(XFSClass<pad_type> &&raw) : hash(raw.hash) {
UNCOV
238
    members.reserve(raw.members.size());
×
239

×
240
    std::transform(std::make_move_iterator(raw.members.begin()),
×
241
                   std::make_move_iterator(raw.members.end()),
×
242
                   std::back_inserter(members),
243
                   [](auto &&item) { return std::move(item); });
244
  }
245

UNCOV
246
  template <class PtrType, bool PSN>
×
247
  XFSClassDesc(XFSClassV2<PtrType, PSN> &&raw) : hash(raw.hash) {
UNCOV
248
    members.reserve(raw.members.size());
×
249

×
250
    std::transform(std::make_move_iterator(raw.members.begin()),
×
251
                   std::make_move_iterator(raw.members.end()),
252
                   std::back_inserter(members),
UNCOV
253
                   [](auto &&item) { return std::move(item); });
×
254
  }
UNCOV
255

×
256
  void ToXML(pugi::xml_node node) const;
×
257
};
×
258

×
259
void XFSClassDesc::ToXML(pugi::xml_node node) const {
260
  auto cNode = node.append_child("class");
261

262
  if (className.empty()) {
UNCOV
263
    char buffer[0x10]{};
×
264
    snprintf(buffer, sizeof(buffer), "%X", hash);
UNCOV
265
    cNode.append_attribute("hash").set_value(buffer);
×
266
  } else {
×
267
    std::string resNme(className);
×
268
    cNode.append_attribute("name").set_value(resNme.c_str());
269
  }
270

271
  for (auto &m : members) {
UNCOV
272
    ReflectorWrap<const XFSClassMember> refl(m);
×
273
    auto mNode = cNode.append_child("member");
274
    ReflectorXMLUtil::Save(refl, mNode,
275
                           {ReflectorXMLUtil::Flags_StringAsAttribute});
276
  }
UNCOV
277
}
×
278

×
279
struct XFSDataResource {
×
280
  std::string type;
×
281
  std::string file;
UNCOV
282

×
283
  void Read(BinReaderRef_e rd) {
×
284
    uint8 numStrings;
×
285
    rd.Read(numStrings); // ctype?
×
286

UNCOV
287
    if (numStrings != 2) {
×
288
      throw std::logic_error("Unexpected number!");
×
289
    }
×
290

×
291
    rd.ReadString(type); // rtype?
292
    rd.ReadString(file); // path?
293
  }
UNCOV
294
};
×
295

296
struct XFSData {
297
  union TypeData {
UNCOV
298
    bool asBool;
×
299
    int8 asInt8;
×
300
    uint8 asUInt8;
301
    int16 asInt16;
302
    uint16 asUInt16;
303
    int32 asInt32;
304
    uint32 asUInt32;
305
    int64 asInt64;
UNCOV
306
    uint64 asUInt64;
×
307
    Vector2 asVector2;
UNCOV
308
    Vector asVector3;
×
309
    Vector4A16 asVector4;
×
310
    IVector4A16 asIVector4;
311
    IVector2 asIVector2;
312
    UIVector2 asUIVector2;
313
    IVector asIVector3;
314
    void *asPointer;
315
    UCVector4 asColor;
UNCOV
316
    float asFloat;
×
317
    double asDouble;
UNCOV
318
    char raw[sizeof(Vector4A16)];
×
319

×
320
    TypeData() { memset(raw, 0, sizeof(raw)); }
321
  };
322

323
  template <class type> type *AllocArray(size_t numItems) {
324
    const size_t allocSize = sizeof(type) * numItems;
325
    mustFree = Free_Free;
UNCOV
326
    auto value = malloc(allocSize);
×
327
    data.asPointer = value;
328
    return static_cast<type *>(value);
329
  }
UNCOV
330
  template <class type> type *AllocClass() {
×
331
    mustFree = Free_DeleteSingle;
332
    auto value = new type();
333
    data.asPointer = value;
334
    return value;
335
  }
336
  template <class type> type *AllocClasses(size_t numItems) {
337
    mustFree = Free_DeleteArray;
UNCOV
338
    auto value = new type[numItems]();
×
339
    data.asPointer = value;
×
340
    return value;
×
341
  }
×
342
  void SetString(std::string_view sw) {
×
343
    if (sw.size() < sizeof(data.raw)) {
344
      memcpy(data.raw, sw.data(), sw.size());
UNCOV
345
      stringInRaw = true;
×
346
    } else {
×
347
      memcpy(AllocArray<char>(sw.size() + 1), sw.data(), sw.size() + 1);
×
348
    }
×
349
  }
×
350

351
  const char *AsString() const {
UNCOV
352
    return stringInRaw ? data.raw : static_cast<const char *>(data.asPointer);
×
353
  }
×
354

×
355
  XFSData(XFSData &&o)
×
356
      : rtti(o.rtti), numItems(o.numItems), stringInRaw(o.stringInRaw),
×
357
        mustFree(o.mustFree), data(o.data) {
358
    o.mustFree = Free_None;
359
  }
360
  XFSData() = default;
UNCOV
361
  XFSData(const XFSData &) = delete;
×
362

×
363
  ~XFSData() {
×
364
    switch (mustFree) {
365
    case Free_Free:
366
      free(data.asPointer);
2✔
367
      break;
UNCOV
368
    case Free_DeleteSingle: {
×
369
      switch (rtti->type) {
370
      case XFSType::_resource_:
371
        delete static_cast<XFSDataResource *>(data.asPointer);
372
        break;
373
      case XFSType::_matrix_:
374
        delete static_cast<es::Matrix44 *>(data.asPointer);
UNCOV
375
        break;
×
376

×
377
      default:
UNCOV
378
        break;
×
379
      }
380
      break;
381
    }
382
    case Free_DeleteArray: {
UNCOV
383
      switch (rtti->type) {
×
384
      case XFSType::_resource_:
×
385
        delete[] static_cast<XFSDataResource *>(data.asPointer);
UNCOV
386
        break;
×
387
      case XFSType::_matrix_:
388
        delete[] static_cast<es::Matrix44 *>(data.asPointer);
389
        break;
390

UNCOV
391
      default:
×
392
        break;
×
393
      }
UNCOV
394
      break;
×
395
    }
396

397
    default:
398
      break;
399
    }
400
  }
UNCOV
401

×
402
  XFSClassMember *rtti = nullptr;
×
403
  uint32 numItems = 0;
UNCOV
404

×
405
private:
406
  bool stringInRaw = false;
407

408
  enum FreeType : uint8 {
UNCOV
409
    Free_None,
×
410
    Free_Free,
×
411
    Free_DeleteSingle,
UNCOV
412
    Free_DeleteArray,
×
413
  };
414
  FreeType mustFree = Free_None;
415

416
public:
UNCOV
417
  TypeData data;
×
418
};
×
419

UNCOV
420
struct XFSClassData {
×
421
  std::vector<XFSData> members;
422
  XFSClassDesc *rtti = nullptr;
423
};
424

UNCOV
425
class revil::XFSImpl {
×
426
public:
×
427
  std::vector<XFSClassDesc> rtti;
UNCOV
428
  std::deque<XFSClassData> dataStore;
×
429
  XFSClassData *root;
430

431
  template <class PtrType>
432
  void ReadData(BinReaderRef_e rd, XFSClassData **root = nullptr);
UNCOV
433
  void ToXML(const XFSClassData &item, pugi::xml_node node);
×
434
  void ToXML(pugi::xml_node node);
×
435
  void RTTIToXML(pugi::xml_node node);
UNCOV
436
  void Load(BinReaderRef_e rd, bool openEnded);
×
437
};
438

439
XFS::XFS() : pi(std::make_unique<XFSImpl>()) {}
440
XFS::~XFS() = default;
441

442
void XFS::Load(BinReaderRef_e rd, bool openEnded) { pi->Load(rd, openEnded); }
443

444
void XFS::ToXML(pugi::xml_node node) const { pi->ToXML(node); }
UNCOV
445

×
446
void XFS::RTTIToXML(pugi::xml_node node) const { pi->RTTIToXML(node); }
×
447

UNCOV
448
template <class PtrType>
×
449
void XFSImpl::ReadData(BinReaderRef_e rd, XFSClassData **root) {
×
450
  XFSMeta meta;
×
451
  rd.Read(meta.data);
×
452

UNCOV
453
  if (!meta->Get<XFSMeta::Active>()) {
×
454
    return;
×
455
  }
456

UNCOV
457
  PtrType chunkSize;
×
458
  const size_t strBegin = rd.Tell();
UNCOV
459
  rd.Read(chunkSize);
×
460

×
461
  auto &&desc = rtti.at(meta->Get<XFSMeta::LayoutIndex>());
462
  XFSClassData classData;
463
  classData.rtti = &desc;
464

UNCOV
465
  for (auto &d : desc.members) {
×
466
    XFSData cType;
467
    cType.rtti = &d;
468
    rd.Read(cType.numItems);
UNCOV
469

×
470
    if (cType.numItems == 1) {
471
      switch (d.type) {
472
      case XFSType::bool_:
UNCOV
473
      case XFSType::s8_:
×
474
      case XFSType::u8_:
×
475
        rd.Read(cType.data.asUInt8);
476
        break;
UNCOV
477
      case XFSType::s16_:
×
478
      case XFSType::u16_:
×
479
        rd.Read(cType.data.asUInt16);
480
        break;
481
      case XFSType::f32_:
482
      case XFSType::s32_:
483
      case XFSType::u32_:
484
        rd.Read(cType.data.asUInt32);
485
        break;
486
      case XFSType::s64_:
487
      case XFSType::u64_:
488
        rd.Read(cType.data.asUInt64);
489
        break;
490
      case XFSType::point_:
491
      case XFSType::size_:
492
      case XFSType::vector2_:
493
        rd.Read(cType.data.asVector2);
494
        break;
495
      case XFSType::vector3_:
496
        rd.Read(cType.data.asVector3);
497
        break;
498
      case XFSType::vector4_:
499
      case XFSType::_vector4_:
500
        rd.Read(cType.data.asVector4);
501
        break;
502
      case XFSType::rect_:
503
        rd.Read(cType.data.asIVector4);
504
        break;
505
      case XFSType::color_:
UNCOV
506
        rd.Read(cType.data.asColor);
×
507
        break;
508
      case XFSType::string_:
509
      case XFSType::string2_: {
UNCOV
510
        std::string temp;
×
511
        rd.ReadString(temp);
×
512
        cType.SetString(temp);
×
513
        break;
×
514
      }
515
      case XFSType::_matrix_:
UNCOV
516
        rd.Read(*cType.AllocClass<es::Matrix44>());
×
517
        break;
×
518
      case XFSType::class_:
×
519
      case XFSType::classref_:
×
520
        ReadData<PtrType>(
×
521
            rd, reinterpret_cast<XFSClassData **>(&cType.data.asPointer));
UNCOV
522
        break;
×
523
      case XFSType::_resource_:
×
524
        rd.Read(*cType.AllocClass<XFSDataResource>());
×
525
        break;
×
526
      default:
×
527
        throw std::runtime_error("Undefined type at: " +
UNCOV
528
                                 std::to_string(rd.Tell()));
×
529
      }
×
530
    } else {
×
531
      switch (d.type) {
×
532
      case XFSType::bool_:
×
533
      case XFSType::s8_:
UNCOV
534
      case XFSType::u8_: {
×
535
        char *adata = cType.AllocArray<char>(cType.numItems);
×
536
        rd.ReadBuffer(adata, cType.numItems);
×
537
        break;
×
538
      }
×
539
      case XFSType::s16_:
UNCOV
540
      case XFSType::u16_: {
×
541
        uint16 *adata = cType.AllocArray<uint16>(cType.numItems);
×
542
        for (size_t i = 0; i < cType.numItems; i++) {
×
543
          rd.Read(*adata++);
×
544
        }
UNCOV
545
        break;
×
546
      }
547
      case XFSType::f32_:
548
      case XFSType::s32_:
549
      case XFSType::u32_: {
UNCOV
550
        uint32 *adata = cType.AllocArray<uint32>(cType.numItems);
×
551
        for (size_t i = 0; i < cType.numItems; i++) {
552
          rd.Read(*adata++);
553
        }
UNCOV
554
        break;
×
555
      }
×
556
      case XFSType::s64_:
×
557
      case XFSType::u64_: {
UNCOV
558
        uint64 *adata = cType.AllocArray<uint64>(cType.numItems);
×
559
        for (size_t i = 0; i < cType.numItems; i++) {
560
          rd.Read(*adata++);
UNCOV
561
        }
×
562
        break;
×
563
      }
×
564
      case XFSType::point_:
×
565
      case XFSType::size_: {
×
566
        Vector2 *adata = cType.AllocArray<Vector2>(cType.numItems);
×
567
        for (size_t i = 0; i < cType.numItems; i++) {
×
568
          rd.Read(*adata++);
×
569
        }
×
570
        break;
UNCOV
571
      }
×
572
      case XFSType::vector3_: {
×
573
        Vector2 *adata = cType.AllocArray<Vector2>(cType.numItems);
574
        for (size_t i = 0; i < cType.numItems; i++) {
575
          rd.Read(*adata++);
576
        }
577
        break;
578
      }
579
      case XFSType::vector4_:
UNCOV
580
      case XFSType::_vector4_: {
×
581
        Vector4A16 *adata = cType.AllocArray<Vector4A16>(cType.numItems);
×
582
        for (size_t i = 0; i < cType.numItems; i++) {
×
583
          rd.Read(*adata++);
×
584
        }
UNCOV
585
        break;
×
586
      }
×
587
      case XFSType::color_: {
588
        const size_t alocSize = cType.numItems * sizeof(UCVector4);
589
        char *adata = cType.AllocArray<char>(alocSize);
590
        rd.ReadBuffer(adata, alocSize);
591
        break;
592
      }
593
      case XFSType::string_: {
594
        throw std::runtime_error("Array string!");
595
      }
596
      case XFSType::_matrix_: {
597
        es::Matrix44 *adata = cType.AllocClasses<es::Matrix44>(cType.numItems);
598
        for (size_t i = 0; i < cType.numItems; i++) {
599
          rd.Read(*adata++);
600
        }
601
        break;
602
      }
603
      case XFSType::class_:
604
      case XFSType::classref_: {
605
        auto adata = cType.AllocArray<XFSClassData *>(cType.numItems);
606
        for (size_t i = 0; i < cType.numItems; i++) {
607
          ReadData<PtrType>(rd, adata++);
608
        }
609
        break;
610
      }
611
      default:
612
        throw std::runtime_error("Undefined type at: " +
613
                                 std::to_string(rd.Tell()));
614
      }
615
    }
616

617
    classData.members.emplace_back(std::move(cType));
UNCOV
618
  }
×
619

620
  dataStore.emplace_back(std::move(classData));
621

622
  if (rd.Tell() != strBegin + chunkSize) {
UNCOV
623
    throw std::runtime_error("Chunk size mismatch!");
×
624
  }
625

626
  if (root) {
627
    *root = &dataStore.back();
628
  }
629
}
630

631
void XMLSetType(const XFSClassData &item, pugi::xml_node node) {
632
  auto attr = node.append_attribute("type");
633

634
  if (item.rtti->className.empty()) {
635
    char buffer[0x10];
636
    snprintf(buffer, sizeof(buffer), "h:%X", item.rtti->hash);
UNCOV
637
    attr.set_value(buffer);
×
638
    return;
×
639
  }
UNCOV
640

×
641
  std::string resNme(item.rtti->className);
UNCOV
642
  attr.set_value(resNme.c_str());
×
643
}
UNCOV
644

×
645
void XFSImpl::RTTIToXML(pugi::xml_node node) {
646
  for (auto &c : rtti) {
UNCOV
647
    c.ToXML(node);
×
648
  }
UNCOV
649
}
×
650

UNCOV
651
void XFSImpl::ToXML(const XFSClassData &item, pugi::xml_node node) {
×
652
  static const auto refEnum = GetReflectedEnum<XFSType>();
×
653

654
  for (auto &m : item.members) {
655
    auto name = [&] {
656
      const size_t numEns = refEnum->numMembers;
UNCOV
657

×
658
      for (size_t i = 0; i < numEns; i++) {
UNCOV
659
        if (refEnum->values[i] == static_cast<uint64>(m.rtti->type)) {
×
660
          return refEnum->names[i];
×
661
        }
×
662
      }
UNCOV
663

×
664
      return "__UNREGISTERED__";
UNCOV
665
    }();
×
666

×
667
    if (m.numItems > 1) {
UNCOV
668
      auto cNode = node.append_child("array");
×
669
      cNode.append_attribute("name").set_value(m.rtti->name.data());
×
670
      cNode.append_attribute("type").set_value(name);
671
      cNode.append_attribute("count").set_value(m.numItems);
672

673
      switch (m.rtti->type) {
674
      case XFSType::class_:
UNCOV
675
      case XFSType::classref_: {
×
676
        auto adata =
UNCOV
677
            reinterpret_cast<const XFSClassData *const *>(m.data.asPointer);
×
678
        for (size_t i = 0; i < m.numItems; i++) {
UNCOV
679
          auto aNode = cNode.append_child(name);
×
680
          auto found = std::find_if(
681
              dataStore.begin(), dataStore.end(),
UNCOV
682
              [adata, i](auto &value) { return &value == adata[i]; });
×
683

UNCOV
684
          if (!es::IsEnd(dataStore, found)) {
×
685
            XMLSetType(*found, aNode);
UNCOV
686
            ToXML(*found, aNode);
×
687
          }
UNCOV
688
        }
×
689
        break;
690
      }
UNCOV
691
      case XFSType::u8_: {
×
692
        auto adata = reinterpret_cast<const uint8 *>(m.data.asPointer);
UNCOV
693

×
694
        for (size_t i = 0; i < m.numItems; i++) {
×
695
          auto aNode = cNode.append_child(name);
UNCOV
696
          aNode.append_attribute("value").set_value(adata[i]);
×
697
        }
UNCOV
698
        break;
×
699
      }
UNCOV
700
      case XFSType::s8_: {
×
701
        auto adata = reinterpret_cast<const int8 *>(m.data.asPointer);
×
702

703
        for (size_t i = 0; i < m.numItems; i++) {
704
          auto aNode = cNode.append_child(name);
705
          aNode.append_attribute("value").set_value(adata[i]);
706
        }
707
        break;
708
      }
UNCOV
709
      case XFSType::s32_: {
×
710
        auto adata = reinterpret_cast<const int32 *>(m.data.asPointer);
×
711

712
        for (size_t i = 0; i < m.numItems; i++) {
UNCOV
713
          auto aNode = cNode.append_child(name);
×
714
          aNode.append_attribute("value").set_value(adata[i]);
×
715
        }
UNCOV
716
        break;
×
717
      }
UNCOV
718
      case XFSType::u32_: {
×
719
        auto adata = reinterpret_cast<const uint32 *>(m.data.asPointer);
720

UNCOV
721
        for (size_t i = 0; i < m.numItems; i++) {
×
722
          auto aNode = cNode.append_child(name);
×
723
          aNode.append_attribute("value").set_value(adata[i]);
UNCOV
724
        }
×
725
        break;
×
726
      }
727
      case XFSType::f32_: {
728
        auto adata = reinterpret_cast<const float *>(m.data.asPointer);
UNCOV
729

×
730
        for (size_t i = 0; i < m.numItems; i++) {
×
731
          auto aNode = cNode.append_child(name);
732
          aNode.append_attribute("value").set_value(adata[i]);
UNCOV
733
        }
×
734
        break;
735
      }
736

UNCOV
737
      case XFSType::color_: {
×
738
        auto adata = reinterpret_cast<const UCVector4 *>(m.data.asPointer);
UNCOV
739

×
740
        for (size_t i = 0; i < m.numItems; i++) {
×
741
          auto aNode = cNode.append_child(name);
×
742
          aNode.append_attribute("r").set_value(adata[i].X);
743
          aNode.append_attribute("g").set_value(adata[i].Y);
744
          aNode.append_attribute("b").set_value(adata[i].Z);
UNCOV
745
          aNode.append_attribute("a").set_value(adata[i].W);
×
746
        }
747
        break;
UNCOV
748
      }
×
749
      default:
×
750
        throw std::runtime_error("Unhandled xml array type");
×
751
      }
752
    } else if (m.numItems == 1) {
753
      auto cNode = node.append_child(name);
UNCOV
754
      cNode.append_attribute("name").set_value(m.rtti->name.data());
×
755
      auto value = cNode.append_attribute("value");
UNCOV
756

×
757
      switch (m.rtti->type) {
×
758
      case XFSType::bool_:
×
759
        value.set_value(m.data.asBool);
760
        break;
761
      case XFSType::s8_:
UNCOV
762
        value.set_value(m.data.asInt8);
×
763
        break;
UNCOV
764
      case XFSType::s16_:
×
765
        value.set_value(m.data.asInt16);
×
766
        break;
×
767
      case XFSType::s32_:
768
        value.set_value(m.data.asInt32);
769
        break;
UNCOV
770
      case XFSType::s64_:
×
771
        value.set_value(m.data.asInt64);
×
772
        break;
×
773
      case XFSType::u8_:
×
774
        value.set_value(m.data.asUInt8);
775
        break;
776
      case XFSType::u16_:
UNCOV
777
        value.set_value(m.data.asUInt16);
×
778
        break;
UNCOV
779
      case XFSType::u32_:
×
780
        value.set_value(m.data.asUInt32);
×
781
        break;
×
782
      case XFSType::u64_:
783
        value.set_value(m.data.asUInt64);
784
        break;
UNCOV
785
      case XFSType::string_:
×
786
      case XFSType::string2_:
×
787
        value.set_value(m.AsString());
788
        break;
789
      case XFSType::color_:
790
        value.set_name("r");
UNCOV
791
        value.set_value(m.data.asColor.X);
×
792
        cNode.append_attribute("g").set_value(m.data.asColor.Y);
×
793
        cNode.append_attribute("b").set_value(m.data.asColor.Z);
UNCOV
794
        cNode.append_attribute("a").set_value(m.data.asColor.W);
×
795
        break;
×
796
      case XFSType::f32_:
×
797
        value.set_value(m.data.asFloat);
×
798
        break;
799
      case XFSType::point_:
800
        value.set_name("x");
UNCOV
801
        value.set_value(m.data.asIVector2.X);
×
802
        cNode.append_attribute("y").set_value(m.data.asIVector2.Y);
UNCOV
803
        break;
×
804
      case XFSType::size_:
×
805
        value.set_name("w");
×
806
        value.set_value(m.data.asUIVector2.X);
807
        cNode.append_attribute("h").set_value(m.data.asUIVector2.Y);
808
        break;
UNCOV
809
      case XFSType::vector2_:
×
810
        value.set_name("x");
×
811
        value.set_value(m.data.asVector2.X);
812
        cNode.append_attribute("y").set_value(m.data.asVector2.Y);
813
        break;
814
      case XFSType::vector3_:
UNCOV
815
        value.set_name("x");
×
816
        value.set_value(m.data.asVector3.X);
817
        cNode.append_attribute("y").set_value(m.data.asVector3.Y);
UNCOV
818
        cNode.append_attribute("z").set_value(m.data.asVector3.Z);
×
819
        break;
UNCOV
820
      case XFSType::vector4_:
×
821
      case XFSType::_vector4_:
×
822
        value.set_name("x");
823
        value.set_value(m.data.asVector4.X);
UNCOV
824
        cNode.append_attribute("y").set_value(m.data.asVector4.Y);
×
825
        cNode.append_attribute("z").set_value(m.data.asVector4.Z);
×
826
        cNode.append_attribute("w").set_value(m.data.asVector4.W);
827
        break;
UNCOV
828
      case XFSType::rect_:
×
829
        value.set_name("x0");
UNCOV
830
        value.set_value(m.data.asIVector4.X);
×
831
        cNode.append_attribute("y0").set_value(m.data.asIVector4.Y);
UNCOV
832
        cNode.append_attribute("x1").set_value(m.data.asIVector4.Z);
×
833
        cNode.append_attribute("y1").set_value(m.data.asIVector4.W);
×
834
        break;
835
      case XFSType::class_:
836
      case XFSType::classref_: {
837
        auto found =
UNCOV
838
            std::find_if(dataStore.begin(), dataStore.end(), [&m](auto &value) {
×
839
              return &value == m.data.asPointer;
UNCOV
840
            });
×
841
        cNode.remove_attribute(value);
×
842

×
843
        if (!es::IsEnd(dataStore, found)) {
UNCOV
844
          XMLSetType(*found, cNode);
×
845
          ToXML(*found, cNode);
UNCOV
846
        }
×
847
        break;
×
848
      }
UNCOV
849
      case XFSType::_resource_: {
×
850
        auto adata = static_cast<const XFSDataResource *>(m.data.asPointer);
×
851
        value.set_name("type");
852
        value.set_value(adata->type.data());
853
        cNode.append_attribute("value").set_value(adata->file.data());
854
        break;
855
      }
UNCOV
856

×
857
      case XFSType::_matrix_: {
UNCOV
858
        auto adata = static_cast<const es::Matrix44 *>(m.data.asPointer);
×
859
        value.set_name("m00");
UNCOV
860
        value.set_value(adata->r1().x);
×
861
        cNode.append_attribute("m01").set_value(adata->r1().y);
862
        cNode.append_attribute("m02").set_value(adata->r1().z);
UNCOV
863
        cNode.append_attribute("m03").set_value(adata->r1().w);
×
864

UNCOV
865
        cNode.append_attribute("m10").set_value(adata->r2().x);
×
866
        cNode.append_attribute("m11").set_value(adata->r2().y);
UNCOV
867
        cNode.append_attribute("m12").set_value(adata->r2().z);
×
868
        cNode.append_attribute("m13").set_value(adata->r2().w);
UNCOV
869

×
870
        cNode.append_attribute("m20").set_value(adata->r3().x);
871
        cNode.append_attribute("m21").set_value(adata->r3().y);
UNCOV
872
        cNode.append_attribute("m22").set_value(adata->r3().z);
×
873
        cNode.append_attribute("m23").set_value(adata->r3().w);
UNCOV
874

×
875
        cNode.append_attribute("m30").set_value(adata->r4().x);
×
876
        cNode.append_attribute("m31").set_value(adata->r4().y);
UNCOV
877
        cNode.append_attribute("m32").set_value(adata->r4().z);
×
878
        cNode.append_attribute("m33").set_value(adata->r4().w);
UNCOV
879
        break;
×
880
      }
UNCOV
881
      default:
×
882
        throw std::runtime_error("Unhandled xml type");
×
883
      }
884
    }
885
  }
886
}
887

888
void XFSImpl::ToXML(pugi::xml_node node) {
889
  auto rNode = node.append_child("class");
UNCOV
890
  auto &&rootData = *root;
×
891
  XMLSetType(rootData, rNode);
×
892
  ToXML(rootData, rNode);
893
}
UNCOV
894

×
895
#ifdef XFS_DEBUG
×
896
std::map<uint32, XFSClassDesc> rttiStore;
UNCOV
897
#endif
×
898

UNCOV
899
static constexpr uint32 XFSID = CompileFourCC("XFS");
×
900
static constexpr uint32 XFSIDBE = CompileFourCC("\0SFX");
901

UNCOV
902
template <class PtrType> void Load(XFSImpl &main, BinReaderRef_e rd) {
×
903
  XFSHeaderV1 header;
×
904
  rd.Read(header);
UNCOV
905
  rd.SetRelativeOrigin(rd.Tell(), false);
×
906
  std::vector<uint32> layoutOffsets;
×
907
  std::vector<XFSClass<PtrType>> layouts;
908
  rd.ReadContainer(layoutOffsets, header.numLayouts);
909
  rd.ReadContainer(layouts, header.numLayouts);
UNCOV
910
  rd.Seek(header.dataStart);
×
911

×
912
  std::transform(std::make_move_iterator(layouts.begin()),
913
                 std::make_move_iterator(layouts.end()),
UNCOV
914
                 std::back_inserter(main.rtti), [](auto &&item) {
×
915
                   if (item.info->template Get<XFSClassInfo::Unk>()) {
916
                     throw std::runtime_error("Some bullshit");
917
                   }
UNCOV
918

×
919
                   return std::move(item);
UNCOV
920
                 });
×
921
}
×
922

×
923
template <class PtrType>
924
void LoadV2(XFSImpl &main, BinReaderRef_e rd, XFSHeaderV2 &header) {
925
  std::vector<PtrType> layoutOffsets;
UNCOV
926
  rd.ReadContainer(layoutOffsets, header.numLayouts);
×
927

928
  // Determine member padding
UNCOV
929
  rd.Push();
×
930
  rd.Skip(sizeof(PtrType));
×
931
  PtrType numMembers;
×
932
  rd.Read(numMembers);
933
  const size_t memberBegin = rd.Tell();
934

UNCOV
935
  PtrType nameOffset;
×
936
  rd.Read(nameOffset);
UNCOV
937
  rd.Pop();
×
938

×
939
  const size_t expectedEnd =
×
940
      layoutOffsets.size() > 1 ? layoutOffsets.at(1) : nameOffset;
941
  const size_t memberSize = (expectedEnd - memberBegin) / numMembers;
942

UNCOV
943
  constexpr size_t singleMemberSize = sizeof(PtrType) * 6;
×
944
  constexpr size_t singleMemberSizePSN = sizeof(PtrType) * 10;
UNCOV
945

×
946
  if (memberSize == singleMemberSize) {
×
947
    std::vector<XFSClassV2<PtrType, false>> layouts;
×
948
    rd.ReadContainer(layouts, header.numLayouts);
949
    std::transform(std::make_move_iterator(layouts.begin()),
950
                   std::make_move_iterator(layouts.end()),
UNCOV
951
                   std::back_inserter(main.rtti),
×
952
                   [](auto &&item) { return std::move(item); });
×
953

×
954
  } else if (memberSize == singleMemberSizePSN) {
×
955
    std::vector<XFSClassV2<PtrType, true>> layouts;
956
    rd.ReadContainer(layouts, header.numLayouts);
957
    std::transform(std::make_move_iterator(layouts.begin()),
UNCOV
958
                   std::make_move_iterator(layouts.end()),
×
959
                   std::back_inserter(main.rtti),
UNCOV
960
                   [](auto &&item) { return std::move(item); });
×
961
  } else {
×
962
    std::runtime_error("Cannot detect member padding");
×
963
  }
964

965
  rd.Seek(header.dataStart);
UNCOV
966
}
×
967

×
968
bool LoadV2(XFSImpl &main, BinReaderRef_e rd) {
969
  XFSHeaderV2 header;
970
  rd.Read(header);
971
  rd.SetRelativeOrigin(rd.Tell(), false);
UNCOV
972
  uint32 offset;
×
973
  rd.Read(offset);
×
974
  rd.Seek(0);
UNCOV
975
  const size_t expectedEndX64 = header.numLayouts * 8;
×
976

×
977
  if (offset == expectedEndX64) {
×
978
    LoadV2<uint64>(main, rd, header);
×
979
    return true;
980
  }
981

UNCOV
982
  LoadV2<uint32>(main, rd, header);
×
983
  return false;
UNCOV
984
}
×
985

×
986
void XFSImpl::Load(BinReaderRef_e rd, bool openEnded) {
×
987
  using pt = Platform;
988
  XFSHeaderBase hdr;
989
  rd.Push();
UNCOV
990
  rd.Read(hdr);
×
991
  rd.Pop();
×
992

993
  if (hdr.id == XFSIDBE) {
994
    rd.SwapEndian(true);
995
    hdr.SwapEndian();
UNCOV
996
  } else if (hdr.id != XFSID) {
×
997
    throw es::InvalidHeaderError(hdr.id);
998
  }
UNCOV
999

×
1000
  pt platform = rd.SwappedEndian() ? pt::PS3 : pt::Win32;
UNCOV
1001
  bool isX64 = false;
×
1002

×
1003
  if (hdr.version == 0xf || hdr.version == 0x10) {
1004
    isX64 = ::LoadV2(*this, rd);
UNCOV
1005
  } else {
×
1006
    if (platform == pt::Win32) {
×
1007
      ::Load<uint32>(*this, rd);
1008
    } else if (platform == pt::PS3) {
UNCOV
1009
      ::Load<uint64>(*this, rd);
×
1010
    } else {
UNCOV
1011
      throw std::runtime_error("Undefined platform!");
×
1012
    }
UNCOV
1013
  }
×
1014

×
1015
  for (auto &c : rtti) {
1016
    c.className = GetClassName(c.hash);
1017
#ifdef XFS_DEBUG
1018
    if (c.className.empty() && !rttiStore.count(c.hash)) {
UNCOV
1019
      rttiStore[c.hash] = c;
×
1020
    }
UNCOV
1021
#endif
×
1022
  }
×
1023

×
1024
  if (isX64) {
UNCOV
1025
    ReadData<uint64>(rd);
×
1026
  } else {
UNCOV
1027
    ReadData<uint32>(rd);
×
1028
  }
×
1029
  root = &dataStore.back();
UNCOV
1030

×
1031
  const size_t eof = rd.GetSize();
×
1032

1033
  if (!openEnded && eof != rd.Tell()) {
1034
    throw std::runtime_error("Unexpected eof");
1035
  }
1036
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc