diff --git a/src/dawnshared/CMakeLists.txt b/src/dawnshared/CMakeLists.txt
index 08003e0e..af53f494 100644
--- a/src/dawnshared/CMakeLists.txt
+++ b/src/dawnshared/CMakeLists.txt
@@ -16,6 +16,7 @@ set(D ${CMAKE_CURRENT_LIST_DIR})
 set(
   DAWN_SHARED_SOURCES
     ${D}/assert/assert.cpp
+    ${D}/util/Xml.cpp
 
   CACHE INTERNAL
     ${DAWN_CACHE_TARGET}
diff --git a/src/dawntools/util/XmlNew.cpp b/src/dawnshared/util/Xml.cpp
similarity index 99%
rename from src/dawntools/util/XmlNew.cpp
rename to src/dawnshared/util/Xml.cpp
index f4a9dae6..bfb3cfcd 100644
--- a/src/dawntools/util/XmlNew.cpp
+++ b/src/dawnshared/util/Xml.cpp
@@ -3,8 +3,7 @@
 // This software is released under the MIT License.
 // https://opensource.org/licenses/MIT
 
-#include "XmlNew.hpp"
-#include "util/array.hpp"
+#include "Xml.hpp"
 
 using namespace Dawn;
 
diff --git a/src/dawntools/util/XmlNew.hpp b/src/dawnshared/util/Xml.hpp
similarity index 97%
rename from src/dawntools/util/XmlNew.hpp
rename to src/dawnshared/util/Xml.hpp
index 3068314c..dff6b645 100644
--- a/src/dawntools/util/XmlNew.hpp
+++ b/src/dawnshared/util/Xml.hpp
@@ -5,6 +5,7 @@
 
 #pragma once
 #include "dawnsharedlibs.hpp"
+#include "util/array.hpp"
 
 namespace Dawn {
   enum XmlParseState {
diff --git a/src/dawnshared/util/mathutils.hpp b/src/dawnshared/util/mathutils.hpp
index 28bfe2e0..5c689eed 100644
--- a/src/dawnshared/util/mathutils.hpp
+++ b/src/dawnshared/util/mathutils.hpp
@@ -6,7 +6,7 @@
  */
 
 #pragma once
-#include "dawnlibs.hpp"
+#include "dawnsharedlibs.hpp"
 
 #define MATH_PI 3.1415926535897f
 
diff --git a/src/dawntools/locale/languagegen/CMakeLists.txt b/src/dawntools/locale/languagegen/CMakeLists.txt
index a209a524..c37b7f5c 100644
--- a/src/dawntools/locale/languagegen/CMakeLists.txt
+++ b/src/dawntools/locale/languagegen/CMakeLists.txt
@@ -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
diff --git a/src/dawntools/locale/languagegen/LanguageGen.cpp b/src/dawntools/locale/languagegen/LanguageGen.cpp
index 592076ce..e2e8994a 100644
--- a/src/dawntools/locale/languagegen/LanguageGen.cpp
+++ b/src/dawntools/locale/languagegen/LanguageGen.cpp
@@ -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();
 }
\ No newline at end of file
diff --git a/src/dawntools/locale/languagegen/LanguageGen.hpp b/src/dawntools/locale/languagegen/LanguageGen.hpp
index 6651360c..e15e4d59 100644
--- a/src/dawntools/locale/languagegen/LanguageGen.hpp
+++ b/src/dawntools/locale/languagegen/LanguageGen.hpp
@@ -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;
   };
 }
\ No newline at end of file
diff --git a/src/dawntools/util/DawnTool.cpp b/src/dawntools/util/DawnTool.cpp
index 31415177..ca560839 100644
--- a/src/dawntools/util/DawnTool.cpp
+++ b/src/dawntools/util/DawnTool.cpp
@@ -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);
 }
\ No newline at end of file
diff --git a/src/dawntools/util/DawnTool.hpp b/src/dawntools/util/DawnTool.hpp
index f58025c8..f9bc1007 100644
--- a/src/dawntools/util/DawnTool.hpp
+++ b/src/dawntools/util/DawnTool.hpp
@@ -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;
   };
-}
\ No newline at end of file
+}
+
+int main(const int32_t argc, const char *argv[]);
\ No newline at end of file
diff --git a/src/dawntools/util/File.hpp b/src/dawntools/util/File.hpp
new file mode 100644
index 00000000..b2c7659a
--- /dev/null
+++ b/src/dawntools/util/File.hpp
@@ -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();
+      }
+  };
+}
\ No newline at end of file
diff --git a/src/dawntools/visualnovel/vnscenegen/CMakeLists.txt b/src/dawntools/visualnovel/vnscenegen/CMakeLists.txt
index f102ff0a..7b56295d 100644
--- a/src/dawntools/visualnovel/vnscenegen/CMakeLists.txt
+++ b/src/dawntools/visualnovel/vnscenegen/CMakeLists.txt
@@ -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}
diff --git a/src/dawntools/visualnovel/vnscenegen/main.cpp b/src/dawntools/visualnovel/vnscenegen/VnSceneGen.cpp
similarity index 95%
rename from src/dawntools/visualnovel/vnscenegen/main.cpp
rename to src/dawntools/visualnovel/vnscenegen/VnSceneGen.cpp
index 0efe69fb..0ae9e4f0 100644
--- a/src/dawntools/visualnovel/vnscenegen/main.cpp
+++ b/src/dawntools/visualnovel/vnscenegen/VnSceneGen.cpp
@@ -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;
 }
\ No newline at end of file
diff --git a/src/dawntools/visualnovel/vnscenegen/VnSceneGen.hpp b/src/dawntools/visualnovel/vnscenegen/VnSceneGen.hpp
new file mode 100644
index 00000000..f0a858e6
--- /dev/null
+++ b/src/dawntools/visualnovel/vnscenegen/VnSceneGen.hpp
@@ -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;
+  };
+}
\ No newline at end of file