activity_sdk_decode_plans_index.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #include "activity_sdk_decode_plans_internal.h"
  2. namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal {
  3. namespace {
  4. /** Codec block: bound handle at +0x10, serialized size at +0x18, field rows from +0x28. */
  5. constexpr std::uint64_t kCodecHandleAt = 0x10;
  6. constexpr std::uint64_t kCodecSerializedAt = 0x18;
  7. constexpr std::uint64_t kCodecFieldsAt = 0x28;
  8. /** Bit offset of one field inside its 40-byte row. */
  9. constexpr std::uint64_t kFieldBitAt = 8;
  10. } // namespace
  11. /**
  12. * Walks every bound record's block chain and rows its codec block.
  13. * The chain must close exactly and a codec block must name its own bound handle.
  14. */
  15. bool build_codec_index(const Image& image,
  16. std::vector<SchemaRow>& rows,
  17. std::vector<std::uint32_t>& fieldValues,
  18. const char*& error) noexcept {
  19. try {
  20. rows.clear();
  21. fieldValues.clear();
  22. for (const auto& [handle, address] : image.slots()) {
  23. std::uint32_t length = 0;
  24. if (!image.u32(address, length)) {
  25. error = "record_read";
  26. return false;
  27. }
  28. std::uint32_t marker = 0;
  29. for (const std::uint32_t candidate : kMarkerOffsets) {
  30. std::uint32_t value = 0;
  31. if (candidate + 8 <= length && image.u32(address + candidate, value)
  32. && value == kReflectionMarker) {
  33. marker = candidate;
  34. break;
  35. }
  36. }
  37. if (marker == 0) {
  38. continue;
  39. }
  40. std::uint64_t cursor = marker;
  41. bool codec = false;
  42. std::uint64_t codecAt = 0;
  43. std::uint32_t codecCount = 0;
  44. while (cursor < length) {
  45. std::uint32_t kind = 0;
  46. std::uint32_t count = 0;
  47. BlockLayout layout{};
  48. if (!image.u32(address + cursor + 4, kind)
  49. || !image.u32(address + cursor + 8, count)) {
  50. error = "record_read";
  51. return false;
  52. }
  53. if (!block_layout(kind, layout)) {
  54. error = "reflection_block_unknown";
  55. return false;
  56. }
  57. const std::uint64_t size = layout.header + std::uint64_t{layout.stride} * count;
  58. if (cursor + size > length) {
  59. error = "reflection_block_extent";
  60. return false;
  61. }
  62. if (kind == kCodecBlock) {
  63. std::uint32_t bound = 0;
  64. if (!image.u32(address + cursor + kCodecHandleAt, bound)) {
  65. error = "record_read";
  66. return false;
  67. }
  68. if (bound != handle) {
  69. error = "codec_handle_mismatch";
  70. return false;
  71. }
  72. if (codec) {
  73. error = "codec_block_repeated";
  74. return false;
  75. }
  76. codec = true;
  77. codecAt = cursor;
  78. codecCount = count;
  79. }
  80. cursor += size;
  81. }
  82. if (cursor != length) {
  83. error = "reflection_chain_open";
  84. return false;
  85. }
  86. if (!codec) {
  87. continue;
  88. }
  89. SchemaRow row{handle, 0, static_cast<std::uint32_t>(fieldValues.size()), codecCount};
  90. if (!image.u32(address + codecAt + kCodecSerializedAt, row.size)) {
  91. error = "record_read";
  92. return false;
  93. }
  94. for (std::uint32_t index = 0; index < codecCount; ++index) {
  95. std::uint32_t bit = 0;
  96. if (!image.u32(address + codecAt + kCodecFieldsAt + kFieldRowSize * index
  97. + kFieldBitAt,
  98. bit)) {
  99. error = "record_read";
  100. return false;
  101. }
  102. fieldValues.push_back(bit);
  103. }
  104. rows.push_back(row);
  105. }
  106. return true;
  107. } catch (...) {
  108. error = "allocation";
  109. return false;
  110. }
  111. }
  112. } // namespace sunrise::client::content::activity::sdk_generation::decode_plans::internal