Explorar o código

Refactoring part 3

Gi1dor (Ivan Arkhipov) %!s(int64=6) %!d(string=hai) anos
pai
achega
fdc52b09b0
Modificáronse 59 ficheiros con 3886 adicións e 2710 borrados
  1. 6 0
      CMakeLists.txt
  2. BIN=BIN
      Source/Common/Yaml/libyaml-cpp.a
  3. BIN=BIN
      Source/Common/Yaml/libyaml-cppmt.lib
  4. 17 0
      Source/Common/Yaml/yaml-cpp/anchor.h
  5. 67 0
      Source/Common/Yaml/yaml-cpp/binary.h
  6. 39 0
      Source/Common/Yaml/yaml-cpp/contrib/anchordict.h
  7. 149 0
      Source/Common/Yaml/yaml-cpp/contrib/graphbuilder.h
  8. 33 0
      Source/Common/Yaml/yaml-cpp/dll.h
  9. 57 0
      Source/Common/Yaml/yaml-cpp/emitfromevents.h
  10. 254 0
      Source/Common/Yaml/yaml-cpp/emitter.h
  11. 16 0
      Source/Common/Yaml/yaml-cpp/emitterdef.h
  12. 137 0
      Source/Common/Yaml/yaml-cpp/emittermanip.h
  13. 16 0
      Source/Common/Yaml/yaml-cpp/emitterstyle.h
  14. 40 0
      Source/Common/Yaml/yaml-cpp/eventhandler.h
  15. 267 0
      Source/Common/Yaml/yaml-cpp/exceptions.h
  16. 29 0
      Source/Common/Yaml/yaml-cpp/mark.h
  17. 331 0
      Source/Common/Yaml/yaml-cpp/node/convert.h
  18. 26 0
      Source/Common/Yaml/yaml-cpp/node/detail/bool_type.h
  19. 185 0
      Source/Common/Yaml/yaml-cpp/node/detail/impl.h
  20. 92 0
      Source/Common/Yaml/yaml-cpp/node/detail/iterator.h
  21. 27 0
      Source/Common/Yaml/yaml-cpp/node/detail/iterator_fwd.h
  22. 46 0
      Source/Common/Yaml/yaml-cpp/node/detail/memory.h
  23. 169 0
      Source/Common/Yaml/yaml-cpp/node/detail/node.h
  24. 127 0
      Source/Common/Yaml/yaml-cpp/node/detail/node_data.h
  25. 180 0
      Source/Common/Yaml/yaml-cpp/node/detail/node_iterator.h
  26. 98 0
      Source/Common/Yaml/yaml-cpp/node/detail/node_ref.h
  27. 32 0
      Source/Common/Yaml/yaml-cpp/node/emit.h
  28. 448 0
      Source/Common/Yaml/yaml-cpp/node/impl.h
  29. 31 0
      Source/Common/Yaml/yaml-cpp/node/iterator.h
  30. 145 0
      Source/Common/Yaml/yaml-cpp/node/node.h
  31. 78 0
      Source/Common/Yaml/yaml-cpp/node/parse.h
  32. 29 0
      Source/Common/Yaml/yaml-cpp/node/ptr.h
  33. 16 0
      Source/Common/Yaml/yaml-cpp/node/type.h
  34. 25 0
      Source/Common/Yaml/yaml-cpp/noncopyable.h
  35. 26 0
      Source/Common/Yaml/yaml-cpp/null.h
  36. 72 0
      Source/Common/Yaml/yaml-cpp/ostream_wrapper.h
  37. 86 0
      Source/Common/Yaml/yaml-cpp/parser.h
  38. 51 0
      Source/Common/Yaml/yaml-cpp/stlemitter.h
  39. 103 0
      Source/Common/Yaml/yaml-cpp/traits.h
  40. 24 0
      Source/Common/Yaml/yaml-cpp/yaml.h
  41. BIN=BIN
      Source/Common/ZLib/zlibstatic.lib
  42. 0 1
      Source/DatFile.h
  43. 1 1
      Source/Database.cpp
  44. 7 12
      Source/Subfile.cpp
  45. 8 4
      Source/Subfile.h
  46. 21 11
      Source/Subfiles/DdsSubfile.cpp
  47. 5 2
      Source/Subfiles/DdsSubfile.h
  48. 30 541
      Source/Subfiles/FontSubfile.cpp
  49. 7 7
      Source/Subfiles/FontSubfile.h
  50. 29 541
      Source/Subfiles/JpgSubfile.cpp
  51. 6 7
      Source/Subfiles/JpgSubfile.h
  52. 28 539
      Source/Subfiles/OggSubfile.cpp
  53. 5 5
      Source/Subfiles/OggSubfile.h
  54. 68 479
      Source/Subfiles/TextSubfile.cpp
  55. 15 9
      Source/Subfiles/TextSubfile.h
  56. 42 0
      Source/Subfiles/UnknownSubfile.cpp
  57. 6 6
      Source/Subfiles/UnknownSubfile.h
  58. 28 539
      Source/Subfiles/WavSubfile.cpp
  59. 6 6
      Source/Subfiles/WavSubfile.h

+ 6 - 0
CMakeLists.txt

@@ -11,6 +11,8 @@ SET(CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS
 set(CMAKE_OUTPUT_DIR ${CMAKE_SOURCE_DIR}/bin)
 set(CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR}/Source)
 
+include_directories(${CMAKE_SOURCE_DIR}/Common/Yaml)
+
 SET(EXECUTABLE_OUTPUT_PATH ${CMAKE_OUTPUT_DIR})
 SET(LIBRARY_OUTPUT_PATH ${CMAKE_OUTPUT_DIR})
 
@@ -63,16 +65,20 @@ set(SOURCE_FILES
 # STATIC LIBRARY
 add_library(LotroDat_static STATIC ${SOURCE_FILES})
 target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
+target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
 
 # SHARED LIBRARY
 add_library(LotroDat SHARED ${SOURCE_FILES})
 target_link_libraries(LotroDat ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
+target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
 
 # FOR EXTRACTOR USE NEXT LINE
 add_executable(LotRO_dat_extract_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/extract_test.cpp)
 target_link_libraries(LotRO_dat_extract_tester ${CMAKE_SOURCE_DIR}/Common/ZLib/libzlibstatic.a)
+target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
 
 # FOR PATCHER USE NEXT LINE
 add_executable(LotRO_dat_pat_tester ${SOURCE_FILES} ${CMAKE_SOURCE_DIR}/Tests/patch_test.cpp)
 target_link_libraries(LotRO_dat_pat_tester ${CMAKE_SOURCE_DIR}/Common/Zlib/libzlibstatic.a)
+target_link_libraries(LotroDat_static ${CMAKE_SOURCE_DIR}/Common/Yaml/libyaml-cpp.a)
 

BIN=BIN
Source/Common/Yaml/libyaml-cpp.a


BIN=BIN
Source/Common/Yaml/libyaml-cppmt.lib


+ 17 - 0
Source/Common/Yaml/yaml-cpp/anchor.h

@@ -0,0 +1,17 @@
+#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <cstddef>
+
+namespace YAML {
+typedef std::size_t anchor_t;
+const anchor_t NullAnchor = 0;
+}
+
+#endif  // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 67 - 0
Source/Common/Yaml/yaml-cpp/binary.h

@@ -0,0 +1,67 @@
+#ifndef BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <string>
+#include <vector>
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+YAML_CPP_API std::string EncodeBase64(const unsigned char *data,
+                                      std::size_t size);
+YAML_CPP_API std::vector<unsigned char> DecodeBase64(const std::string &input);
+
+class YAML_CPP_API Binary {
+ public:
+  Binary() : m_unownedData(0), m_unownedSize(0) {}
+  Binary(const unsigned char *data_, std::size_t size_)
+      : m_unownedData(data_), m_unownedSize(size_) {}
+
+  bool owned() const { return !m_unownedData; }
+  std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; }
+  const unsigned char *data() const {
+    return owned() ? &m_data[0] : m_unownedData;
+  }
+
+  void swap(std::vector<unsigned char> &rhs) {
+    if (m_unownedData) {
+      m_data.swap(rhs);
+      rhs.clear();
+      rhs.resize(m_unownedSize);
+      std::copy(m_unownedData, m_unownedData + m_unownedSize, rhs.begin());
+      m_unownedData = 0;
+      m_unownedSize = 0;
+    } else {
+      m_data.swap(rhs);
+    }
+  }
+
+  bool operator==(const Binary &rhs) const {
+    const std::size_t s = size();
+    if (s != rhs.size())
+      return false;
+    const unsigned char *d1 = data();
+    const unsigned char *d2 = rhs.data();
+    for (std::size_t i = 0; i < s; i++) {
+      if (*d1++ != *d2++)
+        return false;
+    }
+    return true;
+  }
+
+  bool operator!=(const Binary &rhs) const { return !(*this == rhs); }
+
+ private:
+  std::vector<unsigned char> m_data;
+  const unsigned char *m_unownedData;
+  std::size_t m_unownedSize;
+};
+}
+
+#endif  // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 39 - 0
Source/Common/Yaml/yaml-cpp/contrib/anchordict.h

@@ -0,0 +1,39 @@
+#ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <vector>
+
+#include "../anchor.h"
+
+namespace YAML {
+/**
+ * An object that stores and retrieves values correlating to {@link anchor_t}
+ * values.
+ *
+ * <p>Efficient implementation that can make assumptions about how
+ * {@code anchor_t} values are assigned by the {@link Parser} class.
+ */
+template <class T>
+class AnchorDict {
+ public:
+  void Register(anchor_t anchor, T value) {
+    if (anchor > m_data.size()) {
+      m_data.resize(anchor);
+    }
+    m_data[anchor - 1] = value;
+  }
+
+  T Get(anchor_t anchor) const { return m_data[anchor - 1]; }
+
+ private:
+  std::vector<T> m_data;
+};
+}
+
+#endif  // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 149 - 0
Source/Common/Yaml/yaml-cpp/contrib/graphbuilder.h

@@ -0,0 +1,149 @@
+#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/mark.h"
+#include <string>
+
+namespace YAML {
+class Parser;
+
+// GraphBuilderInterface
+// . Abstraction of node creation
+// . pParentNode is always NULL or the return value of one of the NewXXX()
+//   functions.
+class GraphBuilderInterface {
+ public:
+  virtual ~GraphBuilderInterface() = 0;
+
+  // Create and return a new node with a null value.
+  virtual void *NewNull(const Mark &mark, void *pParentNode) = 0;
+
+  // Create and return a new node with the given tag and value.
+  virtual void *NewScalar(const Mark &mark, const std::string &tag,
+                          void *pParentNode, const std::string &value) = 0;
+
+  // Create and return a new sequence node
+  virtual void *NewSequence(const Mark &mark, const std::string &tag,
+                            void *pParentNode) = 0;
+
+  // Add pNode to pSequence.  pNode was created with one of the NewXxx()
+  // functions and pSequence with NewSequence().
+  virtual void AppendToSequence(void *pSequence, void *pNode) = 0;
+
+  // Note that no moew entries will be added to pSequence
+  virtual void SequenceComplete(void *pSequence) { (void)pSequence; }
+
+  // Create and return a new map node
+  virtual void *NewMap(const Mark &mark, const std::string &tag,
+                       void *pParentNode) = 0;
+
+  // Add the pKeyNode => pValueNode mapping to pMap.  pKeyNode and pValueNode
+  // were created with one of the NewXxx() methods and pMap with NewMap().
+  virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) = 0;
+
+  // Note that no more assignments will be made in pMap
+  virtual void MapComplete(void *pMap) { (void)pMap; }
+
+  // Return the node that should be used in place of an alias referencing
+  // pNode (pNode by default)
+  virtual void *AnchorReference(const Mark &mark, void *pNode) {
+    (void)mark;
+    return pNode;
+  }
+};
+
+// Typesafe wrapper for GraphBuilderInterface.  Assumes that Impl defines
+// Node, Sequence, and Map types.  Sequence and Map must derive from Node
+// (unless Node is defined as void).  Impl must also implement function with
+// all of the same names as the virtual functions in GraphBuilderInterface
+// -- including the ones with default implementations -- but with the
+// prototypes changed to accept an explicit Node*, Sequence*, or Map* where
+// appropriate.
+template <class Impl>
+class GraphBuilder : public GraphBuilderInterface {
+ public:
+  typedef typename Impl::Node Node;
+  typedef typename Impl::Sequence Sequence;
+  typedef typename Impl::Map Map;
+
+  GraphBuilder(Impl &impl) : m_impl(impl) {
+    Map *pMap = NULL;
+    Sequence *pSeq = NULL;
+    Node *pNode = NULL;
+
+    // Type consistency checks
+    pNode = pMap;
+    pNode = pSeq;
+  }
+
+  GraphBuilderInterface &AsBuilderInterface() { return *this; }
+
+  virtual void *NewNull(const Mark &mark, void *pParentNode) {
+    return CheckType<Node>(m_impl.NewNull(mark, AsNode(pParentNode)));
+  }
+
+  virtual void *NewScalar(const Mark &mark, const std::string &tag,
+                          void *pParentNode, const std::string &value) {
+    return CheckType<Node>(
+        m_impl.NewScalar(mark, tag, AsNode(pParentNode), value));
+  }
+
+  virtual void *NewSequence(const Mark &mark, const std::string &tag,
+                            void *pParentNode) {
+    return CheckType<Sequence>(
+        m_impl.NewSequence(mark, tag, AsNode(pParentNode)));
+  }
+  virtual void AppendToSequence(void *pSequence, void *pNode) {
+    m_impl.AppendToSequence(AsSequence(pSequence), AsNode(pNode));
+  }
+  virtual void SequenceComplete(void *pSequence) {
+    m_impl.SequenceComplete(AsSequence(pSequence));
+  }
+
+  virtual void *NewMap(const Mark &mark, const std::string &tag,
+                       void *pParentNode) {
+    return CheckType<Map>(m_impl.NewMap(mark, tag, AsNode(pParentNode)));
+  }
+  virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) {
+    m_impl.AssignInMap(AsMap(pMap), AsNode(pKeyNode), AsNode(pValueNode));
+  }
+  virtual void MapComplete(void *pMap) { m_impl.MapComplete(AsMap(pMap)); }
+
+  virtual void *AnchorReference(const Mark &mark, void *pNode) {
+    return CheckType<Node>(m_impl.AnchorReference(mark, AsNode(pNode)));
+  }
+
+ private:
+  Impl &m_impl;
+
+  // Static check for pointer to T
+  template <class T, class U>
+  static T *CheckType(U *p) {
+    return p;
+  }
+
+  static Node *AsNode(void *pNode) { return static_cast<Node *>(pNode); }
+  static Sequence *AsSequence(void *pSeq) {
+    return static_cast<Sequence *>(pSeq);
+  }
+  static Map *AsMap(void *pMap) { return static_cast<Map *>(pMap); }
+};
+
+void *BuildGraphOfNextDocument(Parser &parser,
+                               GraphBuilderInterface &graphBuilder);
+
+template <class Impl>
+typename Impl::Node *BuildGraphOfNextDocument(Parser &parser, Impl &impl) {
+  GraphBuilder<Impl> graphBuilder(impl);
+  return static_cast<typename Impl::Node *>(
+      BuildGraphOfNextDocument(parser, graphBuilder));
+}
+}
+
+#endif  // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 33 - 0
Source/Common/Yaml/yaml-cpp/dll.h

@@ -0,0 +1,33 @@
+#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+// The following ifdef block is the standard way of creating macros which make
+// exporting from a DLL simpler. All files within this DLL are compiled with the
+// yaml_cpp_EXPORTS symbol defined on the command line. This symbol should not
+// be defined on any project that uses this DLL. This way any other project
+// whose source files include this file see YAML_CPP_API functions as being
+// imported from a DLL, whereas this DLL sees symbols defined with this macro as
+// being exported.
+#undef YAML_CPP_API
+
+#ifdef YAML_CPP_DLL      // Using or Building YAML-CPP DLL (definition defined
+                         // manually)
+#ifdef yaml_cpp_EXPORTS  // Building YAML-CPP DLL (definition created by CMake
+                         // or defined manually)
+//	#pragma message( "Defining YAML_CPP_API for DLL export" )
+#define YAML_CPP_API __declspec(dllexport)
+#else  // yaml_cpp_EXPORTS
+//	#pragma message( "Defining YAML_CPP_API for DLL import" )
+#define YAML_CPP_API __declspec(dllimport)
+#endif  // yaml_cpp_EXPORTS
+#else   // YAML_CPP_DLL
+#define YAML_CPP_API
+#endif  // YAML_CPP_DLL
+
+#endif  // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 57 - 0
Source/Common/Yaml/yaml-cpp/emitfromevents.h

@@ -0,0 +1,57 @@
+#ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <stack>
+
+#include "yaml-cpp/anchor.h"
+#include "yaml-cpp/emitterstyle.h"
+#include "yaml-cpp/eventhandler.h"
+
+namespace YAML {
+struct Mark;
+}  // namespace YAML
+
+namespace YAML {
+class Emitter;
+
+class EmitFromEvents : public EventHandler {
+ public:
+  EmitFromEvents(Emitter& emitter);
+
+  virtual void OnDocumentStart(const Mark& mark);
+  virtual void OnDocumentEnd();
+
+  virtual void OnNull(const Mark& mark, anchor_t anchor);
+  virtual void OnAlias(const Mark& mark, anchor_t anchor);
+  virtual void OnScalar(const Mark& mark, const std::string& tag,
+                        anchor_t anchor, const std::string& value);
+
+  virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
+                               anchor_t anchor, EmitterStyle::value style);
+  virtual void OnSequenceEnd();
+
+  virtual void OnMapStart(const Mark& mark, const std::string& tag,
+                          anchor_t anchor, EmitterStyle::value style);
+  virtual void OnMapEnd();
+
+ private:
+  void BeginNode();
+  void EmitProps(const std::string& tag, anchor_t anchor);
+
+ private:
+  Emitter& m_emitter;
+
+  struct State {
+    enum value { WaitingForSequenceEntry, WaitingForKey, WaitingForValue };
+  };
+  std::stack<State::value> m_stateStack;
+};
+}
+
+#endif  // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 254 - 0
Source/Common/Yaml/yaml-cpp/emitter.h

