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

PredatorCZ / RevilLib / 116

05 Nov 2023 02:19PM UTC coverage: 6.277% (-0.02%) from 6.298%
116

push

github

PredatorCZ
make arc fixes

350 of 5576 relevant lines covered (6.28%)

817.98 hits per line

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

0.32
/src/sdl.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/sdl.hpp"
19
#include "pugixml.hpp"
20
#include "revil/hashreg.hpp"
21
#include "spike/except.hpp"
22
#include "spike/io/binreader_stream.hpp"
23
#include "spike/io/binwritter_stream.hpp"
24
#include "spike/reflect/reflector.hpp"
25
#include "spike/type/bitfield.hpp"
26
#include "spike/type/pointer.hpp"
27
#include "spike/type/vectors.hpp"
28
#include <array>
29
#include <cassert>
30
#include <sstream>
31

32
using namespace revil;
33

34
struct XFSClassMember;
35

36
MAKE_ENUM(ENUMSCOPE(class SDLType
1✔
37
                    : uint8, SDLType),
38
          EMEMBERVAL(RootNode, 1),          //
39
          EMEMBER(ClassNode),               //
40
          EMEMBERVAL(ClassMemberNode, 5),   //
41
          EMEMBER(Int32),                   //
42
          EMEMBERVAL(Vector4, 8),           //
43
          EMEMBER(Float),                   //
44
          EMEMBERVAL(Bool, 11),             //
45
          EMEMBER(NodeIndex),               //
46
          EMEMBERVAL(ResourceInstance, 13), //
47
          EMEMBER(String),                  //
48
          EMEMBER(Unit),                    //
49
          EMEMBER(Curve)                    //
50
);
51

52
enum class UsageType : uint8 {
53
  None,
54
  ClassMember,
55
  NodeRef,
56
  Boolean,
57
  Integer = 6,
58
  Decimal = 12,
59
  String = 14,
60
  Color,
61
  Vector3 = 20,
62
  Quaternion = 22,
63
  Vector2 = 34,
64
  Curve = 57,
65
  ResourcePath = 128,
66
};
67

68
struct SDLFrame {
69
  using Frame = BitMemberDecl<0, 24>;
70
  using Flags = BitMemberDecl<1, 8>;
71
  using type = BitFieldType<uint32, Frame, Flags>;
72
  type data;
73

74
  const type *operator->() const { return &data; }
75
  type *operator->() { return &data; }
76
};
77

78
struct SDLEntry {
79
  SDLType type;
80
  UsageType usageType;
81
  uint16 numFrames;
82
  uint32 parentOrSlot;
83
  es::PointerX64<char> name;
84
  uint32 hashOrArrayIndex;
85
  uint32 unk2;
86
  uint64 unk3;
87
  es::PointerX64<SDLFrame> frames;
88
  es::PointerX64<char> data;
89
};
90

91
struct SDLHeader {
92
  uint32 id;
93
  uint16 version;
94
  uint16 numTracks;
95
  uint32 unk0;
96
  SDLFrame maxFrame;
97
  es::PointerX64<char> baseTrack;
98
  es::PointerX64<char> strings;
99
  SDLEntry entries[];
100
};
101

102
static_assert(sizeof(SDLHeader) == 32);
103

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

107
  if (attr.empty()) {
×
108
    throw std::runtime_error("Cannot find attribute: " + std::string(attrName) +
×
109
                             " for node: " + node.name());
110
  }
111

112
  if constexpr (std::is_same_v<C, int32>) {
113
    return attr.as_int();
×
114
  } else if constexpr (std::is_same_v<C, uint32>) {
115
    return attr.as_uint();
×
116
  } else if constexpr (std::is_same_v<C, bool>) {
117
    return attr.as_bool();
×
118
  } else if constexpr (std::is_same_v<C, float>) {
119
    return attr.as_float();
×
120
  } else if constexpr (std::is_same_v<C, double>) {
121
    return attr.as_double();
122
  } else if constexpr (std::is_same_v<C, int64>) {
123
    return attr.as_llong();
124
  } else if constexpr (std::is_same_v<C, uint64>) {
125
    return attr.as_ullong();
126
  } else if constexpr (std::is_same_v<C, const char *>) {
127
    return attr.as_string();
×
128
  }
