FIMS  v0.8.1
Loading...
Searching...
No Matches
fims_json.hpp
Go to the documentation of this file.
1#ifndef FIMS_JSON_HPP
2#define FIMS_JSON_HPP
3
13#include <cctype>
14#include <iostream>
15#include <fstream>
16#include <map>
17#include <sstream>
18#include <string>
19#include <algorithm>
20#include <vector>
21
22namespace fims {
23class JsonValue;
24
28using JsonObject = std::map<std::string, JsonValue>;
29
33using JsonArray = std::vector<JsonValue>;
34
46
50class JsonValue {
51 public:
54
56 JsonValue(int num) : type(JsonValueType::Number), number(num) {}
57
59 JsonValue(double num) : type(JsonValueType::Number), number(num) {}
60
62 JsonValue(const std::string& str) : type(JsonValueType::String), str(str) {}
63
65 JsonValue(bool b) : type(JsonValueType::Bool), boolean(b) {}
66
68 JsonValue(const JsonObject& obj) : type(JsonValueType::Object), object(obj) {}
69
71 JsonValue(const JsonArray& arr) : type(JsonValueType::JArray), array(arr) {}
72
74 JsonValueType GetType() const { return type; }
75
77 int GetInt() const { return static_cast<int>(number); }
78
80 double GetDouble() const { return number; }
81
83 const std::string& GetString() const { return str; }
84
86 bool GetBool() const { return boolean; }
87
89 JsonObject& GetObject() { return object; }
90
92 JsonArray& GetArray() { return array; }
93
94 private:
95 JsonValueType type;
96 double number;
97 std::string str;
98 bool boolean;
99 JsonObject object;
100 JsonArray array;
101};
102
107 public:
109 JsonValue Parse(const std::string& json);
111 void WriteToFile(const std::string& filename, JsonValue jsonValue);
114
116 static std::string removeWhitespace(const std::string& input) {
117 std::string result = input;
118 result.erase(std::remove_if(result.begin(), result.end(), ::isspace),
119 result.end());
120 return result;
121 }
122
128 static std::string PrettyFormatJSON(const std::string& json) {
129 std::string result;
131 int indentLevel = 0;
132 bool inQuotes = false;
133
134 for (size_t i = 0; i < input.size(); ++i) {
135 char current = input[i];
136
137 switch (current) {
138 case '{':
139 case '[':
140 result += current;
141 if (!inQuotes) {
142 result += '\n';
143 indentLevel++;
144 result += std::string(indentLevel * 4, ' ');
145 }
146 break;
147
148 case '}':
149 case ']':
150 if (!inQuotes) {
151 result += '\n';
152 indentLevel--;
153 result += std::string(indentLevel * 4, ' ');
154 }
155 result += current;
156 break;
157
158 case ',':
159 result += current;
160 if (!inQuotes) {
161 result += '\n';
162 result += std::string(indentLevel * 4, ' ');
163 }
164 break;
165
166 case ':':
167 result += current;
168 if (!inQuotes) result += " ";
169 break;
170
171 case '"':
172 result += current;
173 // Toggle inQuotes when we encounter a double-quote
174 if (i == 0 || input[i - 1] != '\\') {
176 }
177 break;
178
179 default:
180 result += current;
181 break;
182 }
183 }
184 return result;
185 }
186
187 private:
189 void SkipWhitespace();
191 JsonValue ParseValue();
193 JsonValue ParseNumber();
195 JsonValue ParseString();
197 JsonValue ParseBool();
199 JsonValue ParseNull();
201 JsonValue ParseObject();
203 JsonValue ParseArray();
205 void WriteJsonValue(std::ofstream& outputFile, JsonValue jsonValue);
207 void PrintJsonValue(std::ostream& outputFile, JsonValue jsonValue);
209 void Indent(std::ostream& outputFile, int level);
211 void Indent(std::ofstream& outputFile, int level);
212
213 std::string data;
214 size_t position;
215};
216
222JsonValue JsonParser::Parse(const std::string& json) {
223 data = json;
224 position = 0;
225 return ParseValue();
226}
227
232void JsonParser::SkipWhitespace() {
233 while (position < data.size() && std::isspace(data[position])) {
234 position++;
235 }
236}
237
242JsonValue JsonParser::ParseValue() {
244 SkipWhitespace();
245 if (position >= data.size()) {
246 return JsonValue();
247 }
248
249 char current = data[position];
250 if (current == '{') {
251 return ParseObject();
252 } else if (current == '[') {
253 return ParseArray();
254 } else if (current == '"') {
255 return ParseString();
256 } else if (current == 't' || current == 'f') {
257 return ParseBool();
258 } else if (current == 'n') {
259 return ParseNull();
260 } else if (std::isdigit(current) || current == '-') {
261 return ParseNumber();
262 } else {
263 // Unknown token.
264 position++;
265 return JsonValue();
266 }
267}
268
273JsonValue JsonParser::ParseNumber() {
274 size_t end_pos = position;
275 bool is_float = false;
276 while (end_pos < data.size() &&
277 (std::isdigit(data[end_pos]) || data[end_pos] == '.' ||
278 data[end_pos] == '-' || data[end_pos] == 'e' ||
279 data[end_pos] == 'E')) {
280 if (data[end_pos] == '.' || data[end_pos] == 'e' || data[end_pos] == 'E') {
281 is_float = true;
282 }
283 end_pos++;
284 }
285
286 std::string num_str = data.substr(position, end_pos - position);
287 position = end_pos;
288
289 if (is_float) {
290 double num = 0.0;
291 std::istringstream(num_str) >> num;
292 return JsonValue(num);
293 } else {
294 int num = 0;
295 std::istringstream(num_str) >> num;
296 return JsonValue(num);
297 }
298}
299
304JsonValue JsonParser::ParseString() {
305 position++; // Skip the initial '"'
306 size_t end_pos = data.find('"', position);
307 if (end_pos == std::string::npos) {
308 std::string str = data.substr(position);
309 position = data.size();
310 return JsonValue(str);
311 }
312 std::string str = data.substr(position, end_pos - position);
313 position = end_pos + 1;
314 return JsonValue(str);
315}
316
321JsonValue JsonParser::ParseBool() {
322 if (data.compare(position, 4, "true") == 0) {
323 position += 4;
324 return JsonValue(true);
325 } else if (data.compare(position, 5, "false") == 0) {
326 position += 5;
327 return JsonValue(false);
328 } else {
329 // Invalid boolean value
330 return JsonValue();
331 }
332}
333
338JsonValue JsonParser::ParseNull() {
339 if (data.compare(position, 4, "null") == 0) {
340 position += 4;
341 return JsonValue();
342 } else {
343 // Invalid null value
344 return JsonValue();
345 }
346}
347
352JsonValue JsonParser::ParseObject() {
354 position++; // Skip the initial '{'
355
356 SkipWhitespace();
357 if (position < data.size() && data[position] == '}') {
358 position++; // Skip empty object close brace
359 return JsonValue(obj);
360 }
361
362 while (position < data.size() && data[position] != '}') {
363 SkipWhitespace();
364 if (position >= data.size() || data[position] != '"') {
365 return JsonValue(obj);
366 }
367 std::string key = ParseString().GetString();
368
369 SkipWhitespace();
370 if (position >= data.size() || data[position] != ':') {
371 return JsonValue(obj);
372 }
373 position++; // Skip the ':'
374 SkipWhitespace();
375 JsonValue value = ParseValue();
376 obj[key] = value;
377
378 SkipWhitespace();
379 if (position < data.size() && data[position] == ',') {
380 position++;
381 }
382 }
383
384 if (position < data.size() && data[position] == '}') {
385 position++; // Skip the trailing '}'
386 }
387 return JsonValue(obj);
388}
389
394JsonValue JsonParser::ParseArray() {
396 position++; // Skip the initial '['
397
398 SkipWhitespace();
399 if (position < data.size() && data[position] == ']') {
400 position++; // Skip empty array close bracket
401 return JsonValue(arr);
402 }
403
404 while (position < data.size() && data[position] != ']') {
405 SkipWhitespace();
406 JsonValue value = ParseValue();
407 arr.push_back(value);
408
409 SkipWhitespace();
410 if (position < data.size() && data[position] == ',') {
411 position++;
412 }
413 }
414
415 if (position < data.size() && data[position] == ']') {
416 position++; // Skip the trailing ']'
417 }
418 return JsonValue(arr);
419}
420
427 std::ofstream outputFile(filename);
428 if (!outputFile) {
429 std::cerr << "Error: Unable to open file " << filename << " for writing."
430 << std::endl;
431 return;
432 }
433
435 WriteJsonValue(outputFile, jsonValue);
436}
437
444void JsonParser::WriteJsonValue(std::ofstream& outputFile,
446 switch (jsonValue.GetType()) {
447 case JsonValueType::Null:
448 outputFile << "null";
449 break;
450 case JsonValueType::Number:
451 outputFile << jsonValue.GetDouble();
452 break;
453 case JsonValueType::String:
454 outputFile << "\"" << jsonValue.GetString() << "\"";
455 break;
456 case JsonValueType::Bool:
457 outputFile << (jsonValue.GetBool() ? "true" : "false");
458 break;
459 case JsonValueType::Object: {
460 JsonObject& obj = jsonValue.GetObject();
461 outputFile << "{";
462 bool first = true;
463 for (const auto& pair : obj) {
464 if (!first) {
465 outputFile << ",";
466 }
467 first = false;
468 outputFile << "\"" << pair.first << "\":";
469 WriteJsonValue(outputFile, pair.second);
470 }
471 outputFile << "}";
472 } break;
473 case JsonValueType::JArray: {
474 JsonArray& arr = jsonValue.GetArray();
475 outputFile << "[";
476 bool first = true;
477 for (const auto& value : arr) {
478 if (!first) {
479 outputFile << ",";
480 }
481 first = false;
482 WriteJsonValue(outputFile, value);
483 }
484 outputFile << "]";
485 } break;
486 }
487}
488
494 this->PrintJsonValue(std::cout, jsonValue);
495 std::cout << std::endl;
496}
497
503void JsonParser::PrintJsonValue(std::ostream& output, JsonValue jsonValue) {
504 switch (jsonValue.GetType()) {
505 case JsonValueType::Null:
506 output << "null";
507 break;
508 case JsonValueType::Number:
509 output << jsonValue.GetDouble();
510 break;
511 case JsonValueType::String:
512 output << "\"" << jsonValue.GetString() << "\"";
513 break;
514 case JsonValueType::Bool:
515 output << (jsonValue.GetBool() ? "true" : "false");
516 break;
517 case JsonValueType::Object: {
518 JsonObject& obj = jsonValue.GetObject();
519 output << "{";
520 bool first = true;
521 for (const auto& pair : obj) {
522 if (!first) {
523 output << ",";
524 }
525 first = false;
526 output << "\"" << pair.first << "\":";
527 PrintJsonValue(output, pair.second);
528 }
529 output << "}";
530 } break;
531 case JsonValueType::JArray: {
532 JsonArray& arr = jsonValue.GetArray();
533 output << "[";
534 bool first = true;
535 for (const auto& value : arr) {
536 if (!first) {
537 output << ",";
538 }
539 first = false;
540 PrintJsonValue(output, value);
541 }
542 output << "]";
543 } break;
544 }
545}
546} // namespace fims
547#endif
Definition fims_json.hpp:106
void Show(JsonValue jsonValue)
Definition fims_json.hpp:493
void WriteToFile(const std::string &filename, JsonValue jsonValue)
Definition fims_json.hpp:426
static std::string PrettyFormatJSON(const std::string &json)
Formats a JSON string.
Definition fims_json.hpp:128
JsonValue Parse(const std::string &json)
Definition fims_json.hpp:222
static std::string removeWhitespace(const std::string &input)
Definition fims_json.hpp:116
Definition fims_json.hpp:50
JsonValue(bool b)
Definition fims_json.hpp:65
JsonValue()
Definition fims_json.hpp:53
JsonValue(const JsonArray &arr)
Definition fims_json.hpp:71
double GetDouble() const
Definition fims_json.hpp:80
JsonArray & GetArray()
Definition fims_json.hpp:92
const std::string & GetString() const
Definition fims_json.hpp:83
JsonValue(const JsonObject &obj)
Definition fims_json.hpp:68
JsonValue(double num)
Definition fims_json.hpp:59
int GetInt() const
Definition fims_json.hpp:77
JsonObject & GetObject()
Definition fims_json.hpp:89
bool GetBool() const
Definition fims_json.hpp:86
JsonValue(const std::string &str)
Definition fims_json.hpp:62
JsonValueType GetType() const
Definition fims_json.hpp:74
JsonValue(int num)
Definition fims_json.hpp:56
std::vector< JsonValue > JsonArray
Definition fims_json.hpp:33
JsonValueType
Definition fims_json.hpp:38
@ Bool
Definition fims_json.hpp:42
@ Number
Definition fims_json.hpp:40
@ String
Definition fims_json.hpp:41
@ Object
Definition fims_json.hpp:43
@ Null
Definition fims_json.hpp:39
@ JArray
Definition fims_json.hpp:44
std::map< std::string, JsonValue > JsonObject
Definition fims_json.hpp:28
void clear_internal()
Clears the internal objects.
Definition rcpp_interface.hpp:239