@@ -0,0 +1,254 @@
+#ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <cstddef>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "yaml-cpp/binary.h"
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/emitterdef.h"
+#include "yaml-cpp/emittermanip.h"
+#include "yaml-cpp/noncopyable.h"
+#include "yaml-cpp/null.h"
+#include "yaml-cpp/ostream_wrapper.h"
+
+namespace YAML {
+class Binary;
+struct _Null;
+}  // namespace YAML
+
+namespace YAML {
+class EmitterState;
+
+class YAML_CPP_API Emitter : private noncopyable {
+ public:
+  Emitter();
+  explicit Emitter(std::ostream& stream);
+  ~Emitter();
+
+  // output
+  const char* c_str() const;
+  std::size_t size() const;
+
+  // state checking
+  bool good() const;
+  const std::string GetLastError() const;
+
+  // global setters
+  bool SetOutputCharset(EMITTER_MANIP value);
+  bool SetStringFormat(EMITTER_MANIP value);
+  bool SetBoolFormat(EMITTER_MANIP value);
+  bool SetIntBase(EMITTER_MANIP value);
+  bool SetSeqFormat(EMITTER_MANIP value);
+  bool SetMapFormat(EMITTER_MANIP value);
+  bool SetIndent(std::size_t n);
+  bool SetPreCommentIndent(std::size_t n);
+  bool SetPostCommentIndent(std::size_t n);
+  bool SetFloatPrecision(std::size_t n);
+  bool SetDoublePrecision(std::size_t n);
+
+  // local setters
+  Emitter& SetLocalValue(EMITTER_MANIP value);
+  Emitter& SetLocalIndent(const _Indent& indent);
+  Emitter& SetLocalPrecision(const _Precision& precision);
+
+  // overloads of write
+  Emitter& Write(const std::string& str);
+  Emitter& Write(bool b);
+  Emitter& Write(char ch);
+  Emitter& Write(const _Alias& alias);
+  Emitter& Write(const _Anchor& anchor);
+  Emitter& Write(const _Tag& tag);
+  Emitter& Write(const _Comment& comment);
+  Emitter& Write(const _Null& n);
+  Emitter& Write(const Binary& binary);
+
+  template <typename T>
+  Emitter& WriteIntegralType(T value);
+
+  template <typename T>
+  Emitter& WriteStreamable(T value);
+
+ private:
+  template <typename T>
+  void SetStreamablePrecision(std::stringstream&) {}
+  std::size_t GetFloatPrecision() const;
+  std::size_t GetDoublePrecision() const;
+
+  void PrepareIntegralStream(std::stringstream& stream) const;
+  void StartedScalar();
+
+ private:
+  void EmitBeginDoc();
+  void EmitEndDoc();
+  void EmitBeginSeq();
+  void EmitEndSeq();
+  void EmitBeginMap();
+  void EmitEndMap();
+  void EmitNewline();
+  void EmitKindTag();
+  void EmitTag(bool verbatim, const _Tag& tag);
+
+  void PrepareNode(EmitterNodeType::value child);
+  void PrepareTopNode(EmitterNodeType::value child);
+  void FlowSeqPrepareNode(EmitterNodeType::value child);
+  void BlockSeqPrepareNode(EmitterNodeType::value child);
+
+  void FlowMapPrepareNode(EmitterNodeType::value child);
+
+  void FlowMapPrepareLongKey(EmitterNodeType::value child);
+  void FlowMapPrepareLongKeyValue(EmitterNodeType::value child);
+  void FlowMapPrepareSimpleKey(EmitterNodeType::value child);
+  void FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child);
+
+  void BlockMapPrepareNode(EmitterNodeType::value child);
+
+  void BlockMapPrepareLongKey(EmitterNodeType::value child);
+  void BlockMapPrepareLongKeyValue(EmitterNodeType::value child);
+  void BlockMapPrepareSimpleKey(EmitterNodeType::value child);
+  void BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child);
+
+  void SpaceOrIndentTo(bool requireSpace, std::size_t indent);
+
+  const char* ComputeFullBoolName(bool b) const;
+  bool CanEmitNewline() const;
+
+ private:
+  std::unique_ptr<EmitterState> m_pState;
+  ostream_wrapper m_stream;
+};
+
+template <typename T>
+inline Emitter& Emitter::WriteIntegralType(T value) {
+  if (!good())
+    return *this;
+
+  PrepareNode(EmitterNodeType::Scalar);
+
+  std::stringstream stream;
+  PrepareIntegralStream(stream);
+  stream << value;
+  m_stream << stream.str();
+
+  StartedScalar();
+
+  return *this;
+}
+
+template <typename T>
+inline Emitter& Emitter::WriteStreamable(T value) {
+  if (!good())
+    return *this;
+
+  PrepareNode(EmitterNodeType::Scalar);
+
+  std::stringstream stream;
+  SetStreamablePrecision<T>(stream);
+  stream << value;
+  m_stream << stream.str();
+
+  StartedScalar();
+
+  return *this;
+}
+
+template <>
+inline void Emitter::SetStreamablePrecision<float>(std::stringstream& stream) {
+  stream.precision(static_cast<std::streamsize>(GetFloatPrecision()));
+}
+
+template <>
+inline void Emitter::SetStreamablePrecision<double>(std::stringstream& stream) {
+  stream.precision(static_cast<std::streamsize>(GetDoublePrecision()));
+}
+
+// overloads of insertion
+inline Emitter& operator<<(Emitter& emitter, const std::string& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, bool v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, char v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, unsigned char v) {
+  return emitter.Write(static_cast<char>(v));
+}
+inline Emitter& operator<<(Emitter& emitter, const _Alias& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, const _Anchor& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, const _Tag& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, const _Comment& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, const _Null& v) {
+  return emitter.Write(v);
+}
+inline Emitter& operator<<(Emitter& emitter, const Binary& b) {
+  return emitter.Write(b);
+}
+
+inline Emitter& operator<<(Emitter& emitter, const char* v) {
+  return emitter.Write(std::string(v));
+}
+
+inline Emitter& operator<<(Emitter& emitter, int v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, unsigned int v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, short v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, unsigned short v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, long v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, unsigned long v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, long long v) {
+  return emitter.WriteIntegralType(v);
+}
+inline Emitter& operator<<(Emitter& emitter, unsigned long long v) {
+  return emitter.WriteIntegralType(v);
+}
+
+inline Emitter& operator<<(Emitter& emitter, float v) {
+  return emitter.WriteStreamable(v);
+}
+inline Emitter& operator<<(Emitter& emitter, double v) {
+  return emitter.WriteStreamable(v);
+}
+
+inline Emitter& operator<<(Emitter& emitter, EMITTER_MANIP value) {
+  return emitter.SetLocalValue(value);
+}
+
+inline Emitter& operator<<(Emitter& emitter, _Indent indent) {
+  return emitter.SetLocalIndent(indent);
+}
+
+inline Emitter& operator<<(Emitter& emitter, _Precision precision) {
+  return emitter.SetLocalPrecision(precision);
+}
+}
+
+#endif  // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 16 - 0
Source/Common/Yaml/yaml-cpp/emitterdef.h

@@ -0,0 +1,16 @@
+#ifndef EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+namespace YAML {
+struct EmitterNodeType {
+  enum value { NoType, Property, Scalar, FlowSeq, BlockSeq, FlowMap, BlockMap };
+};
+}
+
+#endif  // EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 137 - 0
Source/Common/Yaml/yaml-cpp/emittermanip.h

@@ -0,0 +1,137 @@
+#ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <string>
+
+namespace YAML {
+enum EMITTER_MANIP {
+  // general manipulators
+  Auto,
+  TagByKind,
+  Newline,
+
+  // output character set
+  EmitNonAscii,
+  EscapeNonAscii,
+
+  // string manipulators
+  // Auto, // duplicate
+  SingleQuoted,
+  DoubleQuoted,
+  Literal,
+
+  // bool manipulators
+  YesNoBool,      // yes, no
+  TrueFalseBool,  // true, false
+  OnOffBool,      // on, off
+  UpperCase,      // TRUE, N
+  LowerCase,      // f, yes
+  CamelCase,      // No, Off
+  LongBool,       // yes, On
+  ShortBool,      // y, t
+
+  // int manipulators
+  Dec,
+  Hex,
+  Oct,
+
+  // document manipulators
+  BeginDoc,
+  EndDoc,
+
+  // sequence manipulators
+  BeginSeq,
+  EndSeq,
+  Flow,
+  Block,
+
+  // map manipulators
+  BeginMap,
+  EndMap,
+  Key,
+  Value,
+  // Flow, // duplicate
+  // Block, // duplicate
+  // Auto, // duplicate
+  LongKey
+};
+
+struct _Indent {
+  _Indent(int value_) : value(value_) {}
+  int value;
+};
+
+inline _Indent Indent(int value) { return _Indent(value); }
+
+struct _Alias {
+  _Alias(const std::string& content_) : content(content_) {}
+  std::string content;
+};
+
+inline _Alias Alias(const std::string content) { return _Alias(content); }
+
+struct _Anchor {
+  _Anchor(const std::string& content_) : content(content_) {}
+  std::string content;
+};
+
+inline _Anchor Anchor(const std::string content) { return _Anchor(content); }
+
+struct _Tag {
+  struct Type {
+    enum value { Verbatim, PrimaryHandle, NamedHandle };
+  };
+
+  explicit _Tag(const std::string& prefix_, const std::string& content_,
+                Type::value type_)
+      : prefix(prefix_), content(content_), type(type_) {}
+  std::string prefix;
+  std::string content;
+  Type::value type;
+};
+
+inline _Tag VerbatimTag(const std::string content) {
+  return _Tag("", content, _Tag::Type::Verbatim);
+}
+
+inline _Tag LocalTag(const std::string content) {
+  return _Tag("", content, _Tag::Type::PrimaryHandle);
+}
+
+inline _Tag LocalTag(const std::string& prefix, const std::string content) {
+  return _Tag(prefix, content, _Tag::Type::NamedHandle);
+}
+
+inline _Tag SecondaryTag(const std::string content) {
+  return _Tag("", content, _Tag::Type::NamedHandle);
+}
+
+struct _Comment {
+  _Comment(const std::string& content_) : content(content_) {}
+  std::string content;
+};
+
+inline _Comment Comment(const std::string content) { return _Comment(content); }
+
+struct _Precision {
+  _Precision(int floatPrecision_, int doublePrecision_)
+      : floatPrecision(floatPrecision_), doublePrecision(doublePrecision_) {}
+
+  int floatPrecision;
+  int doublePrecision;
+};
+
+inline _Precision FloatPrecision(int n) { return _Precision(n, -1); }
+
+inline _Precision DoublePrecision(int n) { return _Precision(-1, n); }
+
+inline _Precision Precision(int n) { return _Precision(n, n); }
+}
+
+#endif  // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 16 - 0
Source/Common/Yaml/yaml-cpp/emitterstyle.h

@@ -0,0 +1,16 @@
+#ifndef EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+namespace YAML {
+struct EmitterStyle {
+  enum value { Default, Block, Flow };
+};
+}
+
+#endif  // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 40 - 0
Source/Common/Yaml/yaml-cpp/eventhandler.h

@@ -0,0 +1,40 @@
+#ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <string>
+
+#include "yaml-cpp/anchor.h"
+#include "yaml-cpp/emitterstyle.h"
+
+namespace YAML {
+struct Mark;
+
+class EventHandler {
+ public:
+  virtual ~EventHandler() {}
+
+  virtual void OnDocumentStart(const Mark& mark) = 0;
+  virtual void OnDocumentEnd() = 0;
+
+  virtual void OnNull(const Mark& mark, anchor_t anchor) = 0;
+  virtual void OnAlias(const Mark& mark, anchor_t anchor) = 0;
+  virtual void OnScalar(const Mark& mark, const std::string& tag,
+                        anchor_t anchor, const std::string& value) = 0;
+
+  virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
+                               anchor_t anchor, EmitterStyle::value style) = 0;
+  virtual void OnSequenceEnd() = 0;
+
+  virtual void OnMapStart(const Mark& mark, const std::string& tag,
+                          anchor_t anchor, EmitterStyle::value style) = 0;
+  virtual void OnMapEnd() = 0;
+};
+}
+
+#endif  // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 267 - 0
Source/Common/Yaml/yaml-cpp/exceptions.h