129
}
130

×
131
pugi::xml_node XMLChild(pugi::xml_node parentNode, const char *nodeName) {
×
132
  auto node = parentNode.child(nodeName);
133

×
134
  if (node.empty()) {
×
135
    throw std::runtime_error(
136
        "Cannot find child node: " + std::string(nodeName) +
137
        " for node: " + node.name());
138
  }
139

140
  return node;
141
}
142

143
void ToXML(SDLFrame &frame, pugi::xml_node node) {
×
144
  node.append_attribute("frame").set_value(frame->Get<SDLFrame::Frame>());
145
  node.append_attribute("frameFlags").set_value(frame->Get<SDLFrame::Flags>());
146
}
147

148
void FromXML(SDLFrame &frame, pugi::xml_node node) {
149
  frame->Set<SDLFrame::Frame>(FromXMLAttr<uint32>(node, "frame"));
150
  frame->Set<SDLFrame::Flags>(FromXMLAttr<uint32>(node, "frameFlags"));
151
}
152

153
struct PaddingRange {
154
  uint32 offset;
155
  uint32 size;
156
};
×
157

×
158
SDLType GetSDLType(pugi::xml_node node) {
159
  static const auto refEnum = GetReflectedEnum<SDLType>();
×
160

×
161
  for (size_t i = 0; i < refEnum->numMembers; ++i) {
162
    if (std::string_view(refEnum->names[i]) == node.name()) {
163
      return SDLType(refEnum->values[i]);
164
    }
165
  }
×
166

167
  throw std::runtime_error(std::string("Unknown node type: ") + node.name());
168

169
  return SDLType::RootNode;
170
};
171

172
struct NodeRef {
173
  uint32 offset;
174
  std::vector<std::string_view> nodeNames;
175
};
176

177
struct StringPointer {
178
  uint32 offset;
179
  uint32 stringId;
180
};
181

