New File tools

This commit is contained in:
2023-02-08 20:05:41 -08:00
parent c3dbacde76
commit bbe30d9253
13 changed files with 210 additions and 73 deletions

View File

@ -11,7 +11,6 @@ target_sources(languagegen
${DAWN_SHARED_SOURCES}
LanguageGen.cpp
../../util/DawnTool.cpp
../../util/XmlNew.cpp
../../util/file.cpp
../../util/csv.cpp
../../util/xml.cpp
@ -24,6 +23,11 @@ target_include_directories(languagegen
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(languagegen
PUBLIC
DAWN_TOOL_INSTANCE=LanguageGen
DAWN_TOOL_HEADER="LanguageGen.hpp"
)
target_link_libraries(languagegen
PUBLIC

View File

@ -9,36 +9,19 @@
using namespace Dawn;
LanguageGen::LanguageGen(const int argc, const char *argv[]) :
DawnTool(argc, argv)
{
}
int32_t LanguageGen::start() {
if(this->args.size() != 3) {
std::cout << "Invalid number of arguments provided to language gen!" << std::endl;
return 1;
}
auto fileInName = fileNormalizeSlashesNew(this->args[1]);
FILE *fileIn = fopen(fileInName.c_str(), "rb");
if(fileIn == NULL) {
std::cout << "Failed to open input file " << fileInName << std::endl;
auto fileIn = File(this->args[1]);
std::string buffer;
if(!fileIn.readString(&buffer)) {
std::cout << "Failed to open/read input file " << fileIn.filename << std::endl;
return 1;
}
auto size = assetReadString(fileIn, NULL);
char *buffer = (char *)malloc(sizeof(char) * size);
if(buffer == NULL) {
std::cout << "Failed to allocate memory for locale string XML" << std::endl;
fclose(fileIn);
return 1;
}
assetReadString(fileIn, buffer);
fclose(fileIn);
auto xml = Xml::load(std::string(buffer));
free(buffer);
auto xml = Xml::load(buffer);
// Begin parsing. Start by looking for the <language> tags
std::vector<std::string> languages;
@ -102,21 +85,15 @@ int32_t LanguageGen::start() {
it2++;
}
std::string filenameOut = this->args[2];
filenameOut += "/language_" + it->first + ".language";
filenameOut = fileNormalizeSlashesNew(filenameOut);
fileMkdirp((char *)filenameOut.c_str());
FILE *fileOut = fopen(filenameOut.c_str(), "wb");
if(fileOut == NULL) {
std::cout << "Failed to create output file " << filenameOut << std::endl;
File fileOut(this->args[2] + "/language_" + it->first + ".language");
if(!fileOut.mkdirp()) {
std::cout << "Failed to create output folder" << std::endl;
}
if(!fileOut.writeString(bufferOut)) {
std::cout << "Failed to write to output file " << fileOut.filename << std::endl;
return 1;
}
const char_t *strOut = bufferOut.c_str();
fwrite(strOut, sizeof(char_t), strlen(strOut), fileOut);
fclose(fileOut);
auto it3 = keys.begin();
while(it3 != keys.end()) {
auto key = *it3;
@ -190,8 +167,4 @@ int32_t LanguageGen::parseGroup(
}
return 0;
}
int main(const int argc, const char *argv[]) {
return (LanguageGen(argc, argv)).start();
}

View File

@ -5,7 +5,8 @@
#pragma once
#include "util/DawnTool.hpp"
#include "util/XmlNew.hpp"
#include "util/Xml.hpp"
#include "util/File.hpp"
namespace Dawn {
struct LanguageString {
@ -28,8 +29,6 @@ namespace Dawn {
);
public:
LanguageGen(const int argc, const char *argv[]);
int32_t start() override;
};
}

View File

@ -5,10 +5,27 @@
#include "DawnTool.hpp"
#if !defined(DAWN_TOOL_INSTANCE)
#error Dawn Tool Instance, e.g. LanguageTool has not been defined
#endif
#if !defined(DAWN_TOOL_HEADER)
#error Dawn Tool Include, e.g. LanguageTool.hpp has not been defined
#endif
#include DAWN_TOOL_HEADER
using namespace Dawn;
DawnTool::DawnTool(const int argc, const char *argv[]) {
int32_t DawnTool::exec(const int32_t argc, const char *argv[]) {
for(int32_t i = 0; i < argc; i++) {
this->args.push_back(std::string(argv[i]));
}
return this->start();
}
int main(const int32_t argc, const char *argv[]) {
DAWN_TOOL_INSTANCE self;
return self.exec(argc, argv);
}

View File

@ -20,8 +20,9 @@ namespace Dawn {
std::vector<std::string> args;
public:
DawnTool(const int argc, const char *argv[]);
int32_t exec(const int32_t argc, const char *argv[]);
virtual int32_t start() = 0;
};
}
}
int main(const int32_t argc, const char *argv[]);

108
src/dawntools/util/File.hpp Normal file
View File

@ -0,0 +1,108 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "assert/assert.hpp"
#include "util/file.hpp"
#include "util/mathutils.hpp"
#define FILE_BUFFER_SIZE 512
namespace Dawn {
enum FileMode {
FILE_MODE_READ,
FILE_MODE_WRITE
};
class File {
private:
FILE *file = nullptr;
enum FileMode mode;
size_t length;
public:
std::string filename;
File(std::string filename) {
this->filename = fileNormalizeSlashesNew(filename);
}
bool_t open(enum FileMode mode) {
assertNull(this->file);
this->mode = mode;
this->file = fopen(
this->filename.c_str(),
mode == FILE_MODE_READ ? "rb" : "wb"
);
if(this->file == NULL) return false;
fseek(this->file, 0, SEEK_END);
this->length = ftell(this->file);
fseek(this->file, 0, SEEK_SET);
if(this->length <= 0) {
this->close();
return false;
}
return true;
}
bool_t isOpen() {
return this->file != nullptr;
}
void close() {
assertNotNull(this->file);
fclose(this->file);
}
bool_t readString(std::string *out) {
assertNotNull(out);
if(!this->isOpen()) {
if(!this->open(FILE_MODE_READ)) return false;
}
assertTrue(this->mode == FILE_MODE_READ);
out->clear();
size_t i = 0;
char buffer[FILE_BUFFER_SIZE + 1];
while(i != this->length) {
size_t amt = mathMin<size_t>(FILE_BUFFER_SIZE, (this->length - i));
auto amtRead = fread(buffer, sizeof(char), amt, this->file);
if(amtRead != amt) return false;
i += amtRead;
buffer[amtRead + 1] = '\0';
out->append(buffer);
}
return true;
}
bool_t mkdirp() {
fileMkdirp((char *)this->filename.c_str());
return true;
}
bool_t writeString(std::string in) {
if(!this->isOpen()) {
if(!this->open(FILE_MODE_WRITE)) return false;
}
assertTrue(this->mode == FILE_MODE_WRITE);
const char_t *strOut = in.c_str();
// TODO: Validate write length.
fwrite(strOut, sizeof(char_t), in.size(), this->file);
return true;
}
~File() {
if(this->file != nullptr) this->close();
}
};
}

View File

@ -1,223 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "XmlNew.hpp"
#include "util/array.hpp"
using namespace Dawn;
bool_t Xml::isWhitespace(char_t c) {
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
}
Xml Xml::load(std::string data) {
size_t j = 0;
Xml xml;
Xml::load(&xml, data, &j);
return xml;
}
void Xml::load(Xml *xml, std::string data, size_t *j) {
char_t c;
int32_t level = 0;
enum XmlParseState doing = XML_PARSE_STATE_DOING_NOTHING;
enum XmlParseState doingBeforeComment;
bool_t insideTag = false;
std::string buffer = "";
std::string attrKey = "";
size_t i = *j;
while(c = data[i++]) {
switch(doing) {
case XML_PARSE_STATE_DOING_NOTHING:
if(c == '>') continue;
if(c == '<') {
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
doingBeforeComment = doing;
doing = XML_PARSE_STATE_PARSING_COMMENT;
i += 3;
} else if(insideTag) {
i -= 1;
auto child = new Xml();
Xml::load(child, data, &i);
xml->children.push_back(child);
doing = XML_PARSE_STATE_PARSING_CHILD;
} else {
doing = XML_PARSE_STATE_PARSING_TAG_NAME;
level++;
insideTag = true;
}
continue;
}
if(Xml::isWhitespace(c)) continue;
doing = XML_PARSE_STATE_PARSING_VALUE;
buffer += c;
break;
case XML_PARSE_STATE_PARSING_TAG_NAME:
// Just keep reading until we either hit a space (end of the tag name)
// or a closing tag value, either / or >
if(Xml::isWhitespace(c) || c == '>' || c == '/') {
xml->node = buffer;
buffer = "";
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSE_STATE_PARSING_CLOSE;
} else {
doing = c == '>' ? XML_PARSE_STATE_DOING_NOTHING : XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
}
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE:
// Look until we hit either the end of a tag, or the attribute itself
if(Xml::isWhitespace(c) || c == '>' || c == '/' || c == '=') {
if(c == '>' || c == '/') {
doing = XML_PARSE_STATE_DOING_NOTHING;
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSE_STATE_PARSING_CLOSE;
}
} else if(c == '=') {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE;
} else {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
}
if(buffer.size() > 0) {
attrKey = buffer;
xml->attributes[buffer] = "";
buffer = "";
}
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE:
// Keep looking until we find a quote mark
if(Xml::isWhitespace(c)) continue;
if(c == '>' || c == '/') {
doing = XML_PARSE_STATE_DOING_NOTHING;
insideTag = false;
continue;
}
if(c != '"') continue;
doing = XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE;
break;
case XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE:
// Parse the attribute value until we find a quote mark.
if(c == '"') {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
xml->attributes[attrKey] = buffer;
buffer = "";
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_PARSING_VALUE:
// Keep parsing child until we find a < for an opening/closing tag.
if(c == '<') {
// In HTML Spec there could be a child here but not in XML spec.
doing = XML_PARSE_STATE_PARSING_CLOSE;
xml->value = buffer;
buffer = "";
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_PARSING_CHILD:
if(c == '<') {
// Read ahead and confirm this is a close or not
if(data[i] == '/') {
doing = XML_PARSE_STATE_PARSING_CLOSE;
continue;
}
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
doingBeforeComment = doing;
doing = XML_PARSE_STATE_PARSING_COMMENT;
i += 3;
continue;
}
// Likely another child.
auto child = new Xml();
i -= 1;
Xml::load(child, data, &i);
xml->children.push_back(child);
}
if(Xml::isWhitespace(c)) continue;
// In HTML Spec there's a chance for there to be a value here, but not
// in the XML spec.
break;
case XML_PARSE_STATE_PARSING_CLOSE:
// Just keep parsing until the tag closer finishes.
if(c != '>') continue;
doing = XML_PARSE_STATE_DOING_NOTHING;
//TODO: Return index or something?
*j = i;
return;
case XML_PARSE_STATE_PARSING_COMMENT:
if(c != '-') continue;
if(data[i] != '-') continue;
if(data[i+1] != '>') continue;
i += 2;
doing = doingBeforeComment;
break;
default:
break;
}
}
*j = i;
}
std::vector<Xml*> Xml::getChildrenOfType(std::string type) {
std::vector<Xml*> children;
auto itChildren = this->children.begin();
while(itChildren != this->children.end()) {
auto child = *itChildren;
if(child->node == type) children.push_back(child);
++itChildren;
}
return children;
}
Xml * Xml::getFirstChildOfType(std::string type) {
auto itChildren = this->children.begin();
while(itChildren != this->children.end()) {
auto child = *itChildren;
if(child->node == type) return child;
++itChildren;
}
return nullptr;
}
Xml::~Xml() {
auto it = this->children.begin();
while(it != this->children.end()) {
delete *it;
++it;
}
}

View File

@ -1,43 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
namespace Dawn {
enum XmlParseState {
XML_PARSE_STATE_DOING_NOTHING,
XML_PARSE_STATE_PARSING_TAG_NAME,
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE,
XML_PARSE_STATE_PARSING_ATTRIBUTE_NAME,
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE,
XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE,
XML_PARSE_STATE_PARSING_VALUE,
XML_PARSE_STATE_PARSING_CHILD,
XML_PARSE_STATE_PARSING_CLOSE,
XML_PARSE_STATE_PARSING_COMMENT
};
class Xml {
protected:
static bool_t isWhitespace(char_t c);
public:
static Xml load(std::string data);
static void load(Xml *xml, std::string data, size_t *j);
std::string node;
std::string value;
std::map<std::string, std::string> attributes;
std::vector<Xml*> children;
std::vector<Xml*> getChildrenOfType(std::string type);
Xml * getFirstChildOfType(std::string type);
~Xml();
};
}

View File

@ -4,20 +4,30 @@
# https://opensource.org/licenses/MIT
# Texture Build Tool
project(vnscenegen VERSION 1.0)
project(vnscenegen VERSION 1.1)
add_executable(vnscenegen)
target_sources(vnscenegen
PRIVATE
main.cpp
${DAWN_SHARED_SOURCES}
VnSceneGen.cpp
../../util/DawnTool.cpp
../../util/file.cpp
../../util/xml.cpp
)
target_include_directories(vnscenegen
PUBLIC
${DAWN_SHARED_INCLUDES}
${CMAKE_CURRENT_LIST_DIR}/../../
${CMAKE_CURRENT_LIST_DIR}
)
target_compile_definitions(vnscenegen
PUBLIC
DAWN_TOOL_INSTANCE=VnSceneGen
DAWN_TOOL_HEADER="VnSceneGen.hpp"
)
target_link_libraries(vnscenegen
PUBLIC
${DAWN_BUILD_HOST_LIBS}

View File

@ -3,28 +3,9 @@
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "../../util/file.hpp"
#include "../../util/xml.hpp"
#include <iostream>
#include <vector>
#include "VnSceneGen.hpp"
struct CharacterInformation {
std::string clazz;
std::string name;
};
struct Asset {
std::string type;
std::string name;
};
struct HeaderInformation {
std::string type;
std::string name;
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct Asset> assets;
};
using namespace Dawn;
int32_t parseInclude(struct HeaderInformation *info, xml_t *node) {
auto attrPath = xmlGetAttributeByName(node, "path");
@ -211,7 +192,7 @@ std::string parseEvent(xml_t *evt, struct HeaderInformation *header) {
return buffer;
}
int main(int32_t argc, char *args[]) {
int oldmain(int32_t argc, char *args[]) {
if(argc != 3) {
std::cout << "Invalid number of args passed to VNScene Generator" << std::endl;
return 1;
@ -358,5 +339,9 @@ int main(int32_t argc, char *args[]) {
fclose(fout);
std::cout << "Generated Scene " << fileOut << std::endl;
return 0;
}
int32_t VnSceneGen::start() {
return 0;
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/DawnTool.hpp"
#include "util/Xml.hpp"
#include "../../util/file.hpp"
#include "../../util/xml.hpp"
#include <iostream>
#include <vector>
namespace Dawn {
struct CharacterInformation {
std::string clazz;
std::string name;
};
struct Asset {
std::string type;
std::string name;
};
struct HeaderInformation {
std::string type;
std::string name;
std::vector<std::string> includes;
std::vector<struct CharacterInformation> characters;
std::vector<struct Asset> assets;
};
class VnSceneGen : public DawnTool {
protected:
public:
int32_t start() override;
};
}