Skip to content

Commit da1c38d

Browse files
committed
refactor: split exporting from dumping
1 parent bfdfd1b commit da1c38d

8 files changed

Lines changed: 337 additions & 146 deletions

File tree

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@
2121
path = vendor/fmt
2222
url = https://github.com/fmtlib/fmt
2323
shallow = true
24+
[submodule "vendor/json"]
25+
path = vendor/json
26+
url = https://github.com/nlohmann/json
27+
shallow = true
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/**
2+
* =============================================================================
3+
* DumpSource2
4+
* Copyright (C) 2024 ValveResourceFormat Contributors
5+
* =============================================================================
6+
*
7+
* This program is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, version 3.0, as published by the
9+
* Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with
17+
* this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "filesystem_exporter.h"
21+
#include "globalvariables.h"
22+
#include "interfaces.h"
23+
#include <filesystem>
24+
#include <fstream>
25+
#include <map>
26+
#include <unordered_set>
27+
#include <algorithm>
28+
#include <optional>
29+
#include <spdlog/spdlog.h>
30+
31+
namespace Dumpers::Schemas::FilesystemExporter
32+
{
33+
34+
std::string CommentBlock(std::string str)
35+
{
36+
size_t pos = 0;
37+
while ((pos = str.find('\n', pos)) != std::string::npos) {
38+
str.replace(pos, 1, "\n//");
39+
pos += 3;
40+
}
41+
42+
return str;
43+
}
44+
45+
46+
void OutputMetadataEntry(const IntermediateMetadata& entry, std::ofstream& output, bool tabulate)
47+
{
48+
output << (tabulate ? "\t" : "") << "// " << entry.name;
49+
50+
if (entry.hasValue) {
51+
if (entry.stringValue) {
52+
output << " = " << CommentBlock(*entry.stringValue);
53+
}
54+
else
55+
output << " (UNKNOWN FOR PARSER)";
56+
}
57+
58+
output << "\n";
59+
}
60+
61+
void DumpClasses(const std::vector<IntermediateSchemaClass>& classes, std::filesystem::path schemaPath, std::map<std::string, std::unordered_set<std::string>>& foundFiles)
62+
{
63+
for (const auto& intermediateClass : classes)
64+
{
65+
if (!std::filesystem::is_directory(schemaPath / intermediateClass.module))
66+
if (!std::filesystem::create_directory(schemaPath / intermediateClass.module))
67+
return;
68+
69+
// Some classes have :: in them which we can't save.
70+
auto sanitizedFileName = intermediateClass.name;
71+
std::replace(sanitizedFileName.begin(), sanitizedFileName.end(), ':', '_');
72+
73+
// We save the file in a map so that we know which files are outdated and should be removed
74+
foundFiles[intermediateClass.module].insert(sanitizedFileName);
75+
76+
std::ofstream output((schemaPath / intermediateClass.module / sanitizedFileName).replace_extension(".h"));
77+
78+
// Output metadata entries as comments before the class definition
79+
spdlog::trace("Dumping class: '{}'", intermediateClass.name);
80+
for (const auto& metadata : intermediateClass.metadata)
81+
{
82+
OutputMetadataEntry(metadata, output, false);
83+
}
84+
85+
output << "class " << intermediateClass.name;
86+
Globals::stringsIgnoreStream << intermediateClass.name << "\n";
87+
88+
bool wroteBase = false;
89+
for (const auto& parent : intermediateClass.parents)
90+
{
91+
if (!wroteBase)
92+
{
93+
output << " : public " << parent.name;
94+
wroteBase = true;
95+
}
96+
else
97+
{
98+
output << ", public " << parent.name;
99+
}
100+
}
101+
102+
output << "\n{\n";
103+
104+
for (const auto& field : intermediateClass.fields)
105+
{
106+
spdlog::trace("Dumping field: '{}' for class: '{}'", field.name, intermediateClass.name);
107+
// Output metadata entires as comments before the field definition
108+
for (const auto& metadata : field.metadata)
109+
{
110+
OutputMetadataEntry(metadata, output, true);
111+
}
112+
113+
output << "\t" << field.type->m_sTypeName.String() << " " << field.name << ";\n";
114+
Globals::stringsIgnoreStream << field.name << "\n";
115+
}
116+
117+
output << "};\n";
118+
}
119+
}
120+
121+
void DumpEnums(const std::vector<IntermediateSchemaEnum>& enums, std::filesystem::path schemaPath, std::map<std::string, std::unordered_set<std::string>>& foundFiles)
122+
{
123+
for (const auto& intermediateEnum : enums)
124+
{
125+
if (!std::filesystem::is_directory(schemaPath / intermediateEnum.module))
126+
if (!std::filesystem::create_directory(schemaPath / intermediateEnum.module))
127+
return;
128+
129+
// Some classes have :: in them which we can't save.
130+
auto sanitizedFileName = intermediateEnum.name;
131+
std::replace(sanitizedFileName.begin(), sanitizedFileName.end(), ':', '_');
132+
133+
// We save the file in a map so that we know which files are outdated and should be removed
134+
foundFiles[intermediateEnum.module].insert(sanitizedFileName);
135+
136+
std::ofstream output((schemaPath / intermediateEnum.module / sanitizedFileName).replace_extension(".h"));
137+
138+
for(const auto& metadata : intermediateEnum.metadata)
139+
{
140+
OutputMetadataEntry(metadata, output, false);
141+
}
142+
143+
output << "enum " << intermediateEnum.name << " : " << (intermediateEnum.stringAlignment.has_value() ? *intermediateEnum.stringAlignment : "unknown alignment type") << "\n{\n";
144+
Globals::stringsIgnoreStream << intermediateEnum.name << "\n";
145+
146+
for (const auto& member : intermediateEnum.members)
147+
{
148+
// Output metadata entires as comments before the field definition
149+
for(const auto& metadata: member.metadata)
150+
{
151+
OutputMetadataEntry(metadata, output, true);
152+
}
153+
154+
output << "\t" << member.name << " = " << member.value << ",\n";
155+
Globals::stringsIgnoreStream << member.name << "\n";
156+
}
157+
158+
output << "};\n";
159+
}
160+
}
161+
162+
void Dump(const std::vector<IntermediateSchemaEnum>& enums, const std::vector<IntermediateSchemaClass>& classes)
163+
{
164+
spdlog::info("Dumping schemas to filesystem");
165+
const auto schemaPath = Globals::outputPath / "schemas";
166+
167+
if (!std::filesystem::is_directory(schemaPath))
168+
if (!std::filesystem::create_directory(schemaPath))
169+
return;
170+
171+
std::map<std::string, std::unordered_set<std::string>> foundFiles;
172+
173+
DumpClasses(classes, schemaPath, foundFiles);
174+
DumpEnums(enums, schemaPath, foundFiles);
175+
176+
for (const auto& entry : std::filesystem::directory_iterator(schemaPath))
177+
{
178+
auto projectName = entry.path().filename().string();
179+
bool isInMap = foundFiles.find(projectName) != foundFiles.end();
180+
181+
if (entry.is_directory() && !isInMap)
182+
{
183+
spdlog::info("Removing orphan schema folder {}", entry.path().generic_string());
184+
std::filesystem::remove_all(entry.path());
185+
}
186+
else if (isInMap)
187+
{
188+
189+
for (const auto& typeScopePath : std::filesystem::directory_iterator(entry.path()))
190+
{
191+
auto& filesSet = foundFiles[projectName];
192+
193+
if (filesSet.find(typeScopePath.path().stem().string()) == filesSet.end())
194+
{
195+
spdlog::info("Removing orphan schema file {}", typeScopePath.path().generic_string());
196+
std::filesystem::remove(typeScopePath.path());
197+
}
198+
}
199+
}
200+
}
201+
}
202+
203+
} // namespace Dumpers::Schemas::FilesystemExporter
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* =============================================================================
3+
* DumpSource2
4+
* Copyright (C) 2026 ValveResourceFormat Contributors
5+
* =============================================================================
6+
*
7+
* This program is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU General Public License, version 3.0, as published by the
9+
* Free Software Foundation.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU General Public License along with
17+
* this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
#pragma once
20+
#include "schemas.h"
21+
22+
namespace Dumpers::Schemas::FilesystemExporter
23+
{
24+
void Dump(const std::vector<IntermediateSchemaEnum>& enums, const std::vector<IntermediateSchemaClass>& classes);
25+
} // namespace Dumpers::Schemas::FilesystemExporter

src/main/dumpers/schemas/metadata_stringifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ __attribute__((noinline))
9292
// Determine how and if to output metadata entry value based on it's type.
9393
std::optional<std::string> GetMetadataValue(const SchemaMetadataEntryData_t& entry, const char* metadataTargetName)
9494
{
95-
if (g_mapMetadataNameToValue.find(entry.m_pszName) != g_mapMetadataNameToValue.end())
95+
if (entry.m_pData && g_mapMetadataNameToValue.find(entry.m_pszName) != g_mapMetadataNameToValue.end())
9696
{
9797
auto valueType = g_mapMetadataNameToValue.at(entry.m_pszName);
9898
switch (valueType)

0 commit comments

Comments
 (0)