@@ -0,0 +1,267 @@
+#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/mark.h"
+#include "yaml-cpp/traits.h"
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+// This is here for compatibility with older versions of Visual Studio
+// which don't support noexcept
+#ifdef _MSC_VER
+    #define YAML_CPP_NOEXCEPT _NOEXCEPT
+#else
+    #define YAML_CPP_NOEXCEPT noexcept
+#endif
+
+namespace YAML {
+// error messages
+namespace ErrorMsg {
+const char* const YAML_DIRECTIVE_ARGS =
+    "YAML directives must have exactly one argument";
+const char* const YAML_VERSION = "bad YAML version: ";
+const char* const YAML_MAJOR_VERSION = "YAML major version too large";
+const char* const REPEATED_YAML_DIRECTIVE = "repeated YAML directive";
+const char* const TAG_DIRECTIVE_ARGS =
+    "TAG directives must have exactly two arguments";
+const char* const REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
+const char* const CHAR_IN_TAG_HANDLE =
+    "illegal character found while scanning tag handle";
+const char* const TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
+const char* const END_OF_VERBATIM_TAG = "end of verbatim tag not found";
+const char* const END_OF_MAP = "end of map not found";
+const char* const END_OF_MAP_FLOW = "end of map flow not found";
+const char* const END_OF_SEQ = "end of sequence not found";
+const char* const END_OF_SEQ_FLOW = "end of sequence flow not found";
+const char* const MULTIPLE_TAGS =
+    "cannot assign multiple tags to the same node";
+const char* const MULTIPLE_ANCHORS =
+    "cannot assign multiple anchors to the same node";
+const char* const MULTIPLE_ALIASES =
+    "cannot assign multiple aliases to the same node";
+const char* const ALIAS_CONTENT =
+    "aliases can't have any content, *including* tags";
+const char* const INVALID_HEX = "bad character found while scanning hex number";
+const char* const INVALID_UNICODE = "invalid unicode: ";
+const char* const INVALID_ESCAPE = "unknown escape character: ";
+const char* const UNKNOWN_TOKEN = "unknown token";
+const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
+const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
+const char* const CHAR_IN_SCALAR = "illegal character in scalar";
+const char* const TAB_IN_INDENTATION =
+    "illegal tab when looking for indentation";
+const char* const FLOW_END = "illegal flow end";
+const char* const BLOCK_ENTRY = "illegal block entry";
+const char* const MAP_KEY = "illegal map key";
+const char* const MAP_VALUE = "illegal map value";
+const char* const ALIAS_NOT_FOUND = "alias not found after *";
+const char* const ANCHOR_NOT_FOUND = "anchor not found after &";
+const char* const CHAR_IN_ALIAS =
+    "illegal character found while scanning alias";
+const char* const CHAR_IN_ANCHOR =
+    "illegal character found while scanning anchor";
+const char* const ZERO_INDENT_IN_BLOCK =
+    "cannot set zero indentation for a block scalar";
+const char* const CHAR_IN_BLOCK = "unexpected character in block scalar";
+const char* const AMBIGUOUS_ANCHOR =
+    "cannot assign the same alias to multiple nodes";
+const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined";
+
+const char* const INVALID_NODE =
+    "invalid node; this may result from using a map iterator as a sequence "
+    "iterator, or vice-versa";
+const char* const INVALID_SCALAR = "invalid scalar";
+const char* const KEY_NOT_FOUND = "key not found";
+const char* const BAD_CONVERSION = "bad conversion";
+const char* const BAD_DEREFERENCE = "bad dereference";
+const char* const BAD_SUBSCRIPT = "operator[] call on a scalar";
+const char* const BAD_PUSHBACK = "appending to a non-sequence";
+const char* const BAD_INSERT = "inserting in a non-convertible-to-map";
+
+const char* const UNMATCHED_GROUP_TAG = "unmatched group tag";
+const char* const UNEXPECTED_END_SEQ = "unexpected end sequence token";
+const char* const UNEXPECTED_END_MAP = "unexpected end map token";
+const char* const SINGLE_QUOTED_CHAR =
+    "invalid character in single-quoted string";
+const char* const INVALID_ANCHOR = "invalid anchor";
+const char* const INVALID_ALIAS = "invalid alias";
+const char* const INVALID_TAG = "invalid tag";
+const char* const BAD_FILE = "bad file";
+
+template <typename T>
+inline const std::string KEY_NOT_FOUND_WITH_KEY(
+    const T&, typename disable_if<is_numeric<T>>::type* = 0) {
+  return KEY_NOT_FOUND;
+}
+
+inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
+  std::stringstream stream;
+  stream << KEY_NOT_FOUND << ": " << key;
+  return stream.str();
+}
+
+template <typename T>
+inline const std::string KEY_NOT_FOUND_WITH_KEY(
+    const T& key, typename enable_if<is_numeric<T>>::type* = 0) {
+  std::stringstream stream;
+  stream << KEY_NOT_FOUND << ": " << key;
+  return stream.str();
+}
+}
+
+class YAML_CPP_API Exception : public std::runtime_error {
+ public:
+  Exception(const Mark& mark_, const std::string& msg_)
+      : std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {}
+  virtual ~Exception() YAML_CPP_NOEXCEPT;
+
+  Exception(const Exception&) = default;
+
+  Mark mark;
+  std::string msg;
+
+ private:
+  static const std::string build_what(const Mark& mark,
+                                      const std::string& msg) {
+    if (mark.is_null()) {
+      return msg.c_str();
+    }
+
+    std::stringstream output;
+    output << "yaml-cpp: error at line " << mark.line + 1 << ", column "
+           << mark.column + 1 << ": " << msg;
+    return output.str();
+  }
+};
+
+class YAML_CPP_API ParserException : public Exception {
+ public:
+  ParserException(const Mark& mark_, const std::string& msg_)
+      : Exception(mark_, msg_) {}
+  ParserException(const ParserException&) = default;
+  virtual ~ParserException() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API RepresentationException : public Exception {
+ public:
+  RepresentationException(const Mark& mark_, const std::string& msg_)
+      : Exception(mark_, msg_) {}
+  RepresentationException(const RepresentationException&) = default;
+  virtual ~RepresentationException() YAML_CPP_NOEXCEPT;
+};
+
+// representation exceptions
+class YAML_CPP_API InvalidScalar : public RepresentationException {
+ public:
+  InvalidScalar(const Mark& mark_)
+      : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
+  InvalidScalar(const InvalidScalar&) = default;
+  virtual ~InvalidScalar() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API KeyNotFound : public RepresentationException {
+ public:
+  template <typename T>
+  KeyNotFound(const Mark& mark_, const T& key_)
+      : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
+  }
+  KeyNotFound(const KeyNotFound&) = default;
+  virtual ~KeyNotFound() YAML_CPP_NOEXCEPT;
+};
+
+template <typename T>
+class YAML_CPP_API TypedKeyNotFound : public KeyNotFound {
+ public:
+  TypedKeyNotFound(const Mark& mark_, const T& key_)
+      : KeyNotFound(mark_, key_), key(key_) {}
+  virtual ~TypedKeyNotFound() YAML_CPP_NOEXCEPT {}
+
+  T key;
+};
+
+template <typename T>
+inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
+                                                const T& key) {
+  return TypedKeyNotFound<T>(mark, key);
+}
+
+class YAML_CPP_API InvalidNode : public RepresentationException {
+ public:
+  InvalidNode()
+      : RepresentationException(Mark::null_mark(), ErrorMsg::INVALID_NODE) {}
+  InvalidNode(const InvalidNode&) = default;
+  virtual ~InvalidNode() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API BadConversion : public RepresentationException {
+ public:
+  explicit BadConversion(const Mark& mark_)
+      : RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
+  BadConversion(const BadConversion&) = default;
+  virtual ~BadConversion() YAML_CPP_NOEXCEPT;
+};
+
+template <typename T>
+class TypedBadConversion : public BadConversion {
+ public:
+  explicit TypedBadConversion(const Mark& mark_) : BadConversion(mark_) {}
+};
+
+class YAML_CPP_API BadDereference : public RepresentationException {
+ public:
+  BadDereference()
+      : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
+  BadDereference(const BadDereference&) = default;
+  virtual ~BadDereference() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API BadSubscript : public RepresentationException {
+ public:
+  BadSubscript()
+      : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {}
+  BadSubscript(const BadSubscript&) = default;
+  virtual ~BadSubscript() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API BadPushback : public RepresentationException {
+ public:
+  BadPushback()
+      : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
+  BadPushback(const BadPushback&) = default;
+  virtual ~BadPushback() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API BadInsert : public RepresentationException {
+ public:
+  BadInsert()
+      : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
+  BadInsert(const BadInsert&) = default;
+  virtual ~BadInsert() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API EmitterException : public Exception {
+ public:
+  EmitterException(const std::string& msg_)
+      : Exception(Mark::null_mark(), msg_) {}
+  EmitterException(const EmitterException&) = default;
+  virtual ~EmitterException() YAML_CPP_NOEXCEPT;
+};
+
+class YAML_CPP_API BadFile : public Exception {
+ public:
+  BadFile() : Exception(Mark::null_mark(), ErrorMsg::BAD_FILE) {}
+  BadFile(const BadFile&) = default;
+  virtual ~BadFile() YAML_CPP_NOEXCEPT;
+};
+}
+
+#undef YAML_CPP_NOEXCEPT
+
+#endif  // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 29 - 0
Source/Common/Yaml/yaml-cpp/mark.h

@@ -0,0 +1,29 @@
+#ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+struct YAML_CPP_API Mark {
+  Mark() : pos(0), line(0), column(0) {}
+
+  static const Mark null_mark() { return Mark(-1, -1, -1); }
+
+  bool is_null() const { return pos == -1 && line == -1 && column == -1; }
+
+  int pos;
+  int line, column;
+
+ private:
+  Mark(int pos_, int line_, int column_)
+      : pos(pos_), line(line_), column(column_) {}
+};
+}
+
+#endif  // MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 331 - 0
Source/Common/Yaml/yaml-cpp/node/convert.h

@@ -0,0 +1,331 @@
+#ifndef NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <array>
+#include <limits>
+#include <list>
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include "yaml-cpp/binary.h"
+#include "yaml-cpp/node/impl.h"
+#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/node/node.h"
+#include "yaml-cpp/node/type.h"
+#include "yaml-cpp/null.h"
+
+namespace YAML {
+class Binary;
+struct _Null;
+template <typename T>
+struct convert;
+}  // namespace YAML
+
+namespace YAML {
+namespace conversion {
+inline bool IsInfinity(const std::string& input) {
+  return input == ".inf" || input == ".Inf" || input == ".INF" ||
+         input == "+.inf" || input == "+.Inf" || input == "+.INF";
+}
+
+inline bool IsNegativeInfinity(const std::string& input) {
+  return input == "-.inf" || input == "-.Inf" || input == "-.INF";
+}
+
+inline bool IsNaN(const std::string& input) {
+  return input == ".nan" || input == ".NaN" || input == ".NAN";
+}
+}
+
+// Node
+template <>
+struct convert<Node> {
+  static Node encode(const Node& rhs) { return rhs; }
+
+  static bool decode(const Node& node, Node& rhs) {
+    rhs.reset(node);
+    return true;
+  }
+};
+
+// std::string
+template <>
+struct convert<std::string> {
+  static Node encode(const std::string& rhs) { return Node(rhs); }
+
+  static bool decode(const Node& node, std::string& rhs) {
+    if (!node.IsScalar())
+      return false;
+    rhs = node.Scalar();
+    return true;
+  }
+};
+
+// C-strings can only be encoded
+template <>
+struct convert<const char*> {
+  static Node encode(const char*& rhs) { return Node(rhs); }
+};
+
+template <std::size_t N>
+struct convert<const char[N]> {
+  static Node encode(const char(&rhs)[N]) { return Node(rhs); }
+};
+
+template <>
+struct convert<_Null> {
+  static Node encode(const _Null& /* rhs */) { return Node(); }
+
+  static bool decode(const Node& node, _Null& /* rhs */) {
+    return node.IsNull();
+  }
+};
+
+#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op)                \
+  template <>                                                            \
+  struct convert<type> {                                                 \
+    static Node encode(const type& rhs) {                                \
+      std::stringstream stream;                                          \
+      stream.precision(std::numeric_limits<type>::digits10 + 1);         \
+      stream << rhs;                                                     \
+      return Node(stream.str());                                         \
+    }                                                                    \
+                                                                         \
+    static bool decode(const Node& node, type& rhs) {                    \
+      if (node.Type() != NodeType::Scalar)                               \
+        return false;                                                    \
+      const std::string& input = node.Scalar();                          \
+      std::stringstream stream(input);                                   \
+      stream.unsetf(std::ios::dec);                                      \
+      if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \
+        return true;                                                     \
+      if (std::numeric_limits<type>::has_infinity) {                     \
+        if (conversion::IsInfinity(input)) {                             \
+          rhs = std::numeric_limits<type>::infinity();                   \
+          return true;                                                   \
+        } else if (conversion::IsNegativeInfinity(input)) {              \
+          rhs = negative_op std::numeric_limits<type>::infinity();       \
+          return true;                                                   \
+        }                                                                \
+      }                                                                  \
+                                                                         \
+      if (std::numeric_limits<type>::has_quiet_NaN &&                    \
+          conversion::IsNaN(input)) {                                    \
+        rhs = std::numeric_limits<type>::quiet_NaN();                    \
+        return true;                                                     \
+      }                                                                  \
+                                                                         \
+      return false;                                                      \
+    }                                                                    \
+  }
+
+#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \
+  YAML_DEFINE_CONVERT_STREAMABLE(type, -)
+
+#define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \
+  YAML_DEFINE_CONVERT_STREAMABLE(type, +)
+
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long);
+YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned);
+YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short);
+YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long);
+YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long);
+
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char);
+YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char);
+
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double);
+YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double);
+
+#undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED
+#undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED
+#undef YAML_DEFINE_CONVERT_STREAMABLE
+
+// bool
+template <>
+struct convert<bool> {
+  static Node encode(bool rhs) { return rhs ? Node("true") : Node("false"); }
+
+  YAML_CPP_API static bool decode(const Node& node, bool& rhs);
+};
+
+// std::map
+template <typename K, typename V>
+struct convert<std::map<K, V>> {
+  static Node encode(const std::map<K, V>& rhs) {
+    Node node(NodeType::Map);
+    for (typename std::map<K, V>::const_iterator it = rhs.begin();
+         it != rhs.end(); ++it)
+      node.force_insert(it->first, it->second);
+    return node;
+  }
+
+  static bool decode(const Node& node, std::map<K, V>& rhs) {
+    if (!node.IsMap())
+      return false;
+
+    rhs.clear();
+    for (const_iterator it = node.begin(); it != node.end(); ++it)
+#if defined(__GNUC__) && __GNUC__ < 4
+      // workaround for GCC 3:
+      rhs[it->first.template as<K>()] = it->second.template as<V>();
+#else
+      rhs[it->first.as<K>()] = it->second.as<V>();
+#endif
+    return true;
+  }
+};
+
+// std::vector
+template <typename T>
+struct convert<std::vector<T>> {
+  static Node encode(const std::vector<T>& rhs) {
+    Node node(NodeType::Sequence);
+    for (typename std::vector<T>::const_iterator it = rhs.begin();
+         it != rhs.end(); ++it)
+      node.push_back(*it);
+    return node;
+  }
+
+  static bool decode(const Node& node, std::vector<T>& rhs) {
+    if (!node.IsSequence())
+      return false;
+
+    rhs.clear();
+    for (const_iterator it = node.begin(); it != node.end(); ++it)
+#if defined(__GNUC__) && __GNUC__ < 4
+      // workaround for GCC 3:
+      rhs.push_back(it->template as<T>());
+#else
+      rhs.push_back(it->as<T>());
+#endif
+    return true;
+  }
+};
+
+// std::list
+template <typename T>
+struct convert<std::list<T>> {
+  static Node encode(const std::list<T>& rhs) {
+    Node node(NodeType::Sequence);
+    for (typename std::list<T>::const_iterator it = rhs.begin();
+         it != rhs.end(); ++it)
+      node.push_back(*it);
+    return node;
+  }
+
+  static bool decode(const Node& node, std::list<T>& rhs) {
+    if (!node.IsSequence())
+      return false;
+
+    rhs.clear();
+    for (const_iterator it = node.begin(); it != node.end(); ++it)
+#if defined(__GNUC__) && __GNUC__ < 4
+      // workaround for GCC 3:
+      rhs.push_back(it->template as<T>());
+#else
+      rhs.push_back(it->as<T>());
+#endif
+    return true;
+  }
+};
+
+// std::array
+template <typename T, std::size_t N>
+struct convert<std::array<T, N>> {
+  static Node encode(const std::array<T, N>& rhs) {
+    Node node(NodeType::Sequence);
+    for (const auto& element : rhs) {
+      node.push_back(element);
+    }
+    return node;
+  }
+
+  static bool decode(const Node& node, std::array<T, N>& rhs) {
+    if (!isNodeValid(node)) {
+      return false;
+    }
+
+    for (auto i = 0u; i < node.size(); ++i) {
+#if defined(__GNUC__) && __GNUC__ < 4
+      // workaround for GCC 3:
+      rhs[i] = node[i].template as<T>();
+#else
+      rhs[i] = node[i].as<T>();
+#endif
+    }
+    return true;
+  }
+
+ private:
+  static bool isNodeValid(const Node& node) {
+    return node.IsSequence() && node.size() == N;
+  }
+};
+
+// std::pair
+template <typename T, typename U>
+struct convert<std::pair<T, U>> {
+  static Node encode(const std::pair<T, U>& rhs) {
+    Node node(NodeType::Sequence);
+    node.push_back(rhs.first);
+    node.push_back(rhs.second);
+    return node;
+  }
+
+  static bool decode(const Node& node, std::pair<T, U>& rhs) {
+    if (!node.IsSequence())
+      return false;
+    if (node.size() != 2)
+      return false;
+
+#if defined(__GNUC__) && __GNUC__ < 4
+    // workaround for GCC 3:
+    rhs.first = node[0].template as<T>();
+#else
+    rhs.first = node[0].as<T>();
+#endif
+#if defined(__GNUC__) && __GNUC__ < 4
+    // workaround for GCC 3:
+    rhs.second = node[1].template as<U>();
+#else
+    rhs.second = node[1].as<U>();
+#endif
+    return true;
+  }
+};
+
+// binary
+template <>
+struct convert<Binary> {
+  static Node encode(const Binary& rhs) {
+    return Node(EncodeBase64(rhs.data(), rhs.size()));
+  }
+
+  static bool decode(const Node& node, Binary& rhs) {
+    if (!node.IsScalar())
+      return false;
+
+    std::vector<unsigned char> data = DecodeBase64(node.Scalar());
+    if (data.empty() && !node.Scalar().empty())
+      return false;
+
+    rhs.swap(data);
+    return true;
+  }
+};
+}
+
+#endif  // NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 26 - 0
Source/Common/Yaml/yaml-cpp/node/detail/bool_type.h

@@ -0,0 +1,26 @@
+#ifndef NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+namespace YAML {
+namespace detail {
+struct unspecified_bool {
+  struct NOT_ALLOWED;
+  static void true_value(NOT_ALLOWED*) {}
+};
+typedef void (*unspecified_bool_type)(unspecified_bool::NOT_ALLOWED*);
+}
+}
+
+#define YAML_CPP_OPERATOR_BOOL()                                            \
+  operator YAML::detail::unspecified_bool_type() const {                    \
+    return this->operator!() ? 0                                            \
+                             : &YAML::detail::unspecified_bool::true_value; \
+  }
+
+#endif  // NODE_DETAIL_BOOL_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 185 - 0
Source/Common/Yaml/yaml-cpp/node/detail/impl.h

@@ -0,0 +1,185 @@
+#ifndef NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/node/detail/node.h"
+#include "yaml-cpp/node/detail/node_data.h"
+#include <type_traits>
+
+namespace YAML {
+namespace detail {
+template <typename Key, typename Enable = void>
+struct get_idx {
+  static node* get(const std::vector<node*>& /* sequence */,
+                   const Key& /* key */, shared_memory_holder /* pMemory */) {
+    return 0;
+  }
+};
+
+template <typename Key>
+struct get_idx<Key,
+               typename std::enable_if<std::is_unsigned<Key>::value &&
+                                       !std::is_same<Key, bool>::value>::type> {
+  static node* get(const std::vector<node*>& sequence, const Key& key,
+                   shared_memory_holder /* pMemory */) {
+    return key < sequence.size() ? sequence[key] : 0;
+  }
+
+  static node* get(std::vector<node*>& sequence, const Key& key,
+                   shared_memory_holder pMemory) {
+   if (key > sequence.size() || (key > 0 && !sequence[key-1]->is_defined()))
+      return 0;
+    if (key == sequence.size())
+      sequence.push_back(&pMemory->create_node());
+    return sequence[key];
+  }
+};
+
+template <typename Key>
+struct get_idx<Key, typename std::enable_if<std::is_signed<Key>::value>::type> {
+  static node* get(const std::vector<node*>& sequence, const Key& key,
+                   shared_memory_holder pMemory) {
+    return key >= 0 ? get_idx<std::size_t>::get(
+                          sequence, static_cast<std::size_t>(key), pMemory)
+                    : 0;
+  }
+  static node* get(std::vector<node*>& sequence, const Key& key,
+                   shared_memory_holder pMemory) {
+    return key >= 0 ? get_idx<std::size_t>::get(
+                          sequence, static_cast<std::size_t>(key), pMemory)
+                    : 0;
+  }
+};
+
+template <typename T>
+inline bool node::equals(const T& rhs, shared_memory_holder pMemory) {
+  T lhs;
+  if (convert<T>::decode(Node(*this, pMemory), lhs)) {
+    return lhs == rhs;
+  }
+  return false;
+}
+
+inline bool node::equals(const char* rhs, shared_memory_holder pMemory) {
+  return equals<std::string>(rhs, pMemory);
+}
+
+// indexing
+template <typename Key>
+inline node* node_data::get(const Key& key,
+                            shared_memory_holder pMemory) const {
+  switch (m_type) {
+    case NodeType::Map:
+      break;
+    case NodeType::Undefined:
+    case NodeType::Null:
+      return NULL;
+    case NodeType::Sequence:
+      if (node* pNode = get_idx<Key>::get(m_sequence, key, pMemory))
+        return pNode;
+      return NULL;
+    case NodeType::Scalar:
+      throw BadSubscript();
+  }
+
+  for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
+    if (it->first->equals(key, pMemory)) {
+      return it->second;
+    }
+  }
+
+  return NULL;
+}
+
+template <typename Key>
+inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
+  switch (m_type) {
+    case NodeType::Map:
+      break;
+    case NodeType::Undefined:
+    case NodeType::Null:
+    case NodeType::Sequence:
+      if (node* pNode = get_idx<Key>::get(m_sequence, key, pMemory)) {
+        m_type = NodeType::Sequence;
+        return *pNode;
+      }
+
+      convert_to_map(pMemory);
+      break;
+    case NodeType::Scalar:
+      throw BadSubscript();
+  }
+
+  for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
+    if (it->first->equals(key, pMemory)) {
+      return *it->second;
+    }
+  }
+
+  node& k = convert_to_node(key, pMemory);
+  node& v = pMemory->create_node();
+  insert_map_pair(k, v);
+  return v;
+}
+
+template <typename Key>
+inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
+  if (m_type != NodeType::Map)
+    return false;
+
+  for (kv_pairs::iterator it = m_undefinedPairs.begin();
+       it != m_undefinedPairs.end();) {
+    kv_pairs::iterator jt = std::next(it);
+    if (it->first->equals(key, pMemory))
+      m_undefinedPairs.erase(it);
+    it = jt;
+  }
+
+  for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
+    if (it->first->equals(key, pMemory)) {
+      m_map.erase(it);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// map
+template <typename Key, typename Value>
+inline void node_data::force_insert(const Key& key, const Value& value,
+                                    shared_memory_holder pMemory) {
+  switch (m_type) {
+    case NodeType::Map:
+      break;
+    case NodeType::Undefined:
+    case NodeType::Null:
+    case NodeType::Sequence:
+      convert_to_map(pMemory);
+      break;
+    case NodeType::Scalar:
+      throw BadInsert();
+  }
+
+  node& k = convert_to_node(key, pMemory);
+  node& v = convert_to_node(value, pMemory);
+  insert_map_pair(k, v);
+}
+
+template <typename T>
+inline node& node_data::convert_to_node(const T& rhs,
+                                        shared_memory_holder pMemory) {
+  Node value = convert<T>::encode(rhs);
+  value.EnsureNodeExists();
+  pMemory->merge(*value.m_pMemory);
+  return *value.m_pNode;
+}
+}
+}
+
+#endif  // NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 92 - 0
Source/Common/Yaml/yaml-cpp/node/detail/iterator.h

@@ -0,0 +1,92 @@
+#ifndef VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/node.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/detail/node_iterator.h"
+#include <cstddef>
+#include <iterator>
+
+namespace YAML {
+namespace detail {
+struct iterator_value;
+
+template <typename V>
+class iterator_base : public std::iterator<std::forward_iterator_tag, V,
+                                           std::ptrdiff_t, V*, V> {
+
+ private:
+  template <typename>
+  friend class iterator_base;
+  struct enabler {};
+  typedef node_iterator base_type;
+
+  struct proxy {
+    explicit proxy(const V& x) : m_ref(x) {}
+    V* operator->() { return std::addressof(m_ref); }
+    operator V*() { return std::addressof(m_ref); }
+
+    V m_ref;
+  };
+
+ public:
+  typedef typename iterator_base::value_type value_type;
+
+ public:
+  iterator_base() : m_iterator(), m_pMemory() {}
+  explicit iterator_base(base_type rhs, shared_memory_holder pMemory)
+      : m_iterator(rhs), m_pMemory(pMemory) {}
+
+  template <class W>
+  iterator_base(const iterator_base<W>& rhs,
+                typename std::enable_if<std::is_convertible<W*, V*>::value,
+                                        enabler>::type = enabler())
+      : m_iterator(rhs.m_iterator), m_pMemory(rhs.m_pMemory) {}
+
+  iterator_base<V>& operator++() {
+    ++m_iterator;
+    return *this;
+  }
+
+  iterator_base<V> operator++(int) {
+    iterator_base<V> iterator_pre(*this);
+    ++(*this);
+    return iterator_pre;
+  }
+
+  template <typename W>
+  bool operator==(const iterator_base<W>& rhs) const {
+    return m_iterator == rhs.m_iterator;
+  }
+
+  template <typename W>
+  bool operator!=(const iterator_base<W>& rhs) const {
+    return m_iterator != rhs.m_iterator;
+  }
+
+  value_type operator*() const {
+    const typename base_type::value_type& v = *m_iterator;
+    if (v.pNode)
+      return value_type(Node(*v, m_pMemory));
+    if (v.first && v.second)
+      return value_type(Node(*v.first, m_pMemory), Node(*v.second, m_pMemory));
+    return value_type();
+  }
+
+  proxy operator->() const { return proxy(**this); }
+
+ private:
+  base_type m_iterator;
+  shared_memory_holder m_pMemory;
+};
+}
+}
+
+#endif  // VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 27 - 0
Source/Common/Yaml/yaml-cpp/node/detail/iterator_fwd.h

