unused; also not what official StepMania uses.
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
Since a few people have asked me, I figured I'd put a LICENSE file here. I wrote
|
||||
this small library as an excercise. You are welcome to include jsonxx in your
|
||||
project and redistributed it with your code in any license, provided that you
|
||||
don't sue me for anything. Please let me know if you improved it, so that I can
|
||||
merge your changes.
|
||||
@@ -1,44 +0,0 @@
|
||||
h1. Introduction
|
||||
|
||||
JSON++ is a light-weight JSON parser written in C++.
|
||||
|
||||
h2. Why another JSON parser?
|
||||
|
||||
Perhaps because web service clients are usually written in dynamic
|
||||
languages these days, none of the existing C++ JSON parsers suite my
|
||||
needs very well, so I wrote one to used in another project. My goals
|
||||
for JSON++ were:
|
||||
* Efficient in both memory and speed.
|
||||
* No third party dependencies. JSON++ only depends on the standard C++ library.
|
||||
* Cross platform.
|
||||
* Robust.
|
||||
* Small and convenient API. Most of the time, you only need to call one function and two function templates.
|
||||
* Easy to integrate. JSON++ only has one source file and one header file. Just compile the source file and link with your program.
|
||||
|
||||
h3. Usage
|
||||
|
||||
The following snippet is from one of the unit tests. It's quite self-descriptive.
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
string teststr(
|
||||
"{"
|
||||
" \"foo\" : 1,"
|
||||
" \"bar\" : false,"
|
||||
" \"person\" : {\"name\" : \"GWB\", \"age\" : 60},"
|
||||
" \"data\": [\"abcd\", 42]"
|
||||
"}"
|
||||
);
|
||||
istringstream input(teststr);
|
||||
Object o;
|
||||
assert(o.parse(input));
|
||||
assert(1 == o.get<long>("foo"));
|
||||
assert(o.has<bool>("bar"));
|
||||
assert(o.has<Object>("person"));
|
||||
assert(o.get<Object>("person").has<long>("age"));
|
||||
assert(o.has<Array>("data"));
|
||||
assert(o.get<Array>("data").get<long>(1) == 42);
|
||||
assert(o.get<Array>("data").get<string>(0) == "abcd");
|
||||
assert(!o.has<long>("data"));
|
||||
</code>
|
||||
</pre>
|
||||
@@ -1,264 +0,0 @@
|
||||
// Author: Hong Jiang <[email protected]>
|
||||
|
||||
#include "jsonxx.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace jsonxx {
|
||||
|
||||
void eat_whitespaces(std::istream& input) {
|
||||
char ch;
|
||||
do {
|
||||
input.get(ch);
|
||||
} while(isspace(ch));
|
||||
input.putback(ch);
|
||||
}
|
||||
|
||||
// Try to consume characters from the input stream and match the
|
||||
// pattern string. Leading whitespaces from the input are ignored if
|
||||
// ignore_ws is true.
|
||||
bool match(const std::string& pattern, std::istream& input,
|
||||
bool ignore_ws = true) {
|
||||
if (ignore_ws) {
|
||||
eat_whitespaces(input);
|
||||
}
|
||||
std::string::const_iterator cur(pattern.begin());
|
||||
char ch(0);
|
||||
while(input && !input.eof() && cur != pattern.end()) {
|
||||
input.get(ch);
|
||||
if (ch != *cur) {
|
||||
input.putback(ch);
|
||||
return false;
|
||||
} else {
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
return cur == pattern.end();
|
||||
}
|
||||
|
||||
bool parse_string(std::istream& input, std::string* value) {
|
||||
if (!match("\"", input)) {
|
||||
return false;
|
||||
}
|
||||
char ch;
|
||||
while(!input.eof() && input.good()) {
|
||||
input.get(ch);
|
||||
if (ch == '"') {
|
||||
break;
|
||||
}
|
||||
value->push_back(ch);
|
||||
}
|
||||
if (input && ch == '"') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_bool(std::istream& input, bool* value) {
|
||||
if (match("true", input)) {
|
||||
*value = true;
|
||||
return true;
|
||||
}
|
||||
if (match("false", input)) {
|
||||
*value = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_null(std::istream& input) {
|
||||
if (match("null", input)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_number(std::istream& input, long* value) {
|
||||
eat_whitespaces(input);
|
||||
char ch;
|
||||
std::string value_str;
|
||||
int sign = 1;
|
||||
if (match("-", input)) {
|
||||
sign = -1;
|
||||
} else {
|
||||
match("+", input);
|
||||
}
|
||||
while(input && !input.eof()) {
|
||||
input.get(ch);
|
||||
if (!isdigit(ch)) {
|
||||
input.putback(ch);
|
||||
break;
|
||||
}
|
||||
value_str.push_back(ch);
|
||||
}
|
||||
if (value_str.size() > 0) {
|
||||
std::istringstream(value_str) >> *value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Object::Object() : value_map_() {}
|
||||
|
||||
Object::~Object() {
|
||||
std::map<std::string, Value*>::iterator i;
|
||||
for (i = value_map_.begin(); i != value_map_.end(); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
|
||||
bool Object::parse(std::istream& input) {
|
||||
if (!match("{", input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
std::string key;
|
||||
if (!parse_string(input, &key)) {
|
||||
return false;
|
||||
}
|
||||
if (!match(":", input)) {
|
||||
return false;
|
||||
}
|
||||
Value* v = new Value();
|
||||
if (!v->parse(input)) {
|
||||
delete v;
|
||||
break;
|
||||
}
|
||||
value_map_[key] = v;
|
||||
} while (match(",", input));
|
||||
|
||||
if (!match("}", input)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Value::Value() : type_(INVALID_) {}
|
||||
|
||||
Value::~Value() {
|
||||
if (type_ == STRING_) {
|
||||
delete string_value_;
|
||||
}
|
||||
if (type_ == OBJECT_) {
|
||||
delete object_value_;
|
||||
}
|
||||
if (type_ == ARRAY_) {
|
||||
delete array_value_;
|
||||
}
|
||||
}
|
||||
|
||||
bool Value::parse(std::istream& input) {
|
||||
std::string string_value;
|
||||
if (parse_string(input, &string_value)) {
|
||||
string_value_ = new std::string();
|
||||
string_value_->swap(string_value);
|
||||
type_ = STRING_;
|
||||
return true;
|
||||
}
|
||||
if (parse_number(input, &integer_value_)) {
|
||||
type_ = INTEGER_;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parse_bool(input, &bool_value_)) {
|
||||
type_ = BOOL_;
|
||||
return true;
|
||||
}
|
||||
if (parse_null(input)) {
|
||||
type_ = NULL_;
|
||||
return true;
|
||||
}
|
||||
array_value_ = new Array();
|
||||
if (array_value_->parse(input)) {
|
||||
type_ = ARRAY_;
|
||||
return true;
|
||||
}
|
||||
delete array_value_;
|
||||
object_value_ = new Object();
|
||||
if (object_value_->parse(input)) {
|
||||
type_ = OBJECT_;
|
||||
return true;
|
||||
}
|
||||
delete object_value_;
|
||||
return false;
|
||||
}
|
||||
|
||||
Array::Array() : values_() {}
|
||||
|
||||
Array::~Array() {
|
||||
for (unsigned int i = 0; i < values_.size(); ++i) {
|
||||
delete values_[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool Array::parse(std::istream& input) {
|
||||
if (!match("[", input)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
Value* v = new Value();
|
||||
if (!v->parse(input)) {
|
||||
delete v;
|
||||
break;
|
||||
}
|
||||
values_.push_back(v);
|
||||
} while (match(",", input));
|
||||
|
||||
if (!match("]", input)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace jsonxx
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Value& v) {
|
||||
if (v.is<long>()) {
|
||||
return stream << v.get<long>();
|
||||
} else if (v.is<std::string>()) {
|
||||
return stream << '"' << v.get<std::string>() << '"';
|
||||
} else if (v.is<bool>()) {
|
||||
if (v.get<bool>()) {
|
||||
return stream << "true";
|
||||
} else {
|
||||
return stream << "false";
|
||||
}
|
||||
} else if (v.is<jsonxx::Value::Null>()) {
|
||||
return stream << "null";
|
||||
} else if (v.is<jsonxx::Object>()) {
|
||||
return stream << v.get<jsonxx::Object>();
|
||||
} else if (v.is<jsonxx::Array>()){
|
||||
return stream << v.get<jsonxx::Array>();
|
||||
}
|
||||
// Shouldn't reach here.
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Array& v) {
|
||||
stream << "[";
|
||||
const std::vector<jsonxx::Value*>& values(v.values());
|
||||
for (unsigned int i = 0; i < values.size()-1; ++i) {
|
||||
stream << *(values[i]) << ", ";
|
||||
}
|
||||
return stream << *(values[values.size()-1]) << "]";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Object& v) {
|
||||
stream << "{";
|
||||
const std::map<std::string, jsonxx::Value*>& kv(v.kv_map());
|
||||
for (std::map<std::string, jsonxx::Value*>::const_iterator i = kv.begin();
|
||||
i != kv.end(); /**/) {
|
||||
stream << i->first << ": " << *(i->second);
|
||||
++i;
|
||||
if ( i != kv.end()) {
|
||||
stream << ", ";
|
||||
}
|
||||
}
|
||||
return stream << "}";
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
#ifndef JSONXX_H
|
||||
#define JSONXX_H
|
||||
// Author: Hong Jiang <[email protected]>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace jsonxx {
|
||||
|
||||
// TODO: *::parse() should be static functions.
|
||||
|
||||
class Value;
|
||||
|
||||
// A JSON Object
|
||||
class Object {
|
||||
public:
|
||||
Object();
|
||||
~Object();
|
||||
bool parse(std::istream& input);
|
||||
|
||||
template <typename T>
|
||||
bool has(const std::string& key) const;
|
||||
|
||||
// Always call has<>() first. If the key doesn't exist, consider
|
||||
// the behavior undefined.
|
||||
template <typename T>
|
||||
T& get(const std::string& key) const;
|
||||
|
||||
const std::map<std::string, Value*>& kv_map() const { return value_map_; }
|
||||
private:
|
||||
Object(const Object&);
|
||||
Object& operator=(const Object&);
|
||||
|
||||
std::map<std::string, Value*> value_map_;
|
||||
};
|
||||
|
||||
class Value;
|
||||
|
||||
class Array {
|
||||
public:
|
||||
Array();
|
||||
~Array();
|
||||
bool parse(std::istream& input);
|
||||
|
||||
unsigned int size() const { return values_.size(); }
|
||||
|
||||
template <typename T>
|
||||
bool has(unsigned int i) const;
|
||||
|
||||
template <typename T>
|
||||
T& get(unsigned int i) const;
|
||||
|
||||
const std::vector<Value*>& values() const {
|
||||
return values_;
|
||||
}
|
||||
|
||||
private:
|
||||
Array(const Array&);
|
||||
Array& operator=(const Array&);
|
||||
std::vector<Value*> values_;
|
||||
};
|
||||
|
||||
// A value could be a number, an array, a string, an object, a
|
||||
// boolean, or null
|
||||
class Value {
|
||||
public:
|
||||
class Null {};
|
||||
|
||||
Value();
|
||||
~Value();
|
||||
bool parse(std::istream& input);
|
||||
template<typename T>
|
||||
bool is() const;
|
||||
template<typename T>
|
||||
T& get();
|
||||
template<typename T>
|
||||
const T& get() const;
|
||||
private:
|
||||
Value(const Value&);
|
||||
Value& operator=(const Value&);
|
||||
enum {
|
||||
INTEGER_,
|
||||
STRING_,
|
||||
BOOL_,
|
||||
NULL_,
|
||||
ARRAY_,
|
||||
OBJECT_,
|
||||
INVALID_
|
||||
} type_;
|
||||
union {
|
||||
long integer_value_;
|
||||
std::string* string_value_;
|
||||
bool bool_value_;
|
||||
Array* array_value_;
|
||||
Object* object_value_;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool Array::has(unsigned int i) const {
|
||||
if (i >= size()) {
|
||||
return false;
|
||||
} else {
|
||||
Value* v = values_.at(i);
|
||||
return v->is<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& Array::get(unsigned int i) const {
|
||||
assert(i < size());
|
||||
Value* v = values_.at(i);
|
||||
return v->get<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Object::has(const std::string& key) const {
|
||||
std::map<std::string, Value*>::const_iterator it(value_map_.find(key));
|
||||
return it != value_map_.end() && it->second->is<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& Object::get(const std::string& key) const {
|
||||
assert(has<T>(key));
|
||||
return value_map_.find(key)->second->get<T>();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<Value::Null>() const {
|
||||
return type_ == NULL_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<bool>() const {
|
||||
return type_ == BOOL_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<std::string>() const {
|
||||
return type_ == STRING_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<long>() const {
|
||||
return type_ == INTEGER_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<Array>() const {
|
||||
return type_ == ARRAY_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Value::is<Object>() const {
|
||||
return type_ == OBJECT_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool& Value::get<bool>() {
|
||||
assert(is<bool>());
|
||||
return bool_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string& Value::get<std::string>() {
|
||||
assert(is<std::string>());
|
||||
return *string_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline long& Value::get<long>() {
|
||||
assert(is<long>());
|
||||
return integer_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Array& Value::get<Array>() {
|
||||
assert(is<Array>());
|
||||
return *array_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Object& Value::get<Object>() {
|
||||
assert(is<Object>());
|
||||
return *object_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const bool& Value::get<bool>() const {
|
||||
assert(is<bool>());
|
||||
return bool_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const std::string& Value::get<std::string>() const {
|
||||
assert(is<std::string>());
|
||||
return *string_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const long& Value::get<long>() const {
|
||||
assert(is<long>());
|
||||
return integer_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const Array& Value::get<Array>() const {
|
||||
assert(is<Array>());
|
||||
return *array_value_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const Object& Value::get<Object>() const {
|
||||
assert(is<Object>());
|
||||
return *object_value_;
|
||||
}
|
||||
|
||||
} // namespace jsonxx
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Value& v);
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Object& v);
|
||||
std::ostream& operator<<(std::ostream& stream, const jsonxx::Array& v);
|
||||
|
||||
#endif
|
||||
@@ -1,149 +0,0 @@
|
||||
// Author: Hong Jiang <[email protected]>
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "jsonxx.h"
|
||||
|
||||
namespace jsonxx {
|
||||
bool parse_string(std::istream& input, std::string* value);
|
||||
bool parse_number(std::istream& input, long* value);
|
||||
bool match(const std::string& pattern, std::istream& input, bool ignore_ws = true);
|
||||
}
|
||||
|
||||
int main() {
|
||||
using namespace jsonxx;
|
||||
using namespace std;
|
||||
{
|
||||
string teststr("\"field1\"");
|
||||
string value;
|
||||
istringstream input(teststr);
|
||||
assert(parse_string(input, &value));
|
||||
}
|
||||
{
|
||||
string teststr("\" field1\"");
|
||||
string value;
|
||||
istringstream input(teststr);
|
||||
assert(parse_string(input, &value));
|
||||
}
|
||||
{
|
||||
string teststr(" \"field1\"");
|
||||
string value;
|
||||
istringstream input(teststr);
|
||||
assert(parse_string(input, &value));
|
||||
}
|
||||
{
|
||||
string teststr("6");
|
||||
istringstream input(teststr);
|
||||
long value;
|
||||
assert(parse_number(input, &value));
|
||||
}
|
||||
{
|
||||
string teststr(" }");
|
||||
istringstream input(teststr);
|
||||
assert(match("}", input));
|
||||
}
|
||||
{
|
||||
string teststr("{ \"field1\" : 6 }");
|
||||
istringstream input(teststr);
|
||||
Object o;
|
||||
assert(o.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("{ \"field1 : 6 }");
|
||||
istringstream input(teststr);
|
||||
Object o;
|
||||
assert(!o.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("6");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("+6");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("-6");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("asdf");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(!v.parse(input));
|
||||
}
|
||||
{
|
||||
string teststr("true");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
assert(v.is<bool>());
|
||||
}
|
||||
{
|
||||
string teststr("false");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
assert(v.is<bool>());
|
||||
assert(v.get<bool>() == false);
|
||||
}
|
||||
{
|
||||
string teststr("null");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
assert(v.is<Value::Null>());
|
||||
assert(!v.is<bool>());
|
||||
}
|
||||
{
|
||||
string teststr("\"field1\"");
|
||||
istringstream input(teststr);
|
||||
Value v;
|
||||
assert(v.parse(input));
|
||||
assert(v.is<std::string>());
|
||||
assert("field1" == v.get<std::string>());
|
||||
ostringstream stream;
|
||||
stream << v;
|
||||
assert(stream.str() == "\"field1\"");
|
||||
}
|
||||
{
|
||||
string teststr("[\"field1\", 6]");
|
||||
istringstream input(teststr);
|
||||
Array v;
|
||||
assert(v.parse(input));
|
||||
assert(v.has<std::string>(0));
|
||||
assert("field1" == v.get<std::string>(0));
|
||||
assert(v.has<long>(1));
|
||||
assert(6 == v.get<long>(1));
|
||||
assert(!v.has<bool>(2));
|
||||
}
|
||||
{
|
||||
string teststr(
|
||||
"{"
|
||||
" \"foo\" : 1,"
|
||||
" \"bar\" : false,"
|
||||
" \"person\" : {\"name\" : \"GWB\", \"age\" : 60},"
|
||||
" \"data\": [\"abcd\", 42]"
|
||||
"}"
|
||||
);
|
||||
istringstream input(teststr);
|
||||
Object o;
|
||||
assert(o.parse(input));
|
||||
assert(1 == o.get<long>("foo"));
|
||||
assert(o.has<bool>("bar"));
|
||||
assert(o.has<Object>("person"));
|
||||
assert(o.get<Object>("person").has<long>("age"));
|
||||
assert(o.has<Array>("data"));
|
||||
assert(o.get<Array>("data").get<long>(1) == 42);
|
||||
assert(o.get<Array>("data").get<string>(0) == "abcd");
|
||||
assert(!o.has<long>("data"));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
http://hjiang.net/archives/245
|
||||
and
|
||||
http://github.com/hjiang/jsonxx
|
||||
Reference in New Issue
Block a user