Browse Source

Mostly implemented basic patch installation

Ivan Arkhipov 3 years ago
parent
commit
28b1e8baad

+ 1 - 1
import/yaml-cpp/anchor.h

@@ -10,7 +10,7 @@
 #include <cstddef>
 
 namespace YAML {
-typedef std::size_t anchor_t;
+using anchor_t = std::size_t;
 const anchor_t NullAnchor = 0;
 }
 

+ 8 - 4
import/yaml-cpp/binary.h

@@ -19,9 +19,13 @@ 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_) {}
+      : m_data{}, m_unownedData(data_), m_unownedSize(size_) {}
+  Binary() : Binary(nullptr, 0) {}
+  Binary(const Binary &) = default;
+  Binary(Binary &&) = default;
+  Binary &operator=(const Binary &) = default;
+  Binary &operator=(Binary &&) = default;
 
   bool owned() const { return !m_unownedData; }
   std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; }
@@ -35,7 +39,7 @@ class YAML_CPP_API Binary {
       rhs.clear();
       rhs.resize(m_unownedSize);
       std::copy(m_unownedData, m_unownedData + m_unownedSize, rhs.begin());
-      m_unownedData = 0;
+      m_unownedData = nullptr;
       m_unownedSize = 0;
     } else {
       m_data.swap(rhs);
@@ -62,6 +66,6 @@ class YAML_CPP_API Binary {
   const unsigned char *m_unownedData;
   std::size_t m_unownedSize;
 };
-}
+}  // namespace YAML
 
 #endif  // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 2 - 1
import/yaml-cpp/contrib/anchordict.h