182
struct DataBuilder {
×
183
  std::vector<PaddingRange> paddingRanges;
×
184
  std::vector<StringPointer> stringPointers;
185
  std::map<std::string, size_t> strings;
×
186
  std::stringstream sstr;
×
187
  BinWritterRef dataWr{sstr};
188
  std::vector<SDLEntry> items;
189
  std::map<std::string_view, uint32> classNodes;
190
  std::vector<NodeRef> nodeRefs;
191
  bool firstFrame = true;
192

193
  void WriteValues(pugi::xml_node entries, size_t parentIndex) {
194
    auto SetString = [this](auto &ptr, auto str) {
195
      if (auto found = strings.find(str); found != strings.end()) {
196
        ptr = reinterpret_cast<char *>(found->second);
197
      } else {
×
198
        const size_t newId = strings.size();
199
        strings.emplace(str, newId);
200
        ptr = reinterpret_cast<char *>(newId);
201
      }
202
    };
203

204
    auto ResourceType = [](pugi::xml_node &node) -> uint32 {
205
      if (auto rType = node.attribute("resourceType"); !rType.empty()) {
206
        return MTHashV2(rType.as_string());
207
        // TODO validate class
208
      }
×
209

×
210
      auto hashText = FromXMLAttr<const char *>(node, "resourceHash");
211

×
212
      return strtoul(hashText, nullptr, 16);
×
213
    };
214

215
    auto DoValues = [&](pugi::xml_node &node, SDLEntry &entry) {
216
      auto SaveFrames = [&] {
217
        std::vector<SDLFrame> frames;
218

219
        for (auto frame : node.children("frame")) {
220
          ::FromXML(frames.emplace_back(), frame);
221
        }
222

223
        entry.numFrames = frames.size();
224
        size_t reqArea = frames.size() * sizeof(SDLFrame);
225

226
        for (auto it = paddingRanges.begin(); it != paddingRanges.end(); it++) {
227
          if (it->size >= reqArea) {
228
            dataWr.Push();
229
            dataWr.Seek(it->offset);
230
            entry.frames = reinterpret_cast<SDLFrame *>(dataWr.Tell());
231
            dataWr.WriteContainer(frames);
×
232
            dataWr.Pop();
233

234
            if (it->size == reqArea) {
×
235
              paddingRanges.erase(it);
×
236
            } else {
237
              it->offset += reqArea;
×
238
              it->size -= reqArea;
×
239
            }
240
            return;
241
          }
242
        }
243

244
        entry.frames = reinterpret_cast<SDLFrame *>(dataWr.Tell());
245
        dataWr.WriteContainer(frames);
×
246
      };
247

248
      auto WriteValues = [&](auto value, const char *attrName = "value") {
249
        using value_type = decltype(value);
250
        for (auto frame : node.children("frame")) {
251
          dataWr.Write(FromXMLAttr<value_type>(frame, attrName));
252
        }
253
      };
254

255
      if (!firstFrame) {
256
        SaveFrames();
257
      }
258

259
      const size_t padding = GetPadding(dataWr.Tell(), 16);
260

261
      if (padding > 0) {
×
262
        paddingRanges.emplace_back(PaddingRange{
×
263
            .offset = uint32(dataWr.Tell()),
264
            .size = uint32(padding),
×
265
        });
×
266
        dataWr.Skip(padding);
×
267
      }
×
268

269
      entry.data = reinterpret_cast<char *>(dataWr.Tell());
270

×
271
      switch (entry.type) {
272
      case SDLType::Float:
273
        WriteValues(float());
×
274
        break;
×
275
      case SDLType::Vector4:
×
276
        for (auto frame : node.children("frame")) {
277
          dataWr.Write(FromXMLAttr<float>(frame, "x"));
278
          dataWr.Write(FromXMLAttr<float>(frame, "y"));
×
279
          dataWr.Write(FromXMLAttr<float>(frame, "z"));
×
280
          dataWr.Write(FromXMLAttr<float>(frame, "w"));
×
281
        }
282
        break;
283
      case SDLType::Int32:
284
      case SDLType::Unit:
285
        WriteValues(int32());
286
        break;
287
      case SDLType::NodeIndex: {
288
        auto &nodeRef = nodeRefs.emplace_back();
×
289
        nodeRef.offset = dataWr.Tell();
290

291
        for (auto frame : node.children("frame")) {
×
292
          dataWr.Write<uint32>(0);
×
293
          nodeRef.nodeNames.emplace_back(
×
294
              FromXMLAttr<const char *>(frame, "nodeName"));
295
        }
296
        break;
297
      }
×
298
      case SDLType::Bool:
299
        WriteValues(bool());
300
        dataWr.ApplyPadding(4);
301
        break;
302
      case SDLType::ResourceInstance:
×
303
        for (auto frame : node.children("frame")) {
304
          if (frame.attribute("path").empty()) {
305
            dataWr.Write<uintptr_t>(0);
306
            continue;
307
          }
308

309
          const uint32 cHash = ResourceType(frame);
310
          std::string wString(sizeof(cHash), '-');
311
          wString.append(FromXMLAttr<const char *>(frame, "path"));
312
          memcpy(wString.data(), &cHash, sizeof(cHash));
313
          const char *ptr;
314
          SetString(ptr, wString);
315
          stringPointers.emplace_back(StringPointer{
316
              .offset = uint32(dataWr.Tell()),
317
              .stringId = uint32(reinterpret_cast<uintptr_t>(ptr)),
318
          });
319
          dataWr.Write(ptr);
320
        }
321
        break;
322
      case SDLType::String:
323
        for (auto frame : node.children("frame")) {
×
324
          const char *ptr;
×
325
          SetString(ptr, FromXMLAttr<const char *>(frame, "value"));
×
326
          stringPointers.emplace_back(StringPointer{
×
327
              .offset = uint32(dataWr.Tell()),
328
              .stringId = uint32(reinterpret_cast<uintptr_t>(ptr)),
×
329
          });
×
330
          dataWr.Write(ptr);
×
331
        }
332
        break;
333
      case SDLType::Curve:
×
334
        for (auto frame : node.children("frame")) {
×
335
          for (size_t i = 0; i < 16; i++) {
×
336
            auto aName = "e" + std::to_string(i);
337
            dataWr.Write(FromXMLAttr<float>(frame, aName.c_str()));
×
338
          }
339
        }
×
340
        break;
341

342
      default:
×
343
        break;
×
344
      }
×
345

346
      if (firstFrame) {
×
347
        firstFrame = false;
348
        SaveFrames();
×
349
      }
350
    };
351

×
352
    for (auto c : entries.children()) {
×
353
      SDLEntry entry{};
×
354
      entry.type = GetSDLType(c);
355
      entry.usageType = UsageType(FromXMLAttr<uint32>(c, "type"));
×
356
      auto nodeName = FromXMLAttr<const char *>(c, "name");
×
357
      SetString(entry.name, nodeName);
×
358

359
      switch (entry.type) {
360
      case SDLType::RootNode:
361
        classNodes.emplace(nodeName, items.size());
×
362
        items.emplace_back(entry);
×
363
        WriteValues(c, 0);
×
364
        break;
365

366
      case SDLType::ClassNode:
367
        entry.hashOrArrayIndex = ResourceType(c);
×
368
        entry.parentOrSlot = FromXMLAttr<uint32>(c, "entrySlot");
369
        classNodes.emplace(nodeName, items.size());
×
370
        items.emplace_back(entry);
371
        WriteValues(c, items.size() - 1);
372
        break;
×
373

×
374
      case SDLType::ClassMemberNode:
×
375
        entry.hashOrArrayIndex = FromXMLAttr<uint32>(c, "arrayIndex");
376
        entry.parentOrSlot = parentIndex;
×
377
        items.emplace_back(entry);
×
378
        WriteValues(c, items.size() - 1);
379
        break;
380

×
381
      default:
×
382
        entry.hashOrArrayIndex = FromXMLAttr<uint32>(c, "arrayIndex");
383
        entry.parentOrSlot = parentIndex;
×
384
        DoValues(c, entry);
×
385
        items.emplace_back(entry);
386
        break;
×
387
      }
×
388
    }
×
389
  }
390
  /*
391
    void WriteFrames(pugi::xml_node entries) {
×
392
      auto DoFrames = [&](pugi::xml_node &node) {
×
393
        std::vector<SDLFrame> frames;
394

×
395
        for (auto frame : node.children("frame")) {
×
396
          ::FromXML(frames.emplace_back(), frame);
397
        }
398

399
        const size_t reqArea = frames.size() * sizeof(SDLFrame);
400

401
        if (reqArea > 12) {
×
402
          const uint32 retOffset = dataWr.Tell();
×
403
          dataWr.WriteContainer(frames);
404
          return retOffset;
405
        }
×
406

407
        for (auto it = paddingRanges.begin(); it != paddingRanges.end(); it++) {
×
408
          if (it->size == reqArea) {
×
409
            dataWr.Push();
410
            dataWr.Seek(it->offset);
411
            dataWr.WriteContainer(frames);
×
412
            dataWr.Pop();
413
            const uint32 retOffset = it->offset;
×
414
            paddingRanges.erase(it);
×
415
            return retOffset;
416
          }
417
        }
×
418

419
        auto bestAreaIt = paddingRanges.begin();
×
420
        uint32 minSize = 16;
×
421

422
        for (auto it = bestAreaIt; it != paddingRanges.end(); it++) {
423
          if (it->size > reqArea) {
×
424
            if (it->size < minSize) {
425
              bestAreaIt = it;
×
426
              minSize = it->size;
×
427
            }
428
          }
429
        }
430

×
431
        if (minSize < 16) {
×
432
          dataWr.Push();
433
          dataWr.Seek(bestAreaIt->offset);
434
          dataWr.WriteContainer(frames);
435
          dataWr.Pop();
436
          const uint32 retOffset = bestAreaIt->offset;
437
          bestAreaIt->offset += reqArea;
×
438
          bestAreaIt->size -= reqArea;
439
          return retOffset;
440
        }
441

×
442
        const uint32 retOffset = dataWr.Tell();
443
        dataWr.WriteContainer(frames);
444
        return retOffset;
×
445
      };
446

×
447
      for (auto c : entries.children()) {
×
448
        SDLType type = GetSDLType(c);
×
449

450
        switch (type) {
×
451
        case SDLType::RootNode:
×
452
          break;
×
453
        case SDLType::ArrayEntry:
×
454
        case SDLType::ClassNode:
×
455
          WriteFrames(c);
×
456
          break;
457

×
458
        default:
×
459
          frameOffsetStack.emplace_back(DoFrames(c));
460
          break;
×
461
        }
462
      }
×
463
    }*/
×
464
};
×
465

