zonetool/src/IW4/Assets/StringTable.cpp
2024-04-21 18:05:29 +02:00

223 lines
4.7 KiB
C++

// ======================= ZoneTool =======================
// zonetool, a fastfile linker for various
// Call of Duty titles.
//
// Project: https://github.com/ZoneTool/zonetool
// Author: RektInator (https://github.com/RektInator)
// License: GNU GPL v3.0
// ========================================================
#include "stdafx.hpp"
namespace ZoneTool
{
namespace IW4
{
// LEGACY ZONETOOL CODE, FIX ME!
class CSV
{
protected:
std::string _name;
std::vector<std::vector<std::string>> _data;
public:
CSV(std::string name, char sep = ',')
: _name(name)
{
auto fp = FileSystem::FileOpen(name, "r"s);
if (fp)
{
long len = FileSystem::FileSize(fp);
auto buf = std::make_unique<char[]>(len + 1);
memset(buf.get(), 0, len + 1);
fread(buf.get(), len, 1, fp);
fclose(fp);
std::vector<std::string> rows = split(std::string(buf.get()), '\n');
for (auto& row : rows)
{
// Replace literal characters
std::size_t pos;
while ((pos = row.find("\\n")) != std::string::npos)
{
row.replace(pos, 2, "\n");
}
while ((pos = row.find("\\t")) != std::string::npos)
{
row.replace(pos, 2, "\t");
}
_data.push_back(split(row, sep));
}
}
}
std::string entry(std::size_t row, std::size_t column)
{
return _data[row][column];
}
std::size_t rows()
{
return _data.size();
}
std::size_t columns(std::size_t row)
{
return _data[row].size();
}
std::size_t max_columns()
{
std::size_t _max = 0;
for (std::size_t row = 0; row < this->rows(); row++)
{
if (_max < this->columns(row))
_max = this->columns(row);
}
return _max;
}
void clear()
{
for (std::size_t i = 0; i < _data.size(); i++)
{
for (std::size_t j = 0; j < _data[i].size(); j++)
_data[i][j].clear();
_data[i].clear();
}
_data.clear();
}
};
int StringTable_Hash(const char* string)
{
int hash = 0;
char* data = _strdup(string);
while (*data != 0)
{
hash = tolower(*data) + (31 * hash);
data++;
}
return hash;
}
StringTable* StringTable_Parse(std::string name, ZoneMemory* mem)
{
auto table = std::make_unique<CSV>(name);
auto* stringtable = mem->Alloc<StringTable>();
stringtable->name = mem->StrDup(name);
stringtable->rows = static_cast<int>(table->rows());
stringtable->columns = static_cast<int>(table->max_columns());
stringtable->strings = mem->Alloc<StringTableCell>(stringtable->rows * stringtable->columns);
for (size_t row = 0; row < table->rows(); row++)
{
for (size_t col = 0; col < table->columns(row); col++)
{
size_t entry = (row * stringtable->columns) + col;
stringtable->strings[entry].string = mem->StrDup(table->entry(row, col));
stringtable->strings[entry].hash = StringTable_Hash(stringtable->strings[entry].string);
}
}
return stringtable;
}
void IStringTable::init(const std::string& name, ZoneMemory* mem)
{
this->name_ = name;
this->asset_ = DB_FindXAssetHeader(this->type(), this->name().c_str()).stringtable;
if (FileSystem::FileExists(name))
{
ZONETOOL_INFO("Parsing stringtable %s...", name.c_str());
this->asset_ = StringTable_Parse(name, mem);
}
}
void IStringTable::prepare(ZoneBuffer* buf, ZoneMemory* mem)
{
}
void IStringTable::load_depending(IZone* zone)
{
}
std::string IStringTable::name()
{
return this->name_;
}
std::int32_t IStringTable::type()
{
return stringtable;
}
void IStringTable::write(IZone* zone, ZoneBuffer* buf)
{
auto* data = this->asset_;
auto* dest = buf->write(data);
buf->push_stream(3);
START_LOG_STREAM;
dest->name = buf->write_str(this->name());
if (data->strings)
{
buf->align(3);
auto* dest_strings = buf->write(data->strings, data->columns * data->rows);
if (data->columns * data->rows > 0)
{
for (auto i = 0; i < data->columns * data->rows; i++)
{
if (data->strings[i].string)
{
dest_strings[i].string = buf->write_str(data->strings[i].string);
}
}
}
ZoneBuffer::clear_pointer(&dest->strings);
}
END_LOG_STREAM;
buf->pop_stream();
}
void IStringTable::dump(StringTable* asset)
{
const std::string path = asset->name;
auto* file = FileSystem::FileOpen(path, "w"s);
for (auto row = 0; row < asset->rows; row++)
{
for (auto column = 0; column < asset->columns; column++)
{
fprintf(
file,
"%s%s",
(asset->strings[(row * asset->columns) + column].string)
? asset->strings[(row * asset->columns) + column].string
: "",
(column == asset->columns - 1) ? "\n" : ","
);
}
}
FileSystem::FileClose(file);
}
}
}