@@ -0,0 +1,27 @@
+#ifndef VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include <list>
+#include <utility>
+#include <vector>
+
+namespace YAML {
+
+namespace detail {
+struct iterator_value;
+template <typename V>
+class iterator_base;
+}
+
+typedef detail::iterator_base<detail::iterator_value> iterator;
+typedef detail::iterator_base<const detail::iterator_value> const_iterator;
+}
+
+#endif  // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 46 - 0
Source/Common/Yaml/yaml-cpp/node/detail/memory.h

@@ -0,0 +1,46 @@
+#ifndef VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <set>
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/ptr.h"
+
+namespace YAML {
+namespace detail {
+class node;
+}  // namespace detail
+}  // namespace YAML
+
+namespace YAML {
+namespace detail {
+class YAML_CPP_API memory {
+ public:
+  node& create_node();
+  void merge(const memory& rhs);
+
+ private:
+  typedef std::set<shared_node> Nodes;
+  Nodes m_nodes;
+};
+
+class YAML_CPP_API memory_holder {
+ public:
+  memory_holder() : m_pMemory(new memory) {}
+
+  node& create_node() { return m_pMemory->create_node(); }
+  void merge(memory_holder& rhs);
+
+ private:
+  shared_memory m_pMemory;
+};
+}
+}
+
+#endif  // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 169 - 0
Source/Common/Yaml/yaml-cpp/node/detail/node.h

@@ -0,0 +1,169 @@
+#ifndef NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/emitterstyle.h"
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/type.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/detail/node_ref.h"
+#include <set>
+
+namespace YAML {
+namespace detail {
+class node {
+ public:
+  node() : m_pRef(new node_ref) {}
+  node(const node&) = delete;
+  node& operator=(const node&) = delete;
+
+  bool is(const node& rhs) const { return m_pRef == rhs.m_pRef; }
+  const node_ref* ref() const { return m_pRef.get(); }
+
+  bool is_defined() const { return m_pRef->is_defined(); }
+  const Mark& mark() const { return m_pRef->mark(); }
+  NodeType::value type() const { return m_pRef->type(); }
+
+  const std::string& scalar() const { return m_pRef->scalar(); }
+  const std::string& tag() const { return m_pRef->tag(); }
+  EmitterStyle::value style() const { return m_pRef->style(); }
+
+  template <typename T>
+  bool equals(const T& rhs, shared_memory_holder pMemory);
+  bool equals(const char* rhs, shared_memory_holder pMemory);
+
+  void mark_defined() {
+    if (is_defined())
+      return;
+
+    m_pRef->mark_defined();
+    for (nodes::iterator it = m_dependencies.begin();
+         it != m_dependencies.end(); ++it)
+      (*it)->mark_defined();
+    m_dependencies.clear();
+  }
+
+  void add_dependency(node& rhs) {
+    if (is_defined())
+      rhs.mark_defined();
+    else
+      m_dependencies.insert(&rhs);
+  }
+
+  void set_ref(const node& rhs) {
+    if (rhs.is_defined())
+      mark_defined();
+    m_pRef = rhs.m_pRef;
+  }
+  void set_data(const node& rhs) {
+    if (rhs.is_defined())
+      mark_defined();
+    m_pRef->set_data(*rhs.m_pRef);
+  }
+
+  void set_mark(const Mark& mark) { m_pRef->set_mark(mark); }
+
+  void set_type(NodeType::value type) {
+    if (type != NodeType::Undefined)
+      mark_defined();
+    m_pRef->set_type(type);
+  }
+  void set_null() {
+    mark_defined();
+    m_pRef->set_null();
+  }
+  void set_scalar(const std::string& scalar) {
+    mark_defined();
+    m_pRef->set_scalar(scalar);
+  }
+  void set_tag(const std::string& tag) {
+    mark_defined();
+    m_pRef->set_tag(tag);
+  }
+
+  // style
+  void set_style(EmitterStyle::value style) {
+    mark_defined();
+    m_pRef->set_style(style);
+  }
+
+  // size/iterator
+  std::size_t size() const { return m_pRef->size(); }
+
+  const_node_iterator begin() const {
+    return static_cast<const node_ref&>(*m_pRef).begin();
+  }
+  node_iterator begin() { return m_pRef->begin(); }
+
+  const_node_iterator end() const {
+    return static_cast<const node_ref&>(*m_pRef).end();
+  }
+  node_iterator end() { return m_pRef->end(); }
+
+  // sequence
+  void push_back(node& input, shared_memory_holder pMemory) {
+    m_pRef->push_back(input, pMemory);
+    input.add_dependency(*this);
+  }
+  void insert(node& key, node& value, shared_memory_holder pMemory) {
+    m_pRef->insert(key, value, pMemory);
+    key.add_dependency(*this);
+    value.add_dependency(*this);
+  }
+
+  // indexing
+  template <typename Key>
+  node* get(const Key& key, shared_memory_holder pMemory) const {
+    // NOTE: this returns a non-const node so that the top-level Node can wrap
+    // it, and returns a pointer so that it can be NULL (if there is no such
+    // key).
+    return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
+  }
+  template <typename Key>
+  node& get(const Key& key, shared_memory_holder pMemory) {
+    node& value = m_pRef->get(key, pMemory);
+    value.add_dependency(*this);
+    return value;
+  }
+  template <typename Key>
+  bool remove(const Key& key, shared_memory_holder pMemory) {
+    return m_pRef->remove(key, pMemory);
+  }
+
+  node* get(node& key, shared_memory_holder pMemory) const {
+    // NOTE: this returns a non-const node so that the top-level Node can wrap
+    // it, and returns a pointer so that it can be NULL (if there is no such
+    // key).
+    return static_cast<const node_ref&>(*m_pRef).get(key, pMemory);
+  }
+  node& get(node& key, shared_memory_holder pMemory) {
+    node& value = m_pRef->get(key, pMemory);
+    key.add_dependency(*this);
+    value.add_dependency(*this);
+    return value;
+  }
+  bool remove(node& key, shared_memory_holder pMemory) {
+    return m_pRef->remove(key, pMemory);
+  }
+
+  // map
+  template <typename Key, typename Value>
+  void force_insert(const Key& key, const Value& value,
+                    shared_memory_holder pMemory) {
+    m_pRef->force_insert(key, value, pMemory);
+  }
+
+ private:
+  shared_node_ref m_pRef;
+  typedef std::set<node*> nodes;
+  nodes m_dependencies;
+};
+}
+}
+
+#endif  // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 127 - 0
Source/Common/Yaml/yaml-cpp/node/detail/node_data.h

@@ -0,0 +1,127 @@
+#ifndef VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <list>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/detail/node_iterator.h"
+#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/type.h"
+
+namespace YAML {
+namespace detail {
+class node;
+}  // namespace detail
+}  // namespace YAML
+
+namespace YAML {
+namespace detail {
+class YAML_CPP_API node_data {
+ public:
+  node_data();
+  node_data(const node_data&) = delete;
+  node_data& operator=(const node_data&) = delete;
+
+  void mark_defined();
+  void set_mark(const Mark& mark);
+  void set_type(NodeType::value type);
+  void set_tag(const std::string& tag);
+  void set_null();
+  void set_scalar(const std::string& scalar);
+  void set_style(EmitterStyle::value style);
+
+  bool is_defined() const { return m_isDefined; }
+  const Mark& mark() const { return m_mark; }
+  NodeType::value type() const {
+    return m_isDefined ? m_type : NodeType::Undefined;
+  }
+  const std::string& scalar() const { return m_scalar; }
+  const std::string& tag() const { return m_tag; }
+  EmitterStyle::value style() const { return m_style; }
+
+  // size/iterator
+  std::size_t size() const;
+
+  const_node_iterator begin() const;
+  node_iterator begin();
+
+  const_node_iterator end() const;
+  node_iterator end();
+
+  // sequence
+  void push_back(node& node, shared_memory_holder pMemory);
+  void insert(node& key, node& value, shared_memory_holder pMemory);
+
+  // indexing
+  template <typename Key>
+  node* get(const Key& key, shared_memory_holder pMemory) const;
+  template <typename Key>
+  node& get(const Key& key, shared_memory_holder pMemory);
+  template <typename Key>
+  bool remove(const Key& key, shared_memory_holder pMemory);
+
+  node* get(node& key, shared_memory_holder pMemory) const;
+  node& get(node& key, shared_memory_holder pMemory);
+  bool remove(node& key, shared_memory_holder pMemory);
+
+  // map
+  template <typename Key, typename Value>
+  void force_insert(const Key& key, const Value& value,
+                    shared_memory_holder pMemory);
+
+ public:
+  static std::string empty_scalar;
+
+ private:
+  void compute_seq_size() const;
+  void compute_map_size() const;
+
+  void reset_sequence();
+  void reset_map();
+
+  void insert_map_pair(node& key, node& value);
+  void convert_to_map(shared_memory_holder pMemory);
+  void convert_sequence_to_map(shared_memory_holder pMemory);
+
+  template <typename T>
+  static node& convert_to_node(const T& rhs, shared_memory_holder pMemory);
+
+ private:
+  bool m_isDefined;
+  Mark m_mark;
+  NodeType::value m_type;
+  std::string m_tag;
+  EmitterStyle::value m_style;
+
+  // scalar
+  std::string m_scalar;
+
+  // sequence
+  typedef std::vector<node*> node_seq;
+  node_seq m_sequence;
+
+  mutable std::size_t m_seqSize;
+
+  // map
+  typedef std::vector<std::pair<node*, node*>> node_map;
+  node_map m_map;
+
+  typedef std::pair<node*, node*> kv_pair;
+  typedef std::list<kv_pair> kv_pairs;
+  mutable kv_pairs m_undefinedPairs;
+};
+}
+}
+
+#endif  // VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 180 - 0
Source/Common/Yaml/yaml-cpp/node/detail/node_iterator.h

@@ -0,0 +1,180 @@
+#ifndef VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/ptr.h"
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <map>
+#include <utility>
+#include <vector>
+
+namespace YAML {
+namespace detail {
+struct iterator_type {
+  enum value { None, Sequence, Map };
+};
+
+template <typename V>
+struct node_iterator_value : public std::pair<V*, V*> {
+  typedef std::pair<V*, V*> kv;
+
+  node_iterator_value() : kv(), pNode(0) {}
+  explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {}
+  explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(0) {}
+
+  V& operator*() const { return *pNode; }
+  V& operator->() const { return *pNode; }
+
+  V* pNode;
+};
+
+typedef std::vector<node*> node_seq;
+typedef std::vector<std::pair<node*, node*>> node_map;
+
+template <typename V>
+struct node_iterator_type {
+  typedef node_seq::iterator seq;
+  typedef node_map::iterator map;
+};
+
+template <typename V>
+struct node_iterator_type<const V> {
+  typedef node_seq::const_iterator seq;
+  typedef node_map::const_iterator map;
+};
+
+template <typename V>
+class node_iterator_base
+    : public std::iterator<std::forward_iterator_tag, node_iterator_value<V>,
+                           std::ptrdiff_t, node_iterator_value<V>*,
+                           node_iterator_value<V>> {
+ private:
+  struct enabler {};
+
+  struct proxy {
+    explicit proxy(const node_iterator_value<V>& x) : m_ref(x) {}
+    node_iterator_value<V>* operator->() { return std::addressof(m_ref); }
+    operator node_iterator_value<V>*() { return std::addressof(m_ref); }
+
+    node_iterator_value<V> m_ref;
+  };
+
+ public:
+  typedef typename node_iterator_type<V>::seq SeqIter;
+  typedef typename node_iterator_type<V>::map MapIter;
+  typedef node_iterator_value<V> value_type;
+
+  node_iterator_base()
+      : m_type(iterator_type::None), m_seqIt(), m_mapIt(), m_mapEnd() {}
+  explicit node_iterator_base(SeqIter seqIt)
+      : m_type(iterator_type::Sequence),
+        m_seqIt(seqIt),
+        m_mapIt(),
+        m_mapEnd() {}
+  explicit node_iterator_base(MapIter mapIt, MapIter mapEnd)
+      : m_type(iterator_type::Map),
+        m_seqIt(),
+        m_mapIt(mapIt),
+        m_mapEnd(mapEnd) {
+    m_mapIt = increment_until_defined(m_mapIt);
+  }
+
+  template <typename W>
+  node_iterator_base(const node_iterator_base<W>& rhs,
+                     typename std::enable_if<std::is_convertible<W*, V*>::value,
+                                             enabler>::type = enabler())
+      : m_type(rhs.m_type),
+        m_seqIt(rhs.m_seqIt),
+        m_mapIt(rhs.m_mapIt),
+        m_mapEnd(rhs.m_mapEnd) {}
+
+  template <typename>
+  friend class node_iterator_base;
+
+  template <typename W>
+  bool operator==(const node_iterator_base<W>& rhs) const {
+    if (m_type != rhs.m_type)
+      return false;
+
+    switch (m_type) {
+      case iterator_type::None:
+        return true;
+      case iterator_type::Sequence:
+        return m_seqIt == rhs.m_seqIt;
+      case iterator_type::Map:
+        return m_mapIt == rhs.m_mapIt;
+    }
+    return true;
+  }
+
+  template <typename W>
+  bool operator!=(const node_iterator_base<W>& rhs) const {
+    return !(*this == rhs);
+  }
+
+  node_iterator_base<V>& operator++() {
+    switch (m_type) {
+      case iterator_type::None:
+        break;
+      case iterator_type::Sequence:
+        ++m_seqIt;
+        break;
+      case iterator_type::Map:
+        ++m_mapIt;
+        m_mapIt = increment_until_defined(m_mapIt);
+        break;
+    }
+    return *this;
+  }
+
+  node_iterator_base<V> operator++(int) {
+    node_iterator_base<V> iterator_pre(*this);
+    ++(*this);
+    return iterator_pre;
+  }
+
+  value_type operator*() const {
+    switch (m_type) {
+      case iterator_type::None:
+        return value_type();
+      case iterator_type::Sequence:
+        return value_type(**m_seqIt);
+      case iterator_type::Map:
+        return value_type(*m_mapIt->first, *m_mapIt->second);
+    }
+    return value_type();
+  }
+
+  proxy operator->() const { return proxy(**this); }
+
+  MapIter increment_until_defined(MapIter it) {
+    while (it != m_mapEnd && !is_defined(it))
+      ++it;
+    return it;
+  }
+
+  bool is_defined(MapIter it) const {
+    return it->first->is_defined() && it->second->is_defined();
+  }
+
+ private:
+  typename iterator_type::value m_type;
+
+  SeqIter m_seqIt;
+  MapIter m_mapIt, m_mapEnd;
+};
+
+typedef node_iterator_base<node> node_iterator;
+typedef node_iterator_base<const node> const_node_iterator;
+}
+}
+
+#endif  // VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 98 - 0
Source/Common/Yaml/yaml-cpp/node/detail/node_ref.h

@@ -0,0 +1,98 @@
+#ifndef VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/type.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/detail/node_data.h"
+
+namespace YAML {
+namespace detail {
+class node_ref {
+ public:
+  node_ref() : m_pData(new node_data) {}
+  node_ref(const node_ref&) = delete;
+  node_ref& operator=(const node_ref&) = delete;
+
+  bool is_defined() const { return m_pData->is_defined(); }
+  const Mark& mark() const { return m_pData->mark(); }
+  NodeType::value type() const { return m_pData->type(); }
+  const std::string& scalar() const { return m_pData->scalar(); }
+  const std::string& tag() const { return m_pData->tag(); }
+  EmitterStyle::value style() const { return m_pData->style(); }
+
+  void mark_defined() { m_pData->mark_defined(); }
+  void set_data(const node_ref& rhs) { m_pData = rhs.m_pData; }
+
+  void set_mark(const Mark& mark) { m_pData->set_mark(mark); }
+  void set_type(NodeType::value type) { m_pData->set_type(type); }
+  void set_tag(const std::string& tag) { m_pData->set_tag(tag); }
+  void set_null() { m_pData->set_null(); }
+  void set_scalar(const std::string& scalar) { m_pData->set_scalar(scalar); }
+  void set_style(EmitterStyle::value style) { m_pData->set_style(style); }
+
+  // size/iterator
+  std::size_t size() const { return m_pData->size(); }
+
+  const_node_iterator begin() const {
+    return static_cast<const node_data&>(*m_pData).begin();
+  }
+  node_iterator begin() { return m_pData->begin(); }
+
+  const_node_iterator end() const {
+    return static_cast<const node_data&>(*m_pData).end();
+  }
+  node_iterator end() { return m_pData->end(); }
+
+  // sequence
+  void push_back(node& node, shared_memory_holder pMemory) {
+    m_pData->push_back(node, pMemory);
+  }
+  void insert(node& key, node& value, shared_memory_holder pMemory) {
+    m_pData->insert(key, value, pMemory);
+  }
+
+  // indexing
+  template <typename Key>
+  node* get(const Key& key, shared_memory_holder pMemory) const {
+    return static_cast<const node_data&>(*m_pData).get(key, pMemory);
+  }
+  template <typename Key>
+  node& get(const Key& key, shared_memory_holder pMemory) {
+    return m_pData->get(key, pMemory);
+  }
+  template <typename Key>
+  bool remove(const Key& key, shared_memory_holder pMemory) {
+    return m_pData->remove(key, pMemory);
+  }
+
+  node* get(node& key, shared_memory_holder pMemory) const {
+    return static_cast<const node_data&>(*m_pData).get(key, pMemory);
+  }
+  node& get(node& key, shared_memory_holder pMemory) {
+    return m_pData->get(key, pMemory);
+  }
+  bool remove(node& key, shared_memory_holder pMemory) {
+    return m_pData->remove(key, pMemory);
+  }
+
+  // map
+  template <typename Key, typename Value>
+  void force_insert(const Key& key, const Value& value,
+                    shared_memory_holder pMemory) {
+    m_pData->force_insert(key, value, pMemory);
+  }
+
+ private:
+  shared_node_data m_pData;
+};
+}
+}
+
+#endif  // VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 32 - 0
Source/Common/Yaml/yaml-cpp/node/emit.h

@@ -0,0 +1,32 @@
+#ifndef NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <string>
+#include <iosfwd>
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+class Emitter;
+class Node;
+
+/**
+ * Emits the node to the given {@link Emitter}. If there is an error in writing,
+ * {@link Emitter#good} will return false.
+ */
+YAML_CPP_API Emitter& operator<<(Emitter& out, const Node& node);
+
+/** Emits the node to the given output stream. */
+YAML_CPP_API std::ostream& operator<<(std::ostream& out, const Node& node);
+
+/** Converts the node to a YAML string. */
+YAML_CPP_API std::string Dump(const Node& node);
+}  // namespace YAML
+
+#endif  // NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 448 - 0
Source/Common/Yaml/yaml-cpp/node/impl.h

