vfilesys (more robust resource handling to fix #7), (vvd,vtx) clean, vdf better regex...
[tar-legacy.git] / MCDV / vdf.hpp
1 #pragma once
2 #include <iostream>
3 #include <fstream>
4 #include <sstream>
5 #include <vector>
6 #include <map>
7 #include <regex>
8
9 #include <chrono>
10
11 #include "Util.h"
12
13 #define _USE_REGEX
14
15 namespace kv
16 {
17 //const std::regex reg_kv("(\"([^=\"]*)\")|([^=\\s]+)");
18 const std::regex reg_kv(R"vv("(.*?)"|([^\s]+))vv");
19
20 template<typename T>
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()));
24 }
25
26 std::string tryGetStringValue(std::map<std::string, std::string> map, const char* key, std::string defaultValue = "") {
27 if (!map.count(key)) return defaultValue;
28 return map[key];
29 }
30
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;
34
35 int vc = -1;
36 while (map.count(key + (++vc > 0 ? std::to_string(vc) : ""))) list.push_back(map[key + (vc > 0 ? std::to_string(vc) : "")]);
37
38 return list;
39 }
40
41 class DataBlock
42 {
43 public:
44 std::string name = "";
45 std::vector<DataBlock> SubBlocks;
46 std::map<std::string, std::string> Values;
47
48 DataBlock() {}
49
50 DataBlock(std::istringstream* stream, std::string name = "", void* progress_callback = NULL) {
51 this->name = sutil::trim(name);
52
53 std::string line, prev = "";
54 while (std::getline(*stream, line)) {
55 if(progress_callback != NULL) util::CastFunctionPtr(progress_callback); //Increment line counter
56
57 line = split(line, "//")[0];
58
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));
63 continue;
64 }
65 if (sutil::get_unquoted_material(line).find("}") != std::string::npos) {
66 return;
67 }
68
69 #ifndef _USE_REGEX
70 // Regex is so fucking slow in debug mode its unreal
71 // Rather have it mess up than take 10 hours
72
73 std::vector<std::string> s1 = split(line, '"');
74 std::vector<std::string> strings;
75
76 if (s1.size() >= 3)
77 {
78 strings.push_back(s1[1]);
79 strings.push_back(s1[3]);
80 }
81 #endif
82 #ifdef _USE_REGEX
83 std::vector<std::string> strings = sutil::regexmulti(line, reg_kv);
84 #endif
85
86 for (int i = 0; i < strings.size(); i++) {
87 strings[i] = sutil::removeChar(strings[i], '"');
88 }
89
90 if (strings.size() == 2) {
91 // Fix for multiply defined key-values (THANKS VALVE APPRECIATE THAT)
92 std::string keyname = strings[0];
93 int i = -1;
94 while (this->Values.count((++i > 0 ? keyname + std::to_string(i) : keyname)));
95
96 this->Values.insert({ i > 0 ? keyname + std::to_string(i) : keyname, strings[1] });
97 }
98
99 prev = line;
100 }
101 }
102
103 void Serialize(std::ofstream& stream, int depth = 0)
104 {
105 //Build indentation levels
106 std::string indenta = "";
107 for (int i = 0; i < depth; i++)
108 indenta += "\t";
109 std::string indentb = indenta + "\t";
110
111 if (depth >= 0)
112 stream << indenta << this->name << std::endl << indenta << "{" << std::endl;
113
114 //Write kvs
115 for (auto const& x : this->Values)
116 stream << indentb << "\"" << x.first << "\" \"" << x.second << "\"" << std::endl;
117
118 //Write subdata recursively
119 for (int i = 0; i < this->SubBlocks.size(); i++)
120 this->SubBlocks[i].Serialize(stream, depth + 1);
121
122 if (depth >= 0)
123 stream << indenta << "}" << std::endl;
124 }
125
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];
131 }
132
133 return NULL;
134 }
135
136 //Gets all sub blocks by type
137 std::vector<DataBlock> GetAllByName(std::string _name) {
138 std::vector<DataBlock> c;
139
140 for (int i = 0; i < this->SubBlocks.size(); i++) {
141 if (_name == this->SubBlocks[i].name)
142 c.push_back(this->SubBlocks[i]);
143 }
144
145 return c;
146 }
147 };
148
149 class FileData
150 {
151 public:
152 DataBlock headNode;
153
154 FileData(std::string filestring, void* progress_callback = NULL)
155 {
156 std::istringstream sr(filestring);
157
158 auto start = std::chrono::high_resolution_clock::now();
159
160 this->headNode = DataBlock(&sr, "", progress_callback);
161
162
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;
166 }
167
168 FileData()
169 {
170
171 }
172
173 ~FileData() {}
174 };
175 }