@@ -22,6 +22,7 @@ namespace YAML {
 template <class T>
 class AnchorDict {
  public:
+  AnchorDict() : m_data{} {}
   void Register(anchor_t anchor, T value) {
     if (anchor > m_data.size()) {
       m_data.resize(anchor);
@@ -34,6 +35,6 @@ class AnchorDict {
  private:
   std::vector<T> m_data;
 };
-}
+}  // namespace YAML
 
 #endif  // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 12 - 12
import/yaml-cpp/emitfromevents.h

@@ -24,21 +24,21 @@ class EmitFromEvents : public EventHandler {
  public:
   EmitFromEvents(Emitter& emitter);
 
-  virtual void OnDocumentStart(const Mark& mark);
-  virtual void OnDocumentEnd();
+  void OnDocumentStart(const Mark& mark) override;
+  void OnDocumentEnd() override;
 
-  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);
+  void OnNull(const Mark& mark, anchor_t anchor) override;
+  void OnAlias(const Mark& mark, anchor_t anchor) override;
+  void OnScalar(const Mark& mark, const std::string& tag,
+                        anchor_t anchor, const std::string& value) override;
 
-  virtual void OnSequenceStart(const Mark& mark, const std::string& tag,
-                               anchor_t anchor, EmitterStyle::value style);
-  virtual void OnSequenceEnd();
+  void OnSequenceStart(const Mark& mark, const std::string& tag,
+                               anchor_t anchor, EmitterStyle::value style) override;
+  void OnSequenceEnd() override;
 
-  virtual void OnMapStart(const Mark& mark, const std::string& tag,
-                          anchor_t anchor, EmitterStyle::value style);
-  virtual void OnMapEnd();
+  void OnMapStart(const Mark& mark, const std::string& tag,
+                          anchor_t anchor, EmitterStyle::value style) override;
+  void OnMapEnd() override;
 
  private:
   void BeginNode();

+ 29 - 4
import/yaml-cpp/emitter.h

@@ -7,16 +7,18 @@
 #pragma once
 #endif
 
+#include <cmath>
 #include <cstddef>
+#include <limits>
 #include <memory>
 #include <sstream>
 #include <string>
+#include <type_traits>
 
 #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"
 
@@ -28,10 +30,12 @@ struct _Null;
 namespace YAML {
 class EmitterState;
 
-class YAML_CPP_API Emitter : private noncopyable {
+class YAML_CPP_API Emitter {
  public:
   Emitter();
   explicit Emitter(std::ostream& stream);
+  Emitter(const Emitter&) = delete;
+  Emitter& operator=(const Emitter&) = delete;
   ~Emitter();
 
   // output
@@ -152,7 +156,28 @@ inline Emitter& Emitter::WriteStreamable(T value) {
 
   std::stringstream stream;
   SetStreamablePrecision<T>(stream);
-  stream << value;
+
+  bool special = false;
+  if (std::is_floating_point<T>::value) {
+    if ((std::numeric_limits<T>::has_quiet_NaN ||
+         std::numeric_limits<T>::has_signaling_NaN) &&
+        std::isnan(value)) {
+      special = true;
+      stream << ".nan";
+    } else if (std::numeric_limits<T>::has_infinity) {
+      if (value == std::numeric_limits<T>::infinity()) {
+        special = true;
+        stream << ".inf";
+      } else if (value == -std::numeric_limits<T>::infinity()) {
+        special = true;
+        stream << "-.inf";
+      }
+    }
+  }
+
+  if (!special) {
+    stream << value;
+  }
   m_stream << stream.str();
 
   StartedScalar();
@@ -249,6 +274,6 @@ inline Emitter& operator<<(Emitter& emitter, _Indent indent) {
 inline Emitter& operator<<(Emitter& emitter, _Precision precision) {
   return emitter.SetLocalPrecision(precision);
 }
-}
+}  // namespace YAML
 
 #endif  // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 6 - 6
import/yaml-cpp/emittermanip.h

@@ -74,14 +74,14 @@ struct _Alias {
   std::string content;
 };
 
-inline _Alias Alias(const std::string content) { return _Alias(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); }
+inline _Anchor Anchor(const std::string& content) { return _Anchor(content); }
 
 struct _Tag {
   struct Type {
@@ -96,11 +96,11 @@ struct _Tag {
   Type::value type;
 };
 
-inline _Tag VerbatimTag(const std::string content) {
+inline _Tag VerbatimTag(const std::string& content) {
   return _Tag("", content, _Tag::Type::Verbatim);
 }
 
-inline _Tag LocalTag(const std::string content) {
+inline _Tag LocalTag(const std::string& content) {
   return _Tag("", content, _Tag::Type::PrimaryHandle);
 }
 
@@ -108,7 +108,7 @@ 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) {
+inline _Tag SecondaryTag(const std::string& content) {
   return _Tag("", content, _Tag::Type::NamedHandle);
 }
 
@@ -117,7 +117,7 @@ struct _Comment {
   std::string content;
 };
 
-inline _Comment Comment(const std::string content) { return _Comment(content); }
+inline _Comment Comment(const std::string& content) { return _Comment(content); }
 
 struct _Precision {
   _Precision(int floatPrecision_, int doublePrecision_)

+ 7 - 2
import/yaml-cpp/eventhandler.h

@@ -17,7 +17,7 @@ struct Mark;
 
 class EventHandler {
  public:
-  virtual ~EventHandler() {}
+  virtual ~EventHandler() = default;
 
   virtual void OnDocumentStart(const Mark& mark) = 0;
   virtual void OnDocumentEnd() = 0;
@@ -34,7 +34,12 @@ class EventHandler {
   virtual void OnMapStart(const Mark& mark, const std::string& tag,
                           anchor_t anchor, EmitterStyle::value style) = 0;
   virtual void OnMapEnd() = 0;
+
+  virtual void OnAnchor(const Mark& /*mark*/,
+                        const std::string& /*anchor_name*/) {
+    // empty default implementation for compatibility
+  }
 };
-}
+}  // namespace YAML
 
 #endif  // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 52 - 20
import/yaml-cpp/exceptions.h

@@ -15,7 +15,7 @@
 
 // This is here for compatibility with older versions of Visual Studio
 // which don't support noexcept
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && _MSC_VER < 1900
     #define YAML_CPP_NOEXCEPT _NOEXCEPT
 #else
     #define YAML_CPP_NOEXCEPT noexcept
@@ -114,13 +114,42 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY(
   stream << KEY_NOT_FOUND << ": " << key;
   return stream.str();
 }
+
+template <typename T>
+inline const std::string BAD_SUBSCRIPT_WITH_KEY(
+    const T&, typename disable_if<is_numeric<T>>::type* = nullptr) {
+  return BAD_SUBSCRIPT;
+}
+
+inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) {
+  std::stringstream stream;
+  stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
+  return stream.str();
+}
+
+template <typename T>
+inline const std::string BAD_SUBSCRIPT_WITH_KEY(
+    const T& key, typename enable_if<is_numeric<T>>::type* = nullptr) {
+  std::stringstream stream;
+  stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
+  return stream.str();
+}
+
+inline const std::string INVALID_NODE_WITH_KEY(const std::string& key) {
+  std::stringstream stream;
+  if (key.empty()) {
+    return INVALID_NODE;
+  }
+  stream << "invalid node; first invalid key: \"" << 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() YAML_CPP_NOEXCEPT override;
 
   Exception(const Exception&) = default;
 
@@ -131,7 +160,7 @@ class YAML_CPP_API Exception : public std::runtime_error {
   static const std::string build_what(const Mark& mark,
                                       const std::string& msg) {
     if (mark.is_null()) {
-      return msg.c_str();
+      return msg;
     }
 
     std::stringstream output;
@@ -146,7 +175,7 @@ class YAML_CPP_API ParserException : public Exception {
   ParserException(const Mark& mark_, const std::string& msg_)
       : Exception(mark_, msg_) {}
   ParserException(const ParserException&) = default;
-  virtual ~ParserException() YAML_CPP_NOEXCEPT;
+  ~ParserException() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API RepresentationException : public Exception {
@@ -154,7 +183,7 @@ class YAML_CPP_API RepresentationException : public Exception {
   RepresentationException(const Mark& mark_, const std::string& msg_)
       : Exception(mark_, msg_) {}
   RepresentationException(const RepresentationException&) = default;
-  virtual ~RepresentationException() YAML_CPP_NOEXCEPT;
+  ~RepresentationException() YAML_CPP_NOEXCEPT override;
 };
 
 // representation exceptions
@@ -163,7 +192,7 @@ class YAML_CPP_API InvalidScalar : public RepresentationException {
   InvalidScalar(const Mark& mark_)
       : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
   InvalidScalar(const InvalidScalar&) = default;
-  virtual ~InvalidScalar() YAML_CPP_NOEXCEPT;
+  ~InvalidScalar() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API KeyNotFound : public RepresentationException {
@@ -173,7 +202,7 @@ class YAML_CPP_API KeyNotFound : public RepresentationException {
       : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
   }
   KeyNotFound(const KeyNotFound&) = default;
-  virtual ~KeyNotFound() YAML_CPP_NOEXCEPT;
+  ~KeyNotFound() YAML_CPP_NOEXCEPT override;
 };
 
 template <typename T>
@@ -181,7 +210,7 @@ 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 {}
+  ~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default;
 
   T key;
 };
@@ -194,10 +223,11 @@ inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
 
 class YAML_CPP_API InvalidNode : public RepresentationException {
  public:
-  InvalidNode()
-      : RepresentationException(Mark::null_mark(), ErrorMsg::INVALID_NODE) {}
+  InvalidNode(const std::string& key)
+      : RepresentationException(Mark::null_mark(),
+                                ErrorMsg::INVALID_NODE_WITH_KEY(key)) {}
   InvalidNode(const InvalidNode&) = default;
-  virtual ~InvalidNode() YAML_CPP_NOEXCEPT;
+  ~InvalidNode() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API BadConversion : public RepresentationException {
@@ -205,7 +235,7 @@ class YAML_CPP_API BadConversion : public RepresentationException {
   explicit BadConversion(const Mark& mark_)
       : RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
   BadConversion(const BadConversion&) = default;
-  virtual ~BadConversion() YAML_CPP_NOEXCEPT;
+  ~BadConversion() YAML_CPP_NOEXCEPT override;
 };
 
 template <typename T>
@@ -219,15 +249,17 @@ class YAML_CPP_API BadDereference : public RepresentationException {
   BadDereference()
       : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
   BadDereference(const BadDereference&) = default;
-  virtual ~BadDereference() YAML_CPP_NOEXCEPT;
+  ~BadDereference() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API BadSubscript : public RepresentationException {
  public:
-  BadSubscript()
-      : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {}
+  template <typename Key>
+  BadSubscript(const Key& key)
+      : RepresentationException(Mark::null_mark(),
+                                ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {}
   BadSubscript(const BadSubscript&) = default;
-  virtual ~BadSubscript() YAML_CPP_NOEXCEPT;
+  ~BadSubscript() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API BadPushback : public RepresentationException {
@@ -235,7 +267,7 @@ class YAML_CPP_API BadPushback : public RepresentationException {
   BadPushback()
       : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
   BadPushback(const BadPushback&) = default;
-  virtual ~BadPushback() YAML_CPP_NOEXCEPT;
+  ~BadPushback() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API BadInsert : public RepresentationException {
@@ -243,7 +275,7 @@ class YAML_CPP_API BadInsert : public RepresentationException {
   BadInsert()
       : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
   BadInsert(const BadInsert&) = default;
-  virtual ~BadInsert() YAML_CPP_NOEXCEPT;
+  ~BadInsert() YAML_CPP_NOEXCEPT override;
 };
 
 class YAML_CPP_API EmitterException : public Exception {
@@ -251,14 +283,14 @@ class YAML_CPP_API EmitterException : public Exception {
   EmitterException(const std::string& msg_)
       : Exception(Mark::null_mark(), msg_) {}
   EmitterException(const EmitterException&) = default;
-  virtual ~EmitterException() YAML_CPP_NOEXCEPT;
+  ~EmitterException() YAML_CPP_NOEXCEPT override;
 };
 
 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;
+  ~BadFile() YAML_CPP_NOEXCEPT override;
 };
 }
 

+ 39 - 36
import/yaml-cpp/node/convert.h

@@ -88,42 +88,45 @@ struct convert<_Null> {
   }
 };
 
-#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(type, negative_op)                  \
+  template <>                                                              \
+  struct convert<type> {                                                   \
+    static Node encode(const type& rhs) {                                  \
+      std::stringstream stream;                                            \
+      stream.precision(std::numeric_limits<type>::max_digits10);           \
+      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) {                      \
+        if (conversion::IsNaN(input)) {                                    \
+          rhs = std::numeric_limits<type>::quiet_NaN();                    \
+          return true;                                                     \
+        }                                                                  \
+      }                                                                    \
+                                                                           \
+      return false;                                                        \
+    }                                                                      \
   }
 
 #define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \

+ 0 - 26
import/yaml-cpp/node/detail/bool_type.h

@@ -1,26 +0,0 @@
-#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

+ 57 - 24
import/yaml-cpp/node/detail/impl.h

@@ -17,7 +17,7 @@ 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;
+    return nullptr;
   }
 };
 
@@ -27,12 +27,12 @@ struct get_idx<Key,
                                        !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;
+    return key < sequence.size() ? sequence[key] : nullptr;
   }
 
   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()))
+    if (key > sequence.size() || (key > 0 && !sequence[key - 1]->is_defined()))
       return 0;
     if (key == sequence.size())
       sequence.push_back(&pMemory->create_node());
@@ -46,13 +46,44 @@ struct get_idx<Key, typename std::enable_if<std::is_signed<Key>::value>::type> {
                    shared_memory_holder pMemory) {
     return key >= 0 ? get_idx<std::size_t>::get(
                           sequence, static_cast<std::size_t>(key), pMemory)
-                    : 0;
+                    : nullptr;
   }
   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;
+                    : nullptr;
+  }
+};
+
+template <typename Key, typename Enable = void>
+struct remove_idx {
+  static bool remove(std::vector<node*>&, const Key&) { return false; }
+};
+
+template <typename Key>
+struct remove_idx<
+    Key, typename std::enable_if<std::is_unsigned<Key>::value &&
+                                 !std::is_same<Key, bool>::value>::type> {
+
+  static bool remove(std::vector<node*>& sequence, const Key& key) {
+    if (key >= sequence.size()) {
+      return false;
+    } else {
+      sequence.erase(sequence.begin() + key);
+      return true;
+    }
+  }
+};
+
+template <typename Key>
+struct remove_idx<Key,
+                  typename std::enable_if<std::is_signed<Key>::value>::type> {
+
+  static bool remove(std::vector<node*>& sequence, const Key& key) {
+    return key >= 0 ? remove_idx<std::size_t>::remove(
+                          sequence, static_cast<std::size_t>(key))
+                    : false;
   }
 };
 
@@ -78,13 +109,13 @@ inline node* node_data::get(const Key& key,
       break;
     case NodeType::Undefined:
     case NodeType::Null:
-      return NULL;
+      return nullptr;
     case NodeType::Sequence:
       if (node* pNode = get_idx<Key>::get(m_sequence, key, pMemory))
         return pNode;
-      return NULL;
+      return nullptr;
     case NodeType::Scalar:
-      throw BadSubscript();
+      throw BadSubscript(key);
   }
 
   for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
@@ -93,7 +124,7 @@ inline node* node_data::get(const Key& key,
     }
   }
 
-  return NULL;
+  return nullptr;
 }
 
 template <typename Key>
@@ -112,7 +143,7 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
       convert_to_map(pMemory);
       break;
     case NodeType::Scalar:
-      throw BadSubscript();
+      throw BadSubscript(key);
   }
 
   for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
@@ -129,21 +160,23 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) {
 
 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;
-  }
+  if (m_type == NodeType::Sequence) {
+    return remove_idx<Key>::remove(m_sequence, key);
+  } else if (m_type == NodeType::Map) {
+    kv_pairs::iterator it = m_undefinedPairs.begin();
+    while (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;
+    for (node_map::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) {
+      if (iter->first->equals(key, pMemory)) {
+        m_map.erase(iter);
+        return true;
+      }
     }
   }
 

+ 11 - 7
import/yaml-cpp/node/detail/iterator.h

@@ -8,25 +8,25 @@
 #endif
 
 #include "yaml-cpp/dll.h"
+#include "yaml-cpp/node/detail/node_iterator.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> {
+class iterator_base {
 
  private:
   template <typename>
   friend class iterator_base;
   struct enabler {};
-  typedef node_iterator base_type;
+  using base_type = node_iterator;
 
   struct proxy {
     explicit proxy(const V& x) : m_ref(x) {}
@@ -37,7 +37,11 @@ class iterator_base : public std::iterator<std::forward_iterator_tag, V,
   };
 
  public:
-  typedef typename iterator_base::value_type value_type;
+  using iterator_category = std::forward_iterator_tag;
+  using value_type = V;
+  using difference_type = std::ptrdiff_t;
+  using pointer = V*;
+  using reference = V;
 
  public:
   iterator_base() : m_iterator(), m_pMemory() {}
@@ -86,7 +90,7 @@ class iterator_base : public std::iterator<std::forward_iterator_tag, V,
   base_type m_iterator;
   shared_memory_holder m_pMemory;
 };
-}
-}
+}  // namespace detail
+}  // namespace YAML
 
 #endif  // VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 2 - 2
import/yaml-cpp/node/detail/iterator_fwd.h

@@ -20,8 +20,8 @@ template <typename V>
 class iterator_base;
 }
 
-typedef detail::iterator_base<detail::iterator_value> iterator;
-typedef detail::iterator_base<const detail::iterator_value> const_iterator;
+using iterator = detail::iterator_base<detail::iterator_value>;
+using const_iterator = detail::iterator_base<const detail::iterator_value>;
 }
 
 #endif  // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 4 - 3
import/yaml-cpp/node/detail/memory.h

@@ -22,11 +22,12 @@ namespace YAML {
 namespace detail {
 class YAML_CPP_API memory {
  public:
+  memory() : m_nodes{} {}
   node& create_node();
   void merge(const memory& rhs);
 
  private:
-  typedef std::set<shared_node> Nodes;
+  using Nodes = std::set<shared_node>;
   Nodes m_nodes;
 };
 
@@ -40,7 +41,7 @@ class YAML_CPP_API memory_holder {
  private:
   shared_memory m_pMemory;
 };
-}
-}
+}  // namespace detail
+}  // namespace YAML
 
 #endif  // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 9 - 10