466
constexpr uint32 SDL_ID = CompileFourCC("SDL");
×
467

×
468
void revil::SDLFromXML(BinWritterRef wr, pugi::xml_node rootNode) {
×
469
  auto classNode = XMLChild(rootNode, "class");
×
470

471
  if (std::string_view("rScheduler") !=
×
472
      FromXMLAttr<const char *>(classNode, "type")) {
473
    throw std::runtime_error("Invalid class type, expected rScheduler");
×
474
  }
×
475

×
476
  SDLHeader hdr{};
477
  hdr.id = SDL_ID;
×
478
  hdr.version = 0x16;
×
479
  hdr.unk0 = 0xE2316427;
×
480
  ::FromXML(hdr.maxFrame, XMLChild(classNode, "maxFrame"));
×
481
  auto entries = XMLChild(classNode, "entries");
×
482
  DataBuilder dataBuilder;
483
  dataBuilder.WriteValues(entries, 0);
484
  hdr.numTracks = dataBuilder.items.size();
×
485

486
  wr.Write(hdr);
×
487
  wr.WriteContainer(dataBuilder.items);
488
  const size_t dataOffset = wr.Tell();
489
  std::string dataBuffer(std::move(dataBuilder.sstr).str());
×
490
  wr.WriteContainer(dataBuffer);
×
491
  es::Dispose(dataBuffer);
492
  uintptr_t stringBegin = wr.Tell();
493
  hdr.strings = reinterpret_cast<char *>(stringBegin);
494
  std::vector<uintptr_t> stringOffsets;
495
  std::vector<std::string_view> strings;
496
  strings.resize(dataBuilder.strings.size());
×
497

×
498
  for (auto &[str, id] : dataBuilder.strings) {
×
499
    strings.at(id) = str.c_str();
500
  }
×
501

×
502
  for (size_t i = 0; i < strings.size(); i++) {
503
    stringOffsets.emplace_back(wr.Tell() - stringBegin);
504
    wr.WriteT(strings.at(i));
505
  }
506

507
  for (auto &e : dataBuilder.items) {
×
508
    e.name = reinterpret_cast<char *>(
×
509
        stringOffsets.at(reinterpret_cast<uintptr_t &>(e.name)));
×
510

×
511
    if (e.numFrames > 0) {
×
512
      e.data.FixupRelative(reinterpret_cast<char *>(dataOffset));
×
513
      e.frames.FixupRelative(reinterpret_cast<char *>(dataOffset));
514
    }
515
  }
×
516

517
  for (auto p : dataBuilder.stringPointers) {
518
    wr.Seek(dataOffset + p.offset);
519
    wr.Write(stringOffsets.at(p.stringId));
520
  }
521

×
522
  for (auto r : dataBuilder.nodeRefs) {
×
523
    wr.Seek(dataOffset + r.offset);
×
524

525
    for (auto &n : r.nodeNames) {
526
      wr.Write(dataBuilder.classNodes.at(n));
527
    }
×
528
  }
×
529

×
530
  wr.Seek(0);
×
531
  wr.Write(hdr);
×
532
  wr.WriteContainer(dataBuilder.items);
×
533
}
534