@@ -0,0 +1,448 @@
+#ifndef NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/node/node.h"
+#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/node/detail/memory.h"
+#include "yaml-cpp/node/detail/node.h"
+#include "yaml-cpp/exceptions.h"
+#include <string>
+
+namespace YAML {
+inline Node::Node() : m_isValid(true), m_pNode(NULL) {}
+
+inline Node::Node(NodeType::value type)
+    : m_isValid(true),
+      m_pMemory(new detail::memory_holder),
+      m_pNode(&m_pMemory->create_node()) {
+  m_pNode->set_type(type);
+}
+
+template <typename T>
+inline Node::Node(const T& rhs)
+    : m_isValid(true),
+      m_pMemory(new detail::memory_holder),
+      m_pNode(&m_pMemory->create_node()) {
+  Assign(rhs);
+}
+
+inline Node::Node(const detail::iterator_value& rhs)
+    : m_isValid(rhs.m_isValid),
+      m_pMemory(rhs.m_pMemory),
+      m_pNode(rhs.m_pNode) {}
+
+inline Node::Node(const Node& rhs)
+    : m_isValid(rhs.m_isValid),
+      m_pMemory(rhs.m_pMemory),
+      m_pNode(rhs.m_pNode) {}
+
+inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {}
+
+inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory)
+    : m_isValid(true), m_pMemory(pMemory), m_pNode(&node) {}
+
+inline Node::~Node() {}
+
+inline void Node::EnsureNodeExists() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  if (!m_pNode) {
+    m_pMemory.reset(new detail::memory_holder);
+    m_pNode = &m_pMemory->create_node();
+    m_pNode->set_null();
+  }
+}
+
+inline bool Node::IsDefined() const {
+  if (!m_isValid) {
+    return false;
+  }
+  return m_pNode ? m_pNode->is_defined() : true;
+}
+
+inline Mark Node::Mark() const {
+  if (!m_isValid) {
+    throw InvalidNode();
+  }
+  return m_pNode ? m_pNode->mark() : Mark::null_mark();
+}
+
+inline NodeType::value Node::Type() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return m_pNode ? m_pNode->type() : NodeType::Null;
+}
+
+// access
+
+// template helpers
+template <typename T, typename S>
+struct as_if {
+  explicit as_if(const Node& node_) : node(node_) {}
+  const Node& node;
+
+  T operator()(const S& fallback) const {
+    if (!node.m_pNode)
+      return fallback;
+
+    T t;
+    if (convert<T>::decode(node, t))
+      return t;
+    return fallback;
+  }
+};
+
+template <typename S>
+struct as_if<std::string, S> {
+  explicit as_if(const Node& node_) : node(node_) {}
+  const Node& node;
+
+  std::string operator()(const S& fallback) const {
+    if (node.Type() != NodeType::Scalar)
+      return fallback;
+    return node.Scalar();
+  }
+};
+
+template <typename T>
+struct as_if<T, void> {
+  explicit as_if(const Node& node_) : node(node_) {}
+  const Node& node;
+
+  T operator()() const {
+    if (!node.m_pNode)
+      throw TypedBadConversion<T>(node.Mark());
+
+    T t;
+    if (convert<T>::decode(node, t))
+      return t;
+    throw TypedBadConversion<T>(node.Mark());
+  }
+};
+
+template <>
+struct as_if<std::string, void> {
+  explicit as_if(const Node& node_) : node(node_) {}
+  const Node& node;
+
+  std::string operator()() const {
+    if (node.Type() != NodeType::Scalar)
+      throw TypedBadConversion<std::string>(node.Mark());
+    return node.Scalar();
+  }
+};
+
+// access functions
+template <typename T>
+inline T Node::as() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return as_if<T, void>(*this)();
+}
+
+template <typename T, typename S>
+inline T Node::as(const S& fallback) const {
+  if (!m_isValid)
+    return fallback;
+  return as_if<T, S>(*this)(fallback);
+}
+
+inline const std::string& Node::Scalar() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar;
+}
+
+inline const std::string& Node::Tag() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar;
+}
+
+inline void Node::SetTag(const std::string& tag) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->set_tag(tag);
+}
+
+inline EmitterStyle::value Node::Style() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return m_pNode ? m_pNode->style() : EmitterStyle::Default;
+}
+
+inline void Node::SetStyle(EmitterStyle::value style) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->set_style(style);
+}
+
+// assignment
+inline bool Node::is(const Node& rhs) const {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  if (!m_pNode || !rhs.m_pNode)
+    return false;
+  return m_pNode->is(*rhs.m_pNode);
+}
+
+template <typename T>
+inline Node& Node::operator=(const T& rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  Assign(rhs);
+  return *this;
+}
+
+inline void Node::reset(const YAML::Node& rhs) {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  m_pMemory = rhs.m_pMemory;
+  m_pNode = rhs.m_pNode;
+}
+
+template <typename T>
+inline void Node::Assign(const T& rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  AssignData(convert<T>::encode(rhs));
+}
+
+template <>
+inline void Node::Assign(const std::string& rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->set_scalar(rhs);
+}
+
+inline void Node::Assign(const char* rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->set_scalar(rhs);
+}
+
+inline void Node::Assign(char* rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->set_scalar(rhs);
+}
+
+inline Node& Node::operator=(const Node& rhs) {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  if (is(rhs))
+    return *this;
+  AssignNode(rhs);
+  return *this;
+}
+
+inline void Node::AssignData(const Node& rhs) {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  rhs.EnsureNodeExists();
+
+  m_pNode->set_data(*rhs.m_pNode);
+  m_pMemory->merge(*rhs.m_pMemory);
+}
+
+inline void Node::AssignNode(const Node& rhs) {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  rhs.EnsureNodeExists();
+
+  if (!m_pNode) {
+    m_pNode = rhs.m_pNode;
+    m_pMemory = rhs.m_pMemory;
+    return;
+  }
+
+  m_pNode->set_ref(*rhs.m_pNode);
+  m_pMemory->merge(*rhs.m_pMemory);
+  m_pNode = rhs.m_pNode;
+}
+
+// size/iterator
+inline std::size_t Node::size() const {
+  if (!m_isValid)
+    throw InvalidNode();
+  return m_pNode ? m_pNode->size() : 0;
+}
+
+inline const_iterator Node::begin() const {
+  if (!m_isValid)
+    return const_iterator();
+  return m_pNode ? const_iterator(m_pNode->begin(), m_pMemory)
+                 : const_iterator();
+}
+
+inline iterator Node::begin() {
+  if (!m_isValid)
+    return iterator();
+  return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator();
+}
+
+inline const_iterator Node::end() const {
+  if (!m_isValid)
+    return const_iterator();
+  return m_pNode ? const_iterator(m_pNode->end(), m_pMemory) : const_iterator();
+}
+
+inline iterator Node::end() {
+  if (!m_isValid)
+    return iterator();
+  return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator();
+}
+
+// sequence
+template <typename T>
+inline void Node::push_back(const T& rhs) {
+  if (!m_isValid)
+    throw InvalidNode();
+  push_back(Node(rhs));
+}
+
+inline void Node::push_back(const Node& rhs) {
+  if (!m_isValid || !rhs.m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  rhs.EnsureNodeExists();
+
+  m_pNode->push_back(*rhs.m_pNode, m_pMemory);
+  m_pMemory->merge(*rhs.m_pMemory);
+}
+
+// helpers for indexing
+namespace detail {
+template <typename T>
+struct to_value_t {
+  explicit to_value_t(const T& t_) : t(t_) {}
+  const T& t;
+  typedef const T& return_type;
+
+  const T& operator()() const { return t; }
+};
+
+template <>
+struct to_value_t<const char*> {
+  explicit to_value_t(const char* t_) : t(t_) {}
+  const char* t;
+  typedef std::string return_type;
+
+  const std::string operator()() const { return t; }
+};
+
+template <>
+struct to_value_t<char*> {
+  explicit to_value_t(char* t_) : t(t_) {}
+  const char* t;
+  typedef std::string return_type;
+
+  const std::string operator()() const { return t; }
+};
+
+template <std::size_t N>
+struct to_value_t<char[N]> {
+  explicit to_value_t(const char* t_) : t(t_) {}
+  const char* t;
+  typedef std::string return_type;
+
+  const std::string operator()() const { return t; }
+};
+
+// converts C-strings to std::strings so they can be copied
+template <typename T>
+inline typename to_value_t<T>::return_type to_value(const T& t) {
+  return to_value_t<T>(t)();
+}
+}
+
+// indexing
+template <typename Key>
+inline const Node Node::operator[](const Key& key) const {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  detail::node* value = static_cast<const detail::node&>(*m_pNode)
+                            .get(detail::to_value(key), m_pMemory);
+  if (!value) {
+    return Node(ZombieNode);
+  }
+  return Node(*value, m_pMemory);
+}
+
+template <typename Key>
+inline Node Node::operator[](const Key& key) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  detail::node& value = m_pNode->get(detail::to_value(key), m_pMemory);
+  return Node(value, m_pMemory);
+}
+
+template <typename Key>
+inline bool Node::remove(const Key& key) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  return m_pNode->remove(detail::to_value(key), m_pMemory);
+}
+
+inline const Node Node::operator[](const Node& key) const {
+  if (!m_isValid || !key.m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  key.EnsureNodeExists();
+  m_pMemory->merge(*key.m_pMemory);
+  detail::node* value =
+      static_cast<const detail::node&>(*m_pNode).get(*key.m_pNode, m_pMemory);
+  if (!value) {
+    return Node(ZombieNode);
+  }
+  return Node(*value, m_pMemory);
+}
+
+inline Node Node::operator[](const Node& key) {
+  if (!m_isValid || !key.m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  key.EnsureNodeExists();
+  m_pMemory->merge(*key.m_pMemory);
+  detail::node& value = m_pNode->get(*key.m_pNode, m_pMemory);
+  return Node(value, m_pMemory);
+}
+
+inline bool Node::remove(const Node& key) {
+  if (!m_isValid || !key.m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  key.EnsureNodeExists();
+  return m_pNode->remove(*key.m_pNode, m_pMemory);
+}
+
+// map
+template <typename Key, typename Value>
+inline void Node::force_insert(const Key& key, const Value& value) {
+  if (!m_isValid)
+    throw InvalidNode();
+  EnsureNodeExists();
+  m_pNode->force_insert(detail::to_value(key), detail::to_value(value),
+                        m_pMemory);
+}
+
+// free functions
+inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); }
+}
+
+#endif  // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 31 - 0
Source/Common/Yaml/yaml-cpp/node/iterator.h

@@ -0,0 +1,31 @@
+#ifndef VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/node.h"
+#include "yaml-cpp/node/detail/iterator_fwd.h"
+#include "yaml-cpp/node/detail/iterator.h"
+#include <list>
+#include <utility>
+#include <vector>
+
+namespace YAML {
+namespace detail {
+struct iterator_value : public Node, std::pair<Node, Node> {
+  iterator_value() {}
+  explicit iterator_value(const Node& rhs)
+      : Node(rhs),
+        std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {}
+  explicit iterator_value(const Node& key, const Node& value)
+      : Node(Node::ZombieNode), std::pair<Node, Node>(key, value) {}
+};
+}
+}
+
+#endif  // VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 145 - 0
Source/Common/Yaml/yaml-cpp/node/node.h

@@ -0,0 +1,145 @@
+#ifndef NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <stdexcept>
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/emitterstyle.h"
+#include "yaml-cpp/mark.h"
+#include "yaml-cpp/node/detail/bool_type.h"
+#include "yaml-cpp/node/detail/iterator_fwd.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/type.h"
+
+namespace YAML {
+namespace detail {
+class node;
+class node_data;
+struct iterator_value;
+}  // namespace detail
+}  // namespace YAML
+
+namespace YAML {
+class YAML_CPP_API Node {
+ public:
+  friend class NodeBuilder;
+  friend class NodeEvents;
+  friend struct detail::iterator_value;
+  friend class detail::node;
+  friend class detail::node_data;
+  template <typename>
+  friend class detail::iterator_base;
+  template <typename T, typename S>
+  friend struct as_if;
+
+  typedef YAML::iterator iterator;
+  typedef YAML::const_iterator const_iterator;
+
+  Node();
+  explicit Node(NodeType::value type);
+  template <typename T>
+  explicit Node(const T& rhs);
+  explicit Node(const detail::iterator_value& rhs);
+  Node(const Node& rhs);
+  ~Node();
+
+  YAML::Mark Mark() const;
+  NodeType::value Type() const;
+  bool IsDefined() const;
+  bool IsNull() const { return Type() == NodeType::Null; }
+  bool IsScalar() const { return Type() == NodeType::Scalar; }
+  bool IsSequence() const { return Type() == NodeType::Sequence; }
+  bool IsMap() const { return Type() == NodeType::Map; }
+
+  // bool conversions
+  YAML_CPP_OPERATOR_BOOL()
+  bool operator!() const { return !IsDefined(); }
+
+  // access
+  template <typename T>
+  T as() const;
+  template <typename T, typename S>
+  T as(const S& fallback) const;
+  const std::string& Scalar() const;
+
+  const std::string& Tag() const;
+  void SetTag(const std::string& tag);
+
+  // style
+  // WARNING: This API might change in future releases.
+  EmitterStyle::value Style() const;
+  void SetStyle(EmitterStyle::value style);
+
+  // assignment
+  bool is(const Node& rhs) const;
+  template <typename T>
+  Node& operator=(const T& rhs);
+  Node& operator=(const Node& rhs);
+  void reset(const Node& rhs = Node());
+
+  // size/iterator
+  std::size_t size() const;
+
+  const_iterator begin() const;
+  iterator begin();
+
+  const_iterator end() const;
+  iterator end();
+
+  // sequence
+  template <typename T>
+  void push_back(const T& rhs);
+  void push_back(const Node& rhs);
+
+  // indexing
+  template <typename Key>
+  const Node operator[](const Key& key) const;
+  template <typename Key>
+  Node operator[](const Key& key);
+  template <typename Key>
+  bool remove(const Key& key);
+
+  const Node operator[](const Node& key) const;
+  Node operator[](const Node& key);
+  bool remove(const Node& key);
+
+  // map
+  template <typename Key, typename Value>
+  void force_insert(const Key& key, const Value& value);
+
+ private:
+  enum Zombie { ZombieNode };
+  explicit Node(Zombie);
+  explicit Node(detail::node& node, detail::shared_memory_holder pMemory);
+
+  void EnsureNodeExists() const;
+
+  template <typename T>
+  void Assign(const T& rhs);
+  void Assign(const char* rhs);
+  void Assign(char* rhs);
+
+  void AssignData(const Node& rhs);
+  void AssignNode(const Node& rhs);
+
+ private:
+  bool m_isValid;
+  mutable detail::shared_memory_holder m_pMemory;
+  mutable detail::node* m_pNode;
+};
+
+YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
+
+YAML_CPP_API Node Clone(const Node& node);
+
+template <typename T>
+struct convert;
+}
+
+#endif  // NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 78 - 0
Source/Common/Yaml/yaml-cpp/node/parse.h

@@ -0,0 +1,78 @@
+#ifndef VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+class Node;
+
+/**
+ * Loads the input string as a single YAML document.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API Node Load(const std::string& input);
+
+/**
+ * Loads the input string as a single YAML document.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API Node Load(const char* input);
+
+/**
+ * Loads the input stream as a single YAML document.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API Node Load(std::istream& input);
+
+/**
+ * Loads the input file as a single YAML document.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ * @throws {@link BadFile} if the file cannot be loaded.
+ */
+YAML_CPP_API Node LoadFile(const std::string& filename);
+
+/**
+ * Loads the input string as a list of YAML documents.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API std::vector<Node> LoadAll(const std::string& input);
+
+/**
+ * Loads the input string as a list of YAML documents.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API std::vector<Node> LoadAll(const char* input);
+
+/**
+ * Loads the input stream as a list of YAML documents.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ */
+YAML_CPP_API std::vector<Node> LoadAll(std::istream& input);
+
+/**
+ * Loads the input file as a list of YAML documents.
+ *
+ * @throws {@link ParserException} if it is malformed.
+ * @throws {@link BadFile} if the file cannot be loaded.
+ */
+YAML_CPP_API std::vector<Node> LoadAllFromFile(const std::string& filename);
+}  // namespace YAML
+
+#endif  // VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 29 - 0
Source/Common/Yaml/yaml-cpp/node/ptr.h

@@ -0,0 +1,29 @@
+#ifndef VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include <memory>
+
+namespace YAML {
+namespace detail {
+class node;
+class node_ref;
+class node_data;
+class memory;
+class memory_holder;
+
+typedef std::shared_ptr<node> shared_node;
+typedef std::shared_ptr<node_ref> shared_node_ref;
+typedef std::shared_ptr<node_data> shared_node_data;
+typedef std::shared_ptr<memory_holder> shared_memory_holder;
+typedef std::shared_ptr<memory> shared_memory;
+}
+}
+
+#endif  // VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 16 - 0
Source/Common/Yaml/yaml-cpp/node/type.h

@@ -0,0 +1,16 @@
+#ifndef VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+namespace YAML {
+struct NodeType {
+  enum value { Undefined, Null, Scalar, Sequence, Map };
+};
+}
+
+#endif  // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 25 - 0
Source/Common/Yaml/yaml-cpp/noncopyable.h

@@ -0,0 +1,25 @@
+#ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+// this is basically boost::noncopyable
+class YAML_CPP_API noncopyable {
+ protected:
+  noncopyable() {}
+  ~noncopyable() {}
+
+ private:
+  noncopyable(const noncopyable&);
+  const noncopyable& operator=(const noncopyable&);
+};
+}
+
+#endif  // NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 26 - 0
Source/Common/Yaml/yaml-cpp/null.h

@@ -0,0 +1,26 @@
+#ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/dll.h"
+#include <string>
+
+namespace YAML {
+class Node;
+
+struct YAML_CPP_API _Null {};
+inline bool operator==(const _Null&, const _Null&) { return true; }
+inline bool operator!=(const _Null&, const _Null&) { return false; }
+
+YAML_CPP_API bool IsNull(const Node& node);  // old API only
+YAML_CPP_API bool IsNullString(const std::string& str);
+
+extern YAML_CPP_API _Null Null;
+}
+
+#endif  // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 72 - 0
Source/Common/Yaml/yaml-cpp/ostream_wrapper.h

@@ -0,0 +1,72 @@
+#ifndef OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <string>
+#include <vector>
+
+#include "yaml-cpp/dll.h"
+
+namespace YAML {
+class YAML_CPP_API ostream_wrapper {
+ public:
+  ostream_wrapper();
+  explicit ostream_wrapper(std::ostream& stream);
+  ~ostream_wrapper();
+
+  void write(const std::string& str);
+  void write(const char* str, std::size_t size);
+
+  void set_comment() { m_comment = true; }
+
+  const char* str() const {
+    if (m_pStream) {
+      return 0;
+    } else {
+      m_buffer[m_pos] = '\0';
+      return &m_buffer[0];
+    }
+  }
+
+  std::size_t row() const { return m_row; }
+  std::size_t col() const { return m_col; }
+  std::size_t pos() const { return m_pos; }
+  bool comment() const { return m_comment; }
+
+ private:
+  void update_pos(char ch);
+
+ private:
+  mutable std::vector<char> m_buffer;
+  std::ostream* const m_pStream;
+
+  std::size_t m_pos;
+  std::size_t m_row, m_col;
+  bool m_comment;
+};
+
+template <std::size_t N>
+inline ostream_wrapper& operator<<(ostream_wrapper& stream,
+                                   const char(&str)[N]) {
+  stream.write(str, N - 1);
+  return stream;
+}
+
+inline ostream_wrapper& operator<<(ostream_wrapper& stream,
+                                   const std::string& str) {
+  stream.write(str);
+  return stream;
+}
+
+inline ostream_wrapper& operator<<(ostream_wrapper& stream, char ch) {
+  stream.write(&ch, 1);
+  return stream;
+}
+}
+
+#endif  // OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 86 - 0
Source/Common/Yaml/yaml-cpp/parser.h

