17 //const std::regex reg_kv("(\"([^=\"]*)\")|([^=\\s]+)");
18 const std::regex reg_kv(R"vv("(.*?)"|([^\s]+))vv");
21 T tryGetValue(std::map<std::string, std::string> map, const char* key, T defaultValue) {
22 if (!map.count(key)) return defaultValue;
23 return static_cast<T>(::atof(map[key].c_str()));
26 std::string tryGetStringValue(std::map<std::string, std::string> map, const char* key, std::string defaultValue = "") {
27 if (!map.count(key)) return defaultValue;
31 /* Create list from map and key */
32 std::vector<std::string> getList(std::map<std::string, std::string> map, const char* key) {
33 std::vector<std::string> list;
36 while (map.count(key + (++vc > 0 ? std::to_string(vc) : ""))) list.push_back(map[key + (vc > 0 ? std::to_string(vc) : "")]);
44 std::string name = "";
45 std::vector<DataBlock> SubBlocks;
46 std::map<std::string, std::string> Values;
50 DataBlock(std::istringstream* stream, std::string name = "", void* progress_callback = NULL) {
51 this->name = sutil::trim(name);
53 std::string line, prev = "";
54 while (std::getline(*stream, line)) {
55 if(progress_callback != NULL) util::CastFunctionPtr(progress_callback); //Increment line counter
57 line = split(line, "//")[0];
59 if (sutil::get_unquoted_material(line).find("{") != std::string::npos) {
60 std::string pname = prev;
61 prev.erase(std::remove(prev.begin(), prev.end(), '"'), prev.end());
62 this->SubBlocks.push_back(DataBlock(stream, pname, progress_callback));
65 if (sutil::get_unquoted_material(line).find("}") != std::string::npos) {
70 // Regex is so fucking slow in debug mode its unreal
71 // Rather have it mess up than take 10 hours
73 std::vector<std::string> s1 = split(line, '"');
74 std::vector<std::string> strings;
78 strings.push_back(s1[1]);
79 strings.push_back(s1[3]);
83 std::vector<std::string> strings = sutil::regexmulti(line, reg_kv);
86 for (int i = 0; i < strings.size(); i++) {
87 strings[i] = sutil::removeChar(strings[i], '"');
90 if (strings.size() == 2) {
91 // Fix for multiply defined key-values (THANKS VALVE APPRECIATE THAT)
92 std::string keyname = strings[0];
94 while (this->Values.count((++i > 0 ? keyname + std::to_string(i) : keyname)));
96 this->Values.insert({ i > 0 ? keyname + std::to_string(i) : keyname, strings[1] });
103 void Serialize(std::ofstream& stream, int depth = 0)
105 //Build indentation levels
106 std::string indenta = "";
107 for (int i = 0; i < depth; i++)
109 std::string indentb = indenta + "\t";
112 stream << indenta << this->name << std::endl << indenta << "{" << std::endl;
115 for (auto const& x : this->Values)
116 stream << indentb << "\"" << x.first << "\" \"" << x.second << "\"" << std::endl;
118 //Write subdata recursively
119 for (int i = 0; i < this->SubBlocks.size(); i++)
120 this->SubBlocks[i].Serialize(stream, depth + 1);
123 stream << indenta << "}" << std::endl;
126 //Scan for sub block with name
127 DataBlock* GetFirstByName(std::string _name) {
128 for (int i = 0; i < this->SubBlocks.size(); i++) {
129 if (_name == this->SubBlocks[i].name)
130 return &this->SubBlocks[i];
136 //Gets all sub blocks by type
137 std::vector<DataBlock> GetAllByName(std::string _name) {
138 std::vector<DataBlock> c;
140 for (int i = 0; i < this->SubBlocks.size(); i++) {
141 if (_name == this->SubBlocks[i].name)
142 c.push_back(this->SubBlocks[i]);
154 FileData(std::string filestring, void* progress_callback = NULL)
156 std::istringstream sr(filestring);
158 auto start = std::chrono::high_resolution_clock::now();
160 this->headNode = DataBlock(&sr, "", progress_callback);
163 auto elapsed = std::chrono::high_resolution_clock::now() - start;
164 long long milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
165 std::cout << "KV Read time: " << milliseconds << "ms" << std::endl;