×
535
class revil::SDLImpl {
×
536
public:
×
537
  std::string buffer;
×
538

×
539
  void ToXML(pugi::xml_node node) {
540
    auto root = node.append_child("class");
541
    auto hdr = reinterpret_cast<SDLHeader *>(buffer.data());
×
542

×
543
    root.append_attribute("type").set_value("rScheduler");
×
544
    ::ToXML(hdr->maxFrame, root.append_child("maxFrame"));
×
545
    assert(hdr->baseTrack == nullptr);
×
546

×
547
    auto entries = root.append_child("entries");
548
    std::vector<pugi::xml_node> nodes;
549
    pugi::xml_node currentRoot;
×
550

×
551
    for (size_t i = 0; i < hdr->numTracks; i++) {
×
552
      auto &entry = hdr->entries[i];
×
553
      assert(entry.unk2 == 0);
×
554
      assert(entry.unk3 == 0);
555
      static const auto refEnum = GetReflectedEnum<SDLType>();
556
      auto typeName = [&] {
×
557
        const size_t numEns = refEnum->numMembers;
×
558

×
559
        for (size_t i = 0; i < numEns; i++) {
×
560
          if (refEnum->values[i] == static_cast<uint64>(entry.type)) {
×
561
            return refEnum->names[i];
562
          }
563
        }
564

565
        return "__UNREGISTERED__";
566
      }();
567

568
      pugi::xml_node xEntry;
569

570
      auto SetClassName = [](pugi::xml_node &node, uint32 hash) {
571
        auto clName = GetClassName(hash, Platform::Win32);
572

573
        if (clName.empty()) {
574
          char buffer[0x10]{};
575
          snprintf(buffer, sizeof(buffer), "%X", hash);
576
          node.append_attribute("resourceHash").set_value(buffer);
577
        } else {
578
          node.append_attribute("resourceType").set_value(clName.data());
579
        }
580
      };
581

582
      switch (entry.type) {
583
      case SDLType::Float:
584
      case SDLType::Vector4:
585
      case SDLType::Int32:
586
      case SDLType::ClassMemberNode:
587
      case SDLType::Bool:
588
      case SDLType::NodeIndex:
589
      case SDLType::ResourceInstance:
590
      case SDLType::String:
591
      case SDLType::Unit:
592
      case SDLType::Curve:
593
        xEntry = nodes.at(entry.parentOrSlot).append_child(typeName);
594
        xEntry.append_attribute("arrayIndex").set_value(entry.hashOrArrayIndex);
595
        break;
596

597
      default:
598
        xEntry = currentRoot.append_child(typeName);
599
        xEntry.append_attribute("entrySlot").set_value(entry.parentOrSlot);
600
        SetClassName(xEntry, entry.hashOrArrayIndex);
601
        break;
602
      case SDLType::RootNode:
603
        xEntry = currentRoot = entries.append_child(typeName);
604
        assert(entry.parentOrSlot == 0);
605
        break;
606
      }
607

608
      nodes.emplace_back(xEntry);
609

610
      xEntry.append_attribute("name").set_value(entry.name);
611
      xEntry.append_attribute("type").set_value(uint8(entry.usageType));
612

613
      if (entry.numFrames > 0) {
614
        SDLFrame *frames = entry.frames;
615

616
        for (auto f = 0; f < entry.numFrames; f++) {
617
          auto frame = frames[f];
618
          auto xFrame = xEntry.append_child("frame");
619
          ::ToXML(frame, xFrame);
620

621
          switch (entry.type) {
622
          case SDLType::Int32:
623
          case SDLType::Unit:
624
            xFrame.append_attribute("value").set_value(
625
                reinterpret_cast<int32 *>(static_cast<char *>(entry.data))[f]);
626
            break;
627
          case SDLType::Vector4: {
628
            auto &value =
629
                reinterpret_cast<Vector4 *>(static_cast<char *>(entry.data))[f];
630
            xFrame.append_attribute("x").set_value(value.x);
631
            xFrame.append_attribute("y").set_value(value.y);
632
            xFrame.append_attribute("z").set_value(value.z);
633
            xFrame.append_attribute("w").set_value(value.w);
634
            break;
635
          }
636
          case SDLType::Float:
637
            xFrame.append_attribute("value").set_value(
638
                reinterpret_cast<float *>(static_cast<char *>(entry.data))[f]);
639
            break;
640
          case SDLType::Bool:
641
            xFrame.append_attribute("value").set_value(
642
                reinterpret_cast<bool *>(static_cast<char *>(entry.data))[f]);
643
            break;
×
644
          case SDLType::NodeIndex:
×
645
            xFrame.append_attribute("nodeName")
646
                .set_value(hdr->entries[reinterpret_cast<uint32 *>(
647
                                            static_cast<char *>(entry.data))[f]]
×
648
                               .name);
×
649
            break;
650

651
          case SDLType::ResourceInstance: {
×
652
            auto &dataPtr = reinterpret_cast<es::PointerX64<uint32> *>(
×
653
                static_cast<char *>(entry.data))[f];
×
654

×
655
            if (dataPtr) {
×
656
              SetClassName(xFrame, *dataPtr);
×
657
              xFrame.append_attribute("path").set_value(
×
658
                  reinterpret_cast<const char *>(dataPtr.operator->() + 1));
×
659
            }
×
660

661
            break;
662
          }
×
663

664
          case SDLType::Curve: {
665
            auto &value = reinterpret_cast<std::array<float, 16> *>(
666
                static_cast<char *>(entry.data))[f];
667
            for (size_t i = 0; i < value.size(); i++) {
668
              auto aName = "e" + std::to_string(i);
×
669
              xFrame.append_attribute(aName.c_str()).set_value(value[i]);
×
670
            }
×
671
            break;
×
672
          }
673

×
674
          case SDLType::String:
×
675
            xFrame.append_attribute("value").set_value(
676
                reinterpret_cast<es::PointerX64<char> *>(
677
                    static_cast<char *>(entry.data))[f]);
×
678

×
679
            break;
×
680

681
          default:
682
            break;
×
683
          }
684
        }
×
685
      }
686
    }
×
687
  }
×
688
  void Load(BinReaderRef_e rd) {
689
    uint32 id;
690
    rd.Read(id);
691
    rd.Seek(0);
692

×
693
    if (id != SDL_ID) {
×
694
      throw es::InvalidHeaderError(id);
×
695
    }
696

697
    rd.ReadContainer(buffer, rd.GetSize());
×
698

×
699
    auto hdr = reinterpret_cast<SDLHeader *>(buffer.data());
700
    es::FixupPointers(buffer.data(), hdr->baseTrack, hdr->strings);
×
701

×
702
    for (size_t i = 0; i < hdr->numTracks; i++) {
703
      auto &entry = hdr->entries[i];
704
      es::FixupPointers(buffer.data(), entry.data, entry.frames);
705
      // This can be misleading, since null is allowed only for root nodes
706
      entry.name.FixupRelative(hdr->strings);
707

×
708
      if (entry.type == SDLType::ResourceInstance ||
709
          entry.type == SDLType::String) {
710
        for (auto f = 0; f < entry.numFrames; f++) {
×
711
          reinterpret_cast<es::PointerX64<char> *>(
712
              static_cast<char *>(entry.data))[f]
713
              .Fixup(hdr->strings);
714
        }
×
715
      }
×
716
    }
717
  }
718
};
×
719

×
720
SDL::SDL() : pi(std::make_unique<SDLImpl>()) {}
721
SDL::~SDL() = default;
722

×
723
void SDL::Load(BinReaderRef_e rd) { pi->Load(rd); }
×
724

×
725
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