Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 24 additions & 50 deletions src/main/dumpers/schemas/metadata_stringifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@
#include <fmt/format.h>
#include "metadata_stringifier.h"
#include <modules.h>
#include "../../vendor/json.hpp"

using json = nlohmann::ordered_json;
#include <unordered_set>

class SimpleCUtlString {
public:
Expand All @@ -46,26 +44,25 @@ class SimpleCUtlString {
namespace Dumpers::Schemas
{

// Recursively replace all primitive values in JSON with their defaults
void NormalizePrimitiveValues(json& j) {
if (j.is_number_integer()) {
j = 0;
}
else if (j.is_number_float()) {
j = 0.0;
}
else if (j.is_boolean()) {
j = false;
}
else if (j.is_array()) {
for (auto& element : j) {
NormalizePrimitiveValues(element);
}
}
else if (j.is_object()) {
for (auto& [key, value] : j.items()) {
NormalizePrimitiveValues(value);
}
std::unordered_set<std::string> g_classWithBrokenDefaults =
{
"CastSphereSATParams_t",
"Dop26_t",
"FourCovMatrices3",
"VMixVocoderDesc_t",
};

// Any function called after this will have uninitialized variables set to zero
#ifdef WIN32
__declspec(noinline)
#else
__attribute__((noinline))
#endif
void CleanStack() {
// stack size might need to be increased for larger classes (perhaps use alloca with class size + extra)
volatile char stack[0x10000];
for(size_t i = 0; i < sizeof(stack); ++i) {
stack[i] = 0;
}
}

Expand Down Expand Up @@ -133,8 +130,9 @@ namespace Dumpers::Schemas
typedef void* (*GetKV3DefaultsFn)();
typedef int (*SaveKV3AsJsonFn)(void* kv3, SimpleCUtlString& err, SimpleCUtlString& str);

if (!entry.m_pData || !(*(void**)entry.m_pData) || !strcmp(metadataTargetName, "CastSphereSATParams_t")) return "Could not parse KV3 Defaults";
if (!entry.m_pData || !(*(void**)entry.m_pData) || g_classWithBrokenDefaults.contains(metadataTargetName)) return "Could not parse KV3 Defaults";

CleanStack(); // Prepare stack for uninitialized variables in class constructor inside GetKV3Defaults
auto value = reinterpret_cast<GetKV3DefaultsFn>(*(void**)entry.m_pData)();

if (!value) return "Could not parse KV3 Defaults";
Expand All @@ -154,31 +152,7 @@ namespace Dumpers::Schemas
int res = SaveKV3AsJson(*(void**)value, err, buf);

if (res) {
std::string out = buf.Get();

// Fix invalid JSON values produced by SaveKV3AsJson bug (e.g., -nan, nan)
size_t pos = 0;
while ((pos = out.find("nan", pos)) != std::string::npos) {
bool validPrefix = (pos == 0 || out[pos - 1] == ' ' || out[pos - 1] == '\t' || out[pos - 1] == '\n' || out[pos - 1] == '-');
bool validSuffix = (pos + 3 >= out.length() || out[pos + 3] == ' ' || out[pos + 3] == '\n' || out[pos + 3] == ',');

if (validPrefix && validSuffix) {
out[pos] = '0';
out[pos + 1] = '.';
out[pos + 2] = '0';
}
++pos;
}

try {
auto jsonObj = json::parse(out);
NormalizePrimitiveValues(jsonObj);
return jsonObj.dump(1, '\t');
}
catch (const json::parse_error& e) {
spdlog::warn("Failed to parse KV3 JSON for normalization: {}\nJSON content:\n{}", e.what(), out);
return out;
}
return buf.Get();
}

return "Could not parse KV3 Defaults";
Expand All @@ -188,4 +162,4 @@ namespace Dumpers::Schemas
return {};
}

} // namespace Dumpers::Schemas
} // namespace Dumpers::Schemas