Select Git revision
-
Alexis Nasr authoredAlexis Nasr authored
json.h 7.44 KiB
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
namespace json {
typedef enum { Null, True, False, Number, String, List, Object } Type;
std::string replace_all(std::string subject, const std::string& search, const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
class Value {
public:
Type type;
double number;
std::string string;
std::vector<Value> list;
std::map<std::string, Value> object;
public:
Value() : type(Null) { }
Value(Type _type) : type(_type) { }
Value(const std::string& text) : type(String), string(text) { }
Value(double _number) : type(Number), number(_number) { }
void append(const Value& v) { list.push_back(v); }
Value& operator[](int index) { return list[index]; }
Value& operator[](const std::string& key) {
return object[key]; }
int length() const {
if(type == List) { return list.size(); }
if(type == Object) { return object.size(); }
if(type == String) { return string.length(); }
return 1;
}
std::string to_json() const {
std::stringstream out;
if(type == String) out << "\"" << replace_all(string, "\"", "\\\"") << "\"";
else if(type == Null) out << "null";
else if(type == True) out << "true";
else if(type == False) out << "false";
else if(type == Number) out << number;
else if(type == List) {
out << "[";
for(int i = 0; i < length(); i++) {
if(i > 0) out << ",";
out << list[i].to_json();
}
out << "]";
} else if(type == Object) {
out << "{";
for(std::map<std::string, Value>::const_iterator i = begin(); i != end(); i++) {
if(i != begin()) out << ",";
out << "\"" << i->first << "\":" << i->second.to_json();
}
out << "}";
} else {
out << "error";
}
return out.str();
}
std::string to_string() const { return string; }
int to_int() const { return (int) number; }
double to_double() const { return (double) number; }
std::map<std::string, Value>::const_iterator begin() const { return object.begin(); }
std::map<std::string, Value>::const_iterator end() const { return object.end(); }
};
class Iterator {
const Value& backend;
std::map<std::string, Value>::const_iterator iterator;
public:
Iterator(const Value& target) : backend(target), iterator(target.begin()) { }
const std::string key() { return iterator->first; }
const Value value() { return iterator->second; }
bool hasNext() { return iterator != backend.end(); }
void next() { iterator++; }
};
class Parser {
const char* input;
void error() {
throw std::string("error at \"" + std::string(input) + "\"");
}
void space() {
while(*input != '\0' && (*input == ' ' || *input == '\t' || *input == '\n' || *input == '\r')) input++;
}
Value null() {
input += 4;
return Value(Null);
}
Value _false() {
input += 5;
return Value(False);
}
Value _true() {
input += 4;
return Value(True);
}
Value number() {
char* end = NULL;
double value = strtod(input, &end);
input = end;
return Value(value);
}
Value string() {
input++;
char prev = '"';
const char* start = input;
while(*input != '\0') {
if(*input == '"' && prev != '\\') {
char text[input - start + 1];
strncpy(text, start, input - start);
text[input - start] = '\0';
input++;
return Value(replace_all(text, "\\\"", "\""));
}
prev = *input;
input++;
}
error();
return Value(Null);
}
Value list() {
input++;
Value l(List);
while(*input != '\0') {
space();
if(*input == ']') {
input++;
return l;
}
l.append(value());
space();
if(*input == ']') {
input++;
return l;
} else if(*input == ',') {
input++;
} else {
error();
}
}
error();
return Value(Null);
}
Value object() {
input++;
Value o(Object);
while(*input != '\0') {
space();
if(*input == '}') {
input++;
return o;
}
std::string key = string().to_string();
space();
if(*input != ':') error();
else {
input++;
space();
o[key] = value();
space();
}
if(*input == '}') {
input++;
return o;
} else if(*input == ',') {
input++;
} else {
error();
return Value(Null);
}
}
error();
return Value(Null);
}
Value value() {
if(*input == '{') return object();
else if(*input == '[') return list();
else if(*input == '"') return string();
else if(!strncmp(input, "true", 4)) return _true();
else if(!strncmp(input, "false", 5)) return _false();
else if(!strncmp(input, "null", 4)) return null();
else return number();
}
public:
Value parse(const char* p) {
input = p;
space();
Value v = value();
space();
if(*input != '\0') error();
return v;
}
};
Value parse(const std::string& str) {
return Parser().parse(str.c_str());
}
Value parse(const char* input) {
return Parser().parse(input);
}
Value parse_file(const char* filename) {
FILE* fp = fopen(filename, "r");
if(!fp) { std::cerr << "ERROR: cannot load file \"" << filename << "\"\n"; exit(1); }
fseek(fp, 0, SEEK_END);
off_t length = ftell(fp);
char* content = new char[length + 1];
fseek(fp, 0, SEEK_SET);
size_t read = fread(content, length, 1, fp);
if(read != 1) { std::cerr << "ERROR: could not read content of \"" << filename << "\"\n"; exit(1); }
fclose(fp);
content[length] = '\0';
Value v = parse(content);
delete[] content;
return v;
}
}