import/yaml-cpp/node/detail/node.h

@@ -7,18 +7,18 @@
 #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/emitterstyle.h"
 #include "yaml-cpp/node/detail/node_ref.h"
+#include "yaml-cpp/node/ptr.h"
+#include "yaml-cpp/node/type.h"
 #include <set>
 
 namespace YAML {
 namespace detail {
 class node {
  public:
-  node() : m_pRef(new node_ref) {}
+  node() : m_pRef(new node_ref), m_dependencies{} {}
   node(const node&) = delete;
   node& operator=(const node&) = delete;
 
@@ -42,9 +42,8 @@ class node {
       return;
 
     m_pRef->mark_defined();
-    for (nodes::iterator it = m_dependencies.begin();
-         it != m_dependencies.end(); ++it)
-      (*it)->mark_defined();
+    for (node* dependency : m_dependencies)
+      dependency->mark_defined();
     m_dependencies.clear();
   }
 
@@ -160,10 +159,10 @@ class node {
 
  private:
   shared_node_ref m_pRef;
-  typedef std::set<node*> nodes;
+  using nodes = std::set<node*>;
   nodes m_dependencies;
 };
-}
-}
+}  // namespace detail
+}  // namespace YAML
 
 #endif  // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 5 - 5
import/yaml-cpp/node/detail/node_data.h

@@ -81,7 +81,7 @@ class YAML_CPP_API node_data {
                     shared_memory_holder pMemory);
 
  public:
-  static std::string empty_scalar;
+  static const std::string& empty_scalar();
 
  private:
   void compute_seq_size() const;
@@ -108,17 +108,17 @@ class YAML_CPP_API node_data {
   std::string m_scalar;
 
   // sequence
-  typedef std::vector<node*> node_seq;
+  using node_seq = std::vector<node *>;
   node_seq m_sequence;
 
   mutable std::size_t m_seqSize;
 
   // map
-  typedef std::vector<std::pair<node*, node*>> node_map;
+  using node_map = std::vector<std::pair<node*, node*>>;
   node_map m_map;
 
-  typedef std::pair<node*, node*> kv_pair;
-  typedef std::list<kv_pair> kv_pairs;
+  using kv_pair = std::pair<node*, node*>;
+  using kv_pairs = std::list<kv_pair>;
   mutable kv_pairs m_undefinedPairs;
 };
 }

+ 19 - 19
import/yaml-cpp/node/detail/node_iterator.h

