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

PredatorCZ / RevilLib / 186

21 Apr 2026 08:16PM UTC coverage: 8.612%. Remained the same
186

push

github

PredatorCZ
update sdl

3 of 459 new or added lines in 1 file covered. (0.65%)

676 existing lines in 2 files now uncovered.

762 of 8848 relevant lines covered (8.61%)

4773.72 hits per line

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

0.19
/src/sdl.cpp
1
/*  Revil Format Library
2
    Copyright(C) 2021-2026 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 "spike/crypto/crc32.hpp"
19
#define ES_COPYABLE_POINTER
20

21
#include "property.hpp"
22
#include "pugixml.hpp"
23
#include "revil/hashreg.hpp"
24
#include "revil/sdl.hpp"
25
#include "spike/except.hpp"
26
#include "spike/io/binreader_stream.hpp"
27
#include "spike/io/binwritter_stream.hpp"
28
#include "spike/master_printer.hpp"
29
#include "spike/reflect/reflector.hpp"
30
#include "spike/type/bitfield.hpp"
31
#include "spike/type/pointer.hpp"
32
#include "spike/type/vectors.hpp"
33
#include "spike/util/endian.hpp"
34
#include <array>
35
#include <cassert>
36
#include <sstream>
37

38
using namespace revil;
39

40
struct XFSClassMember;
41

42
MAKE_ENUM(ENUMSCOPE(class SDLTrackType1 : uint8, SDLTrackType1),
1✔
43
          EMEMBER(invalid_),          //
44
          EMEMBER(RootTrack),         //
45
          EMEMBER(UnitTrack),         //
46
          EMEMBER(SystemTrack),       //
47
          EMEMBER(Separator),         //
48
          EMEMBER(ParamTrack),        //
49
          EMEMBER(IntTrack),          //
50
          EMEMBER(VectorTrack),       //
51
          EMEMBER(FloatTrack),        //
52
          EMEMBER(BoolTrack),         //
53
          EMEMBER(RefTrack),          //
54
          EMEMBER(ResourceTrack),     //
55
          EMEMBER(StringTrack),       //
56
          EMEMBER(EventTrack),        //
57
          EMEMBER(HermiteCurveTrack), //
58
          // UNUSED BELOW
59
          EMEMBERVAL(LongTrack, 128), //
60
          EMEMBER(DoubleTrack),       //
61
          EMEMBER(MatrixTrack)        //
62

63
);
64

65
MAKE_ENUM(ENUMSCOPE(class SDLTrackType2 : uint8, SDLTrackType2),
1✔
66
          EMEMBER(invalid_),         //
67
          EMEMBER(RootTrack),        //
68
          EMEMBER(UnitTrack),        //
69
          EMEMBER(SystemTrack),      //
70
          EMEMBER(Separator),        //
71
          EMEMBER(ParamTrack),       //
72
          EMEMBER(IntTrack),         //
73
          EMEMBER(LongTrack),        //
74
          EMEMBER(VectorTrack),      //
75
          EMEMBER(FloatTrack),       //
76
          EMEMBER(DoubleTrack),      //
77
          EMEMBER(BoolTrack),        //
78
          EMEMBER(RefTrack),         //
79
          EMEMBER(ResourceTrack),    //
80
          EMEMBER(StringTrack),      //
81
          EMEMBER(EventTrack),       //
82
          EMEMBER(MatrixTrack),      //
83
          EMEMBER(HermiteCurveTrack) //
84
);
85

86
MAKE_ENUM(ENUMSCOPE(class SDLType2Legacy : uint8, SDLType2Legacy),
1✔
87
          EMEMBERVAL(RootNode, 1),          //
88
          EMEMBER(ClassNode),               //
89
          EMEMBERVAL(ClassMemberNode, 5),   //
90
          EMEMBER(Int32),                   //
91
          EMEMBERVAL(Vector4, 8),           //
92
          EMEMBER(Float),                   //
93
          EMEMBERVAL(Bool, 11),             //
94
          EMEMBER(NodeIndex),               //
95
          EMEMBERVAL(ResourceInstance, 13), //
96
          EMEMBER(String),                  //
97
          EMEMBER(Unit),                    //
98
          EMEMBER(Curve)                    //
99
);
100

101
struct MtHermiteCurve {
102
  float x[8];
103
  float y[8];
104
};
105

106
struct SDLFrame {
107
  using Frame = BitMemberDecl<0, 24>;
108
  using Mode = BitMemberDecl<1, 8>;
109
  using type = BitFieldType<uint32, Frame, Mode>;
110
  type data;
111

112
  const type *operator->() const { return &data; }
113
  type *operator->() { return &data; }
114
};
115

116
struct SDLHeaderBase {
117
  uint32 id;
118
  SDLVersion version;
119
  uint16 numTracks;
120
};
121

122
struct SDLEntryV1 {
123
  SDLTrackType1 trackType;
124
  MtPropertyType propertyType;
125
  uint16 numFrames;
126
  uint32 parentOrSlot;
127
  es::PointerX86<char> name;
128
  uint32 hashOrArrayIndex;
129
  es::PointerX86<SDLFrame> frames;
130
  es::PointerX86<char> data;
131
};
132

UNCOV
133
struct SDLHeaderV1 : SDLHeaderBase {
×
134
  SDLFrame maxFrame;
135
  uint32 baseTrack = 0;
136
  es::PointerX86<char> strings;
137
  SDLEntryV1 entries[];
138
};
139

140
struct SDLEntryV2_x64 {
141
  SDLTrackType2 trackType;
142
  MtPropertyType propertyType;
143
  uint16 numFrames;
144
  uint32 parentOrSlot;
145
  es::PointerX64<char> name;
146
  uint32 hashOrArrayIndex;
147
  uint64 unitGroup;
148
  es::PointerX64<SDLFrame> frames;
149
  es::PointerX64<char> data;
150
};
151

UNCOV
152
struct SDLHeaderV2_x64 : SDLHeaderBase {
×
153
  uint32 crc;
154
  SDLFrame maxFrame;
155
  uint32 baseTrack = 0;
156
  es::PointerX64<char> strings;
157
  SDLEntryV2_x64 entries[];
158
};
159

UNCOV
160
struct SDLHeaderV2_x86 : SDLHeaderBase {
×
161
  uint32 crc;
162
  SDLFrame maxFrame;
163
  uint32 baseTrack = 0;
164
  es::PointerX86<char> strings;
165
  SDLEntryV1 entries[];
166
};
167

168
static_assert(sizeof(SDLHeaderV2_x64) == 32);
169
static_assert(sizeof(SDLHeaderV2_x86) == 24);
170

UNCOV
171
template <> void FByteswapper(SDLEntryV1 &item, bool) {
×
172
  FByteswapper(item.parentOrSlot);
×
UNCOV
173
  FByteswapper(item.numFrames);
×
UNCOV
174
  FByteswapper(item.name);
×
UNCOV
175
  FByteswapper(item.hashOrArrayIndex);
×
UNCOV
176
  FByteswapper(item.frames);
×
UNCOV
177
  FByteswapper(item.data);
×
178
}
179

UNCOV
180
template <> void FByteswapper(SDLEntryV2_x64 &, bool) {
×
181
  // Not implemented
182
}
183

184
template <> void FByteswapper(SDLHeaderBase &item, bool) {
×
185
  FByteswapper(item.numTracks);
×
186
  FByteswapper(item.version);
×
187
}
188

189
template <> void FByteswapper(SDLHeaderV1 &item, bool way) {
×
UNCOV
190
  FByteswapper(static_cast<SDLHeaderBase &>(item));
×
UNCOV
191
  FByteswapper(item.baseTrack);
×
192
  FByteswapper(item.maxFrame.data, way);
×
UNCOV
193
  FByteswapper(item.strings);
×
194
}
195

196
template <> void FByteswapper(SDLHeaderV2_x86 &item, bool way) {
×
197
  FByteswapper(static_cast<SDLHeaderBase &>(item));
×
198
  FByteswapper(item.baseTrack);
×
UNCOV
199
  FByteswapper(item.maxFrame.data, way);
×
UNCOV
200
  FByteswapper(item.strings);
×
NEW
201
  FByteswapper(item.crc);
×
202
}
203

204
template <> void FByteswapper(SDLHeaderV2_x64 &, bool) {
×
205
  // Not implemented
206
}
207

208
template <class C> void SwapData(C &entry, bool way = false) {
×
209
  size_t numBlocks = 0;
210
  using EnumType = decltype(entry.trackType);
211

NEW
212
  switch (entry.trackType) {
×
NEW
213
  case EnumType::FloatTrack:
×
214
  case EnumType::IntTrack:
215
  case EnumType::RefTrack:
216
  case EnumType::ResourceTrack:
217
  case EnumType::StringTrack:
218
  case EnumType::EventTrack:
219
    numBlocks = 1;
UNCOV
220
    break;
×
221

NEW
222
  case EnumType::VectorTrack:
×
223
    numBlocks = 4;
224
    break;
×
NEW
225
  case EnumType::MatrixTrack:
×
226
  case EnumType::HermiteCurveTrack:
227
    numBlocks = 16;
UNCOV
228
    break;
×
229

230
  default:
231
    break;
232
  }
233

234
  const size_t numSwaps = numBlocks * entry.numFrames;
×
235
  char *dataRaw = entry.data;
236
  uint32 *data = reinterpret_cast<uint32 *>(dataRaw);
237

UNCOV
238
  for (size_t i = 0; i < numSwaps; i++) {
×
UNCOV
239
    FByteswapper(data[i]);
×
240
  }
241

242
  SDLFrame *frames = entry.frames;
243

UNCOV
244
  for (size_t i = 0; i < numSwaps; i++) {
×
UNCOV
245
    FByteswapper(frames[i].data, way);
×
246
  }
247
}
UNCOV
248

×
249
template <class C> C FromXMLAttr(pugi::xml_node node, const char *attrName) {
250
  auto attr = node.attribute(attrName);
251

UNCOV
252
  if (attr.empty()) {
×
UNCOV
253
    throw std::runtime_error("Cannot find attribute: " + std::string(attrName) +
×
254
                             " for node: " + node.name());
255
  }
256

257
  if constexpr (std::is_same_v<C, int32>) {
258
    return attr.as_int();
259
  } else if constexpr (std::is_same_v<C, uint32>) {
260
    return attr.as_uint();
×
261
  } else if constexpr (std::is_same_v<C, bool>) {
UNCOV
262
    return attr.as_bool();
×
263
  } else if constexpr (std::is_same_v<C, float>) {
264
    return attr.as_float();
×
265
  } else if constexpr (std::is_same_v<C, double>) {
×
266
    return attr.as_double();
267
  } else if constexpr (std::is_same_v<C, int64>) {
UNCOV
268
    return attr.as_llong();
×
269
  } else if constexpr (std::is_same_v<C, uint64>) {
270
    return attr.as_ullong();
271
  } else if constexpr (std::is_same_v<C, const char *>) {
272
    return attr.as_string();
273
  }
274
}
×
275

276
pugi::xml_node GetXMLNode(pugi::xml_node node, MtPropertyType type,
277
                          const char *propName) {
NEW
278
  auto subNode = node.find_child_by_attribute(PropType(type), "name", propName);
×
NEW
279

×
280
  if (subNode.empty()) {
281
    throw std::runtime_error(
282
        "Cannot find sub-node: <" + std::string(PropType(type)) + " name=\"" +
283
        std::string(propName) + "\" ...> for node: " + node.name());
NEW
284
  }
×
NEW
285

×
286
  return subNode;
287
}
NEW
288

×
289
template <class C>
290
C FromXMLProp(pugi::xml_node node, MtPropertyType type, const char *propName,
291
              const char *valueName = "value") {
NEW
292
  auto subNode = GetXMLNode(node, type, propName);
×
NEW
293
  auto attr = subNode.attribute(valueName);
×
294

295
  if (attr.empty()) {
296
    throw std::runtime_error(std::string("Cannot find " +
297
                                         std::string(valueName) +
298
                                         " attribute for node: ") +
299
                             subNode.name());
NEW
300
  }
×
301

NEW
302
  if constexpr (std::is_same_v<C, int32>) {
×
303
    return attr.as_int();
NEW
304
  } else if constexpr (std::is_same_v<C, uint32>) {
×
NEW
305
    return attr.as_uint();
×
306
  } else if constexpr (std::is_same_v<C, bool>) {
307
    return attr.as_bool();
NEW
308
  } else if constexpr (std::is_same_v<C, float>) {
×
309
    return attr.as_float();
310
  } else if constexpr (std::is_same_v<C, double>) {
311
    return attr.as_double();
312
  } else if constexpr (std::is_same_v<C, int64>) {
313
    return attr.as_llong();
NEW
314
  } else if constexpr (std::is_same_v<C, uint64>) {
×
315
    return attr.as_ullong();
316
  } else if constexpr (std::is_same_v<C, const char *>) {
317
    return attr.as_string();
NEW
318
  }
×
NEW
319
}
×
320

321
pugi::xml_node XMLChild(pugi::xml_node parentNode, const char *nodeName) {
322
  auto node = parentNode.child(nodeName);
323

UNCOV
324
  if (node.empty()) {
×
325
    throw std::runtime_error(
×
326
        "Cannot find child node: " + std::string(nodeName) +
327
        " for node: " + node.name());
328
  }
UNCOV
329

×
UNCOV
330
  return node;
×
331
}
UNCOV
332

×
NEW
333
void FromXMLLegacy(SDLFrame &frame, pugi::xml_node node) {
×
334
  frame->Set<SDLFrame::Frame>(FromXMLAttr<uint32>(node, "frame"));
335
  frame->Set<SDLFrame::Mode>(FromXMLAttr<uint32>(node, "frameFlags"));
336
}
337

NEW
338
SDLTrackType1 GetTrackTypeV1(std::string_view className) {
×
339
  static const auto refEnum = GetReflectedEnum<SDLTrackType1>();
NEW
340
  className.remove_prefix(className.find_last_of(':') + 1);
×
341

NEW
342
  for (size_t i = 0; i < refEnum->numMembers; ++i) {
×
343
    if (std::string_view(refEnum->names[i]) == className) {
NEW
344
      return SDLTrackType1(refEnum->values[i]);
×
345
    }
346
  }
347

348
  throw std::runtime_error("Unknown node type: " + std::string(className));
349

350
  return SDLTrackType1::RootTrack;
351
};
NEW
352

×
353
MtPropertyType GetPropertyType(std::string_view typeName) {
354
  static const auto refEnum = GetReflectedEnum<MtPropertyType>();
NEW
355

×
NEW
356
  for (size_t i = 0; i < refEnum->numMembers; ++i) {
×
357
    if (std::string_view(refEnum->names[i]) == typeName) {
NEW
358
      return MtPropertyType(refEnum->values[i]);
×
NEW
359
    }
×
360
  }
361

362
  throw std::runtime_error("Unknown property type: " + std::string(typeName));
363

364
  return MtPropertyType::invalid;
365
};
366

367
uint32 GetClassHashV1(std::string_view name) {
NEW
368
  if (name.starts_with("0x")) {
×
369
    name.remove_prefix(2);
370
    return strtoul(name.data(), nullptr, 16);
371
  } else {
372
    return MTHashV1(name);
373
  }
374
}
375

376
uint32 GetClassHashV2(std::string_view name) {
377
  if (name.starts_with("0x")) {
378
    name.remove_prefix(2);
379
    return strtoul(name.data(), nullptr, 16);
380
  } else {
NEW
381
    return MTHashV2(name);
×
NEW
382
  }
×
383
}
NEW
384

×
NEW
385
void FromXML(SDLEntryV1 &item, pugi::xml_node node,
×
386
             uint32 (*GetClassHash)(std::string_view name)) {
387
  std::string_view className = FromXMLAttr<const char *>(node, "type");
388
  item.trackType = GetTrackTypeV1(className);
389

NEW
390
  if (item.trackType >= SDLTrackType1::ParamTrack) {
×
391
    const char *propType =
392
        FromXMLProp<const char *>(node, MtPropertyType::string_, "mPropType");
393
    item.propertyType = GetPropertyType(propType);
394
    if (item.trackType > SDLTrackType1::ParamTrack) {
395
      item.numFrames = GetXMLNode(node, MtPropertyType::array, "mpKey")
396
                           .attribute("count")
397
                           .as_uint();
398
    }
399
  } else if (item.trackType == SDLTrackType1::UnitTrack) {
400
    std::string_view unitType =
401
        FromXMLProp<const char *>(node, MtPropertyType::string_, "UnitType");
402
    item.hashOrArrayIndex = GetClassHash(unitType);
403
    item.parentOrSlot =
404
        FromXMLProp<int32>(node, MtPropertyType::s32_, "MoveLine");
405
  } else if (item.trackType == SDLTrackType1::SystemTrack) {
406
    std::string_view systemType =
NEW
407
        FromXMLProp<const char *>(node, MtPropertyType::string_, "SystemType");
×
NEW
408
    item.hashOrArrayIndex = GetClassHash(systemType);
×
409
  }
NEW
410
}
×
NEW
411

×
412
void FromXML(SDLFrame &item, pugi::xml_node node) {
413
  item->Set<SDLFrame::Frame>(
414
      FromXMLProp<uint32>(node, MtPropertyType::u32_, "mFrame"));
415
  item->Set<SDLFrame::Mode>(
416
      FromXMLProp<uint32>(node, MtPropertyType::u32_, "mMode"));
417
}
418

419
struct PaddingRange {
420
  uint32 offset;
421
  uint32 size;
UNCOV
422
};
×
423

424
SDLTrackType2 GetSDLTypeV2Legacy(pugi::xml_node node) {
425
  static const auto refEnum = GetReflectedEnum<SDLType2Legacy>();
426

427
  for (size_t i = 0; i < refEnum->numMembers; ++i) {
428
    if (std::string_view(refEnum->names[i]) == node.name()) {
429
      return SDLTrackType2(refEnum->values[i]);
430
    }
431
  }
432

433
  throw std::runtime_error(std::string("Unknown node type: ") + node.name());
×
UNCOV
434

×
435
  return SDLTrackType2::RootTrack;
UNCOV
436
};
×
437

×
438
struct NodeRef {
439
  uint32 offset;
440
  std::vector<std::string_view> nodeNames;
441
};
442

443
struct StringPointer {
444
  uint32 offset;
445
  uint32 stringId;
446
};
447

448
struct DataBuilder {
449
  std::vector<PaddingRange> paddingRanges;
450
  std::vector<StringPointer> stringPointers;
451
  std::map<std::string, size_t> strings;
452
  std::stringstream sstr;
453
  BinWritterRef dataWr{sstr};
454
  std::vector<SDLEntryV1> itemsV1;
455
  std::vector<SDLEntryV2_x64> itemsV2;
UNCOV
456
  std::map<std::string_view, uint32> classNodes;
×
457
  std::vector<NodeRef> nodeRefs;
458
  bool firstFrame = true;
NEW
459
  uint32 baseTrack = 0;
×
NEW
460
  uint32 (*GetClassHash)(std::string_view name) = GetClassHashV1;
×
461

NEW
462
  uint32 GetString(auto str) {
×
NEW
463
    if (auto found = strings.find(str); found != strings.end()) {
×
464
      return found->second;
465
    } else {
466
      const size_t newId = strings.size();
467
      strings.emplace(str, newId);
468
      return newId;
469
    }
NEW
470
  }
×
471

472
  void SetString(auto &ptr, auto str) {
473
    if (auto found = strings.find(str); found != strings.end()) {
474
      ptr.Reset(found->second);
475
    } else {
476
      const size_t newId = strings.size();
477
      strings.emplace(str, newId);
478
      ptr.Reset(newId);
479
    }
480
  }
481

482
  void ProcessNodeTree(pugi::xml_node node, size_t parentIndex) {
483
    uint32 newParentIndex = itemsV1.size();
484
    SDLEntryV1 &entry = itemsV1.emplace_back();
485
    FromXML(entry, node, GetClassHash);
NEW
486
    const char *nodeName = nullptr;
×
487

NEW
488
    if (entry.trackType >= SDLTrackType1::ParamTrack) {
×
489
      entry.parentOrSlot = parentIndex;
NEW
490
      nodeName =
×
NEW
491
          FromXMLProp<const char *>(node, MtPropertyType::string_, "mPropName");
×
NEW
492
      SetString(entry.name, nodeName);
×
NEW
493

×
494
      if (nodeName == std::string_view("mCut")) {
495
        if (const uint32 hash = itemsV1.at(parentIndex).hashOrArrayIndex;
NEW
496
            hash == MTHashV1("uMotionCamera") ||
×
497
            hash == MTHashV2("uMotionCamera")) {
498
          baseTrack = newParentIndex;
499
        }
NEW
500
      }
×
501
    } else {
NEW
502
      nodeName = FromXMLProp<const char *>(node, MtPropertyType::string_,
×
NEW
503
                                           "mTrackName");
×
504
      SetString(entry.name, nodeName);
NEW
505
    }
×
NEW
506

×
NEW
507
    auto children = GetXMLNode(node, MtPropertyType::array, "Track");
×
508

509
    switch (entry.trackType) {
510
    case SDLTrackType1::RootTrack:
511
      newParentIndex = 0;
512
      [[fallthrough]];
NEW
513
    case SDLTrackType1::UnitTrack:
×
514
    case SDLTrackType1::SystemTrack:
NEW
515
    case SDLTrackType1::Separator:
×
516
      classNodes.emplace(nodeName, newParentIndex);
NEW
517
      [[fallthrough]];
×
518
    case SDLTrackType1::ParamTrack:
NEW
519

×
520
      for (auto &c : children) {
521
        ProcessNodeTree(c, newParentIndex);
522
      }
523
      return;
524

525
    default:
526
      break;
NEW
527
    }
×
528

529
    auto keys = GetXMLNode(node, MtPropertyType::array, "mpKey").children();
NEW
530

×
531
    auto SaveKeys = [&] {
NEW
532
      std::vector<SDLFrame> keyData;
×
NEW
533

×
534
      for (auto k : keys) {
NEW
535
        auto &nKey = keyData.emplace_back();
×
NEW
536
        FromXML(nKey, k);
×
NEW
537
      }
×
538

539
      size_t reqArea = keyData.size() * sizeof(SDLFrame);
540

541
      for (auto it = paddingRanges.begin(); it != paddingRanges.end(); it++) {
542
        if ((it->offset % alignof(SDLFrame)) == 0 && it->size >= reqArea) {
543
          dataWr.Push();
544
          dataWr.Seek(it->offset);
545
          entry.frames.Reset(it->offset);
546
          dataWr.WriteContainer(keyData);
NEW
547
          dataWr.Pop();
×
548

549
          if (it->size == reqArea) {
550
            paddingRanges.erase(it);
551
          } else {
552
            it->offset += reqArea;
553
            it->size -= reqArea;
554
          }
555
          return;
556
        }
557
      }
558

559
      dataWr.ApplyPadding(4);
NEW
560
      entry.frames.Reset(dataWr.Tell());
×
561
      dataWr.WriteContainer(keyData);
NEW
562
    };
×
NEW
563

×
564
    auto WriteValues = [&](auto value) {
NEW
565
      using value_type = decltype(value);
×
NEW
566
      for (auto key : keys) {
×
NEW
567
        dataWr.Write(
×
568
            FromXMLProp<value_type>(key, entry.propertyType, "mValue"));
569
      }
570
    };
571

572
    auto AlignData = [&](uint32 align) {
573
      const size_t padding = GetPadding(dataWr.Tell(), align);
574

575
      if (padding > 0) {
576
        paddingRanges.emplace_back(PaddingRange{
577
            .offset = uint32(dataWr.Tell()),
578
            .size = uint32(padding),
NEW
579
        });
×
580
        dataWr.Skip(padding);
581
      }
582

583
      entry.data.Reset(dataWr.Tell());
584
    };
585

586
    SaveKeys();
587

588
    switch (entry.propertyType) {
589
    case MtPropertyType::u8_:
NEW
590
    case MtPropertyType::u16_:
×
591
    case MtPropertyType::u32_:
NEW
592
    case MtPropertyType::event32:
×
NEW
593
    case MtPropertyType::event:
×
594
      AlignData(4);
NEW
595
      WriteValues(uint32{});
×
NEW
596
      break;
×
NEW
597
    case MtPropertyType::s8_:
×
598
    case MtPropertyType::s16_:
599
    case MtPropertyType::s32_:
600
      AlignData(4);
601
      WriteValues(int32{});
602
      break;
603
    case MtPropertyType::f32_:
604
      AlignData(4);
NEW
605
      WriteValues(float{});
×
606
      break;
607
    case MtPropertyType::bool_:
608
      AlignData(1);
609
      WriteValues(bool{});
610
      break;
611
    case MtPropertyType::classref: {
612
      AlignData(4);
613
      auto &nodeRef = nodeRefs.emplace_back();
614
      nodeRef.offset = dataWr.Tell();
615

616
      for (auto key : keys) {
617
        dataWr.Write<uint32>(0);
618
        nodeRef.nodeNames.emplace_back(
619
            FromXMLProp<const char *>(key, MtPropertyType::string_, "mValue"));
NEW
620
      }
×
621
      break;
NEW
622
    }
×
NEW
623
    case MtPropertyType::vector2:
×
624
    case MtPropertyType::float2: {
NEW
625
      AlignData(16);
×
NEW
626
      for (auto key : keys) {
×
NEW
627
        dataWr.Write(
×
628
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x"));
629
        dataWr.Write(
630
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y"));
631
        dataWr.Skip(8);
632
      }
NEW
633
      break;
×
634
    }
635
    case MtPropertyType::rangef: {
636
      AlignData(16);
637
      for (auto key : keys) {
638
        dataWr.Write(
639
            FromXMLProp<float>(key, entry.propertyType, "mValue", "s"));
640
        dataWr.Write(
641
            FromXMLProp<float>(key, entry.propertyType, "mValue", "r"));
642
        dataWr.Skip(8);
643
      }
644
      break;
645
    }
646
    case MtPropertyType::easecurve: {
647
      AlignData(16);
648
      for (auto key : keys) {
649
        dataWr.Write(
NEW
650
            FromXMLProp<float>(key, entry.propertyType, "mValue", "p1"));
×
651
        dataWr.Write(
NEW
652
            FromXMLProp<float>(key, entry.propertyType, "mValue", "p2"));
×
NEW
653
        dataWr.Skip(8);
×
654
      }
NEW
655
      break;
×
NEW
656
    }
×
NEW
657
    case MtPropertyType::vector3:
×
658
    case MtPropertyType::float3: {
659
      AlignData(16);
660
      for (auto key : keys) {
661
        dataWr.Write(
662
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x"));
663
        dataWr.Write(
664
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y"));
665
        dataWr.Write(
666
            FromXMLProp<float>(key, entry.propertyType, "mValue", "z"));
667
        dataWr.Skip(4);
668
      }
669
      break;
670
    }
671
    case MtPropertyType::vector4:
672
    case MtPropertyType::float4:
673
    case MtPropertyType::quaternion: {
674
      AlignData(16);
675
      for (auto key : keys) {
676
        dataWr.Write(
NEW
677
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x"));
×
678
        dataWr.Write(
679
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y"));
680
        dataWr.Write(
NEW
681
            FromXMLProp<float>(key, entry.propertyType, "mValue", "z"));
×
NEW
682
        dataWr.Write(
×
683
            FromXMLProp<float>(key, entry.propertyType, "mValue", "w"));
NEW
684
      }
×
NEW
685
      break;
×
NEW
686
    }
×
NEW
687
    case MtPropertyType::color: {
×
688
      AlignData(16);
689
      for (auto key : keys) {
NEW
690
        dataWr.Write(
×
691
            FromXMLProp<float>(key, entry.propertyType, "mValue", "r"));
692
        dataWr.Write(
NEW
693
            FromXMLProp<float>(key, entry.propertyType, "mValue", "g"));
×
NEW
694
        dataWr.Write(
×
NEW
695
            FromXMLProp<float>(key, entry.propertyType, "mValue", "b"));
×
696
        dataWr.Write(
697
            FromXMLProp<float>(key, entry.propertyType, "mValue", "a"));
NEW
698
      }
×
699
      break;
NEW
700
    }
×
701
    case MtPropertyType::custom: {
NEW
702
      AlignData(4);
×
NEW
703
      for (auto key : keys) {
×
NEW
704
        std::string_view cType = FromXMLProp<const char *>(
×
705
            key, MtPropertyType::custom, "mValue", "ctype");
706

707
        if (cType != "resource") {
NEW
708
          throw es::RuntimeError("Invalid frame value ctype for custom "
×
709
                                 "property, resource expected");
710
        }
711

712
        std::string_view rType = FromXMLProp<const char *>(
NEW
713
            key, MtPropertyType::custom, "mValue", "rtype");
×
714
        const uint32 classHash = GetClassHash(rType);
715
        std::string_view path = FromXMLProp<const char *>(
NEW
716
            key, MtPropertyType::custom, "mValue", "path");
×
NEW
717

×
NEW
718
        if (path.empty()) {
×
719
          dataWr.Skip(sizeof(entry.data));
720
          continue;
721
        }
NEW
722

×
723
        std::string wString(sizeof(classHash), '-');
724
        wString.append(path);
725
        memcpy(wString.data(), &classHash, sizeof(classHash));
726
        stringPointers.emplace_back(StringPointer{
NEW
727
            .offset = uint32(dataWr.Tell()),
×
NEW
728
            .stringId = GetString(wString),
×
729
        });
NEW
730
        dataWr.Skip(sizeof(entry.data));
×
731
      }
NEW
732

×
733
      break;
734
    }
735

NEW
736
    case MtPropertyType::hermitecurve: {
×
NEW
737
      AlignData(16);
×
738
      for (auto key : keys) {
NEW
739
        dataWr.Write(
×
740
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x0"));
NEW
741
        dataWr.Write(
×
742
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x1"));
743
        dataWr.Write(
744
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x2"));
NEW
745
        dataWr.Write(
×
746
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x3"));
NEW
747
        dataWr.Write(
×
NEW
748
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x4"));
×
749
        dataWr.Write(
NEW
750
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x5"));
×
751
        dataWr.Write(
NEW
752
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x6"));
×
NEW
753
        dataWr.Write(
×
NEW
754
            FromXMLProp<float>(key, entry.propertyType, "mValue", "x7"));
×
NEW
755
        dataWr.Write(
×
NEW
756
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y0"));
×
NEW
757
        dataWr.Write(
×
758
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y1"));
NEW
759
        dataWr.Write(
×
760
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y2"));
NEW
761
        dataWr.Write(
×
NEW
762
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y3"));
×
NEW
763
        dataWr.Write(
×
NEW
764
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y4"));
×
NEW
765
        dataWr.Write(
×
766
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y5"));
NEW
767
        dataWr.Write(
×
NEW
768
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y6"));
×
769
        dataWr.Write(
770
            FromXMLProp<float>(key, entry.propertyType, "mValue", "y7"));
771
      }
NEW
772
      break;
×
NEW
773
    }
×
774
    case MtPropertyType::string_: {
NEW
775
      AlignData(4);
×
776
      for (auto key : keys) {
777
        std::string value =
778
            FromXMLProp<const char *>(key, MtPropertyType::string_, "mValue");
779

780
        if (value.empty()) {
781
          dataWr.Skip(sizeof(entry.data));
782
          continue;
783
        }
NEW
784

×
785
        stringPointers.emplace_back(StringPointer{
786
            .offset = uint32(dataWr.Tell()),
NEW
787
            .stringId = GetString(value),
×
NEW
788
        });
×
NEW
789
        dataWr.Skip(sizeof(entry.data));
×
790
      }
791

792
      break;
NEW
793
    }
×
794

795
    default:
796
      throw es::RuntimeError("Unhandled property type");
797
      break;
NEW
798
    }
×
799
  }
800

801
  void WriteValuesLegacy(pugi::xml_node entries, size_t parentIndex) {
802
    auto ResourceType = [](pugi::xml_node &node) -> uint32 {
803
      if (auto rType = node.attribute("resourceType"); !rType.empty()) {
804
        return MTHashV2(rType.as_string());
805
        // TODO validate class
806
      }
807

808
      auto hashText = FromXMLAttr<const char *>(node, "resourceHash");
809

810
      return strtoul(hashText, nullptr, 16);
811
    };
812

813
    auto DoValues = [&](pugi::xml_node &node, SDLEntryV2_x64 &entry) {
814
      auto SaveFrames = [&] {
815
        std::vector<SDLFrame> frames;
816

817
        for (auto frame : node.children("frame")) {
818
          ::FromXMLLegacy(frames.emplace_back(), frame);
819
        }
820

821
        entry.numFrames = frames.size();
UNCOV
822
        size_t reqArea = frames.size() * sizeof(SDLFrame);
×
823

×
824
        for (auto it = paddingRanges.begin(); it != paddingRanges.end(); it++) {
×
825
          if (it->size >= reqArea) {
UNCOV
826
            dataWr.Push();
×
UNCOV
827
            dataWr.Seek(it->offset);
×
UNCOV
828
            entry.frames = reinterpret_cast<SDLFrame *>(dataWr.Tell());
×
829
            dataWr.WriteContainer(frames);
830
            dataWr.Pop();
831

UNCOV
832
            if (it->size == reqArea) {
×
833
              paddingRanges.erase(it);
×
UNCOV
834
            } else {
×
835
              it->offset += reqArea;
UNCOV
836
              it->size -= reqArea;
×
UNCOV
837
            }
×
UNCOV
838
            return;
×
839
          }
840
        }
UNCOV
841

×
UNCOV
842
        entry.frames = reinterpret_cast<SDLFrame *>(dataWr.Tell());
×
UNCOV
843
        dataWr.WriteContainer(frames);
×
844
      };
UNCOV
845

×
846
      auto WriteValues = [&](auto value, const char *attrName = "value") {
847
        using value_type = decltype(value);
848
        for (auto frame : node.children("frame")) {
849
          dataWr.Write(FromXMLAttr<value_type>(frame, attrName));
850
        }
×
UNCOV
851
      };
×
UNCOV
852

×
853
      if (!firstFrame) {
UNCOV
854
        SaveFrames();
×
855
      }
×
UNCOV
856

×
857
      const size_t padding = GetPadding(dataWr.Tell(), 16);
858

UNCOV
859
      if (padding > 0) {
×
UNCOV
860
        paddingRanges.emplace_back(PaddingRange{
×
UNCOV
861
            .offset = uint32(dataWr.Tell()),
×
862
            .size = uint32(padding),
UNCOV
863
        });
×
864
        dataWr.Skip(padding);
UNCOV
865
      }
×
866

867
      entry.data = reinterpret_cast<char *>(dataWr.Tell());
868

NEW
869
      switch (entry.trackType) {
×
NEW
870
      case SDLTrackType2::FloatTrack:
×
871
        WriteValues(float());
×
872
        break;
×
NEW
873
      case SDLTrackType2::VectorTrack:
×
874
        for (auto frame : node.children("frame")) {
875
          dataWr.Write(FromXMLAttr<float>(frame, "x"));
×
876
          dataWr.Write(FromXMLAttr<float>(frame, "y"));
×
UNCOV
877
          dataWr.Write(FromXMLAttr<float>(frame, "z"));
×
UNCOV
878
          dataWr.Write(FromXMLAttr<float>(frame, "w"));
×
UNCOV
879
        }
×
880
        break;
NEW
881
      case SDLTrackType2::IntTrack:
×
NEW
882
      case SDLTrackType2::EventTrack:
×
UNCOV
883
        WriteValues(int32());
×
UNCOV
884
        break;
×
NEW
885
      case SDLTrackType2::RefTrack: {
×
886
        auto &nodeRef = nodeRefs.emplace_back();
887
        nodeRef.offset = dataWr.Tell();
888

UNCOV
889
        for (auto frame : node.children("frame")) {
×
890
          dataWr.Write<uint32>(0);
UNCOV
891
          nodeRef.nodeNames.emplace_back(
×
892
              FromXMLAttr<const char *>(frame, "nodeName"));
893
        }
UNCOV
894
        break;
×
895
      }
NEW
896
      case SDLTrackType2::BoolTrack:
×
UNCOV
897
        WriteValues(bool());
×
898
        dataWr.ApplyPadding(4);
×
899
        break;
NEW
900
      case SDLTrackType2::ResourceTrack:
×
901
        for (auto frame : node.children("frame")) {
902
          if (frame.attribute("path").empty()) {
903
            dataWr.Write<uintptr_t>(0);
904
            continue;
UNCOV
905
          }
×
906

UNCOV
907
          const uint32 cHash = ResourceType(frame);
×
UNCOV
908
          std::string wString(sizeof(cHash), '-');
×
909
          wString.append(FromXMLAttr<const char *>(frame, "path"));
UNCOV
910
          memcpy(wString.data(), &cHash, sizeof(cHash));
×
911
          es::PointerX86<char> ptr;
912
          SetString(ptr, wString);
913
          stringPointers.emplace_back(StringPointer{
914
              .offset = uint32(dataWr.Tell()),
915
              .stringId = reinterpret_cast<uint32 &>(ptr),
UNCOV
916
          });
×
917
          dataWr.Write(ptr);
UNCOV
918
        }
×
UNCOV
919
        break;
×
920
      case SDLTrackType2::StringTrack:
921
        for (auto frame : node.children("frame")) {
×
NEW
922
          es::PointerX86<char> ptr;
×
UNCOV
923
          SetString(ptr, FromXMLAttr<const char *>(frame, "value"));
×
924
          stringPointers.emplace_back(StringPointer{
925
              .offset = uint32(dataWr.Tell()),
NEW
926
              .stringId = reinterpret_cast<uint32 &>(ptr),
×
927
          });
928
          dataWr.Write(ptr);
×
UNCOV
929
        }
×
930
        break;
NEW
931
      case SDLTrackType2::MatrixTrack:
×
UNCOV
932
        for (auto frame : node.children("frame")) {
×
UNCOV
933
          for (size_t i = 0; i < 16; i++) {
×
934
            auto aName = "e" + std::to_string(i);
935
            dataWr.Write(FromXMLAttr<float>(frame, aName.c_str()));
UNCOV
936
          }
×
UNCOV
937
        }
×
938
        break;
UNCOV
939

×
UNCOV
940
      default:
×
941
        break;
942
      }
943

944
      if (firstFrame) {
945
        firstFrame = false;
UNCOV
946
        SaveFrames();
×
UNCOV
947
      }
×
UNCOV
948
    };
×
949

950
    for (auto c : entries.children()) {
951
      SDLEntryV2_x64 entry{};
×
952
      entry.trackType = GetSDLTypeV2Legacy(c);
NEW
953
      entry.propertyType = MtPropertyType(FromXMLAttr<uint32>(c, "type"));
×
954
      auto nodeName = FromXMLAttr<const char *>(c, "name");
×
955
      SetString(entry.name, nodeName);
×
956

957
      switch (entry.trackType) {
NEW
958
      case SDLTrackType2::RootTrack:
×
959
        classNodes.emplace(nodeName, itemsV2.size());
NEW
960
        itemsV2.emplace_back(entry);
×
NEW
961
        WriteValuesLegacy(c, 0);
×
UNCOV
962
        break;
×
963

964
      case SDLTrackType2::UnitTrack:
965
        entry.hashOrArrayIndex = ResourceType(c);
×
966
        entry.parentOrSlot = FromXMLAttr<uint32>(c, "entrySlot");
NEW
967
        classNodes.emplace(nodeName, itemsV2.size());
×
NEW
968
        itemsV2.emplace_back(entry);
×
NEW
969
        WriteValuesLegacy(c, itemsV2.size() - 1);
×
970
        break;
971

NEW
972
      case SDLTrackType2::ParamTrack:
×
973
        entry.hashOrArrayIndex = FromXMLAttr<uint32>(c, "arrayIndex");
UNCOV
974
        entry.parentOrSlot = parentIndex;
×
NEW
975
        itemsV2.emplace_back(entry);
×
NEW
976
        WriteValuesLegacy(c, itemsV2.size() - 1);
×
977
        break;
978

UNCOV
979
      default:
×
980
        entry.hashOrArrayIndex = FromXMLAttr<uint32>(c, "arrayIndex");
UNCOV
981
        entry.parentOrSlot = parentIndex;
×
982
        DoValues(c, entry);
×
NEW
983
        itemsV2.emplace_back(entry);
×
984
        break;
985
      }
986
    }
UNCOV
987
  }
×
UNCOV
988
};
×
989

UNCOV
990
constexpr uint32 SDL_ID = CompileFourCC("SDL");
×
UNCOV
991
constexpr uint32 SDL_ID_BE = CompileFourCC("\0LDS");
×
992

993
void SDLFromXml(pugi::xml_node rootNode, SDLFrame &maxFrame,
994
                DataBuilder &dataBuilder) {
UNCOV
995
  auto classNode = XMLChild(rootNode, "class");
×
996
  const char *typeName = FromXMLAttr<const char *>(classNode, "type");
997

NEW
998
  if (std::string_view("rScheduler") == typeName) {
×
999
    ::FromXMLLegacy(maxFrame, XMLChild(classNode, "maxFrame"));
1000
    auto entries = XMLChild(classNode, "entries");
NEW
1001
    dataBuilder.WriteValuesLegacy(entries, 0);
×
1002
  } else if (std::string_view("rSchedulerXml") == typeName) {
NEW
1003
    auto rootTrack =
×
NEW
1004
        GetXMLNode(classNode, MtPropertyType::class_, "mRootTrack");
×
1005
    maxFrame->Set<SDLFrame::Frame>(
1006
        FromXMLProp<uint32>(rootTrack, MtPropertyType::u32_, "mFrameMax"));
1007
    maxFrame->Set<SDLFrame::Mode>(
1008
        FromXMLProp<bool>(rootTrack, MtPropertyType::bool_, "mFloorFrame"));
NEW
1009
    dataBuilder.ProcessNodeTree(rootTrack, -1);
×
NEW
1010
  } else {
×
1011
    throw es::RuntimeError("Invalid class type, expected rScheduler");
UNCOV
1012
  }
×
1013
}
1014

NEW
1015
template <class HeaderType>
×
NEW
1016
void SDLFromXMLV2(BinWritterRef wr, pugi::xml_node rootNode,
×
1017
                  SDLVersion version) {
NEW
1018
  HeaderType hdr;
×
UNCOV
1019
  hdr.id = SDL_ID;
×
NEW
1020
  hdr.version = version;
×
1021
  hdr.crc = 0xE2316427;
UNCOV
1022
  DataBuilder dataBuilder;
×
NEW
1023
  SDLFromXml(rootNode, hdr.maxFrame, dataBuilder);
×
UNCOV
1024

×
1025
  hdr.baseTrack = dataBuilder.baseTrack;
NEW
1026
  hdr.numTracks = dataBuilder.itemsV2.size();
×
UNCOV
1027
  wr.Write(hdr);
×
NEW
1028
  wr.WriteContainer(dataBuilder.itemsV2);
×
1029
  const size_t dataOffset = wr.Tell();
×
1030
  std::string dataBuffer(std::move(dataBuilder.sstr).str());
UNCOV
1031
  wr.WriteContainer(dataBuffer);
×
1032
  es::Dispose(dataBuffer);
×
1033
  uintptr_t stringBegin = wr.Tell();
×
1034
  hdr.strings = reinterpret_cast<char *>(stringBegin);
×
1035
  std::vector<uintptr_t> stringOffsets;
UNCOV
1036
  std::vector<std::string_view> strings;
×
1037
  strings.resize(dataBuilder.strings.size());
UNCOV
1038

×
1039
  for (auto &[str, id] : dataBuilder.strings) {
1040
    strings.at(id) = str.c_str();
×
UNCOV
1041
  }
×
1042

UNCOV
1043
  for (size_t i = 0; i < strings.size(); i++) {
×
1044
    stringOffsets.emplace_back(wr.Tell() - stringBegin);
UNCOV
1045
    wr.WriteT(strings.at(i));
×
UNCOV
1046
  }
×
1047

NEW
1048
  for (auto &e : dataBuilder.itemsV2) {
×
1049
    e.name = reinterpret_cast<char *>(
UNCOV
1050
        stringOffsets.at(reinterpret_cast<uintptr_t &>(e.name)));
×
UNCOV
1051

×
UNCOV
1052
    if (e.numFrames > 0) {
×
1053
      e.data.FixupRelative(reinterpret_cast<char *>(dataOffset));
UNCOV
1054
      e.frames.FixupRelative(reinterpret_cast<char *>(dataOffset));
×
1055
    }
UNCOV
1056
  }
×
1057

×
1058
  for (auto p : dataBuilder.stringPointers) {
1059
    wr.Seek(dataOffset + p.offset);
×
1060
    wr.Write(stringOffsets.at(p.stringId));
UNCOV
1061
  }
×
1062

×
1063
  for (auto r : dataBuilder.nodeRefs) {
×
1064
    wr.Seek(dataOffset + r.offset);
UNCOV
1065

×
1066
    for (auto &n : r.nodeNames) {
UNCOV
1067
      wr.Write(dataBuilder.classNodes.at(n));
×
UNCOV
1068
    }
×
1069
  }
UNCOV
1070

×
1071
  wr.Seek(0);
UNCOV
1072
  wr.Write(hdr);
×
1073
  wr.WriteContainer(dataBuilder.itemsV2);
NEW
1074
}
×
NEW
1075

×
1076
template <class HeaderType>
NEW
1077
void SDLFromXMLV1(BinWritterRef wr, pugi::xml_node rootNode,
×
1078
                  SDLVersion version) {
NEW
1079
  HeaderType hdr;
×
1080
  hdr.id = SDL_ID;
NEW
1081
  hdr.version = version;
×
NEW
1082
  DataBuilder dataBuilder;
×
1083

NEW
1084
  if (hdr.version > SDLVersion::V_16) {
×
1085
    dataBuilder.GetClassHash = GetClassHashV2;
NEW
1086
  }
×
1087

1088
  SDLFromXml(rootNode, hdr.maxFrame, dataBuilder);
NEW
1089

×
NEW
1090
  hdr.baseTrack = dataBuilder.baseTrack;
×
1091
  hdr.numTracks = dataBuilder.itemsV1.size();
NEW
1092
  wr.Write(hdr);
×
1093
  wr.WriteContainer(dataBuilder.itemsV1);
NEW
1094
  wr.ApplyPadding();
×
1095
  const size_t dataOffset = wr.Tell();
NEW
1096
  std::string dataBuffer(std::move(dataBuilder.sstr).str());
×
1097
  wr.WriteContainer(dataBuffer);
NEW
1098
  es::Dispose(dataBuffer);
×
1099
  uint32 stringBegin = wr.Tell();
NEW
1100
  hdr.strings.Reset(stringBegin);
×
1101
  std::vector<uint32> stringOffsets;
NEW
1102
  std::vector<std::string_view> strings;
×
NEW
1103
  strings.resize(dataBuilder.strings.size());
×
NEW
1104

×
1105
  for (auto &[str, id] : dataBuilder.strings) {
NEW
1106
    strings.at(id) = str;
×
1107
  }
NEW
1108

×
1109
  for (size_t i = 0; i < strings.size(); i++) {
NEW
1110
    stringOffsets.emplace_back(wr.Tell() - stringBegin);
×
1111
    wr.WriteT(strings.at(i));
NEW
1112
  }
×
1113

NEW
1114
  for (auto &e : dataBuilder.itemsV1) {
×
1115
    e.name.Reset(stringOffsets.at(reinterpret_cast<uint32 &>(e.name)));
NEW
1116

×
NEW
1117
    if (e.numFrames > 0) {
×
NEW
1118
      e.data.Reset(dataOffset + e.data.RawValue());
×
1119
      e.frames.Reset(dataOffset + e.frames.RawValue());
NEW
1120
    }
×
1121
  }
NEW
1122

×
1123
  for (auto p : dataBuilder.stringPointers) {
NEW
1124
    wr.Seek(dataOffset + p.offset);
×
1125
    wr.Write(stringOffsets.at(p.stringId));
1126
  }
1127

NEW
1128
  for (auto r : dataBuilder.nodeRefs) {
×
NEW
1129
    wr.Seek(dataOffset + r.offset);
×
1130

NEW
1131
    for (auto &n : r.nodeNames) {
×
1132
      wr.Write(dataBuilder.classNodes.at(n));
NEW
1133
    }
×
NEW
1134
  }
×
NEW
1135

×
1136
  wr.Seek(0);
1137
  wr.Write(hdr);
1138
  wr.WriteContainer(dataBuilder.itemsV1);
1139
}
1140

NEW
1141
void revil::SDLFromXML(BinWritterRef wr, pugi::xml_node rootNode,
×
1142
                       SDLVersion version) {
NEW
1143
  if (version == SDLVersion::V_16) {
×
1144
    SDLFromXMLV2<SDLHeaderV2_x64>(wr, rootNode, version);
NEW
1145
  } else if (version < SDLVersion::V_20) {
×
1146
    SDLFromXMLV1<SDLHeaderV1>(wr, rootNode, version);
1147
  } else {
NEW
1148
    SDLFromXMLV1<SDLHeaderV2_x86>(wr, rootNode, version);
×
1149
  }
1150
}
NEW
1151

×
NEW
1152
template <class EnumType>
×
NEW
1153
pugi::xml_node NewTrack(EnumType type, pugi::xml_node &parent) {
×
1154
  static const auto refEnum = GetReflectedEnum<EnumType>();
NEW
1155
  std::string typeName = [&] {
×
1156
    const size_t numEns = refEnum->numMembers;
NEW
1157

×
1158
    for (size_t i = 0; i < numEns; i++) {
NEW
1159
      if (refEnum->values[i] == static_cast<uint64>(type)) {
×
1160
        return refEnum->names[i];
NEW
1161
      }
×
1162
    }
NEW
1163

×
1164
    return "__UNREGISTERED__";
NEW
1165
  }();
×
1166

NEW
1167
  pugi::xml_node node;
×
1168

NEW
1169
  switch (type) {
×
1170
  case EnumType::RootTrack:
NEW
1171
    node = parent.append_child("class");
×
1172
    node.append_attribute("name").set_value("mRootTrack");
NEW
1173
    break;
×
1174

NEW
1175
  default:
×
1176
    node = parent.append_child("classref");
NEW
1177
    break;
×
1178
  }
NEW
1179

×
1180
  typeName = "rSchedulerXml::" + typeName;
NEW
1181
  node.append_attribute("type").set_value(typeName.c_str());
×
1182
  return node;
NEW
1183
};
×
1184

NEW
1185
pugi::xml_node SetupTrack(pugi::xml_node &node, const char *name, uint32 id,
×
1186
                          uint16 numFrames, MtPropertyType propType,
NEW
1187
                          uint32 classHash, int type) {
×
1188
  node.append_attribute("id").set_value(id);
NEW
1189

×
NEW
1190
  if (type < 5) {
×
NEW
1191
    pugi::xml_node trackName = NewProperty(MtPropertyType::string_, node);
×
1192
    trackName.append_attribute("name").set_value("mTrackName");
NEW
1193
    trackName.append_attribute("value").set_value(name);
×
1194
  }
NEW
1195

×
NEW
1196
  pugi::xml_node trackTrack = NewProperty(MtPropertyType::array, node);
×
1197
  trackTrack.append_attribute("name").set_value("Track");
1198
  trackTrack.append_attribute("type").set_value("classref");
1199
  trackTrack.append_attribute("count").set_value(0);
NEW
1200

×
1201
  if (type < 2) {
NEW
1202
    return {};
×
1203
  }
NEW
1204

×
1205
  pugi::xml_node trackType = NewProperty(MtPropertyType::string_, node);
1206

NEW
1207
  auto SetClassName = [classHash, name, type](pugi::xml_node &node) {
×
1208
    auto clName = GetClassName(classHash);
1209

NEW
1210
    if (clName.empty()) {
×
NEW
1211
      char buffer[0x10]{};
×
1212
      snprintf(buffer, sizeof(buffer), "0x%X", classHash);
1213
      node.append_attribute("value").set_value(buffer);
1214
      PrintError(type, " ", buffer, " Unknown class: ", name);
1215
    } else {
NEW
1216
      std::string resNme(clName);
×
NEW
1217
      // PrintInfo(clName);
×
NEW
1218
      node.append_attribute("value").set_value(resNme.c_str());
×
NEW
1219
    }
×
1220
  };
1221

1222
  switch (type) {
NEW
1223
  case 2:
×
1224
    trackType.append_attribute("name").set_value("UnitType");
NEW
1225
    SetClassName(trackType);
×
1226
    break;
1227
  case 3:
NEW
1228
    trackType.append_attribute("name").set_value("SystemType");
×
NEW
1229
    SetClassName(trackType);
×
NEW
1230
    break;
×
1231
  case 4:
NEW
1232
    node.remove_child(trackType);
×
NEW
1233
    break;
×
1234

1235
  default: {
NEW
1236
    trackType.append_attribute("name").set_value("mPropName");
×
NEW
1237
    trackType.append_attribute("value").set_value(name);
×
1238

NEW
1239
    pugi::xml_node propNode = NewProperty(MtPropertyType::string_, node);
×
NEW
1240
    propNode.append_attribute("name").set_value("mPropType");
×
1241
    propNode.append_attribute("value").set_value(PropType(propType));
NEW
1242

×
NEW
1243
    if (type > 5) {
×
NEW
1244
      pugi::xml_node keys = NewProperty(MtPropertyType::array, node);
×
1245
      keys.append_attribute("name").set_value("mpKey");
1246
      keys.append_attribute("type").set_value("classref");
NEW
1247
      keys.append_attribute("count").set_value(numFrames);
×
NEW
1248

×
1249
      return keys;
NEW
1250
    }
×
NEW
1251
  }
×
1252
  }
1253

1254
  return {};
1255
}
1256

NEW
1257
auto MakePair(std::string_view name) {
×
NEW
1258
  static uint32 prev = 0xFFFFFFFF;
×
1259
  prev = ~crc32b(~prev, name.data(), name.size());
1260
  return std::make_pair(prev, name);
UNCOV
1261
}
×
1262

NEW
1263
static const std::map<uint32, std::string_view> LINE_NAMES{
×
NEW
1264
    MakePair("Line0"),  MakePair("Line1"),     MakePair("Line2"),
×
1265
    MakePair("Line3"),  MakePair("Line4"),     MakePair("Line5"),
1266
    MakePair("Line6"),  MakePair("Line7"),     MakePair("Line8"),
NEW
1267
    MakePair("Line9"),  MakePair("Line10"),    MakePair("Line11"),
×
1268
    MakePair("Line12"), MakePair("Line13"),    MakePair("Line14"),
NEW
1269
    MakePair("Line15"), MakePair("Line16"),    MakePair("Line17"),
×
NEW
1270
    MakePair("Line18"), MakePair("Line19"),    MakePair("Line20"),
×
1271
    MakePair("Line21"), MakePair("Line22"),    MakePair("Line23"),
1272
    MakePair("Line24"), MakePair("Line25"),    MakePair("Line26"),
NEW
1273
    MakePair("Line27"), MakePair("Line28"),    MakePair("Line29"),
×
1274
    MakePair("Line30"), MakePair("Line31"),    MakePair("Line32"),
NEW
1275
    MakePair("Line33"), MakePair("Line34"),    MakePair("Line35"),
×
NEW
1276
    MakePair("Line36"), MakePair("Line37"),    MakePair("Line38"),
×
1277
    MakePair("Line39"), MakePair("Line40"),    MakePair("Line41"),
1278
    MakePair("Line42"), MakePair("Line43"),    MakePair("Line44"),
NEW
1279
    MakePair("Line45"), MakePair("Line46"),    MakePair("Line47"),
×
1280
    MakePair("Line48"), MakePair("Line49"),    MakePair("Line50"),
NEW
1281
    MakePair("Line51"), MakePair("Line52"),    MakePair("Line53"),
×
NEW
1282
    MakePair("Line54"), MakePair("Line55"),    MakePair("Line56"),
×
1283
    MakePair("Line57"), MakePair("Line58"),    MakePair("Line59"),
1284
    MakePair("Line60"), MakePair("Line61"),    MakePair("Line62"),
1285
    MakePair("Line63"), MakePair("Undefined"),
NEW
1286
};
×
NEW
1287

×
1288
template <class HdrType> void ToXML(HdrType *hdr, pugi::xml_node root) {
1289
  using EntryType = std::decay_t<decltype(hdr->entries[0])>;
1290
  using EnumType = decltype(EntryType::trackType);
1291
  using PtrTypeChar = decltype(hdr->strings);
1292
  using PtrTypeUint =
UNCOV
1293
      std::conditional_t<sizeof(PtrTypeChar) == 8, es::PointerX64<uint32>,
×
1294
                         es::PointerX86<uint32>>;
1295

1296
  if constexpr (std::is_same_v<HdrType, SDLHeaderV2_x86>) {
NEW
1297
    // pugi::xml_node lineName = NewProperty(MtPropertyType::string_, root);
×
1298
    // lineName.append_attribute("name").set_value("mLineName");
1299
    // lineName.append_attribute("value").set_value(
NEW
1300
    //     LINE_NAMES.at(hdr->crc).data());
×
1301
    //assert(hdr->crc == 3843825908);
UNCOV
1302
  }
×
UNCOV
1303

×
UNCOV
1304
  std::vector<pugi::xml_node> nodes;
×
1305
  uint32 curId = 1;
UNCOV
1306

×
1307
  for (size_t i = 0; i < hdr->numTracks; i++) {
×
1308
    auto &entry = hdr->entries[i];
×
NEW
1309
    pugi::xml_node trackNode;
×
UNCOV
1310

×
NEW
1311
    switch (entry.trackType) {
×
1312
    case EnumType::RootTrack: {
NEW
1313
      trackNode = NewTrack(entry.trackType, root);
×
UNCOV
1314

×
1315
      pugi::xml_node frameMax = NewProperty(MtPropertyType::u32_, trackNode);
NEW
1316
      frameMax.append_attribute("name").set_value("mFrameMax");
×
1317
      frameMax.append_attribute("value").set_value(
NEW
1318
          hdr->maxFrame->template Get<SDLFrame::Frame>());
×
1319

×
NEW
1320
      pugi::xml_node floorFrame = NewProperty(MtPropertyType::bool_, trackNode);
×
1321
      floorFrame.append_attribute("name").set_value("mFloorFrame");
NEW
1322
      floorFrame.append_attribute("value").set_value(
×
NEW
1323
          bool(hdr->maxFrame->template Get<SDLFrame::Mode>()));
×
UNCOV
1324

×
UNCOV
1325
      break;
×
1326
    }
NEW
1327
    case EnumType::UnitTrack: {
×
1328
      pugi::xml_node parent =
NEW
1329
          nodes.front().find_child_by_attribute("array", "name", "Track");
×
NEW
1330
      pugi::xml_attribute countAttr = parent.attribute("count");
×
NEW
1331
      countAttr.set_value(countAttr.as_uint(0) + 1);
×
1332
      trackNode = NewTrack(entry.trackType, parent);
NEW
1333
      pugi::xml_node moveLine = NewProperty(MtPropertyType::s32_, trackNode);
×
NEW
1334
      moveLine.append_attribute("name").set_value("MoveLine");
×
NEW
1335
      moveLine.append_attribute("value").set_value(entry.parentOrSlot);
×
NEW
1336
      break;
×
NEW
1337
    }
×
1338
    case EnumType::Separator:
1339
    case EnumType::SystemTrack: {
NEW
1340
      pugi::xml_node parent =
×
1341
          nodes.front().find_child_by_attribute("array", "name", "Track");
NEW
1342
      pugi::xml_attribute countAttr = parent.attribute("count");
×
1343
      countAttr.set_value(countAttr.as_uint(0) + 1);
NEW
1344
      trackNode = NewTrack(entry.trackType, parent);
×
UNCOV
1345
      break;
×
NEW
1346
    }
×
1347
    default: {
NEW
1348
      pugi::xml_node parent =
×
1349
          nodes.at(entry.parentOrSlot)
1350
              .find_child_by_attribute("array", "name", "Track");
1351
      pugi::xml_attribute countAttr = parent.attribute("count");
NEW
1352
      countAttr.set_value(countAttr.as_uint(0) + 1);
×
NEW
1353
      trackNode = NewTrack(entry.trackType, parent);
×
1354
      break;
×
1355
    }
×
NEW
1356
    }
×
1357

×
1358
    pugi::xml_node keys = SetupTrack(
NEW
1359
        trackNode, entry.name, curId++, entry.numFrames, entry.propertyType,
×
1360
        entry.hashOrArrayIndex, int(entry.trackType));
1361

1362
    if (entry.trackType == EnumType::ResourceTrack) {
NEW
1363
      // for some reason it's hermitecurve
×
NEW
1364
      trackNode.find_child_by_attribute("string", "name", "mPropType")
×
NEW
1365
          .attribute("value")
×
NEW
1366
          .set_value("custom");
×
NEW
1367
    } else if (entry.trackType == EnumType::RefTrack && entry.propertyType == MtPropertyType::invalid) {
×
NEW
1368
      // RE5: sometimes is invalid
×
1369
      trackNode.find_child_by_attribute("string", "name", "mPropType")
1370
          .attribute("value")
NEW
1371
          .set_value("classref");
×
1372
    } else if (entry.trackType == EnumType::BoolTrack && entry.propertyType == MtPropertyType::invalid) {
1373
      // LP2: sometimes is invalid
1374
      entry.propertyType = MtPropertyType::bool_;
1375
      trackNode.find_child_by_attribute("string", "name", "mPropType")
1376
          .attribute("value")
NEW
1377
          .set_value("bool");
×
NEW
1378
    }
×
NEW
1379

×
1380
    // trackNode.append_attribute("nodeid").set_value(nodes.size());
1381
    nodes.emplace_back(trackNode);
1382

NEW
1383
    SDLFrame *frames = entry.frames;
×
NEW
1384
    std::string keyTypeName(trackNode.attribute("type").as_string());
×
NEW
1385
    keyTypeName.append("::Key");
×
NEW
1386

×
NEW
1387
    for (uint16 f = 0; f < entry.numFrames; f++) {
×
NEW
1388
      SDLFrame frame = frames[f];
×
1389

NEW
1390
      pugi::xml_node keyNode = NewProperty(MtPropertyType::classref, keys);
×
NEW
1391
      keyNode.append_attribute("type").set_value(keyTypeName.c_str());
×
NEW
1392
      keyNode.append_attribute("id").set_value(curId++);
×
NEW
1393

×
NEW
1394
      pugi::xml_node frameNode = NewProperty(MtPropertyType::u32_, keyNode);
×
1395
      frameNode.append_attribute("name").set_value("mFrame");
1396
      frameNode.append_attribute("value").set_value(
NEW
1397
          frame->Get<SDLFrame::Frame>());
×
1398

×
NEW
1399
      pugi::xml_node modeNode = NewProperty(MtPropertyType::u32_, keyNode);
×
NEW
1400
      modeNode.append_attribute("name").set_value("mMode");
×
NEW
1401
      modeNode.append_attribute("value").set_value(
×
NEW
1402
          frame->Get<SDLFrame::Mode>());
×
1403

1404
      pugi::xml_node valueNode = NewProperty(entry.propertyType, keyNode);
NEW
1405
      valueNode.append_attribute("name").set_value("mValue");
×
1406

×
NEW
1407
      switch (entry.trackType) {
×
NEW
1408
      case EnumType::IntTrack: {
×
NEW
1409
        const int32 value =
×
1410
            reinterpret_cast<int32 *>(static_cast<char *>(entry.data))[f];
1411

NEW
1412
        switch (entry.propertyType) {
×
NEW
1413
        case MtPropertyType::s32_:
×
NEW
1414
        case MtPropertyType::s16_:
×
NEW
1415
        case MtPropertyType::s8_:
×
NEW
1416
          valueNode.append_attribute("value").set_value(value);
×
1417
          break;
1418
        case MtPropertyType::u32_:
1419
        case MtPropertyType::u16_:
1420
        case MtPropertyType::u8_:
1421
          valueNode.append_attribute("value").set_value(uint32(value));
1422
          break;
1423

1424
        case MtPropertyType::bool_:
1425
          valueNode.append_attribute("value").set_value(bool(value));
NEW
1426
          break;
×
1427

NEW
1428
        default:
×
NEW
1429
          PrintError("Unknown property type ", PropType(entry.propertyType),
×
1430
                     " for track type ", int(entry.trackType));
1431
          break;
×
1432
        }
×
NEW
1433

×
NEW
1434
        break;
×
NEW
1435
      }
×
1436

NEW
1437
      case EnumType::VectorTrack: {
×
NEW
1438
        auto &value =
×
1439
            reinterpret_cast<Vector4 *>(static_cast<char *>(entry.data))[f];
NEW
1440

×
NEW
1441
        switch (entry.propertyType) {
×
NEW
1442
        case MtPropertyType::vector4:
×
1443
        case MtPropertyType::quaternion:
NEW
1444
        case MtPropertyType::float4:
×
1445
          valueNode.append_attribute("x").set_value(value.x);
1446
          valueNode.append_attribute("y").set_value(value.y);
1447
          valueNode.append_attribute("z").set_value(value.z);
1448
          valueNode.append_attribute("w").set_value(value.w);
NEW
1449
          break;
×
1450
        case MtPropertyType::vector3:
1451
        case MtPropertyType::float3:
NEW
1452
          valueNode.append_attribute("x").set_value(value.x);
×
NEW
1453
          valueNode.append_attribute("y").set_value(value.y);
×
NEW
1454
          valueNode.append_attribute("z").set_value(value.z);
×
NEW
1455
          break;
×
NEW
1456
        case MtPropertyType::color:
×
1457
          valueNode.append_attribute("r").set_value(value.x);
NEW
1458
          valueNode.append_attribute("g").set_value(value.y);
×
NEW
1459
          valueNode.append_attribute("b").set_value(value.z);
×
1460
          valueNode.append_attribute("a").set_value(value.w);
1461
          break;
×
1462
        case MtPropertyType::easecurve:
1463
          valueNode.append_attribute("p1").set_value(value.x);
1464
          valueNode.append_attribute("p2").set_value(value.y);
1465
          break;
1466
        case MtPropertyType::float2:
NEW
1467
        case MtPropertyType::vector2:
×
NEW
1468
          valueNode.append_attribute("x").set_value(value.x);
×
NEW
1469
          valueNode.append_attribute("y").set_value(value.y);
×
UNCOV
1470
          break;
×
1471
        case MtPropertyType::rangef:
NEW
1472
          valueNode.append_attribute("s").set_value(value.x);
×
NEW
1473
          valueNode.append_attribute("r").set_value(value.y);
×
1474
          break;
1475
        default:
NEW
1476
          PrintError("Unknown property type ", PropType(entry.propertyType),
×
NEW
1477
                     " for track type ", int(entry.trackType));
×
NEW
1478
          break;
×
1479
        }
1480
        break;
UNCOV
1481

×
NEW
1482
        break;
×
NEW
1483
      }
×
1484

NEW
1485
      case EnumType::FloatTrack: {
×
NEW
1486
        const float value =
×
1487
            reinterpret_cast<float *>(static_cast<char *>(entry.data))[f];
1488

1489
        switch (entry.propertyType) {
1490
        case MtPropertyType::f32_:
NEW
1491
          valueNode.append_attribute("value").set_value(value);
×
UNCOV
1492
          break;
×
UNCOV
1493

×
1494
        default:
1495
          PrintError("Unknown property type ", PropType(entry.propertyType),
NEW
1496
                     " for track type ", int(entry.trackType));
×
1497
          break;
×
1498
        }
1499

×
NEW
1500
        break;
×
1501
      }
1502

1503
      case EnumType::BoolTrack: {
1504
        const bool value =
1505
            reinterpret_cast<bool *>(static_cast<char *>(entry.data))[f];
1506

×
1507
        switch (entry.propertyType) {
1508
        case MtPropertyType::bool_:
1509
          valueNode.append_attribute("value").set_value(value);
1510
          break;
×
1511

1512
        default:
NEW
1513
          PrintError("Unknown property type ", PropType(entry.propertyType),
×
NEW
1514
                     " for track type ", int(entry.trackType));
×
1515
          break;
×
1516
        }
NEW
1517

×
NEW
1518
        break;
×
1519
      }
1520

NEW
1521
      case EnumType::ResourceTrack: {
×
1522
        auto &dataPtr =
NEW
1523
            reinterpret_cast<PtrTypeUint *>(static_cast<char *>(entry.data))[f];
×
NEW
1524
        valueNode.append_attribute("ctype").set_value("resource");
×
1525
        valueNode.set_name("custom");
NEW
1526

×
NEW
1527
        if (dataPtr) {
×
1528
          auto clName = GetClassName(*dataPtr);
1529

1530
          if (clName.empty()) {
1531
            char buffer[0x10]{};
1532
            snprintf(buffer, sizeof(buffer), "0x%X", *dataPtr);
NEW
1533
            valueNode.append_attribute("rtype").set_value(buffer);
×
NEW
1534
            PrintError("Unknown resource class: ", *dataPtr);
×
NEW
1535
          } else {
×
NEW
1536
            std::string resNme(clName);
×
1537
            valueNode.append_attribute("rtype").set_value(resNme.c_str());
NEW
1538
          }
×
NEW
1539

×
1540
          valueNode.append_attribute("path").set_value(
1541
              reinterpret_cast<const char *>(dataPtr.operator->() + 1));
NEW
1542
        } else {
×
NEW
1543
          valueNode.append_attribute("rtype").set_value("null");
×
NEW
1544
          valueNode.append_attribute("path");
×
1545
        }
1546
        break;
NEW
1547
      }
×
NEW
1548

×
1549
      case EnumType::RefTrack: {
NEW
1550
        const char *value =
×
NEW
1551
            hdr->entries[reinterpret_cast<uint32 *>(
×
NEW
1552
                             static_cast<char *>(entry.data))[f]]
×
1553
                .name;
1554
        valueNode.append_attribute("value").set_value(value);
1555
        valueNode.set_name("string");
NEW
1556
        break;
×
NEW
1557
      }
×
NEW
1558

×
1559
      case EnumType::EventTrack: {
1560
        const uint32 value =
NEW
1561
            reinterpret_cast<uint32 *>(static_cast<char *>(entry.data))[f];
×
NEW
1562
        valueNode.append_attribute("value").set_value(value);
×
1563
        break;
NEW
1564
      }
×
NEW
1565

×
1566
      case EnumType::HermiteCurveTrack: {
1567
        auto &value = reinterpret_cast<MtHermiteCurve *>(
1568
            static_cast<char *>(entry.data))[f];
1569
        assert(entry.propertyType == MtPropertyType::hermitecurve);
1570

NEW
1571
        valueNode.append_attribute("x0").set_value(value.x[0]);
×
1572
        valueNode.append_attribute("x1").set_value(value.x[1]);
NEW
1573
        valueNode.append_attribute("x2").set_value(value.x[2]);
×
1574
        valueNode.append_attribute("x3").set_value(value.x[3]);
1575
        valueNode.append_attribute("x4").set_value(value.x[4]);
NEW
1576
        valueNode.append_attribute("x5").set_value(value.x[5]);
×
NEW
1577
        valueNode.append_attribute("x6").set_value(value.x[6]);
×
NEW
1578
        valueNode.append_attribute("x7").set_value(value.x[7]);
×
1579
        valueNode.append_attribute("y0").set_value(value.y[0]);
NEW
1580
        valueNode.append_attribute("y1").set_value(value.y[1]);
×
NEW
1581
        valueNode.append_attribute("y2").set_value(value.y[2]);
×
1582
        valueNode.append_attribute("y3").set_value(value.y[3]);
1583
        valueNode.append_attribute("y4").set_value(value.y[4]);
NEW
1584
        valueNode.append_attribute("y5").set_value(value.y[5]);
×
1585
        valueNode.append_attribute("y6").set_value(value.y[6]);
NEW
1586
        valueNode.append_attribute("y7").set_value(value.y[7]);
×
NEW
1587
        break;
×
1588
      }
NEW
1589

×
NEW
1590
      case EnumType::StringTrack: {
×
1591
        auto &dataPtr =
1592
            reinterpret_cast<PtrTypeChar *>(static_cast<char *>(entry.data))[f];
1593
        auto attr = valueNode.append_attribute("value");
1594

1595
        if (dataPtr) {
NEW
1596
          attr.set_value(dataPtr.operator->());
×
NEW
1597
        }
×
NEW
1598
        break;
×
NEW
1599
      }
×
1600

NEW
1601
      default: {
×
NEW
1602
        // const char *data = entry.data;
×
1603
        PrintError("Unknown track type ", int(entry.trackType));
1604
        break;
NEW
1605
      }
×
UNCOV
1606
      }
×
UNCOV
1607
    }
×
1608
  }
1609
}
1610

×
1611
class revil::SDLImpl {
×
1612
public:
1613
  std::string buffer;
×
UNCOV
1614

×
UNCOV
1615
  bool IsX86() const {
×
1616
    auto hdr = reinterpret_cast<const SDLHeaderV2_x86 *>(buffer.data());
1617
    // Member strings overlaps with padding after baseTrack
1618
    // Big endian are always x86
1619
    // There are no MTF V1 x64 schedulers
×
1620

×
NEW
1621
    return int(hdr->version) < 0x10 || hdr->id == SDL_ID_BE || hdr->strings;
×
1622
  }
1623

1624
  void ToXML(pugi::xml_node node) {
×
NEW
1625
    pugi::xml_node schedNode = NewProperty(MtPropertyType::class_, node);
×
1626
    schedNode.append_attribute("name").set_value("Scheduler");
NEW
1627
    schedNode.append_attribute("type").set_value("rSchedulerXml");
×
NEW
1628
    schedNode.append_attribute("id").set_value("0");
×
1629
    auto hdrBase = reinterpret_cast<SDLHeaderBase *>(buffer.data());
1630

1631
    if (!(int(hdrBase->version) == 0x10 && !IsX86()) &&
1632
        hdrBase->version < SDLVersion::V_20) {
1633
      auto hdr = reinterpret_cast<SDLHeaderV1 *>(buffer.data());
NEW
1634
      ::ToXML(hdr, schedNode);
×
1635
    } else {
1636
      if (IsX86()) {
×
1637
        auto hdr = reinterpret_cast<SDLHeaderV2_x86 *>(buffer.data());
1638
        ::ToXML(hdr, schedNode);
UNCOV
1639
      } else {
×
1640
        auto hdrx64 = reinterpret_cast<SDLHeaderV2_x64 *>(buffer.data());
×
NEW
1641
        ::ToXML(hdrx64, schedNode);
×
1642
      }
1643
    }
×
1644
  }
×
1645
  void Load(BinReaderRef_e rd) {
1646
    uint32 id;
1647
    rd.Read(id);
×
1648
    rd.Seek(0);
1649

×
1650
    if (id == SDL_ID_BE) {
×
1651
      rd.SwapEndian(true);
1652
    } else if (id != SDL_ID) {
×
1653
      throw es::InvalidHeaderError(id);
×
1654
    }
1655

1656
    rd.ReadContainer(buffer, rd.GetSize());
1657

1658
    auto hdrBase = reinterpret_cast<SDLHeaderBase *>(buffer.data());
UNCOV
1659

×
NEW
1660
    if (!(int(hdrBase->version) == 0x10 && !IsX86()) &&
×
NEW
1661
        hdrBase->version < SDLVersion::V_20) {
×
1662
      auto hdr = reinterpret_cast<SDLHeaderV1 *>(buffer.data());
×
1663
      hdr->strings.Fixup(buffer.data());
UNCOV
1664

×
UNCOV
1665
      for (size_t i = 0; i < hdr->numTracks; i++) {
×
1666
        auto &entry = hdr->entries[i];
1667
        es::FixupPointers(buffer.data(), entry.data, entry.frames);
1668
        // This can be misleading, since null is allowed only for root nodes
×
1669
        entry.name.FixupRelative(hdr->strings);
×
1670

×
1671
        if (entry.trackType == SDLTrackType1::ResourceTrack ||
1672
            entry.trackType == SDLTrackType1::StringTrack) {
UNCOV
1673
          for (auto f = 0; f < entry.numFrames; f++) {
×
UNCOV
1674
            reinterpret_cast<es::PointerX86<char> *>(
×
1675
                static_cast<char *>(entry.data))[f]
UNCOV
1676
                .Fixup(hdr->strings);
×
1677
          }
×
UNCOV
1678
        }
×
1679
      }
1680
    } else {
1681
      auto FixupStuff = [&](auto *hdr) {
1682
        const bool shouldSwap = hdr->id == SDL_ID_BE;
×
NEW
1683
        using PtrTypeChar = decltype(hdr->strings);
×
UNCOV
1684

×
1685
        if (shouldSwap) {
1686
          FByteswapper(*hdr);
UNCOV
1687
        }
×
UNCOV
1688

×
1689
        hdr->strings.Fixup(buffer.data());
UNCOV
1690

×
1691
        for (size_t i = 0; i < hdr->numTracks; i++) {
×
1692
          auto &entry = hdr->entries[i];
1693
          if (shouldSwap) {
1694
            FByteswapper(entry);
1695
          }
1696

UNCOV
1697
          es::FixupPointers(buffer.data(), entry.data, entry.frames);
×
1698
          // This can be misleading, since null is allowed only for root nodes
1699
          entry.name.FixupRelative(hdr->strings);
UNCOV
1700

×
1701
          if (shouldSwap) {
1702
            SwapData(entry);
×
UNCOV
1703
          }
×
1704

×
NEW
1705
          using EnumType = decltype(entry.trackType);
×
1706

NEW
1707
          if (entry.trackType == EnumType::ResourceTrack ||
×
1708
              entry.trackType == EnumType::StringTrack) {
1709
            for (auto f = 0; f < entry.numFrames; f++) {
1710
              reinterpret_cast<PtrTypeChar *>(
1711
                  static_cast<char *>(entry.data))[f]
1712
                  .Fixup(hdr->strings);
×
1713
            }
UNCOV
1714
          }
×
UNCOV
1715
        }
×
1716
      };
UNCOV
1717

×
UNCOV
1718
      if (IsX86()) {
×
1719
        auto hdr = reinterpret_cast<SDLHeaderV2_x86 *>(buffer.data());
×
1720
        FixupStuff(hdr);
1721
      } else {
1722
        auto hdr = reinterpret_cast<SDLHeaderV2_x64 *>(buffer.data());
1723
        FixupStuff(hdr);
1724
      }
1725
    }
1726
  }
×
1727
};
1728

×
UNCOV
1729
SDL::SDL() : pi(std::make_unique<SDLImpl>()) {}
×
UNCOV
1730
SDL::~SDL() = default;
×
1731

×
UNCOV
1732
void SDL::Load(BinReaderRef_e rd) { pi->Load(rd); }
×
1733

1734
void SDL::ToXML(pugi::xml_node node) const { pi->ToXML(node); }
×
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

© 2026 Coveralls, Inc