summary refs log tree commit diff stats
path: root/heading.cpp
blob: ff4a1a6dea859f7977770f7c28cdbfa2d25bcef6 (plain) (blame)
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
116
117
118
119
120
121
#include <stdlib.h>

#include <sstream>
#include <stdexcept>
#include <string>
#include <string_view>

#include "heading.h"

Heading::Heading(std::string_view line) {
  std::string original_line(line);

  if (line[0] != '[') {
    std::ostringstream errormsg;
    errormsg << "Heading must start with [." << std::endl
             << "Bad heading: " << original_line;
    throw std::invalid_argument(errormsg.str());
  }

  line.remove_prefix(1);
  int divider = line.find_first_of(" ]");
  if (divider == std::string_view::npos) {
    std::ostringstream errormsg;
    errormsg << "Malformatted heading: " << line << std::endl
             << "Original line: " << original_line;
    throw std::invalid_argument(errormsg.str());
  }

  type_ = line.substr(0, divider);
  line.remove_prefix(divider + 1);

  while (!line.empty()) {
    divider = line.find_first_of("=");
    if (divider == std::string_view::npos) {
      std::ostringstream errormsg;
      errormsg << "Malformatted heading: " << line << std::endl
               << "Original line: " << original_line;
      throw std::invalid_argument(errormsg.str());
    }

    std::string key(line.substr(0, divider));
    line.remove_prefix(divider + 1);

    if (line[0] == '"') {
      line.remove_prefix(1);
      divider = line.find_first_of("\"");

      if (divider == std::string_view::npos) {
        std::ostringstream errormsg;
        errormsg << "Malformatted heading: " << line << std::endl
                 << "Original line: " << original_line;
        throw std::invalid_argument(errormsg.str());
      }

      std::string strval(line.substr(0, divider));
      line.remove_prefix(divider + 2);

      keyvals_[key] = strval;
    } else if (line[0] == 'S' || line[0] == 'E') {
      ResourceRef rrval;
      rrval.internal = (line[0] == 'S');

      line.remove_prefix(13);  // SubResource(#
      divider = line.find_first_of(" ");

      if (divider == std::string_view::npos) {
        std::ostringstream errormsg;
        errormsg << "Malformatted heading: " << line << std::endl
                 << "Original line: " << original_line;
        throw std::invalid_argument(errormsg.str());
      }

      rrval.id = std::atoi(line.substr(0, divider).data());
      line.remove_prefix(divider + 3);

      keyvals_[key] = rrval;
    } else {
      divider = line.find_first_of(" ]");

      if (divider == std::string_view::npos) {
        std::ostringstream errormsg;
        errormsg << "Malformatted heading: " << line << std::endl
                 << "Original line: " << original_line;
        throw std::invalid_argument(errormsg.str());
      }

      int numval = std::atoi(line.substr(0, divider).data());
      line.remove_prefix(divider + 1);

      keyvals_[key] = numval;
    }
  }
}

std::string Heading::ToString() const {
  std::ostringstream output;
  output << "[";
  output << type_;

  for (const auto& [key, value] : keyvals_) {
    output << " " << key << "=";

    if (std::holds_alternative<int>(value)) {
      output << std::get<int>(value);
    } else if (std::holds_alternative<ResourceRef>(value)) {
      const auto& rrval = std::get<ResourceRef>(value);
      if (rrval.internal) {
        output << "Sub";
      } else {
        output << "Ext";
      }
      output << "Resource( " << rrval.id << " )";
    } else {
      output << "\"" << std::get<std::string>(value) << "\"";
    }
  }

  output << "]" << std::endl;

  return output.str();
}