@@ -0,0 +1,86 @@
+#ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <ios>
+#include <memory>
+
+#include "yaml-cpp/dll.h"
+#include "yaml-cpp/noncopyable.h"
+
+namespace YAML {
+class EventHandler;
+class Node;
+class Scanner;
+struct Directives;
+struct Token;
+
+/**
+ * A parser turns a stream of bytes into one stream of "events" per YAML
+ * document in the input stream.
+ */
+class YAML_CPP_API Parser : private noncopyable {
+ public:
+  /** Constructs an empty parser (with no input. */
+  Parser();
+
+  /**
+   * Constructs a parser from the given input stream. The input stream must
+   * live as long as the parser.
+   */
+  explicit Parser(std::istream& in);
+
+  ~Parser();
+
+  /** Evaluates to true if the parser has some valid input to be read. */
+  explicit operator bool() const;
+
+  /**
+   * Resets the parser with the given input stream. Any existing state is
+   * erased.
+   */
+  void Load(std::istream& in);
+
+  /**
+   * Handles the next document by calling events on the {@code eventHandler}.
+   *
+   * @throw a ParserException on error.
+   * @return false if there are no more documents
+   */
+  bool HandleNextDocument(EventHandler& eventHandler);
+
+  void PrintTokens(std::ostream& out);
+
+ private:
+  /**
+   * Reads any directives that are next in the queue, setting the internal
+   * {@code m_pDirectives} state.
+   */
+  void ParseDirectives();
+
+  void HandleDirective(const Token& token);
+
+  /**
+   * Handles a "YAML" directive, which should be of the form 'major.minor' (like
+   * a version number).
+   */
+  void HandleYamlDirective(const Token& token);
+
+  /**
+   * Handles a "TAG" directive, which should be of the form 'handle prefix',
+   * where 'handle' is converted to 'prefix' in the file.
+   */
+  void HandleTagDirective(const Token& token);
+
+ private:
+  std::unique_ptr<Scanner> m_pScanner;
+  std::unique_ptr<Directives> m_pDirectives;
+};
+}
+
+#endif  // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 51 - 0
Source/Common/Yaml/yaml-cpp/stlemitter.h

@@ -0,0 +1,51 @@
+#ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include <vector>
+#include <list>
+#include <set>
+#include <map>
+
+namespace YAML {
+template <typename Seq>
+inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) {
+  emitter << BeginSeq;
+  for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it)
+    emitter << *it;
+  emitter << EndSeq;
+  return emitter;
+}
+
+template <typename T>
+inline Emitter& operator<<(Emitter& emitter, const std::vector<T>& v) {
+  return EmitSeq(emitter, v);
+}
+
+template <typename T>
+inline Emitter& operator<<(Emitter& emitter, const std::list<T>& v) {
+  return EmitSeq(emitter, v);
+}
+
+template <typename T>
+inline Emitter& operator<<(Emitter& emitter, const std::set<T>& v) {
+  return EmitSeq(emitter, v);
+}
+
+template <typename K, typename V>
+inline Emitter& operator<<(Emitter& emitter, const std::map<K, V>& m) {
+  typedef typename std::map<K, V> map;
+  emitter << BeginMap;
+  for (typename map::const_iterator it = m.begin(); it != m.end(); ++it)
+    emitter << Key << it->first << Value << it->second;
+  emitter << EndMap;
+  return emitter;
+}
+}
+
+#endif  // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 103 - 0
Source/Common/Yaml/yaml-cpp/traits.h

@@ -0,0 +1,103 @@
+#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+namespace YAML {
+template <typename>
+struct is_numeric {
+  enum { value = false };
+};
+
+template <>
+struct is_numeric<char> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned char> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<int> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned int> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<long int> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned long int> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<short int> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned short int> {
+  enum { value = true };
+};
+#if defined(_MSC_VER) && (_MSC_VER < 1310)
+template <>
+struct is_numeric<__int64> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned __int64> {
+  enum { value = true };
+};
+#else
+template <>
+struct is_numeric<long long> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<unsigned long long> {
+  enum { value = true };
+};
+#endif
+template <>
+struct is_numeric<float> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<double> {
+  enum { value = true };
+};
+template <>
+struct is_numeric<long double> {
+  enum { value = true };
+};
+
+template <bool, class T = void>
+struct enable_if_c {
+  typedef T type;
+};
+
+template <class T>
+struct enable_if_c<false, T> {};
+
+template <class Cond, class T = void>
+struct enable_if : public enable_if_c<Cond::value, T> {};
+
+template <bool, class T = void>
+struct disable_if_c {
+  typedef T type;
+};
+
+template <class T>
+struct disable_if_c<true, T> {};
+
+template <class Cond, class T = void>
+struct disable_if : public disable_if_c<Cond::value, T> {};
+}
+
+#endif  // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 24 - 0
Source/Common/Yaml/yaml-cpp/yaml.h

@@ -0,0 +1,24 @@
+#ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
+
+#if defined(_MSC_VER) ||                                            \
+    (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
+     (__GNUC__ >= 4))  // GCC supports "pragma once" correctly since 3.4
+#pragma once
+#endif
+
+#include "yaml-cpp/parser.h"
+#include "yaml-cpp/emitter.h"
+#include "yaml-cpp/emitterstyle.h"
+#include "yaml-cpp/stlemitter.h"
+#include "yaml-cpp/exceptions.h"
+
+#include "yaml-cpp/node/node.h"
+#include "yaml-cpp/node/impl.h"
+#include "yaml-cpp/node/convert.h"
+#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/node/detail/impl.h"
+#include "yaml-cpp/node/parse.h"
+#include "yaml-cpp/node/emit.h"
+
+#endif  // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66

BIN=BIN
Source/Common/ZLib/zlibstatic.lib


+ 0 - 1
Source/DatFile.h

@@ -59,7 +59,6 @@ namespace LOTRO_DAT
     public:
         DatFile();
         explicit DatFile(const char* filename, int dat_id);
-        explicit DatFile(const std::string &filename, int dat_id);
         ~DatFile();
 
         bool ExtractFile(long long file_id, const std::string path = "");

+ 1 - 1
Source/Database.cpp

@@ -46,7 +46,7 @@ namespace LOTRO_DAT {
 		ExecSql("PRAGMA count_changes = OFF");
 		ExecSql("PRAGMA journal_mode = MEMORY");
 		ExecSql("PRAGMA temp_store = MEMORY");
-		//ExecSql("PRAGMA encoding = \"UTF-8\";");
+		ExecSql("PRAGMA encoding = \"UTF-8\";");
 
         ExecSql(CreateBinaryTableCommand_);
         ExecSql(CreateTextTableCommand_);

+ 7 - 12
Source/Subfile.cpp

@@ -69,19 +69,14 @@ namespace LOTRO_DAT {
         throw DatException("Bad Subfile::Extension() - function is not implemented for this type.", SUBFILE_EXCEPTION);
     }
 
-    bool Subfile::PrepareAsBinary(BinaryData &data) {
-        throw DatException("Bad Subfile::PrepareAsBinary() - function is not implemented for this type.", EXPORT_EXCEPTION);
+    bool Subfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                        std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        throw DatException("Bad Subfile::PrepareForExport() - function is not implemented for this type.", EXPORT_EXCEPTION);
     }
 
-    bool Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-        throw DatException("Bad Subfile::PrepareAsText() - function is not implemented for this type.", EXPORT_EXCEPTION);
+    BinaryData Subfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                           const YAML::Node &options) {
+        throw DatException("Bad Subfile::MakeForImport() - function is not implemented for this type.", IMPORT_EXCEPTION);
     }
 
-    BinaryData Subfile::MakeFromBinary(const BinaryData &data) {
-        throw DatException("Bad Subfile::MakeFromBinary() - function is not implemented fot this type.", EXPORT_EXCEPTION);
-    }
-
-    BinaryData Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-        throw DatException("Bad Subfile::MakeFromText() - function is not implemented for this type.", EXPORT_EXCEPTION);
-    }
-};
+ };

+ 8 - 4
Source/Subfile.h

@@ -4,7 +4,11 @@
 
 #ifndef LOTRO_DAT_PATCHER_SUBFILE_H
 #define LOTRO_DAT_PATCHER_SUBFILE_H
+
 #include <string>
+#include <vector>
+#include "yaml-cpp/yaml.h"
+#include "BinaryData.h"
 
 extern "C++"
 {
@@ -25,11 +29,11 @@ namespace LOTRO_DAT
         virtual FILE_TYPE FileType() const;
         virtual std::string Extension() const;
 
-        virtual bool PrepareAsBinary(BinaryData &data);
-        virtual bool PrepareAsText(std::string &text, std::string &args, std::string &args_order);
+        virtual bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                             std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options);
 
-        virtual BinaryData MakeFromBinary(const BinaryData &data);
-        virtual BinaryData MakeFromText(const std::string &text, const std::string &args, const std::string &args_order);
+        virtual BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                const std::u16string &text_data, const YAML::Node &options);
 
         long long fragments_count() const;
         long long unknown1() const;

+ 21 - 11
Source/Subfiles/DdsSubfile.cpp

@@ -7,11 +7,6 @@
 #include "../BinaryData.h"
 #include "../DatFile.h"
 #include "../Common/DatException.h"
-#include "../Database.h"
-#include "../Common/CommonFunctions.h"
-
-#include <algorithm>
-
 
 namespace LOTRO_DAT {
     DdsSubfile::DdsSubfile() {}
@@ -34,7 +29,9 @@ namespace LOTRO_DAT {
         return ".dds";
     }
 
-    bool DdsSubfile::PrepareAsBinary(BinaryData &data) {
+    bool DdsSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        BinaryData data = file_data;
         if (compressed_)
             data = data.DecompressData(4);
 
@@ -140,13 +137,26 @@ namespace LOTRO_DAT {
             default:
                 throw DatException("Bad DdsSubfile::PrepareAsBinary() - unknown header format.", EXPORT_EXCEPTION);
         }
-        data = ddsData;
-        return true;
-    }
 
+        export_size = 1;
+        binary_data.emplace_back(ddsData);
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
 
-    BinaryData DdsSubfile::MakeFromBinary(const BinaryData &data) {
-        return data.CutData(128).CompressData();
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
+        return true;
     }
 
+    BinaryData DdsSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                              const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
+        }
+        if (compressed_)
+            return old_data.CutData(0, 12) + (old_data.CutData(12, 16) + binary_data.CutData(128)).CompressData();
+        else
+            return old_data.CutData(0, 16) + binary_data.CutData(128);
+    }
 };

+ 5 - 2
Source/Subfiles/DdsSubfile.h

@@ -17,8 +17,11 @@ namespace LOTRO_DAT {
         FILE_TYPE FileType() const override;
         std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        BinaryData MakeFromBinary(const BinaryData &data) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
+
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
 
     private:
         bool compressed_;

+ 30 - 541
Source/Subfiles/FontSubfile.cpp

@@ -1,558 +1,47 @@
-/*
 //
 // Created by Иван_Архипов on 24.11.2017.
 //
 
-#include "FontSubFile.h"
+#include "FontSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
 
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "Common/DatException.h"
-#include "Database.h"
-#include "Common/CommonFunctions.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-// will be recognized as incorrect and passed.
-// This should be done because
-
-LOTRO_DAT::Subfile::Subfile() {
-    ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-    ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
-
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
+namespace LOTRO_DAT {
+    FontSubfile::FontSubfile() {}
 
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
-    // Text check based on file_id
-    if ((file_id_ >> 24ll) == 0x25ll)
-        return TEXT;
-
-    // Font check based on file_id
-    if ((file_id_ >> 24ll) == 0x42ll)
-        return FONT;
-
-    BinaryData header(64);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
-    }
-
-    // jpeg / dds check
-    if ((file_id_ >> 24ll) == 0x41ll) {
-        long long soi = header.ToNumber<2>(24);
-        long long marker = header.ToNumber<2>(26);
-
-        //auto markerSize = header.ToNumber<short>(28);
-        //auto four = header.ToNumber<int>(30);
-
-        if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
-            return JPG;
-        return DDS;
+    FontSubfile::FontSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp,
+                           long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
     }
 
-    // Ogg and Wav check
-    if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
-        return OGG;
-    if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
-        return WAV;
-
-    return UNKNOWN;
-}
-
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-    switch (ext)
-    {
-        case LOTRO_DAT::TEXT:
-            return ".txt";
-        case LOTRO_DAT::JPG:
-            return ".jpg";
-        case LOTRO_DAT::DDS:
-            return ".dds";
-        case LOTRO_DAT::WAV:
-            return ".wav";
-        case LOTRO_DAT::OGG:
-            return ".ogg";
-        case LOTRO_DAT::FONT:
-            return ".fontbin";
-        case LOTRO_DAT::UNKNOWN:
-            return ".unk";
-        default:
-            return "";
+    FILE_TYPE FontSubfile::FileType() const {
+        return FONT;
     }
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
 
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
+    std::string FontSubfile::Extension() const {
+        return ".fontbin";
     }
 
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
+    bool FontSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                       std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 1;
+        binary_data.emplace_back(file_data);
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
         return true;
     }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-            , IMPORT_EXCEPTION);
-    return true;
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-    try {
-        BinaryData data;
 
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return false;
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
+    BinaryData FontSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                               const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        db->PushBinaryFile(file_id_, data);
-        return true;
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
-    }
-
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
-
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-    long long text_fragment_num = data.ToNumber<1>(offset);
-    if ((text_fragment_num & 0x80) != 0) {
-        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-        offset += 1;
+        return old_data.CutData(0, 16) + binary_data;
     }
-    offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-
-            BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
-            std::u16string piece;
-
-            for (long long k = 0; k < piece_size; k++) {
-                char16_t c = char16_t(((short(piece_data[2 * k + 1])) << 8) | (short(piece_data[2 * k])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_references; j++) {
-            arg_references.emplace_back(data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            arg_strings.emplace_back();
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
-
-                arg_strings[j].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
-        }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
-    }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
-
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
-    }
-
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + block_size() - 8 * fragments_number);
-
-
-    for (long long i = 0; i < fragments_number; i++) {
-        long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-        long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
-    }
-
-    return data;
-}
-
-LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
-    return nullptr;
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-    return false;
-}
-
-LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
-    return <#initializer#>;
-}
-
-LOTRO_DAT::BinaryData &
-LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-    return <#initializer#>;
-}
-
-*/
-/*
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        data.DecompressData(4);
-
-    BinaryData ddsData(data.size() - 24 + 128);
-    for (int i = 0; i < 128; i++)
-        ddsData[i] = 0;
-
-    memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-    ddsData[0] = 0x44; // D
-    ddsData[1] = 0x44; // D
-    ddsData[2] = 0x53; // S
-    ddsData[3] = 0x20;
-    ddsData[4] = 0x7C;
-
-    ddsData[8] = 7;
-    ddsData[9] = 0x10;
-
-    // width, height
-    ddsData[12] = data[12];
-    ddsData[13] = data[13];
-    ddsData[14] = data[14];
-    ddsData[15] = data[15];
-
-    ddsData[16] = data[8];
-    ddsData[17] = data[9];
-    ddsData[18] = data[10];
-    ddsData[19] = data[11];
-
-    long long compression = data.ToNumber<4>(0x10);
-
-    switch (compression) {
-        case 20:        // 14 00 00 00 - 888 (R8G8B8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x18;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x20;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            ddsData[0x6B] = 0xFF;
-            break;
-        case 28:        // 1C 00 00 00 - 332 (?)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x08;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 827611204: // 44 58 54 31 - DXT1
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 49;
-            break;
-        case 861165636: // 44 58 54 33 - DXT3
-            ddsData[22] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 51;
-
-            ddsData[108] = 8;
-            ddsData[109] = 16;
-            ddsData[110] = 64;
-            break;
-        case 894720068: // 44 58 54 35 - DXT5
-            ddsData[10] = 8;
-            ddsData[22] = 1;
-            ddsData[28] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 53;
-
-            ddsData[88] = 32;
-            ddsData[94] = 255;
-            ddsData[97] = 255;
-            ddsData[100] = 255;
-            ddsData[107] = 255;
-            ddsData[109] = 16;
-            break;
-    }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
-*/
+};

+ 7 - 7
Source/Subfiles/FontSubfile.h

@@ -12,16 +12,16 @@ namespace LOTRO_DAT {
     class FontSubfile : Subfile {
         FontSubfile();
         FontSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                   long long file_size, long long timestamp, long long version, long long block_size) override;
+                   long long file_size, long long timestamp, long long version, long long block_size);
 
-        virtual FILE_TYPE FileType() const override;
-        virtual std::string GetExtension() const override;
+        FILE_TYPE FileType() const override;
+        std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                         const std::u16string &text_data, const YAML::Node &options) override;
 
     };
 };

+ 29 - 541
Source/Subfiles/JpgSubfile.cpp

