First pass idLib conversion from hex rays4.

This commit is contained in:
Justin Marshall
2026-08-08 13:54:26 -07:00
parent 3d01d735ce
commit 09a4cb91c3
120 changed files with 17718 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "../text/str.h"
class idXMLAttribute {
public:
idXMLAttribute(const char* attributeName = "", const char* attributeValue = "")
: name(attributeName), value(attributeValue) {
name.TrimWhitespaceRecovered();
}
const char* GetName() const { return name.c_str(); }
const char* GetValue() const { return value.c_str(); }
void SetValue(const char* newValue) { value = newValue; }
void FormatEntities() {
name.ReplaceRecovered("&", "&");
name.ReplaceRecovered("&lt;", "<");
name.ReplaceRecovered("&gt;", ">");
value.ReplaceRecovered("&amp;", "&");
value.ReplaceRecovered("&lt;", "<");
value.ReplaceRecovered("&gt;", ">");
}
private:
idStr name;
idStr value;
};
static_assert(sizeof(idXMLAttribute) == 64,
"Recovered idXMLAttribute ABI changed");
+71
View File
@@ -0,0 +1,71 @@
#include "xmlelement.h"
idXMLElement::idXMLElement(const char* const elementName)
: name(elementName), value(), attributes(), children() {
}
idXMLElement::idXMLElement(const char* const elementName,
const char* const elementValue)
: name(elementName), value(elementValue), attributes(), children() {
}
idXMLElement::~idXMLElement() {
for (int index = 0; index < children.Num(); ++index) {
idXMLElement* const child = children[index];
if (child != nullptr) {
child->~idXMLElement();
std::free(child);
}
}
}
idXMLAttribute* idXMLElement::AddAttribute(const char* const attributeName,
const char* const attributeValue) {
return attributes.Append(idXMLAttribute(attributeName, attributeValue));
}
idXMLElement* idXMLElement::AddChild(const char* const childName,
const char* const childValue) {
idXMLElement* const child = Create(childName, childValue);
if (child == nullptr) {
return nullptr;
}
if (children.Append(child) == nullptr) {
Destroy(child);
return nullptr;
}
return child;
}
idXMLElement* idXMLElement::Create(const char* const elementName,
const char* const elementValue) {
void* const storage = std::malloc(sizeof(idXMLElement));
return storage == nullptr ? nullptr
: new (storage) idXMLElement(elementName, elementValue);
}
void idXMLElement::Destroy(idXMLElement* const element) {
if (element != nullptr) {
element->~idXMLElement();
std::free(element);
}
}
void idXMLElement::FormatStrings() {
FormatStrings_R(this);
}
void idXMLElement::FormatStrings_R(idXMLElement* const element) {
for (int index = 0; index < element->children.Num(); ++index) {
FormatStrings_R(element->children[index]);
}
element->name.ReplaceRecovered("&amp;", "&");
element->name.ReplaceRecovered("&lt;", "<");
element->name.ReplaceRecovered("&gt;", ">");
element->value.ReplaceRecovered("&amp;", "&");
element->value.ReplaceRecovered("&lt;", "<");
element->value.ReplaceRecovered("&gt;", ">");
for (int index = 0; index < element->attributes.Num(); ++index) {
element->attributes[index].FormatEntities();
}
}
+129
View File
@@ -0,0 +1,129 @@
#pragma once
#include "xmlattribute.h"
#include <cstdint>
#include <cstdlib>
#include <new>
template<typename type>
class idRecoveredList {
public:
explicit idRecoveredList(const std::uint8_t tag = 44,
const std::int16_t initialGranularity = 16)
: list(nullptr), num(0), size(0), granularity(initialGranularity),
memTag(tag), listStatic(0) {
}
~idRecoveredList() {
Clear();
}
idRecoveredList(const idRecoveredList&) = delete;
idRecoveredList& operator=(const idRecoveredList&) = delete;
int Num() const { return num; }
type& operator[](const int index) { return list[index]; }
const type& operator[](const int index) const { return list[index]; }
type* Append(const type& value) {
if (num == size && !Grow()) {
return nullptr;
}
list[num] = value;
return &list[num++];
}
void Clear() {
if (list != nullptr) {
for (int index = 0; index < size; ++index) {
list[index].~type();
}
std::free(list);
}
list = nullptr;
num = 0;
size = 0;
}
private:
type* list;
int num;
int size;
std::int16_t granularity;
std::uint8_t memTag;
std::uint8_t listStatic;
bool Grow() {
const int amount = granularity > 0 ? granularity : 16;
const int newSize = size + amount;
type* const replacement = static_cast<type*>(
std::malloc(sizeof(type) * static_cast<std::size_t>(newSize))
);
if (replacement == nullptr) {
return false;
}
for (int index = 0; index < newSize; ++index) {
new (&replacement[index]) type();
}
for (int index = 0; index < num; ++index) {
replacement[index] = list[index];
}
if (list != nullptr) {
for (int index = 0; index < size; ++index) {
list[index].~type();
}
std::free(list);
}
list = replacement;
size = newSize;
return true;
}
};
static_assert(sizeof(idRecoveredList<int>) == 16,
"Recovered idList ABI changed");
class idXMLElement {
public:
explicit idXMLElement(const char* elementName = "");
idXMLElement(const char* elementName, const char* elementValue);
~idXMLElement();
idXMLElement(const idXMLElement&) = delete;
idXMLElement& operator=(const idXMLElement&) = delete;
const char* GetName() const { return name.c_str(); }
const char* GetValue() const { return value.c_str(); }
void SetValue(const char* newValue) { value = newValue; }
idXMLAttribute* AddAttribute(const char* attributeName,
const char* attributeValue);
idXMLElement* AddChild(const char* childName, const char* childValue = "");
bool AdoptChild(idXMLElement* child) { return children.Append(child) != nullptr; }
void AppendValue(const char* text) { value.Append(text); }
void AppendValue(char character) { value.Append(character); }
int NumAttributes() const { return attributes.Num(); }
int NumChildren() const { return children.Num(); }
idXMLAttribute& GetAttribute(const int index) { return attributes[index]; }
const idXMLAttribute& GetAttribute(const int index) const { return attributes[index]; }
idXMLElement* GetChild(const int index) { return children[index]; }
const idXMLElement* GetChild(const int index) const { return children[index]; }
void FormatStrings();
static idXMLElement* Create(const char* elementName,
const char* elementValue = "");
static void Destroy(idXMLElement* element);
private:
idStr name;
idStr value;
idRecoveredList<idXMLAttribute> attributes;
idRecoveredList<idXMLElement*> children;
void FormatStrings_R(idXMLElement* element);
};
static_assert(sizeof(idXMLElement) == 96,
"Recovered idXMLElement ABI changed");
+201
View File
@@ -0,0 +1,201 @@
#include "xmlreader.h"
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
idXMLReader::idXMLReader(const char* const fileName)
: sourceName(fileName), document(nullptr), cursor(nullptr), end(nullptr) {
FILE* file = nullptr;
if (fileName == nullptr || fopen_s(&file, fileName, "rb") != 0
|| file == nullptr) {
return;
}
std::fseek(file, 0, SEEK_END);
const long length = std::ftell(file);
std::fseek(file, 0, SEEK_SET);
if (length >= 0) {
document = static_cast<char*>(std::malloc(static_cast<std::size_t>(length) + 1));
if (document != nullptr) {
const std::size_t read = std::fread(document, 1,
static_cast<std::size_t>(length), file);
document[read] = '\0';
cursor = document;
end = document + read;
}
}
std::fclose(file);
}
idXMLReader::~idXMLReader() {
std::free(document);
}
void idXMLReader::SkipWhitespace() {
while (cursor < end
&& std::isspace(static_cast<unsigned char>(*cursor)) != 0) {
++cursor;
}
}
bool idXMLReader::Consume(const char character) {
if (cursor < end && *cursor == character) {
++cursor;
return true;
}
return false;
}
bool idXMLReader::Consume(const char* const text) {
const std::size_t length = std::strlen(text);
if (static_cast<std::size_t>(end - cursor) >= length
&& std::memcmp(cursor, text, length) == 0) {
cursor += length;
return true;
}
return false;
}
bool idXMLReader::SkipMisc() {
SkipWhitespace();
if (Consume("<?")) {
const char* close = std::strstr(cursor, "?>");
if (close == nullptr || close > end) return false;
cursor = close + 2;
return true;
}
if (Consume("<!--")) {
const char* close = std::strstr(cursor, "-->");
if (close == nullptr || close > end) return false;
cursor = close + 3;
return true;
}
return false;
}
idStr idXMLReader::ReadName() {
idStr result;
while (cursor < end) {
const unsigned char character = static_cast<unsigned char>(*cursor);
if (std::isalnum(character) == 0 && character != '_'
&& character != '-' && character != ':' && character != '.'
&& character != '&' && character != ';' && character != '#') {
break;
}
result.Append(*cursor++);
}
return result;
}
idStr idXMLReader::ReadQuotedValue() {
idStr result;
if (cursor >= end || (*cursor != '"' && *cursor != '\'')) {
return result;
}
const char quote = *cursor++;
while (cursor < end && *cursor != quote) {
result.Append(*cursor++);
}
Consume(quote);
return result;
}
idXMLElement* idXMLReader::ReadElement_R() {
SkipWhitespace();
while (SkipMisc()) {
SkipWhitespace();
}
if (!Consume('<') || (cursor < end && *cursor == '/')) {
return nullptr;
}
const idStr name = ReadName();
if (name.Length() == 0) {
return nullptr;
}
idXMLElement* const element = idXMLElement::Create(name.c_str());
if (element == nullptr) {
return nullptr;
}
for (;;) {
SkipWhitespace();
if (Consume("/>")) {
return element;
}
if (Consume('>')) {
break;
}
const idStr attributeName = ReadName();
SkipWhitespace();
if (attributeName.Length() == 0 || !Consume('=')) {
idXMLElement::Destroy(element);
return nullptr;
}
SkipWhitespace();
const idStr attributeValue = ReadQuotedValue();
if (element->AddAttribute(attributeName.c_str(), attributeValue.c_str()) == nullptr) {
idXMLElement::Destroy(element);
return nullptr;
}
}
for (;;) {
if (cursor >= end) {
idXMLElement::Destroy(element);
return nullptr;
}
if (Consume("<!--")) {
const char* close = std::strstr(cursor, "-->");
if (close == nullptr || close > end) {
idXMLElement::Destroy(element);
return nullptr;
}
cursor = close + 3;
continue;
}
if (Consume("<![CDATA[")) {
const char* close = std::strstr(cursor, "]]>");
if (close == nullptr || close > end) {
idXMLElement::Destroy(element);
return nullptr;
}
while (cursor < close) element->AppendValue(*cursor++);
cursor = close + 3;
continue;
}
if (Consume("</")) {
const idStr closeName = ReadName();
SkipWhitespace();
if (!Consume('>') || std::strcmp(name.c_str(), closeName.c_str()) != 0) {
idXMLElement::Destroy(element);
return nullptr;
}
return element;
}
if (*cursor == '<') {
idXMLElement* const child = ReadElement_R();
if (child == nullptr || !element->AdoptChild(child)) {
idXMLElement::Destroy(child);
idXMLElement::Destroy(element);
return nullptr;
}
} else {
element->AppendValue(*cursor++);
}
}
}
idXMLElement* idXMLReader::ReadDocument() {
if (document == nullptr) {
return nullptr;
}
cursor = document;
while (SkipMisc()) {
}
idXMLElement* const root = ReadElement_R();
if (root != nullptr) {
root->FormatStrings();
}
return root;
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "xmlelement.h"
class idXMLReader {
public:
explicit idXMLReader(const char* fileName);
~idXMLReader();
idXMLElement* ReadDocument();
bool IsLoaded() const { return document != nullptr; }
private:
idStr sourceName;
char* document;
const char* cursor;
const char* end;
void SkipWhitespace();
bool SkipMisc();
bool Consume(char character);
bool Consume(const char* text);
idStr ReadName();
idStr ReadQuotedValue();
idXMLElement* ReadElement_R();
};
+218
View File
@@ -0,0 +1,218 @@
#include "xmlwriter.h"
#include <cstdlib>
#include <cstring>
#include <new>
idXMLWriter::idXMLWriter()
: xmlFile(nullptr), tabLevel(0), hasRoot(false),
firstOpenTag(nullptr), lastOpenTag(nullptr) {
}
idXMLWriter::~idXMLWriter() {
CloseFile();
}
bool idXMLWriter::OpenFile(const char* const fileName, const bool append,
const bool writeDeclaration) {
if (xmlFile != nullptr || fileName == nullptr) {
return false;
}
if (fopen_s(&xmlFile, fileName, append ? "ab" : "wb") != 0
|| xmlFile == nullptr) {
xmlFile = nullptr;
return false;
}
tabLevel = 0;
hasRoot = append;
if (!append && writeDeclaration) {
std::fputs("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n", xmlFile);
}
return true;
}
bool idXMLWriter::CloseFile() {
if (xmlFile == nullptr) {
return true;
}
while (firstOpenTag != nullptr) {
CloseElement();
}
const bool success = std::fclose(xmlFile) == 0;
xmlFile = nullptr;
tabLevel = 0;
hasRoot = false;
return success;
}
bool idXMLWriter::TestRoot(const char*) {
if (xmlFile == nullptr) {
return false;
}
if (tabLevel == 0 && hasRoot) {
return false;
}
if (tabLevel == 0) {
hasRoot = true;
}
return true;
}
bool idXMLWriter::WriteIndent() {
if (xmlFile == nullptr) {
return false;
}
for (int index = 0; index < tabLevel; ++index) {
if (std::fputs(" ", xmlFile) < 0) {
return false;
}
}
return true;
}
bool idXMLWriter::WriteEscaped(const char* text) {
if (xmlFile == nullptr) {
return false;
}
const char* cursor = text == nullptr ? "" : text;
while (*cursor != '\0') {
const char* escaped = nullptr;
switch (*cursor) {
case '&': escaped = "&amp;"; break;
case '<': escaped = "&lt;"; break;
case '>': escaped = "&gt;"; break;
case '"': escaped = "&quot;"; break;
case '\'': escaped = "&apos;"; break;
default: break;
}
if (escaped != nullptr) {
if (std::fputs(escaped, xmlFile) < 0) return false;
} else if (std::fputc(*cursor, xmlFile) == EOF) {
return false;
}
++cursor;
}
return true;
}
bool idXMLWriter::WriteAttributes(
const idRecoveredList<idXMLAttribute>& attributes) {
for (int index = 0; index < attributes.Num(); ++index) {
if (std::fputc(' ', xmlFile) == EOF
|| !WriteEscaped(attributes[index].GetName())
|| std::fputs("=\"", xmlFile) < 0
|| !WriteEscaped(attributes[index].GetValue())
|| std::fputc('"', xmlFile) == EOF) {
return false;
}
}
return true;
}
bool idXMLWriter::PushTag(const char* const name) {
void* const storage = std::malloc(sizeof(stackXMLTag_t));
if (storage == nullptr) {
return false;
}
stackXMLTag_t* const tag = new (storage) stackXMLTag_t;
tag->tagName = name;
tag->next = firstOpenTag;
firstOpenTag = tag;
if (lastOpenTag == nullptr) {
lastOpenTag = tag;
}
return true;
}
bool idXMLWriter::OpenElement(const char* const name) {
idRecoveredList<idXMLAttribute> noAttributes;
return OpenElement(name, noAttributes);
}
bool idXMLWriter::OpenElement(const char* const name,
const idRecoveredList<idXMLAttribute>& attributes) {
if (!TestRoot(name) || !WriteIndent() || std::fputc('<', xmlFile) == EOF
|| !WriteEscaped(name) || !WriteAttributes(attributes)
|| std::fputs(">\n", xmlFile) < 0 || !PushTag(name)) {
return false;
}
++tabLevel;
return true;
}
bool idXMLWriter::WriteElement(const char* const name, const char* const value) {
idRecoveredList<idXMLAttribute> noAttributes;
return WriteElement(name, value, noAttributes);
}
bool idXMLWriter::WriteElement(const char* const name, const char* const value,
const idRecoveredList<idXMLAttribute>& attributes) {
if (!TestRoot(name) || !WriteIndent() || std::fputc('<', xmlFile) == EOF
|| !WriteEscaped(name) || !WriteAttributes(attributes)) {
return false;
}
if (value == nullptr || value[0] == '\0') {
return std::fputs("/>\n", xmlFile) >= 0;
}
return std::fputc('>', xmlFile) != EOF && WriteEscaped(value)
&& std::fputs("</", xmlFile) >= 0 && WriteEscaped(name)
&& std::fputs(">\n", xmlFile) >= 0;
}
bool idXMLWriter::CloseElement() {
if (xmlFile == nullptr || firstOpenTag == nullptr) {
return false;
}
stackXMLTag_t* const tag = firstOpenTag;
firstOpenTag = tag->next;
if (firstOpenTag == nullptr) {
lastOpenTag = nullptr;
}
--tabLevel;
const bool success = WriteIndent() && std::fputs("</", xmlFile) >= 0
&& WriteEscaped(tag->tagName.c_str()) && std::fputs(">\n", xmlFile) >= 0;
tag->~stackXMLTag_t();
std::free(tag);
return success;
}
bool idXMLWriter::CloseDocument() {
while (firstOpenTag != nullptr) {
if (!CloseElement()) {
return false;
}
}
return CloseFile();
}
bool idXMLWriter::WriteElement_R(const idXMLElement* const element) {
if (element == nullptr) {
return false;
}
if (element->NumChildren() == 0) {
idRecoveredList<idXMLAttribute> attributes;
for (int index = 0; index < element->NumAttributes(); ++index) {
attributes.Append(element->GetAttribute(index));
}
return WriteElement(element->GetName(), element->GetValue(), attributes);
}
idRecoveredList<idXMLAttribute> attributes;
for (int index = 0; index < element->NumAttributes(); ++index) {
attributes.Append(element->GetAttribute(index));
}
if (!OpenElement(element->GetName(), attributes)) {
return false;
}
if (element->GetValue()[0] != '\0') {
if (!WriteIndent() || !WriteEscaped(element->GetValue())
|| std::fputc('\n', xmlFile) == EOF) return false;
}
for (int index = 0; index < element->NumChildren(); ++index) {
if (!WriteElement_R(element->GetChild(index))) return false;
}
return CloseElement();
}
bool idXMLWriter::WriteDocument(const idXMLElement* const root) {
return xmlFile != nullptr && !hasRoot && WriteElement_R(root);
}
+47
View File
@@ -0,0 +1,47 @@
#pragma once
#include "xmlelement.h"
#include <cstdio>
class idXMLWriter {
public:
idXMLWriter();
~idXMLWriter();
bool OpenFile(const char* fileName, bool append = false,
bool writeDeclaration = true);
bool CloseFile();
bool OpenElement(const char* name);
bool OpenElement(const char* name,
const idRecoveredList<idXMLAttribute>& attributes);
bool WriteElement(const char* name, const char* value);
bool WriteElement(const char* name, const char* value,
const idRecoveredList<idXMLAttribute>& attributes);
bool CloseElement();
bool CloseDocument();
bool WriteDocument(const idXMLElement* root);
private:
struct stackXMLTag_t {
idStr tagName;
stackXMLTag_t* next;
};
std::FILE* xmlFile;
int tabLevel;
bool hasRoot;
stackXMLTag_t* firstOpenTag;
stackXMLTag_t* lastOpenTag;
bool TestRoot(const char* name);
bool WriteIndent();
bool WriteEscaped(const char* text);
bool WriteAttributes(const idRecoveredList<idXMLAttribute>& attributes);
bool PushTag(const char* name);
bool WriteElement_R(const idXMLElement* element);
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idXMLWriter) == 20, "Recovered idXMLWriter ABI changed");
#endif