Files
verify/sdk/cpp/json.hpp
T
admin ed4a561704 feat: add application API documentation and C++ SDK
- Add complete API documentation for application integration (docs/API_DOCUMENT.md)
- Fix check-update API to use version ID comparison instead of string comparison
- Add validation: client version must exist in server version list
- Add support for patch/incremental updates with base_version check
- Add C++ SDK with HTTP client, JSON parser, and crypto support
- Add simple_test.cpp for standalone testing on Windows

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 11:58:44 +08:00

354 lines
12 KiB
C++

// 简化版JSON库 - 仅包含测试所需功能
#ifndef SIMPLE_JSON_HPP
#define SIMPLE_JSON_HPP
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <stdexcept>
#include <cstdint>
#include <cmath>
namespace simple {
class json {
public:
enum class type_t {
null,
boolean,
number,
string,
array,
object
};
json() : type_(type_t::null) {}
json(std::nullptr_t) : type_(type_t::null) {}
json(bool b) : type_(type_t::boolean), bool_val_(b) {}
json(int n) : type_(type_t::number), num_val_(n) {}
json(int64_t n) : type_(type_t::number), num_val_(static_cast<double>(n)) {}
json(uint64_t n) : type_(type_t::number), num_val_(static_cast<double>(n)) {}
json(double n) : type_(type_t::number), num_val_(n) {}
json(const char* s) : type_(type_t::string), str_val_(s) {}
json(const std::string& s) : type_(type_t::string), str_val_(s) {}
type_t type() const { return type_; }
bool is_null() const { return type_ == type_t::null; }
bool is_bool() const { return type_ == type_t::boolean; }
bool is_number() const { return type_ == type_t::number; }
bool is_string() const { return type_ == type_t::string; }
bool is_array() const { return type_ == type_t::array; }
bool is_object() const { return type_ == type_t::object; }
size_t size() const {
if (type_ == type_t::array) return arr_val_.size();
if (type_ == type_t::object) return obj_val_.size();
return 0;
}
// Array access
json& operator[](size_t idx) {
if (type_ != type_t::array) {
type_ = type_t::array;
arr_val_.clear();
}
if (idx >= arr_val_.size()) arr_val_.resize(idx + 1);
return arr_val_[idx];
}
const json& operator[](size_t idx) const {
static json null_val;
if (type_ != type_t::array || idx >= arr_val_.size()) return null_val;
return arr_val_[idx];
}
// Object access
json& operator[](const std::string& key) {
if (type_ != type_t::object) {
type_ = type_t::object;
obj_val_.clear();
}
return obj_val_[key];
}
const json& operator[](const std::string& key) const {
static json null_val;
if (type_ != type_t::object) return null_val;
auto it = obj_val_.find(key);
return (it != obj_val_.end()) ? it->second : null_val;
}
// const char* overload to avoid ambiguity
json& operator[](const char* key) {
return (*this)[std::string(key)];
}
const json& operator[](const char* key) const {
return (*this)[std::string(key)];
}
bool contains(const std::string& key) const {
return type_ == type_t::object && obj_val_.find(key) != obj_val_.end();
}
// Value getters
bool get_bool() const { return bool_val_; }
double get_double() const { return num_val_; }
int64_t get_int64() const { return static_cast<int64_t>(num_val_); }
uint64_t get_uint64() const { return static_cast<uint64_t>(num_val_); }
int get_int() const { return static_cast<int>(num_val_); }
const std::string& get_string() const { return str_val_; }
// Implicit conversions
operator bool() const { return type_ == type_t::boolean ? bool_val_ : false; }
operator int() const { return static_cast<int>(num_val_); }
operator int64_t() const { return static_cast<int64_t>(num_val_); }
operator uint64_t() const { return static_cast<uint64_t>(num_val_); }
operator double() const { return num_val_; }
operator std::string() const { return str_val_; }
// Push back for arrays
void push_back(const json& val) {
if (type_ != type_t::array) {
type_ = type_t::array;
arr_val_.clear();
}
arr_val_.push_back(val);
}
// Serialization
std::string dump(int indent = -1) const {
std::ostringstream ss;
dump_impl(ss, indent >= 0 ? indent : -1, 0);
return ss.str();
}
static json parse(const std::string& str) {
size_t pos = 0;
return parse_impl(str, pos);
}
static json array() {
json j;
j.type_ = type_t::array;
return j;
}
static json object() {
json j;
j.type_ = type_t::object;
return j;
}
// Iterator support for arrays
std::vector<json>::iterator begin() { return arr_val_.begin(); }
std::vector<json>::iterator end() { return arr_val_.end(); }
std::vector<json>::const_iterator begin() const { return arr_val_.begin(); }
std::vector<json>::const_iterator end() const { return arr_val_.end(); }
// Get object items
std::map<std::string, json>::const_iterator obj_begin() const { return obj_val_.begin(); }
std::map<std::string, json>::const_iterator obj_end() const { return obj_val_.end(); }
private:
type_t type_ = type_t::null;
bool bool_val_ = false;
double num_val_ = 0.0;
std::string str_val_;
std::vector<json> arr_val_;
std::map<std::string, json> obj_val_;
void dump_impl(std::ostringstream& ss, int indent, int level) const {
switch (type_) {
case type_t::null:
ss << "null";
break;
case type_t::boolean:
ss << (bool_val_ ? "true" : "false");
break;
case type_t::number:
if (num_val_ == static_cast<int64_t>(num_val_)) {
ss << static_cast<int64_t>(num_val_);
} else {
ss << num_val_;
}
break;
case type_t::string:
ss << '"';
for (char c : str_val_) {
switch (c) {
case '"': ss << "\\\""; break;
case '\\': ss << "\\\\"; break;
case '\n': ss << "\\n"; break;
case '\r': ss << "\\r"; break;
case '\t': ss << "\\t"; break;
default: ss << c;
}
}
ss << '"';
break;
case type_t::array:
ss << '[';
if (indent >= 0) {
ss << '\n';
for (int i = 0; i <= level; ++i) ss << std::string(indent, ' ');
}
for (size_t i = 0; i < arr_val_.size(); ++i) {
if (i > 0) {
ss << ',';
if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' ');
}
arr_val_[i].dump_impl(ss, indent, level + 1);
}
if (indent >= 0) ss << '\n' << std::string(level * indent, ' ');
ss << ']';
break;
case type_t::object:
ss << '{';
if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' ');
bool first = true;
for (const auto& p : obj_val_) {
if (!first) {
ss << ',';
if (indent >= 0) ss << '\n' << std::string((level + 1) * indent, ' ');
}
first = false;
ss << '"' << p.first << "\":";
if (indent >= 0) ss << ' ';
p.second.dump_impl(ss, indent, level + 1);
}
if (indent >= 0) ss << '\n' << std::string(level * indent, ' ');
ss << '}';
break;
}
}
static json parse_impl(const std::string& str, size_t& pos) {
skip_whitespace(str, pos);
if (pos >= str.size()) throw std::runtime_error("Unexpected end of input");
char c = str[pos];
if (c == 'n') {
pos += 4;
return json();
} else if (c == 't') {
pos += 4;
return json(true);
} else if (c == 'f') {
pos += 5;
return json(false);
} else if (c == '"') {
return json(parse_string(str, pos));
} else if (c == '[') {
return parse_array(str, pos);
} else if (c == '{') {
return parse_object(str, pos);
} else if (c == '-' || std::isdigit(c)) {
return parse_number(str, pos);
}
throw std::runtime_error(std::string("Unexpected character: ") + c);
}
static void skip_whitespace(const std::string& str, size_t& pos) {
while (pos < str.size() && std::isspace(str[pos])) ++pos;
}
static std::string parse_string(const std::string& str, size_t& pos) {
++pos; // skip opening quote
std::string result;
while (pos < str.size() && str[pos] != '"') {
if (str[pos] == '\\' && pos + 1 < str.size()) {
++pos;
switch (str[pos]) {
case '"': result += '"'; break;
case '\\': result += '\\'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
default: result += str[pos];
}
} else {
result += str[pos];
}
++pos;
}
if (pos < str.size()) ++pos; // skip closing quote
return result;
}
static json parse_number(const std::string& str, size_t& pos) {
size_t start = pos;
if (str[pos] == '-') ++pos;
while (pos < str.size() && std::isdigit(str[pos])) ++pos;
if (pos < str.size() && str[pos] == '.') {
++pos;
while (pos < str.size() && std::isdigit(str[pos])) ++pos;
}
if (pos < str.size() && (str[pos] == 'e' || str[pos] == 'E')) {
++pos;
if (pos < str.size() && (str[pos] == '+' || str[pos] == '-')) ++pos;
while (pos < str.size() && std::isdigit(str[pos])) ++pos;
}
return json(std::stod(str.substr(start, pos - start)));
}
static json parse_array(const std::string& str, size_t& pos) {
json arr = json::array();
++pos; // skip '['
skip_whitespace(str, pos);
if (pos < str.size() && str[pos] == ']') {
++pos;
return arr;
}
while (pos < str.size()) {
arr.push_back(parse_impl(str, pos));
skip_whitespace(str, pos);
if (pos >= str.size() || str[pos] == ']') {
++pos;
break;
}
if (str[pos] == ',') ++pos;
skip_whitespace(str, pos);
}
return arr;
}
static json parse_object(const std::string& str, size_t& pos) {
json obj = json::object();
++pos; // skip '{'
skip_whitespace(str, pos);
if (pos < str.size() && str[pos] == '}') {
++pos;
return obj;
}
while (pos < str.size()) {
skip_whitespace(str, pos);
if (str[pos] != '"') throw std::runtime_error("Expected string key");
std::string key = parse_string(str, pos);
skip_whitespace(str, pos);
if (pos >= str.size() || str[pos] != ':') throw std::runtime_error("Expected ':'");
++pos;
obj[key] = parse_impl(str, pos);
skip_whitespace(str, pos);
if (pos >= str.size() || str[pos] == '}') {
++pos;
break;
}
if (str[pos] == ',') ++pos;
}
return obj;
}
};
// Type alias for compatibility
using nlohmann_json = json;
} // namespace simple
namespace nlohmann {
using json = simple::json;
}
#endif // SIMPLE_JSON_HPP