@@ -1,558 +1,46 @@
-/*
 //
 // Created by Иван_Архипов on 24.11.2017.
 //
 
 #include "JpgSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
 
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "Common/DatException.h"
-#include "Database.h"
-#include "Common/CommonFunctions.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-// will be recognized as incorrect and passed.
-// This should be done because
-
-LOTRO_DAT::Subfile::Subfile() {
-    ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-    ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
-
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
-
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
-    // Text check based on file_id
-    if ((file_id_ >> 24ll) == 0x25ll)
-        return TEXT;
-
-    // Font check based on file_id
-    if ((file_id_ >> 24ll) == 0x42ll)
-        return FONT;
-
-    BinaryData header(64);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
-    }
-
-    // jpeg / dds check
-    if ((file_id_ >> 24ll) == 0x41ll) {
-        long long soi = header.ToNumber<2>(24);
-        long long marker = header.ToNumber<2>(26);
-
-        //auto markerSize = header.ToNumber<short>(28);
-        //auto four = header.ToNumber<int>(30);
-
-        if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
-            return JPG;
-        return DDS;
-    }
-
-    // Ogg and Wav check
-    if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
-        return OGG;
-    if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
-        return WAV;
-
-    return UNKNOWN;
-}
+namespace LOTRO_DAT {
+    JpgSubfile::JpgSubfile() {}
 
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-    switch (ext)
-    {
-        case LOTRO_DAT::TEXT:
-            return ".txt";
-        case LOTRO_DAT::JPG:
-            return ".jpg";
-        case LOTRO_DAT::DDS:
-            return ".dds";
-        case LOTRO_DAT::WAV:
-            return ".wav";
-        case LOTRO_DAT::OGG:
-            return ".ogg";
-        case LOTRO_DAT::FONT:
-            return ".fontbin";
-        case LOTRO_DAT::UNKNOWN:
-            return ".unk";
-        default:
-            return "";
+    JpgSubfile::JpgSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                             long long file_id, long long file_offset, long long file_size,
+                             long long timestamp,
+                             long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
     }
-}
 
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
-
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
-    }
-
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
-        return true;
-    }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-            , IMPORT_EXCEPTION);
-    return true;
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-    try {
-        BinaryData data;
-
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return false;
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        db->PushBinaryFile(file_id_, data);
-        return true;
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
+    FILE_TYPE JpgSubfile::FileType() const {
+        return FONT;
     }
-}
 
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
+    std::string JpgSubfile::Extension() const {
+        return ".fontbin";
     }
 
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
-
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-    long long text_fragment_num = data.ToNumber<1>(offset);
-    if ((text_fragment_num & 0x80) != 0) {
-        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-        offset += 1;
+    bool JpgSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 1;
+        binary_data.emplace_back(file_data.CutData(24));
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
     }
-    offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-
-            BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
-            std::u16string piece;
-
-            for (long long k = 0; k < piece_size; k++) {
-                char16_t c = char16_t(((short(piece_data[2 * k + 1])) << 8) | (short(piece_data[2 * k])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_references; j++) {
-            arg_references.emplace_back(data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            arg_strings.emplace_back();
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
 
-                arg_strings[j].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
+    BinaryData JpgSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                              const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
-    }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
-
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
-    }
-
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + block_size() - 8 * fragments_number);
-
-
-    for (long long i = 0; i < fragments_number; i++) {
-        long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-        long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
-    }
-
-    return data;
-}
-
-LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
-    return nullptr;
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-    return false;
-}
-
-LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
-    return <#initializer#>;
-}
-
-LOTRO_DAT::BinaryData &
-LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-    return <#initializer#>;
-}
-
-*/
-/*
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        data.DecompressData(4);
-
-    BinaryData ddsData(data.size() - 24 + 128);
-    for (int i = 0; i < 128; i++)
-        ddsData[i] = 0;
-
-    memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-    ddsData[0] = 0x44; // D
-    ddsData[1] = 0x44; // D
-    ddsData[2] = 0x53; // S
-    ddsData[3] = 0x20;
-    ddsData[4] = 0x7C;
-
-    ddsData[8] = 7;
-    ddsData[9] = 0x10;
-
-    // width, height
-    ddsData[12] = data[12];
-    ddsData[13] = data[13];
-    ddsData[14] = data[14];
-    ddsData[15] = data[15];
-
-    ddsData[16] = data[8];
-    ddsData[17] = data[9];
-    ddsData[18] = data[10];
-    ddsData[19] = data[11];
-
-    long long compression = data.ToNumber<4>(0x10);
-
-    switch (compression) {
-        case 20:        // 14 00 00 00 - 888 (R8G8B8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x18;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x20;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            ddsData[0x6B] = 0xFF;
-            break;
-        case 28:        // 1C 00 00 00 - 332 (?)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x08;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 827611204: // 44 58 54 31 - DXT1
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 49;
-            break;
-        case 861165636: // 44 58 54 33 - DXT3
-            ddsData[22] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 51;
-
-            ddsData[108] = 8;
-            ddsData[109] = 16;
-            ddsData[110] = 64;
-            break;
-        case 894720068: // 44 58 54 35 - DXT5
-            ddsData[10] = 8;
-            ddsData[22] = 1;
-            ddsData[28] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 53;
-
-            ddsData[88] = 32;
-            ddsData[94] = 255;
-            ddsData[97] = 255;
-            ddsData[100] = 255;
-            ddsData[107] = 255;
-            ddsData[109] = 16;
-            break;
+        return old_data.CutData(0, 40) + binary_data;
     }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
- */
+};

+ 6 - 7
Source/Subfiles/JpgSubfile.h

@@ -12,17 +12,16 @@ namespace LOTRO_DAT {
     class JpgSubfile : Subfile {
         JpgSubfile();
         JpgSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                   long long file_size, long long timestamp, long long version, long long block_size) override;
+                   long long file_size, long long timestamp, long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
-        std::string GetExtension() const override;
+        std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
-
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
     };
 };
 

+ 28 - 539
Source/Subfiles/OggSubfile.cpp

@@ -1,558 +1,47 @@
-/*
 //
 // Created by Иван_Архипов on 24.11.2017.
 //
 
 #include "OggSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
 
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "Common/DatException.h"
-#include "Database.h"
-#include "Common/CommonFunctions.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-// will be recognized as incorrect and passed.
-// This should be done because
-
-LOTRO_DAT::Subfile::Subfile() {
-    ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-    ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
+namespace LOTRO_DAT {
+    OggSubfile::OggSubfile() {}
 
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
-
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
-    // Text check based on file_id
-    if ((file_id_ >> 24ll) == 0x25ll)
-        return TEXT;
-
-    // Font check based on file_id
-    if ((file_id_ >> 24ll) == 0x42ll)
-        return FONT;
-
-    BinaryData header(64);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
-    }
-
-    // jpeg / dds check
-    if ((file_id_ >> 24ll) == 0x41ll) {
-        long long soi = header.ToNumber<2>(24);
-        long long marker = header.ToNumber<2>(26);
-
-        //auto markerSize = header.ToNumber<short>(28);
-        //auto four = header.ToNumber<int>(30);
-
-        if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
-            return JPG;
-        return DDS;
+    OggSubfile::OggSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp,
+                           long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
     }
 
-    // Ogg and Wav check
-    if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
+    FILE_TYPE OggSubfile::FileType() const {
         return OGG;
-    if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
-        return WAV;
-
-    return UNKNOWN;
-}
-
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-    switch (ext)
-    {
-        case LOTRO_DAT::TEXT:
-            return ".txt";
-        case LOTRO_DAT::JPG:
-            return ".jpg";
-        case LOTRO_DAT::DDS:
-            return ".dds";
-        case LOTRO_DAT::WAV:
-            return ".wav";
-        case LOTRO_DAT::OGG:
-            return ".ogg";
-        case LOTRO_DAT::FONT:
-            return ".fontbin";
-        case LOTRO_DAT::UNKNOWN:
-            return ".unk";
-        default:
-            return "";
     }
-}
 
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
-
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
+    std::string OggSubfile::Extension() const {
+        return ".ogg";
     }
 
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
+    bool OggSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 1;
+        binary_data.emplace_back(file_data.CutData(8));
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
         return true;
     }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-            , IMPORT_EXCEPTION);
-    return true;
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-    try {
-        BinaryData data;
-
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return false;
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
 
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
+    BinaryData OggSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                              const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-
-        db->PushBinaryFile(file_id_, data);
-        return true;
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
-    }
-
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
-
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-    long long text_fragment_num = data.ToNumber<1>(offset);
-    if ((text_fragment_num & 0x80) != 0) {
-        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-        offset += 1;
+        return old_data.CutData(0, 24) + binary_data;
     }
-    offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-
-            BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
-            std::u16string piece;
-
-            for (long long k = 0; k < piece_size; k++) {
-                char16_t c = char16_t(((short(piece_data[2 * k + 1])) << 8) | (short(piece_data[2 * k])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_references; j++) {
-            arg_references.emplace_back(data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            arg_strings.emplace_back();
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
-
-                arg_strings[j].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
-        }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
-    }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
-
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
-    }
-
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + block_size() - 8 * fragments_number);
-
-
-    for (long long i = 0; i < fragments_number; i++) {
-        long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-        long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
-    }
-
-    return data;
-}
-
-LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
-    return nullptr;
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-    return false;
-}
-
-LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
-    return <#initializer#>;
-}
-
-LOTRO_DAT::BinaryData &
-LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-    return <#initializer#>;
-}
-
-*/
-/*
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        data.DecompressData(4);
-
-    BinaryData ddsData(data.size() - 24 + 128);
-    for (int i = 0; i < 128; i++)
-        ddsData[i] = 0;
-
-    memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-    ddsData[0] = 0x44; // D
-    ddsData[1] = 0x44; // D
-    ddsData[2] = 0x53; // S
-    ddsData[3] = 0x20;
-    ddsData[4] = 0x7C;
-
-    ddsData[8] = 7;
-    ddsData[9] = 0x10;
-
-    // width, height
-    ddsData[12] = data[12];
-    ddsData[13] = data[13];
-    ddsData[14] = data[14];
-    ddsData[15] = data[15];
-
-    ddsData[16] = data[8];
-    ddsData[17] = data[9];
-    ddsData[18] = data[10];
-    ddsData[19] = data[11];
-
-    long long compression = data.ToNumber<4>(0x10);
-
-    switch (compression) {
-        case 20:        // 14 00 00 00 - 888 (R8G8B8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x18;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x20;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            ddsData[0x6B] = 0xFF;
-            break;
-        case 28:        // 1C 00 00 00 - 332 (?)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x08;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 827611204: // 44 58 54 31 - DXT1
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 49;
-            break;
-        case 861165636: // 44 58 54 33 - DXT3
-            ddsData[22] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 51;
-
-            ddsData[108] = 8;
-            ddsData[109] = 16;
-            ddsData[110] = 64;
-            break;
-        case 894720068: // 44 58 54 35 - DXT5
-            ddsData[10] = 8;
-            ddsData[22] = 1;
-            ddsData[28] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 53;
-
-            ddsData[88] = 32;
-            ddsData[94] = 255;
-            ddsData[97] = 255;
-            ddsData[100] = 255;
-            ddsData[107] = 255;
-            ddsData[109] = 16;
-            break;
-    }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
- */
+};

+ 5 - 5
Source/Subfiles/OggSubfile.h

@@ -14,13 +14,13 @@ namespace LOTRO_DAT {
                    long long file_size, long long timestamp, long long version, long long block_size) override;
 
         FILE_TYPE FileType() const override;
-        std::string GetExtension() const override;
+        std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
     };
 };
 

+ 68 - 479
Source/Subfiles/TextSubfile.cpp

@@ -1,273 +1,88 @@
-/*
 //
 // Created by Иван_Архипов on 24.11.2017.
 //
 
 #include "TextSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
+
+namespace LOTRO_DAT {
+    TextSubfile::TextSubfile() = default;
+
+    TextSubfile::TextSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp,
+                           long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+    }
 
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "Common/DatException.h"
-#include "Database.h"
-#include "Common/CommonFunctions.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-// will be recognized as incorrect and passed.
-// This should be done because
-
-LOTRO_DAT::Subfile::Subfile() {
-    ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-    ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
-
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
-
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
-    // Text check based on file_id
-    if ((file_id_ >> 24ll) == 0x25ll)
+    FILE_TYPE TextSubfile::FileType() const {
         return TEXT;
-
-    // Font check based on file_id
-    if ((file_id_ >> 24ll) == 0x42ll)
-        return FONT;
-
-    BinaryData header(64);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
     }
 
-    // jpeg / dds check
-    if ((file_id_ >> 24ll) == 0x41ll) {
-        long long soi = header.ToNumber<2>(24);
-        long long marker = header.ToNumber<2>(26);
-
-        //auto markerSize = header.ToNumber<short>(28);
-        //auto four = header.ToNumber<int>(30);
-
-        if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
-            return JPG;
-        return DDS;
-    }
+    bool TextSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                       std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 0;
+        binary_data.clear();
+        text_data.clear();
+        options.clear();
 
-    // Ogg and Wav check
-    if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
-        return OGG;
-    if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
-        return WAV;
+        if (file_size() <= 10) // File is empty, nothing to do;
+            return false;
 
-    return UNKNOWN;
-}
+        long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
 
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-    switch (ext)
-    {
-        case LOTRO_DAT::TEXT:
-            return ".txt";
-        case LOTRO_DAT::JPG:
-            return ".jpg";
-        case LOTRO_DAT::DDS:
-            return ".dds";
-        case LOTRO_DAT::WAV:
-            return ".wav";
-        case LOTRO_DAT::OGG:
-            return ".ogg";
-        case LOTRO_DAT::FONT:
-            return ".fontbin";
-        case LOTRO_DAT::UNKNOWN:
-            return ".unk";
-        default:
-            return "";
-    }
-}
+        long long text_fragment_num = file_data.ToNumber<1>(offset);
+        if ((text_fragment_num & 0x80) != 0) {
+            text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | file_data.ToNumber<1>(offset + 1));
+            offset += 1;
+        }
+        offset += 1;
 
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
+        for (long long i = 0; i < text_fragment_num; i++) {
+            long long fragment_id = file_data.ToNumber<8>(offset);
+            offset += 8;
 
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
-    }
+            std::vector<std::u16string> text_pieces = MakePieces(file_data, offset);
+            std::vector<long long> arg_references = MakeArgumentReferences(file_data, offset);
+            std::vector<std::vector<BinaryData>> arg_strings = MakeArgumentStrings(file_data, offset);
 
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
-        return true;
-    }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-            , IMPORT_EXCEPTION);
-    return true;
-}
+            std::u16string text = u"[";
+            for (int j = 0; j + 1 < text_pieces.size(); j++)
+                text += text_pieces[j] + u"<--DO_NOT_TOUCH!-->";
+            text += text_pieces[text_pieces.size() - 1] + u"]";
 
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-    try {
-        BinaryData data;
+            std::string arguments;
+            for (int j = 0; j + 1 < arg_references.size(); j++)
+                arguments += std::to_string(arg_references[j]) + "-";
+            if (!arg_references.empty())
+                arguments += std::to_string(arg_references[arg_references.size() - 1]);
 
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return false;
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
+            binary_data.emplace_back(BinaryData());
+            text_data.emplace_back(text);
+            options.emplace_back(YAML::Node());
 
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
+            options[export_size]["file_id"] = file_id();
+            options[export_size]["gossip_id"] = fragment_id;
+            options[export_size]["extension"] = Extension();
+            options[export_size]["arguments"] = arguments;
 
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
+            ++export_size;
         }
-
-        db->PushBinaryFile(file_id_, data);
         return true;
     }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
-    }
-
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
 
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-    long long text_fragment_num = data.ToNumber<1>(offset);
-    if ((text_fragment_num & 0x80) != 0) {
-        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-        offset += 1;
+    BinaryData TextSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                               const YAML::Node &options) {
+        return Subfile::MakeForImport(old_data, binary_data, text_data, options);
     }
-    offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
 
+    std::vector<std::u16string> TextSubfile::MakePieces(const BinaryData &data, long long &offset) {
         long long num_pieces = data.ToNumber<4>(offset);
         offset += 4;
 
         std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
 
         for (long long j = 0; j < num_pieces; j++) {
             long long piece_size = data.ToNumber<1>(offset);
@@ -288,6 +103,11 @@ bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
             text_pieces.push_back(piece);
             offset += piece_size * 2;
         }
+        return text_pieces;
+    }
+
+    std::vector<long long> TextSubfile::MakeArgumentReferences(const BinaryData &data, long long &offset) {
+        std::vector<long long> arg_references;
 
         long long num_references = data.ToNumber<4>(offset);
         offset += 4;
@@ -297,6 +117,11 @@ bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
             offset += 4;
         }
 
+        return arg_references;
+    }
+
+    std::vector<std::vector<BinaryData>> TextSubfile::MakeArgumentStrings(const BinaryData &data, long long &offset) {
+        std::vector<std::vector<BinaryData> > arg_strings;
         long long num_arg_strings = data.ToNumber<1>(offset);
         offset += 1;
 
@@ -317,242 +142,6 @@ bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
                 offset += string_size * 2;
             }
         }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
-    }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
-
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
-    }
-
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + block_size() - 8 * fragments_number);
-
-
-    for (long long i = 0; i < fragments_number; i++) {
-        long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-        long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
+        return arg_strings;
     }
-
-    return data;
-}
-
-LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
-    return nullptr;
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-    return false;
-}
-
-LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
-    return <#initializer#>;
-}
-
-LOTRO_DAT::BinaryData &
-LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-    return <#initializer#>;
-}
-
-*/
-/*
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        data.DecompressData(4);
-
-    BinaryData ddsData(data.size() - 24 + 128);
-    for (int i = 0; i < 128; i++)
-        ddsData[i] = 0;
-
-    memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-    ddsData[0] = 0x44; // D
-    ddsData[1] = 0x44; // D
-    ddsData[2] = 0x53; // S
-    ddsData[3] = 0x20;
-    ddsData[4] = 0x7C;
-
-    ddsData[8] = 7;
-    ddsData[9] = 0x10;
-
-    // width, height
-    ddsData[12] = data[12];
-    ddsData[13] = data[13];
-    ddsData[14] = data[14];
-    ddsData[15] = data[15];
-
-    ddsData[16] = data[8];
-    ddsData[17] = data[9];
-    ddsData[18] = data[10];
-    ddsData[19] = data[11];
-
-    long long compression = data.ToNumber<4>(0x10);
-
-    switch (compression) {
-        case 20:        // 14 00 00 00 - 888 (R8G8B8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x18;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x20;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            ddsData[0x6B] = 0xFF;
-            break;
-        case 28:        // 1C 00 00 00 - 332 (?)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x08;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 827611204: // 44 58 54 31 - DXT1
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 49;
-            break;
-        case 861165636: // 44 58 54 33 - DXT3
-            ddsData[22] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 51;
-
-            ddsData[108] = 8;
-            ddsData[109] = 16;
-            ddsData[110] = 64;
-            break;
-        case 894720068: // 44 58 54 35 - DXT5
-            ddsData[10] = 8;
-            ddsData[22] = 1;
-            ddsData[28] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 53;
-
-            ddsData[88] = 32;
-            ddsData[94] = 255;
-            ddsData[97] = 255;
-            ddsData[100] = 255;
-            ddsData[107] = 255;
-            ddsData[109] = 16;
-            break;
-    }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
-*/
+};

+ 15 - 9
Source/Subfiles/TextSubfile.h

@@ -5,27 +5,33 @@
 #ifndef LOTRO_DAT_LIBRARY_TEXTSUBFILE_H
 #define LOTRO_DAT_LIBRARY_TEXTSUBFILE_H
 
-
 #include "../Subfile.h"
+#include <vector>
 
 namespace LOTRO_DAT {
     class TextSubfile : Subfile {
+    public:
         TextSubfile();
-        TextSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                   long long file_size, long long timestamp, long long version, long long block_size) override;
+
+        TextSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id,
+                    long long file_offset,
+                    long long file_size, long long timestamp, long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
-        std::string GetExtension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
+    private:
+        std::vector<std::u16string> MakePieces(const BinaryData &data, long long &offset);
 
+        std::vector<long long> MakeArgumentReferences(const BinaryData &data, long long &offset);
+
+        std::vector<std::vector<BinaryData>> MakeArgumentStrings(const BinaryData &data, long long &offset);
     };
 };
 
 
-
 #endif //LOTRO_DAT_LIBRARY_TEXTSUBFILE_H

+ 42 - 0
Source/Subfiles/UnknownSubfile.cpp

@@ -3,3 +3,45 @@
 //
 
 #include "UnknownSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
+
+namespace LOTRO_DAT {
+    UnknownSubfile::UnknownSubfile() {}
+
+    UnknownSubfile::UnknownSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp,
+                           long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
+    }
+
+    FILE_TYPE UnknownSubfile::FileType() const {
+        return UNKNOWN;
+    }
+
+    std::string UnknownSubfile::Extension() const {
+        return ".unknown";
+    }
+
+    bool UnknownSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                          std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 1;
+        binary_data.emplace_back(file_data);
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
+        return true;
+    }
+
+    BinaryData UnknownSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                             const std::u16string &text_data, const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
+        }
+        return old_data.CutData(0, 16) + binary_data;
+    }
+};

+ 6 - 6
Source/Subfiles/UnknownSubfile.h

@@ -11,16 +11,16 @@ namespace LOTRO_DAT {
     class UnknownSubfile : Subfile {
         UnknownSubfile();
         UnknownSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                   long long file_size, long long timestamp, long long version, long long block_size) override;
+                   long long file_size, long long timestamp, long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
-        std::string GetExtension() const override;
+        std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
 
     };
 };

+ 28 - 539
Source/Subfiles/WavSubfile.cpp

