aboutsummaryrefslogtreecommitdiff
path: root/libs/installer_bsplugins/src/TESData/FormParser.h
blob: b0220a03fa6b7012dde470624dd406fa8acfdf1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#ifndef TESDATA_FORMPARSER_H
#define TESDATA_FORMPARSER_H

#include "DataItem.h"
#include "TESFile/Stream.h"
#include "TESFile/Type.h"

#include <coroutine>
#include <istream>
#include <map>
#include <memory>
#include <span>
#include <string>

using namespace Qt::Literals::StringLiterals;

namespace TESData
{

namespace Parse
{
  struct Promise;

  struct Task : std::coroutine_handle<Promise>
  {
    using promise_type = Promise;

    Task(std::coroutine_handle<Promise>&& promise)
        : std::coroutine_handle<Promise>::coroutine_handle(promise)
    {}
  };

  struct Promise
  {
    Task get_return_object() { return {Task::from_promise(*this)}; }
    std::suspend_always initial_suspend() noexcept { return {}; }
    std::suspend_always final_suspend() noexcept { return {}; }
    void return_void() {}
    void unhandled_exception() {}
  };
}  // namespace Parse

using ParseTask = Parse::Task;

class IFormParser
{
public:
  virtual void parseFlags(DataItem* root, int fileIndex, std::uint32_t flags) const = 0;

  virtual ParseTask parseForm(DataItem* root, int fileIndex, bool localized,
                              std::span<const std::string> masters,
                              const std::string& plugin, const TESFile::Type& signature,
                              std::istream* const& stream) const = 0;
};

class FormParserManager final
{
  template <typename T, TESFile::Type Type>
  friend struct RegisterFormParser;

public:
  enum class Game
  {
    TES4,
    FO3,
    FNV,
    TES5,
    FO4,
    SSE,

    Unknown
  };

  FormParserManager() = delete;

  [[nodiscard]] static std::shared_ptr<const IFormParser> getParser(Game game,
                                                                    TESFile::Type type);

private:
  using RegistrationMap = std::map<TESFile::Type, std::shared_ptr<IFormParser>>;

  static auto registrationMap() -> RegistrationMap&;
};

template <typename T, TESFile::Type Type>
struct [[maybe_unused]] RegisterFormParser
{
  explicit RegisterFormParser()
  {
    FormParserManager::registrationMap().emplace(Type, std::make_shared<T>());
  }
};

template <TESFile::Type Type = {}>
class FormParser : public IFormParser
{
  inline static RegisterFormParser<FormParser<Type>, Type> reg{};

public:
  void parseFlags(DataItem* root, int fileIndex, std::uint32_t flags) const override;

  ParseTask parseForm(DataItem* root, int fileIndex, bool localized,
                      std::span<const std::string> masters, const std::string& plugin,
                      const TESFile::Type& signature,
                      std::istream* const& stream) const override;
};

QString readBytes(std::istream& stream, int size);
QString readLstring(bool localized, std::istream& stream);
QString readFormId(std::span<const std::string> masters, const std::string& plugin,
                   std::istream& stream);

}  // namespace TESData

#endif  // TESDATA_FORMPARSER_H