@@ -19,16 +19,16 @@
 namespace YAML {
 namespace detail {
 struct iterator_type {
-  enum value { None, Sequence, Map };
+  enum value { NoneType, Sequence, Map };
 };
 
 template <typename V>
 struct node_iterator_value : public std::pair<V*, V*> {
-  typedef std::pair<V*, V*> kv;
+  using kv = std::pair<V*, V*>;
 
-  node_iterator_value() : kv(), pNode(0) {}
+  node_iterator_value() : kv(), pNode(nullptr) {}
   explicit node_iterator_value(V& rhs) : kv(), pNode(&rhs) {}
-  explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(0) {}
+  explicit node_iterator_value(V& key, V& value) : kv(&key, &value), pNode(nullptr) {}
 
   V& operator*() const { return *pNode; }
   V& operator->() const { return *pNode; }
@@ -36,19 +36,19 @@ struct node_iterator_value : public std::pair<V*, V*> {
   V* pNode;
 };
 
-typedef std::vector<node*> node_seq;
-typedef std::vector<std::pair<node*, node*>> node_map;
+using node_seq = std::vector<node *>;
+using node_map = std::vector<std::pair<node*, node*>>;
 
 template <typename V>
 struct node_iterator_type {
-  typedef node_seq::iterator seq;
-  typedef node_map::iterator map;
+  using seq = node_seq::iterator;
+  using map = node_map::iterator;
 };
 
 template <typename V>
 struct node_iterator_type<const V> {
-  typedef node_seq::const_iterator seq;
-  typedef node_map::const_iterator map;
+  using seq = node_seq::const_iterator;
+  using map = node_map::const_iterator;
 };
 
 template <typename V>
@@ -68,12 +68,12 @@ class node_iterator_base
   };
 
  public:
-  typedef typename node_iterator_type<V>::seq SeqIter;
-  typedef typename node_iterator_type<V>::map MapIter;
-  typedef node_iterator_value<V> value_type;
+  using SeqIter = typename node_iterator_type<V>::seq;
+  using MapIter = typename node_iterator_type<V>::map;
+  using value_type = node_iterator_value<V>;
 
   node_iterator_base()
-      : m_type(iterator_type::None), m_seqIt(), m_mapIt(), m_mapEnd() {}
+      : m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {}
   explicit node_iterator_base(SeqIter seqIt)
       : m_type(iterator_type::Sequence),
         m_seqIt(seqIt),
@@ -105,7 +105,7 @@ class node_iterator_base
       return false;
 
     switch (m_type) {
-      case iterator_type::None:
+      case iterator_type::NoneType:
         return true;
       case iterator_type::Sequence:
         return m_seqIt == rhs.m_seqIt;
@@ -122,7 +122,7 @@ class node_iterator_base
 
   node_iterator_base<V>& operator++() {
     switch (m_type) {
-      case iterator_type::None:
+      case iterator_type::NoneType:
         break;
       case iterator_type::Sequence:
         ++m_seqIt;
@@ -143,7 +143,7 @@ class node_iterator_base
 
   value_type operator*() const {
     switch (m_type) {
-      case iterator_type::None:
+      case iterator_type::NoneType:
         return value_type();
       case iterator_type::Sequence:
         return value_type(**m_seqIt);
@@ -172,8 +172,8 @@ class node_iterator_base
   MapIter m_mapIt, m_mapEnd;
 };
 
-typedef node_iterator_base<node> node_iterator;
-typedef node_iterator_base<const node> const_node_iterator;
+using node_iterator = node_iterator_base<node>;
+using const_node_iterator = node_iterator_base<const node>;
 }
 }
 

+ 54 - 75
import/yaml-cpp/node/impl.h

@@ -7,18 +7,21 @@
 #pragma once
 #endif
 
-#include "yaml-cpp/node/node.h"
-#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/exceptions.h"
 #include "yaml-cpp/node/detail/memory.h"
 #include "yaml-cpp/node/detail/node.h"
-#include "yaml-cpp/exceptions.h"
+#include "yaml-cpp/node/iterator.h"
+#include "yaml-cpp/node/node.h"
+#include <sstream>
 #include <string>
 
 namespace YAML {
-inline Node::Node() : m_isValid(true), m_pNode(NULL) {}
+inline Node::Node()
+    : m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {}
 
 inline Node::Node(NodeType::value type)
     : m_isValid(true),
+      m_invalidKey{},
       m_pMemory(new detail::memory_holder),
       m_pNode(&m_pMemory->create_node()) {
   m_pNode->set_type(type);
@@ -27,6 +30,7 @@ inline Node::Node(NodeType::value type)
 template <typename T>
 inline Node::Node(const T& rhs)
     : m_isValid(true),
+      m_invalidKey{},
       m_pMemory(new detail::memory_holder),
       m_pNode(&m_pMemory->create_node()) {
   Assign(rhs);
@@ -34,24 +38,26 @@ inline Node::Node(const T& rhs)
 
 inline Node::Node(const detail::iterator_value& rhs)
     : m_isValid(rhs.m_isValid),
+      m_invalidKey(rhs.m_invalidKey),
       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(const Node& rhs) = default;
 
-inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {}
+inline Node::Node(Zombie)
+    : m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}
+
+inline Node::Node(Zombie, const std::string& key)
+    : m_isValid(false), m_invalidKey(key), m_pMemory{}, m_pNode(nullptr) {}
 
 inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory)
-    : m_isValid(true), m_pMemory(pMemory), m_pNode(&node) {}
+    : m_isValid(true), m_invalidKey{}, m_pMemory(pMemory), m_pNode(&node) {}
 
-inline Node::~Node() {}
+inline Node::~Node() = default;
 
 inline void Node::EnsureNodeExists() const {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   if (!m_pNode) {
     m_pMemory.reset(new detail::memory_holder);
     m_pNode = &m_pMemory->create_node();
@@ -68,14 +74,14 @@ inline bool Node::IsDefined() const {
 
 inline Mark Node::Mark() const {
   if (!m_isValid) {
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   }
   return m_pNode ? m_pNode->mark() : Mark::null_mark();
 }
 
 inline NodeType::value Node::Type() const {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   return m_pNode ? m_pNode->type() : NodeType::Null;
 }
 
@@ -142,7 +148,7 @@ struct as_if<std::string, void> {
 template <typename T>
 inline T Node::as() const {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   return as_if<T, void>(*this)();
 }
 
@@ -155,32 +161,28 @@ inline T Node::as(const S& fallback) const {
 
 inline const std::string& Node::Scalar() const {
   if (!m_isValid)
-    throw InvalidNode();
-  return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar;
+    throw InvalidNode(m_invalidKey);
+  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;
+    throw InvalidNode(m_invalidKey);
+  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();
+    throw InvalidNode(m_invalidKey);
   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);
 }
@@ -188,7 +190,7 @@ inline void Node::SetStyle(EmitterStyle::value style) {
 // assignment
 inline bool Node::is(const Node& rhs) const {
   if (!m_isValid || !rhs.m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   if (!m_pNode || !rhs.m_pNode)
     return false;
   return m_pNode->is(*rhs.m_pNode);
@@ -196,15 +198,20 @@ inline bool Node::is(const Node& rhs) const {
 
 template <typename T>
 inline Node& Node::operator=(const T& rhs) {
-  if (!m_isValid)
-    throw InvalidNode();
   Assign(rhs);
   return *this;
 }
 
+inline Node& Node::operator=(const Node& rhs) {
+  if (is(rhs))
+    return *this;
+  AssignNode(rhs);
+  return *this;
+}
+
 inline void Node::reset(const YAML::Node& rhs) {
   if (!m_isValid || !rhs.m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   m_pMemory = rhs.m_pMemory;
   m_pNode = rhs.m_pNode;
 }
@@ -212,44 +219,27 @@ inline void Node::reset(const YAML::Node& rhs) {
 template <typename T>
 inline void Node::Assign(const T& rhs) {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   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();
 
@@ -258,8 +248,8 @@ inline void Node::AssignData(const Node& rhs) {
 }
 
 inline void Node::AssignNode(const Node& rhs) {
-  if (!m_isValid || !rhs.m_isValid)
-    throw InvalidNode();
+  if (!m_isValid)
+    throw InvalidNode(m_invalidKey);
   rhs.EnsureNodeExists();
 
   if (!m_pNode) {
@@ -276,7 +266,7 @@ inline void Node::AssignNode(const Node& rhs) {
 // size/iterator
 inline std::size_t Node::size() const {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   return m_pNode ? m_pNode->size() : 0;
 }
 
@@ -309,13 +299,11 @@ inline iterator Node::end() {
 template <typename T>
 inline void Node::push_back(const T& rhs) {
   if (!m_isValid)
-    throw InvalidNode();
+    throw InvalidNode(m_invalidKey);
   push_back(Node(rhs));
 }
 
 inline void Node::push_back(const Node& rhs) {
-  if (!m_isValid || !rhs.m_isValid)
-    throw InvalidNode();
   EnsureNodeExists();
   rhs.EnsureNodeExists();
 
@@ -329,7 +317,7 @@ template <typename T>
 struct to_value_t {
   explicit to_value_t(const T& t_) : t(t_) {}
   const T& t;
-  typedef const T& return_type;
+  using return_type = const T &;
 
   const T& operator()() const { return t; }
 };
@@ -338,7 +326,7 @@ template <>
 struct to_value_t<const char*> {
   explicit to_value_t(const char* t_) : t(t_) {}
   const char* t;
-  typedef std::string return_type;
+  using return_type = std::string;
 
   const std::string operator()() const { return t; }
 };
@@ -347,7 +335,7 @@ template <>
 struct to_value_t<char*> {
   explicit to_value_t(char* t_) : t(t_) {}
   const char* t;
-  typedef std::string return_type;
+  using return_type = std::string;
 
   const std::string operator()() const { return t; }
 };
@@ -356,7 +344,7 @@ 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;
+  using return_type = std::string;
 
   const std::string operator()() const { return t; }
 };
@@ -366,26 +354,27 @@ template <typename T>
 inline typename to_value_t<T>::return_type to_value(const T& t) {
   return to_value_t<T>(t)();
 }
+}  // namespace detail
+
+template<typename Key>
+std::string key_to_string(const Key& key) {
+  return streamable_to_string<Key, is_streamable<std::stringstream, Key>::value>().impl(key);
 }
 
 // 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);
+  detail::node* value = static_cast<const detail::node&>(*m_pNode).get(
+      detail::to_value(key), m_pMemory);
   if (!value) {
-    return Node(ZombieNode);
+    return Node(ZombieNode, key_to_string(key));
   }
   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);
@@ -393,29 +382,23 @@ inline Node Node::operator[](const Key& key) {
 
 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(ZombieNode, key_to_string(key));
   }
   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);
@@ -424,8 +407,6 @@ inline Node Node::operator[](const Node& key) {
 }
 
 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);
@@ -434,8 +415,6 @@ inline bool Node::remove(const Node& key) {
 // 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);
@@ -443,6 +422,6 @@ inline void Node::force_insert(const Key& key, const Value& value) {
 
 // free functions
 inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); }
-}
+}  // namespace YAML
 
 #endif  // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 1 - 1
import/yaml-cpp/node/iterator.h

@@ -18,7 +18,7 @@
 namespace YAML {
 namespace detail {
 struct iterator_value : public Node, std::pair<Node, Node> {
-  iterator_value() {}
+  iterator_value() = default;
   explicit iterator_value(const Node& rhs)
       : Node(rhs),
         std::pair<Node, Node>(Node(Node::ZombieNode), Node(Node::ZombieNode)) {}

+ 7 - 4
import/yaml-cpp/node/node.h

@@ -8,11 +8,11 @@
 #endif
 
 #include <stdexcept>
+#include <string>
 
 #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"
@@ -38,8 +38,8 @@ class YAML_CPP_API Node {
   template <typename T, typename S>
   friend struct as_if;
 
-  typedef YAML::iterator iterator;
-  typedef YAML::const_iterator const_iterator;
+  using iterator = YAML::iterator;
+  using const_iterator = YAML::const_iterator;
 
   Node();
   explicit Node(NodeType::value type);
@@ -58,7 +58,7 @@ class YAML_CPP_API Node {
   bool IsMap() const { return Type() == NodeType::Map; }
 
   // bool conversions
-  YAML_CPP_OPERATOR_BOOL()
+  explicit operator bool() const { return IsDefined(); }
   bool operator!() const { return !IsDefined(); }
 
   // access
@@ -116,6 +116,7 @@ class YAML_CPP_API Node {
  private:
   enum Zombie { ZombieNode };
   explicit Node(Zombie);
+  explicit Node(Zombie, const std::string&);
   explicit Node(detail::node& node, detail::shared_memory_holder pMemory);
 
   void EnsureNodeExists() const;
@@ -130,6 +131,8 @@ class YAML_CPP_API Node {
 
  private:
   bool m_isValid;
+  // String representation of invalid key, if the node is invalid.
+  std::string m_invalidKey;
   mutable detail::shared_memory_holder m_pMemory;
   mutable detail::node* m_pNode;
 };

+ 5 - 5
import/yaml-cpp/node/ptr.h

@@ -18,11 +18,11 @@ 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;
+using shared_node = std::shared_ptr<node>;
+using shared_node_ref = std::shared_ptr<node_ref>;
+using shared_node_data = std::shared_ptr<node_data>;
+using shared_memory_holder = std::shared_ptr<memory_holder>;
+using shared_memory = std::shared_ptr<memory>;
 }
 }
 

+ 0 - 25
import/yaml-cpp/noncopyable.h

@@ -1,25 +0,0 @@
-#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

+ 7 - 3
import/yaml-cpp/ostream_wrapper.h

@@ -17,6 +17,10 @@ class YAML_CPP_API ostream_wrapper {
  public:
   ostream_wrapper();
   explicit ostream_wrapper(std::ostream& stream);
+  ostream_wrapper(const ostream_wrapper&) = delete;
+  ostream_wrapper(ostream_wrapper&&) = delete;
+  ostream_wrapper& operator=(const ostream_wrapper&) = delete;
+  ostream_wrapper& operator=(ostream_wrapper&&) = delete;
   ~ostream_wrapper();
 
   void write(const std::string& str);
@@ -26,7 +30,7 @@ class YAML_CPP_API ostream_wrapper {
 
   const char* str() const {
     if (m_pStream) {
-      return 0;
+      return nullptr;
     } else {
       m_buffer[m_pos] = '\0';
       return &m_buffer[0];
@@ -52,7 +56,7 @@ class YAML_CPP_API ostream_wrapper {
 
 template <std::size_t N>
 inline ostream_wrapper& operator<<(ostream_wrapper& stream,
-                                   const char(&str)[N]) {
+                                   const char (&str)[N]) {
   stream.write(str, N - 1);
   return stream;
 }
@@ -67,6 +71,6 @@ inline ostream_wrapper& operator<<(ostream_wrapper& stream, char ch) {
   stream.write(&ch, 1);
   return stream;
 }
-}
+}  // namespace YAML
 
 #endif  // OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 7 - 3
import/yaml-cpp/parser.h

@@ -11,7 +11,6 @@
 #include <memory>
 
 #include "yaml-cpp/dll.h"
-#include "yaml-cpp/noncopyable.h"
 
 namespace YAML {
 class EventHandler;
@@ -24,11 +23,16 @@ 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 {
+class YAML_CPP_API Parser {
  public:
   /** Constructs an empty parser (with no input. */
   Parser();
 
+  Parser(const Parser&) = delete;
+  Parser(Parser&&) = delete;
+  Parser& operator=(const Parser&) = delete;
+  Parser& operator=(Parser&&) = delete;
+
   /**
    * Constructs a parser from the given input stream. The input stream must
    * live as long as the parser.
@@ -81,6 +85,6 @@ class YAML_CPP_API Parser : private noncopyable {
   std::unique_ptr<Scanner> m_pScanner;
   std::unique_ptr<Directives> m_pDirectives;
 };
-}
+}  // namespace YAML
 
 #endif  // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 34 - 2
import/yaml-cpp/traits.h

@@ -7,6 +7,11 @@
 #pragma once
 #endif
 
+#include <type_traits>
+#include <utility>
+#include <string>
+#include <sstream>
+
 namespace YAML {
 template <typename>
 struct is_numeric {
@@ -79,7 +84,7 @@ struct is_numeric<long double> {
 
 template <bool, class T = void>
 struct enable_if_c {
-  typedef T type;
+  using type = T;
 };
 
 template <class T>
@@ -90,7 +95,7 @@ struct enable_if : public enable_if_c<Cond::value, T> {};
 
 template <bool, class T = void>
 struct disable_if_c {
-  typedef T type;
+  using type = T;
 };
 
 template <class T>
@@ -100,4 +105,31 @@ template <class Cond, class T = void>
 struct disable_if : public disable_if_c<Cond::value, T> {};
 }
 
+template <typename S, typename T>
+struct is_streamable {
+  template <typename SS, typename TT>
+  static auto test(int)
+      -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
+
+  template <typename, typename>
+  static auto test(...) -> std::false_type;
+
+  static const bool value = decltype(test<S, T>(0))::value;
+};
+
+template<typename Key, bool Streamable>
+struct streamable_to_string {
+  static std::string impl(const Key& key) {
+    std::stringstream ss;
+    ss << key;
+    return ss.str();
+  }
+};
+
+template<typename Key>
+struct streamable_to_string<Key, false> {
+  static std::string impl(const Key&) {
+    return "";
+  }
+};
 #endif  // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

+ 13 - 0
src/Legacy/legacyapplication.cpp

@@ -24,6 +24,18 @@ LegacyApplication::LegacyApplication() {
     modules_init_timer_.stop();
 }
 
+LegacyApplication::~LegacyApplication() {
+    PatchInstaller::instance().moveToThread(QThread::currentThread());
+    PatchDownloader::instance().moveToThread(QThread::currentThread());
+    patch_installer_thread_->terminate();
+    patch_downloader_thread_->terminate();
+    patch_installer_thread_->wait(10 * 1000); // waiting up to 10 seconds
+    patch_downloader_thread_->wait(10 * 1000); // waiting up to 10 seconds
+    delete patch_installer_thread_;
+    delete patch_downloader_thread_;
+    delete gui;
+}
+
 bool LegacyApplication::init()
 {
     qt_ntfs_permission_lookup++;
@@ -93,6 +105,7 @@ void LegacyApplication::InitModules()
     emit ErrorStatusChanged(status);
 
     if (status == E_NO_ERRORS) {
+        connect(&PatchDownloader::instance(), &PatchDownloader::finished, &PatchInstaller::instance(), &PatchInstaller::startPatchInstallationChain);
         QMetaObject::invokeMethod(&PatchInstaller::instance(), &PatchInstaller::init, Qt::QueuedConnection);
         QMetaObject::invokeMethod(&PatchDownloader::instance(), &PatchDownloader::init, Qt::QueuedConnection);
         QMetaObject::invokeMethod(&PatchDownloader::instance(), &PatchDownloader::startPatchDownloaderChain, Qt::QueuedConnection);

+ 1 - 0
src/Legacy/legacyapplication.h

@@ -19,6 +19,7 @@ public:
         return instance;
     }
 
+    ~LegacyApplication();
 private:
     LegacyApplication();
 

+ 148 - 54
src/Legacy/models/patchinstaller.cpp

@@ -1,6 +1,5 @@
 #include "patchinstaller.h"
 #include "models/filesystem.h"
-#include "models/downloader.h"
 #include "models/settings.h"
 
 #include <QDebug>
@@ -48,13 +47,17 @@ bool PatchInstaller::datPathIsRelevant() {
 }
 
 void PatchInstaller::deinit() {
-    emit operationStarted("deinitializeManager");
+    emit started();
     client_local_file_->Deinit();
     client_general_file_->Deinit();
-    emit operationFinished("deinitializeManager");
+    emit finished();
 }
 
-void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database& database) {
+void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database* database) {
+    if (!Settings::getValue("DatabaseNeedInstall/" + patch_name).toBool()) {
+        return;
+    }
+
     if (patch_name == "loadscreen") {
         installLoadscreens(database);
         return;
@@ -70,17 +73,17 @@ void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database& datab
         return;
     }
 
-    size_t patched_files_num = 0;
-
     LOTRO_DAT::SubfileData file;
-    int i = 0;
-    const int total_files = database.CountRows();
-    qDebug() << "Patching all files from database...";
-    while (!(file = database.GetNextFile()).Empty()) {
-        if (i * 100 / total_files != (i - 1) * 100 / total_files) {
-            qDebug() << "Completed " << i * 100 / total_files << "%";
+    qDebug() << "Total files in database " << database->CountRows();
+    qDebug() << "Patching all files from database..." << database;
+    while (!(file = database->GetNextFile()).Empty()) {
+
+        current_status.finished_parts++;
+        if (current_status.finished_parts * 100 / current_status.total_parts !=
+                (current_status.finished_parts - 1) * 100 * 10 / current_status.total_parts) {
+            // emitting if changed at least on 0.1%
+            emit progressChanged(current_status);
         }
-        ++i;
 
         if (!file.options["fid"]) {
             continue;
@@ -91,8 +94,7 @@ void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database& datab
         if (!Settings::getValue("Components/" + component_name).toBool()) {
             continue;
         }
-
-        const int dat_id = file.options["fid"].as<int>();
+        const int dat_id = file.options["did"] ? file.options["did"].as<int>() : 0;
 
         if (dat_id == E_CLIENT_LOCAL) {
             client_local_file_->PatchFile(file);
@@ -101,17 +103,15 @@ void PatchInstaller::installPatch(QString patch_name, LOTRO_DAT::Database& datab
         } else {
             qWarning() << "Unknown dat id parameter for file " << file.options["fid"].as<long long>() << " (dat id value = " << dat_id << "), SKIPPING!";
         }
-        ++patched_files_num;
     }
     Settings::setValue("DatabaseNeedInstall/" + patch_name, false);
     return;
 }
 
-// TODO
-void PatchInstaller::installLoadscreens(LOTRO_DAT::Database& database) {
-    if (!Settings::getValue("DatabaseNeedInstall/loadscreen").toBool() ||
-        !Settings::getValue("Components/loadscreens").toBool())
-    {
+void PatchInstaller::installLoadscreens(LOTRO_DAT::Database* database) {
+    if (!Settings::getValue("Components/loadscreens").toBool()) {
+        current_status.finished_parts += database->CountRows();
+        emit progressChanged(current_status);
         Settings::setValue("DatabaseNeedInstall/loadscreen", false);
         return;
     }
@@ -136,31 +136,81 @@ void PatchInstaller::installLoadscreens(LOTRO_DAT::Database& database) {
 
     QString logo_path = Settings::getValue("Lotro/game_path").toString() + "/raw/" + (locale_prefix == "English" ? "en" : locale_prefix) + "/logo/";
 
-    for (size_t i = 0; i < qMin(size_t(loadscreens_filenames.size()), database.CountRows()); ++i) {
-        data = database.GetNextFile();
+    for (size_t i = 0; i < qMin(size_t(loadscreens_filenames.size()), database->CountRows()); ++i) {
+        data = database->GetNextFile();
         QFile::remove(logo_path + loadscreens_filenames[i]);
 
         if (!data.binary_data.WriteToFile((logo_path + loadscreens_filenames[i]).toLocal8Bit())) {
             qWarning() << "InstallLoadscreens: Cannot write to file " << logo_path + loadscreens_filenames[i];
         }
 
-//        progress.install_finished_parts++;
-//        emit progressChanged(progress, this);
+        current_status.finished_parts++;
+        if (current_status.finished_parts * 100 / current_status.total_parts !=
+                (current_status.finished_parts - 1) * 100 * 10 / current_status.total_parts) {
+            // emitting if changed at least on 0.1%
+            emit progressChanged(current_status);
+        }
     }
 
     Settings::setValue("DatabaseNeedInstall/loadscreen", false);
 }
 
-// TODO
-void PatchInstaller::installVideos(LOTRO_DAT::Database& database) {
+void PatchInstaller::installVideos(LOTRO_DAT::Database* database) {
+    current_status.finished_parts += database->CountRows();
+    emit progressChanged(current_status);
+
+    if (!Settings::getValue("Components/videos").toBool()) {
+        Settings::setValue("DatabaseNeedInstall/video", false);
+        return;
+    }
+    video_downloaders_status.clear();
+    QVector<Downloader*> video_downloaders;
+
+    LOTRO_DAT::SubfileData file;
+    while (!(file = database->GetNextFile()).Empty()) {
+        if (!file.options["name"] || !file.options["url"] || !file.options["hash"] || !file.options["folder"]) {
+            continue;
+        }
+
+        const QString filename = QString::fromStdString(file.options["name"].as<std::string>());
+        const QString url = QString::fromStdString(file.options["url"].as<std::string>());
+        const QString hash = QString::fromStdString(file.options["hash"].as<std::string>());
+        const QString folder = QString::fromStdString(file.options["folder"].as<std::string>());
+
+        const QString full_filename = Settings::getValue("Lotro/game_path").toString() + "/" + folder + "/" + filename;
+        FileSystem::createFilePath(full_filename);
+        if (FileSystem::fileExists(full_filename) && FileSystem::fileHash(full_filename) == hash) {
+            continue;
+        }
+
+        QFile target_file(full_filename);
+        target_file.open(QIODevice::WriteOnly);
+
+        Downloader* video_downloader = new Downloader(this);
+        video_downloaders_status[video_downloader] = Downloader::Status();
+        video_downloader->setUrl(url);
+        video_downloader->targetFile = &target_file;
+        video_downloader->start();
+        video_downloaders.push_back(video_downloader);
+    }
+
+    for (Downloader* downloader: video_downloaders) {
+        downloader->waitForDownloaded();
+        downloader->targetFile->close();
+        downloader->targetFile = nullptr;
+        downloader->deleteLater();
+    }
+
+    Settings::setValue("DatabaseNeedInstall/video", false);
 }
 
 // ############## PUBLIC SLOTS ############## //
 
 void PatchInstaller::init()
 {
-    emit operationStarted("initializeManager");
+    emit started();
     qDebug() << __FUNCTION__ << "Starting initialisation of LotroDatManager";
+    qRegisterMetaType<PatchInstaller::Status>();
 
     QString game_folder = Settings::getValue("Lotro/game_path").toString();
     QString locale_prefix = Settings::getValue("Lotro/original_locale").toString();
@@ -169,8 +219,8 @@ void PatchInstaller::init()
     QString client_general_filepath = game_folder + "/client_general.dat";
 
     if (!FileSystem::fileExists(client_local_filepath) || !FileSystem::fileExists(client_general_filepath)) {
-        emit errorOccured("initializeManager", {}, "DatFilesNotFound");
-        emit operationFinished("initializeManager", {}, false);
+        qCritical() << __FUNCTION__ << "DatFiles do not exist!" << client_local_filepath << " " << client_general_filepath;
+        emit finished();
         return;
     }
 
@@ -196,10 +246,8 @@ void PatchInstaller::init()
         client_local_file_->Deinit();
         client_general_file_->Deinit();
 
-        qDebug() << __FUNCTION__ << "Finished LotroDatManager initialisation - error: DatFile initialisation error!";
-
-        emit errorOccured("initializeManager", {}, "DatInitError");
-        emit operationFinished("initializeManager", {}, false);
+        qCritical() << __FUNCTION__ << "Finished LotroDatManager initialisation - error: DatFile initialisation error!";
+        emit finished();
         return;
     }
 
@@ -207,45 +255,41 @@ void PatchInstaller::init()
              << QString::fromStdString(client_general_file_->GetFilename())
              << QString::fromStdString(client_local_file_->GetFilename());
 
-    emit operationFinished("initializeManager", {}, true);
+    emit finished();
 }
 
 void PatchInstaller::startGame(bool freeze_updates) {
     // if freeze_updates is set to True, original game
     // launcher will be replaced with special program,
     // which controls lotro startup and prevents from updates
-    emit operationStarted("startGame");
+    emit started();
 
     QString game_folder = Settings::getValue("Lotro/game_path").toString();
 
     if (game_folder == "none") {
-        qDebug() << __FUNCTION__ << "Starting game FAILED - game folder wasnt set!";
-        emit errorOccured("startGame", {}, "GameFolderNotSet");
-        emit operationFinished("startGame", {}, false);
+        qCritical() << __FUNCTION__ << "Starting game FAILED - game folder wasnt set!";
+        emit finished();
         return;
     }
 
     if (!FileSystem::fileExists(QApplication::applicationDirPath() + "/Launcher.exe")) {
-        qDebug() << __FUNCTION__ << "Starting game FAILED - no game launcher in legacy directory found!";
-        emit errorOccured("startGame", {}, "NoGameLauncherInLegacyDir");
-        emit operationFinished("startGame", {}, false);
+        qCritical() << __FUNCTION__ << "Starting game FAILED - no game launcher in legacy directory found!";
+        emit finished();
         return;
     }
 
     if (freeze_updates) {
         QFile::remove(game_folder + "/lotro_ru.exe");
         if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/lotro_ru.exe")) {
-            qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher to lotro_ru.exe!!";
-            emit errorOccured("startGame", {}, "LauncherCopyFailed");
-            emit operationFinished("startGame", {}, false);
+            qCritical() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher to lotro_ru.exe!!";
+            emit finished();
             return;
         }
 
         QFile::remove(game_folder + "/LotroLauncher.exe");
         if (!QFile::copy(QApplication::applicationDirPath() + "/Launcher.exe", game_folder + "/LotroLauncher.exe")) {
-            qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy GameLauncher to LotroLauncher!!";
-            emit errorOccured("startGame", {}, "NoAccessToGameLauncher");
-            emit operationFinished("startGame", {}, false);
+            qCritical() << __FUNCTION__ << "Starting game FAILED - cannot copy GameLauncher to LotroLauncher!!";
+            emit finished();
             return;
         }
 
@@ -257,9 +301,8 @@ void PatchInstaller::startGame(bool freeze_updates) {
     } else {
         QFile::remove(game_folder + "/LotroLauncher.exe");
         if (!QFile::copy(QApplication::applicationDirPath() + "/LotroLauncher.exe", game_folder + "/LotroLauncher.exe")) {
-            qDebug() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher from working dir to LotroLauncher in lotro dir!!";
-            emit errorOccured("startGame", {}, "NoAccessToGameLauncher");
-            emit operationFinished("startGame", {}, false);
+            qCritical() << __FUNCTION__ << "Starting game FAILED - cannot copy LotroLauncher from working dir to LotroLauncher in lotro dir!!";
+            emit finished();
             return;
         }
     }
@@ -301,11 +344,62 @@ void PatchInstaller::startGame(bool freeze_updates) {
         QApplication::quit();
     }
 
-    emit operationFinished("startGame");
+    emit finished();
 }
 
-
-// TODO
 void PatchInstaller::startPatchInstallationChain() {
+    emit started();
+    qInfo() << "PatchInstaller: Starting installation chain...";
+    const QVector<QString> patches = {"text", "font", "image", "loadscreen", "texture", "sound", "video", "micro"};
+    QMap<QString, LOTRO_DAT::Database*> patch_databases;
+
+    current_status.total_parts = 0;
+    current_status.finished_parts = 0;
+
+    for (const QString& patch: patches) {
+        if (!Settings::getValue("DatabaseNeedInstall/" + patch).toBool()) {
+            continue;
+        }
+
+        const QString patch_hashsum = Settings::getValue("PatchDatabases/" + patch + "/hashsum").toString();
+        const QString patch_filename = Settings::getValue("PatchDatabases/" + patch + "/path").toString();
+
+        const QString real_file_hashsum = FileSystem::fileHash(patch_filename);
+        if (!FileSystem::fileExists(patch_filename) || real_file_hashsum != patch_hashsum) {
+            qCritical() << "PatchInstallation: Incorrect patch file: " << patch_filename << ", hashsum: " << real_file_hashsum << ", expected: " << patch_hashsum;
+            continue;
+        }
 
+        LOTRO_DAT::Database* db = new LOTRO_DAT::Database();
+        if (!db->InitDatabase(patch_filename.toStdString())) {
+            qCritical() << "PatchInstallation: failed to initialize db " << patch_filename;
+            continue;
+        }
+        LOTRO_DAT::SubfileData data = db->GetNextFile();
+        patch_databases[patch] = db;
+        current_status.total_parts += db->CountRows();
+    }
+
+    emit progressChanged(current_status);
+    for (const QString patch_name: patch_databases.keys()) {
+        qInfo() << "PatchInstaller: Installing patch " << patch_name;
+        installPatch(patch_name, patch_databases[patch_name]);
+        patch_databases[patch_name]->CloseDatabase();
+        delete patch_databases[patch_name];
+    }
+
+    qInfo() << "PatchInstaller: Finished installation chain...";
+    emit finished();
+}
+
+
+// ############## PRIVATE SLOTS ############## //
+void PatchInstaller::onDownloaderProgressChanged(Downloader* context, Downloader::Status progress) {
+    video_downloaders_status[context] = progress;
+
+    Downloader::Status cumulative_status;
+    for (const Downloader::Status& status: video_downloaders_status.values()) {
+        cumulative_status = cumulative_status + status;
+    }
+    emit videosDownloadProgressChanged(cumulative_status);
 }

+ 18 - 18
src/Legacy/models/patchinstaller.h

@@ -7,6 +7,7 @@
 #include <QVector>
 #include <QVariant>
 
+#include "models/downloader.h"
 #include <LotroDat/datfile.h>
 #include <LotroDat/database.h>
 
@@ -16,6 +17,8 @@ class PatchInstaller : public QObject
 
 public:
     struct Status {
+        size_t total_parts = 0;
+        size_t finished_parts = 0;
 
     };
 
@@ -32,17 +35,6 @@ public:
 
 
 private:
-    enum Category : int {
-        E_TEXTS_COMMON = 100,
-        E_TEXTS_ITEMS = 101,
-        E_TEXTS_EMOTES = 102,
-        E_TEXTS_VIDEOS_REFS = 103,
-        E_MAPS_COMMON = 200,
-        E_TEXTURES_COMMON = 201,
-        E_AUDIOS_COMMON = 300,
-        E_FONTS_COMMON = 400
-    };
-
     enum RESOURCE_FILE_TYPE : int {
         E_CLIENT_LOCAL = 0,
         E_CLIENT_GENERAL = 1
@@ -54,26 +46,34 @@ private:
 
     void deinit();
 
-    void installPatch(QString patch_name, LOTRO_DAT::Database& database);
+    void installPatch(QString patch_name, LOTRO_DAT::Database* database);
 
-    void installLoadscreens(LOTRO_DAT::Database& database);
+    void installLoadscreens(LOTRO_DAT::Database* database);
 
-    void installVideos(LOTRO_DAT::Database& database);
+    void installVideos(LOTRO_DAT::Database* database);
 
 public slots:
     void init();
     void startGame(bool freeze_updates);
     void startPatchInstallationChain();
 
+private slots:
+    void onDownloaderProgressChanged(Downloader* context, Downloader::Status progress);
+
 signals:
-    void operationStarted(QString operation_name, QVector<QVariant> args = {});
-    void errorOccured(QString operation_name, QVector<QVariant> args = {}, QString message = "No error message provided");
-    void operationFinished(QString operation_name, QVector<QVariant> args = {}, bool successful = true);
-    void statusChanged(Status status);
+    void started();
+    void progressChanged(PatchInstaller::Status status);
+    void videosDownloadProgressChanged(Downloader::Status status);
+    void finished();
 
 private:
     LOTRO_DAT::DatFile* client_local_file_;
     LOTRO_DAT::DatFile* client_general_file_;
+
+    Status current_status;
+    QMap<Downloader*, Downloader::Status> video_downloaders_status;
 };
 
+Q_DECLARE_METATYPE(PatchInstaller::Status)
+
 #endif // LEGACYAPP_H

+ 32 - 1
src/Legacy/widgets/settingswidget.cpp

@@ -2,6 +2,7 @@
 
 #include "models/settings.h"
 #include "models/filesystem.h"
+#include "models/patchdownloader.h"
 
 #include "widgets/settingswidget.h"
 #include "widgets/mainwindow.h"
@@ -457,7 +458,37 @@ void SettingsWidget::on_patch_video_checkbox_clicked()
 
 void SettingsWidget::on_patch_force_apply_button_clicked()
 {
-//    QMetaObject::invokeMethod(legacy_patches_, "forceInstallPatches");
+    const auto isComponentActivated = [](QString component_name) -> bool {
+        return Settings::getValue("Components/" + component_name).toBool();
+    };
+
+    const bool texts_activated = (isComponentActivated("videos") || isComponentActivated("texts_main") || isComponentActivated("texts_items") || isComponentActivated("texts_emotes"));
+    const bool fonts_activated = (isComponentActivated("texts_main") || isComponentActivated("texts_items") || isComponentActivated("texts_emotes"));
+    const bool images_activated = isComponentActivated("maps");
+    const bool loadscreens_activated = isComponentActivated("loadscreens");
+    const bool textures_activated = isComponentActivated("textures");
+    const bool sounds_activated = isComponentActivated("sounds");
+    const bool videos_activated = isComponentActivated("videos");
+    const bool micropatch_activated = isComponentActivated("micropatch");
+
+    if (texts_activated)
+        Settings::setValue("DatabaseNeedInstall/text", true);
+    if (fonts_activated)
+        Settings::setValue("DatabaseNeedInstall/font", true);
+    if (images_activated)
+        Settings::setValue("DatabaseNeedInstall/image", true);
+    if (loadscreens_activated)
+        Settings::setValue("DatabaseNeedInstall/loadscreen", true);
+    if (textures_activated)
+        Settings::setValue("DatabaseNeedInstall/texture", true);
+    if (sounds_activated)
+        Settings::setValue("DatabaseNeedInstall/sound", true);
+    if (videos_activated)
+        Settings::setValue("DatabaseNeedInstall/video", true);
+    if (micropatch_activated)
+        Settings::setValue("DatabaseNeedInstall/micro", true);
+
+    QMetaObject::invokeMethod(&PatchDownloader::instance(), "startPatchDownloaderChain");
 }
 
 void SettingsWidget::on_micropatch_checkbox_clicked()

+ 43 - 23
src/Legacy/widgets/statuswidget.cpp

@@ -35,6 +35,10 @@ StatusWidget::StatusWidget(QWidget *parent)
     connect(&PatchDownloader::instance(), &PatchDownloader::progressChanged, this, &StatusWidget::onPatchDownloaderProgressChanged);
     connect(&PatchDownloader::instance(), &PatchDownloader::finished, this, &StatusWidget::onPatchDownloaderFinished);
 
+    connect(&PatchInstaller::instance(), &PatchInstaller::started, this, &StatusWidget::onPatchInstallerStarted);
+    connect(&PatchInstaller::instance(), &PatchInstaller::progressChanged, this, &StatusWidget::onPatchInstallerProgressChanged);
+    connect(&PatchInstaller::instance(), &PatchInstaller::finished, this, &StatusWidget::onPatchInstallerFinished);
+
     generateRandomTooltipMessage();
     random_tooltip_generator_timer_.setInterval(5 * 1000);
     connect(&random_tooltip_generator_timer_, &QTimer::timeout, this, &StatusWidget::generateRandomTooltipMessage);
@@ -248,7 +252,7 @@ void StatusWidget::onPatchDownloaderFinished() {
 }
 
 void StatusWidget::onPatchDownloaderProgressChanged(Downloader::Status status) {
-    if (last_statusbar_update_time_.elapsed() > 1000) {
+    if (last_statusbar_update_time_.elapsed() > 650) {
         double download_percent = double(status.downloaded_bytes) * 100.0 / double(status.total_bytes);
         QString text = "Загрузка данных: " + QString::number(download_percent, 'f', 1) + "% ("
                      + Downloader::getSizeFormatted(status.downloaded_bytes) + "/"
@@ -260,34 +264,50 @@ void StatusWidget::onPatchDownloaderProgressChanged(Downloader::Status status) {
     }
 }
 
+void StatusWidget::onPatchInstallerStarted() {
+    all_patch_operations_finished_ = false;
+    ui->game_button->setEnabled(false);
+    ui->check_for_updates_button->setEnabled(false);
+    setToolTipMessage("Подготовка русификатора...", E_PROCESS);
+}
+
+void StatusWidget::onPatchInstallerFinished() {
+    all_patch_operations_finished_ = true;
+    ui->game_button->setEnabled(true);
+    ui->check_for_updates_button->setEnabled(true);
+    setToolTipMessage("Все операции выполнены!", E_PROCESS);
+    process_completed_tooltip_hide_timer_.start();
+}
+
+void StatusWidget::onPatchInstallerProgressChanged(PatchInstaller::Status status) {
+    if (last_statusbar_update_time_.elapsed() > 650 || status.finished_parts == 0) {
+        QString text = "Установка русификации: "
+                     + QString::number(double(status.finished_parts) * 100.0 / double(status.total_parts), 'f', 1)
+                     + "% (" + QString::number(status.finished_parts)
+                     + " фрагментов из " + QString::number(status.total_parts) + ")";
+        setToolTipMessage(text, E_PROCESS);
+        last_statusbar_update_time_.restart();
+    }
+}
+
+void StatusWidget::onPatchInstallerVideoProgressChanged(Downloader::Status status) {
+    if (last_statusbar_update_time_.elapsed() > 650) {
+        double download_percent = double(status.downloaded_bytes) * 100.0 / double(status.total_bytes);
+        QString text = "Загрузка видеороликов: " + QString::number(download_percent, 'f', 1) + "% ("
+                     + Downloader::getSizeFormatted(status.downloaded_bytes) + "/"
+                     + Downloader::getSizeFormatted(status.total_bytes) + ")\n"
+                     + "До конца загрузки: " + Downloader::getElapsedTimeFormatted(status.elapsed_time);
+        setToolTipMessage(text, E_PROCESS);
+        last_statusbar_update_time_.restart();
+    }
+}
+
 void StatusWidget::on_game_button_clicked()
 {
     MainWindow* window = qobject_cast<MainWindow*>(parentWidget()->parentWidget()->parentWidget());
     window->showChooseVersionDialog();
 }
 
-//void StatusWidget::updatePatchProgressStatus(Patch::OperationProgress progress)
-//{
-//    if (last_statusbar_update_time_.elapsed() > 200) {
-//        QString text = "Выполнение операций...";
-//        if (progress.download_total_bytes != 0) {
-//            text += "\nЗагрузка данных: " + QString::number(progress.getDownloadPercent(), 'f', 1) + "% ("
-//                    + Downloader::getSizeFormatted(progress.download_finished_bytes) + "/"
-//                    + Downloader::getSizeFormatted(progress.download_total_bytes) + ", "
-//                    + Downloader::getSpeedFormatted(progress.download_speed) + ")\n"
-//                    + "До конца загрузки: " + Downloader::getElapsedTimeFormatted(progress.download_elapsed_time);
-//        }
-
-//        if (progress.install_total_parts != 0) {
-//            text += "\nПрименение патчей: " + QString::number(progress.getInstallPercent()) + "% "
-//                    + "(часть " + QString::number(progress.install_finished_parts + 1) + " из " + QString::number(progress.install_total_parts);
-//        }
-
-//        setToolTipMessage(text, E_PROCESS);
-//        last_statusbar_update_time_.restart();
-//    }
-//}
-
 void StatusWidget::createTooltipMessageWidget(QString tooltip_id)
 {
     tooltip_widgets_[tooltip_id] = new QLabel(ui->galadriel_widget);

+ 8 - 1
src/Legacy/widgets/statuswidget.h

@@ -11,6 +11,7 @@
 
 #include "legacyapplication.h"
 #include "models/downloader.h"
+#include "models/patchinstaller.h"
 
 namespace Ui {
 class StatusWidget;
@@ -58,7 +59,13 @@ private slots:
 
     void onPatchDownloaderProgressChanged(Downloader::Status status);
 
-//    void updatePatchProgressStatus(Patch::OperationProgress progress);
+    void onPatchInstallerStarted();
+
+    void onPatchInstallerFinished();
+
+    void onPatchInstallerProgressChanged(PatchInstaller::Status status);
+
+    void onPatchInstallerVideoProgressChanged(Downloader::Status status);
 
     void on_game_button_clicked();