@@ -1,558 +1,47 @@
-/*
 //
 // Created by Иван_Архипов on 24.11.2017.
 //
 
 #include "WavSubfile.h"
+#include "../BinaryData.h"
+#include "../DatFile.h"
+#include "../Common/DatException.h"
 
-//
-// Created by Иван_Архипов on 01.11.2017.
-//
-
-#include "Subfile.h"
-#include "BinaryData.h"
-#include "DatFile.h"
-#include "Common/DatException.h"
-#include "Database.h"
-#include "Common/CommonFunctions.h"
-
-#include <algorithm>
-
-const long long MAXSIZE = 50ll * 1024ll * 1024ll; // Setting maximal file size 50 MB; Files with size more than 50 mb
-// will be recognized as incorrect and passed.
-// This should be done because
-
-LOTRO_DAT::Subfile::Subfile() {
-    ext_ = UNKNOWN;
-    compressed_ = false;
-}
-
-LOTRO_DAT::Subfile::Subfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                            long long file_size, long long timestamp, long long version, long long block_size) :
-        dat_(dat), fragments_count_(fragments_count), unknown1_(unknown1), file_id_(file_id), file_offset_(file_offset),
-        file_size_(file_size), timestamp_(timestamp), version_(version), block_size_(block_size) {
-
-    if (file_size_ > MAXSIZE)
-        throw DatException("Bad Subfile::Subfile() - File size is too much... Maybe it's incorrect..?", SUBFILE_EXCEPTION);
-    ext_ = GetExtension();
-
-    BinaryData header(20);
-    dat_->ReadData(header, 10, file_offset_ + 8);
-    compressed_ = header.CheckCompression();
-}
-
-long long LOTRO_DAT::Subfile::fragments_count() const {
-    return fragments_count_;
-}
-
-long long LOTRO_DAT::Subfile::unknown1() const {
-    return unknown1_;
-}
-
-long long LOTRO_DAT::Subfile::file_id() const {
-    return file_id_;
-}
-
-long long LOTRO_DAT::Subfile::file_offset() const {
-    return file_offset_;
-}
-
-long long LOTRO_DAT::Subfile::file_size() const {
-    return file_size_;
-}
+namespace LOTRO_DAT {
+    WavSubfile::WavSubfile() = default;
 
-long long LOTRO_DAT::Subfile::timestamp() const {
-    return timestamp_;
-}
-
-long long LOTRO_DAT::Subfile::version() const {
-    return version_;
-}
-
-long long LOTRO_DAT::Subfile::block_size() const {
-    return block_size_;
-}
-
-LOTRO_DAT::FILE_TYPE LOTRO_DAT::Subfile::GetExtension() const {
-    // Text check based on file_id
-    if ((file_id_ >> 24ll) == 0x25ll)
-        return TEXT;
-
-    // Font check based on file_id
-    if ((file_id_ >> 24ll) == 0x42ll)
-        return FONT;
-
-    BinaryData header(64);
-    try {
-        dat_->ReadData(header, 64, (unsigned) file_offset_ + 8);
-    } catch (DatException &e) {
-        if (e.type() == READ_EXCEPTION) {
-            std::string err =
-                    "Bad Subfile::getExtension() - unable to read header of file with id = " + std::to_string(file_id()) +
-                    " and offset = " + std::to_string(file_offset());
-            throw DatException(err.c_str(), SUBFILE_EXCEPTION);
-        } else
-            throw e;
-    }
-
-    // jpeg / dds check
-    if ((file_id_ >> 24ll) == 0x41ll) {
-        long long soi = header.ToNumber<2>(24);
-        long long marker = header.ToNumber<2>(26);
-
-        //auto markerSize = header.ToNumber<short>(28);
-        //auto four = header.ToNumber<int>(30);
-
-        if (soi == 0xD8FFll && marker == 0xE0FFll || marker == 0xE1FFll)
-            return JPG;
-        return DDS;
+    WavSubfile::WavSubfile(DatFile *dat, long long fragments_count, long long unknown1,
+                           long long file_id, long long file_offset, long long file_size,
+                           long long timestamp,
+                           long long version, long long block_size)
+            : Subfile(dat, fragments_count, unknown1, file_id, file_offset, file_size, timestamp, version, block_size) {
     }
 
-    // Ogg and Wav check
-    if (header[8] == 0x4F && header[9] == 0x67 && header[10] == 0x67 && header[11] == 0x53)
-        return OGG;
-    if (header[8] == 0x52 && header[9] == 0x49 && header[10] == 0x46 && header[11] == 0x46)
+    FILE_TYPE WavSubfile::FileType() const {
         return WAV;
-
-    return UNKNOWN;
-}
-
-std::string LOTRO_DAT::Subfile::ExtensionToString(LOTRO_DAT::FILE_TYPE ext) const {
-    switch (ext)
-    {
-        case LOTRO_DAT::TEXT:
-            return ".txt";
-        case LOTRO_DAT::JPG:
-            return ".jpg";
-        case LOTRO_DAT::DDS:
-            return ".dds";
-        case LOTRO_DAT::WAV:
-            return ".wav";
-        case LOTRO_DAT::OGG:
-            return ".ogg";
-        case LOTRO_DAT::FONT:
-            return ".fontbin";
-        case LOTRO_DAT::UNKNOWN:
-            return ".unk";
-        default:
-            return "";
     }
-}
 
-bool LOTRO_DAT::Subfile::PatchBinaryFile(const LOTRO_DAT::BinaryData &file) {
-    LOTRO_DAT::BinaryData data;
-
-    // Making data for placing in .dat, depending on file extension
-    switch (ext_)
-    {
-        case LOTRO_DAT::TEXT:
-            throw LOTRO_DAT::DatException("Bad Subfile::PatchBinaryFile() - trying to patch text file");
-        case LOTRO_DAT::JPG:
-            data = MakeFromJPG(file); break;
-        case LOTRO_DAT::DDS:
-            data = MakeFromDDS(file); break;
-        case LOTRO_DAT::WAV:
-            data = MakeFromWAV(file); break;
-        case LOTRO_DAT::OGG:
-            data = MakeFromOGG(file); break;
-        case LOTRO_DAT::FONT:
-            data = MakeFromFont(file); break;
-        case LOTRO_DAT::UNKNOWN:
-            data = MakeFromUnk(file); break;
-        default:
-            break;
+    std::string WavSubfile::Extension() const {
+        return ".wav";
     }
 
-    if (block_size() >= data.size() + 8) {
-        dat_->WriteData(data, data.size(), file_offset() + 8);
+    bool WavSubfile::PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                                      std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) {
+        export_size = 1;
+        binary_data.emplace_back(file_data.CutData(8));
+        text_data.emplace_back(u"");
+        options.emplace_back(YAML::Node());
+        options[0]["file_id"] = file_id();
+        options[0]["extension"] = Extension();
         return true;
     }
-    throw DatException("Bad Subfile::PatchBinaryFile() - new data size is bigger, than block_size. This is not implemented yet"
-            , IMPORT_EXCEPTION);
-    return true;
-}
-
-bool LOTRO_DAT::Subfile::ExportFile(const char *filename) const {
-    try {
-        BinaryData data;
-
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return false;
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
-        }
-
-        std::string s = std::string(filename) + std::string(ExtensionToString(ext_));
-        return data.WriteToFile(s);
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
 
-bool LOTRO_DAT::Subfile::ExportFile(Database *db) const {
-    try {
-        BinaryData data;
-        switch (ext_)
-        {
-            case LOTRO_DAT::TEXT:
-                return ExportFileAsTXT(db);
-            case LOTRO_DAT::JPG:
-                data = PrepareAsJPG(); break;
-            case LOTRO_DAT::DDS:
-                data = PrepareAsDDS(); break;
-            case LOTRO_DAT::WAV:
-                data = PrepareAsWAV(); break;
-            case LOTRO_DAT::OGG:
-                data = PrepareAsOGG(); break;
-            case LOTRO_DAT::FONT:
-                data = PrepareAsFont(); break;
-            case LOTRO_DAT::UNKNOWN:
-                data = PrepareAsUnk(); break;
-            default:
-                break;
+    BinaryData WavSubfile::MakeForImport(const BinaryData &old_data, const BinaryData &binary_data, const std::u16string &text_data,
+                              const YAML::Node &options) {
+        if (!options["extension"] || options["extension"].as<std::string>() != Extension() ||
+            !options["file_id"] || options["file_id"].as<long long>() != file_id()) {
+            throw DatException("Bad DdsSubfile::MakeForImport() - invalid options data!", IMPORT_EXCEPTION);
         }
-
-        db->PushBinaryFile(file_id_, data);
-        return true;
-    }
-    catch (DatException &e) {
-        fprintf(stderr, "Caught exception while unpacking the file with id %lld and offset %lld. Continuing without this file...\n", file_id(), file_offset());
-        fprintf(stderr, "%s\n", e.what());
-        return false;
-    }
-}
-
-bool LOTRO_DAT::Subfile::ExportFileAsTXT(Database *db) const {
-    if (db == nullptr) {
-        return false;
-    }
-
-    if (file_size() == 10) // File is empty, nothing to do;
-        return false;
-
-    BinaryData data = GetFileData();
-
-    long long offset = 9; // first 4 bytes - file_id, then 4 bytes - unknown, then 1 byte - unknown
-
-    long long text_fragment_num = data.ToNumber<1>(offset);
-    if ((text_fragment_num & 0x80) != 0) {
-        text_fragment_num = (((text_fragment_num ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-        offset += 1;
+        return old_data.CutData(0, 24) + binary_data;
     }
-    offset += 1;
-
-    for (long long i = 0; i < text_fragment_num; i++) {
-        long long fragment_id = data.ToNumber<8>(offset);
-        offset += 8;
-
-        long long num_pieces = data.ToNumber<4>(offset);
-        offset += 4;
-
-        std::vector<std::u16string> text_pieces;
-        std::vector<long long> arg_references;
-        std::vector<std::vector<BinaryData> > arg_strings;
-
-        for (long long j = 0; j < num_pieces; j++) {
-            long long piece_size = data.ToNumber<1>(offset);
-            if ((piece_size & 128) != 0) {
-                piece_size = (((piece_size ^ 128) << 8) | data.ToNumber<1>(offset + 1));
-                offset += 1;
-            }
-            offset += 1;
-
-            BinaryData piece_data = data.CutData(offset, offset + piece_size * 2);
-            std::u16string piece;
-
-            for (long long k = 0; k < piece_size; k++) {
-                char16_t c = char16_t(((short(piece_data[2 * k + 1])) << 8) | (short(piece_data[2 * k])));
-                piece += c;
-            }
-
-            text_pieces.push_back(piece);
-            offset += piece_size * 2;
-        }
-
-        long long num_references = data.ToNumber<4>(offset);
-        offset += 4;
-
-        for (long long j = 0; j < num_references; j++) {
-            arg_references.emplace_back(data.ToNumber<4>(offset));
-            offset += 4;
-        }
-
-        long long num_arg_strings = data.ToNumber<1>(offset);
-        offset += 1;
-
-        for (long long j = 0; j < num_arg_strings; j++) {
-            long long num_args = data.ToNumber<4>(offset);
-            offset += 4;
-
-            arg_strings.emplace_back();
-            for (long long k = 0; k < num_args; k++) {
-                long long string_size = data.ToNumber<1>(offset);
-                if ((string_size & 0x80) != 0) {
-                    string_size = (((string_size ^ 0x80) << 8) | data.ToNumber<1>(offset + 1));
-                    offset += 1;
-                }
-                offset += 1;
-
-                arg_strings[j].emplace_back(data.CutData(offset, offset + string_size * 2));
-                offset += string_size * 2;
-            }
-        }
-
-        std::u16string text = u"[";
-        for (int i = 0; i + 1 < text_pieces.size(); i++)
-            text += text_pieces[i] + u"<--DO_NOT_TOUCH!-->";
-        text += text_pieces[text_pieces.size() - 1] + u"]";
-
-        std::string arguments;
-        for (int i = 0; i + 1 < arg_references.size(); i++)
-            arguments += std::to_string(arg_references[i]) + "-";
-        if (arg_references.size() >= 1)
-            arguments += std::to_string(arg_references[arg_references.size() - 1]);
-
-        db->PushTextFile(file_id(), fragment_id, text.c_str(), arguments.c_str());
-    }
-    return true;
-}
-
-LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::GetFileData(long long offset) const {
-    BinaryData mfile_id(4);
-    dat_->ReadData(mfile_id, 4, file_offset() + 8);
-    if (file_id() != mfile_id.ToNumber<4>(0))
-        throw DatException("Bad Subfile::GetFileData() - file_id doesn't match to dictionary", READ_EXCEPTION);
-
-    BinaryData data((unsigned)(file_size()));
-    if (block_size() >= file_size() + 8) {
-        dat_->ReadData(data, file_size(), file_offset() + offset);
-        return data;
-    }
-
-    BinaryData fragments_count(4);
-    dat_->ReadData(fragments_count, 4, file_offset());
-
-    long long fragments_number = fragments_count.ToNumber<4>(0);
-
-    long long current_block_size = block_size() - offset - 8 * fragments_number;
-
-    dat_->ReadData(data, current_block_size , file_offset() + offset);
-
-    BinaryData FragmentsDictionary(8 * unsigned(fragments_number));
-    dat_->ReadData(FragmentsDictionary, 8 * unsigned(fragments_number), file_offset() + block_size() - 8 * fragments_number);
-
-
-    for (long long i = 0; i < fragments_number; i++) {
-        long long fragment_size = FragmentsDictionary.ToNumber<4>(8 * i);
-        long long fragment_offset = FragmentsDictionary.ToNumber<4>(8 * i + 4);
-        dat_->ReadData(data, std::min(fragment_size, file_size() - current_block_size), fragment_offset, current_block_size );
-        current_block_size += fragment_size;
-    }
-
-    return data;
-}
-
-LOTRO_DAT::Subfile *LOTRO_DAT::Subfile::initialize(LOTRO_DAT::DatFile *dat, long long file_off) {
-    return nullptr;
-}
-
-bool LOTRO_DAT::Subfile::PatchBinaryFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(std::string text, std::string args, std::string args_order) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PatchTextFile(LOTRO_DAT::Database *db) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsBinary(LOTRO_DAT::BinaryData &data) {
-    return false;
-}
-
-bool LOTRO_DAT::Subfile::PrepareAsText(std::string &text, std::string &args, std::string &args_order) {
-    return false;
-}
-
-LOTRO_DAT::BinaryData &LOTRO_DAT::Subfile::MakeFromBinary(const LOTRO_DAT::BinaryData &data) {
-    return <#initializer#>;
-}
-
-LOTRO_DAT::BinaryData &
-LOTRO_DAT::Subfile::MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) {
-    return <#initializer#>;
-}
-
-*/
-/*
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsJPG() const {
-    return GetFileData().CutData(24);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsDDS() const {
-    BinaryData data = GetFileData();
-    if (compressed_)
-        data.DecompressData(4);
-
-    BinaryData ddsData(data.size() - 24 + 128);
-    for (int i = 0; i < 128; i++)
-        ddsData[i] = 0;
-
-    memcpy(ddsData.data() + 128, data.data() + 24, data.size() - 24);
-
-    ddsData[0] = 0x44; // D
-    ddsData[1] = 0x44; // D
-    ddsData[2] = 0x53; // S
-    ddsData[3] = 0x20;
-    ddsData[4] = 0x7C;
-
-    ddsData[8] = 7;
-    ddsData[9] = 0x10;
-
-    // width, height
-    ddsData[12] = data[12];
-    ddsData[13] = data[13];
-    ddsData[14] = data[14];
-    ddsData[15] = data[15];
-
-    ddsData[16] = data[8];
-    ddsData[17] = data[9];
-    ddsData[18] = data[10];
-    ddsData[19] = data[11];
-
-    long long compression = data.ToNumber<4>(0x10);
-
-    switch (compression) {
-        case 20:        // 14 00 00 00 - 888 (R8G8B8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x18;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 21:        // 15 00 00 00 - 8888 (R8G8B8A8)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x20;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            ddsData[0x6B] = 0xFF;
-            break;
-        case 28:        // 1C 00 00 00 - 332 (?)
-            ddsData[0x4C] = 0x20;  // ?
-            ddsData[0x50] = 0x40;  // compressed or not
-
-            ddsData[0x58] = 0x08;  // bytes per pixel
-            ddsData[0x5E] = 0xFF;
-            ddsData[0x61] = 0xFF;
-            ddsData[0x64] = 0xFF;
-            break;
-        case 827611204: // 44 58 54 31 - DXT1
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 49;
-            break;
-        case 861165636: // 44 58 54 33 - DXT3
-            ddsData[22] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 51;
-
-            ddsData[108] = 8;
-            ddsData[109] = 16;
-            ddsData[110] = 64;
-            break;
-        case 894720068: // 44 58 54 35 - DXT5
-            ddsData[10] = 8;
-            ddsData[22] = 1;
-            ddsData[28] = 1;
-            ddsData[76] = 32;
-            ddsData[80] = 4;
-
-            ddsData[84] = 68;
-            ddsData[85] = 88;
-            ddsData[86] = 84;
-            ddsData[87] = 53;
-
-            ddsData[88] = 32;
-            ddsData[94] = 255;
-            ddsData[97] = 255;
-            ddsData[100] = 255;
-            ddsData[107] = 255;
-            ddsData[109] = 16;
-            break;
-    }
-	return ddsData;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsOGG() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsFont() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsWAV() const {
-    return GetFileData().CutData(8);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::PrepareAsUnk() const {
-    return GetFileData();
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromJPG(const LOTRO_DAT::BinaryData &file) const {
-    return GetFileData().CutData(0, 24) + file;
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromDDS(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromDDS() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromOGG(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromOGG() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromFont(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromFont() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromWAV(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromWAV() - not implemented yet", IMPORT_EXCEPTION);
-}
-
-const LOTRO_DAT::BinaryData LOTRO_DAT::Subfile::MakeFromUnk(const LOTRO_DAT::BinaryData &file) const {
-    throw LOTRO_DAT::DatException("Bad Subfile::MakeFromUnk() - not implemented yet", IMPORT_EXCEPTION);
-}
- */
+};

+ 6 - 6
Source/Subfiles/WavSubfile.h

@@ -11,16 +11,16 @@ namespace LOTRO_DAT {
     class WavSubfile : Subfile {
         WavSubfile();
         WavSubfile(DatFile *dat, long long fragments_count, long long unknown1, long long file_id, long long file_offset,
-                   long long file_size, long long timestamp, long long version, long long block_size) override;
+                   long long file_size, long long timestamp, long long version, long long block_size);
 
         FILE_TYPE FileType() const override;
-        std::string GetExtension() const override;
+        std::string Extension() const override;
 
-        bool PrepareAsBinary(BinaryData &data) override;
-        bool PrepareAsText(std::string &text, std::string &args, std::string &args_order) override;
+        bool PrepareForExport(const BinaryData &file_data, long long &export_size, std::vector<BinaryData> &binary_data,
+                              std::vector<std::u16string> &text_data, std::vector<YAML::Node> &options) override;
 
-        BinaryData& MakeFromBinary(const BinaryData &data) override;
-        BinaryData& MakeFromText(const std::string &text, const std::string &args, const std::string &args_order) override;
+        BinaryData MakeForImport(const BinaryData &old_data, const BinaryData &binary_data,
+                                 const std::u16string &text_data, const YAML::Node &options) override;
 
     };
 };