Qt寫一個惠爾頓網路自動登入程式
阿新 • • 發佈:2022-04-22
QT做一個惠爾頓自動登入程式。
出於某種要求,公司使用了這個惠爾頓網路安全審計系統。
關鍵是這個做得不太行吧,提供的GUI程式,又大又難用(搞不懂,簡單的東西做這麼複雜)。
還提供了網頁登入程式,這個就簡單,只需要輸入賬號密碼點選登入即可。
但是吧,他喵的,必須保持登入頁面開啟,也就是一直佔用那個瀏覽器的一個標籤頁。
這他喵的也很噁心了,尤其是針對瀏覽器使用和切換都很頻繁的人來說。
是可忍,孰不可忍。使用fidlder一抓包,一Compaser post一下,就發現了登入的網頁,以及引數。
POST http://192.168.0.98/user-login-auth HTTP/1.1 Host: 192.168.0.98 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 param%5BUserName%5D=username¶m%5BUserPswd%5D=123456
網頁版確實簡單,可以精簡到簡單的post賬號和密碼就能驗證通過,當然,需要對一些字元進行url編碼
沒什麼好分析的,彈需求。
1.越簡單越好,我們只想使用這軟體一次,以後再也不用自己輸出賬號密碼,然後點選登入。 那就需要讀寫檔案,儲存賬號密碼。//簡單起見,自己構造個json檔案即可 那就需要開機自動執行。//登錄檔操作 2.雖然我沒遇見過,但是他們反映使用過程中,雖然登入成功,但是後面還是斷網了。也就是連線可能不穩定。 那就需要不停的檢測網路連線,斷網就需要自己post登入。 3.雖然直接打包成壓縮檔案也能用,但是使用的物件不全是程式設計師,要是隨便的移動軟體,豈不是多了很多登錄檔垃圾。 那就弄成安裝包吧。
主題程式碼如下:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QDebug> #include <QNetworkRequest> #include <QMessageBox> #include <QNetworkReply> #include <QNetworkAccessManager> #include <QFile> #include <iostream> #include <QCloseEvent> #include <QTimer> //#define DEBUG #define QS(x) QString::fromUtf8(x) QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); bool checkFile(); void autoLogin(QString un,QString ps); void CreateSystemTrayIcon(); private slots: void on_pushButton_clicked(); void requestFinished(QNetworkReply*); void on_lineEdit_2_returnPressed(); private: Ui::Widget *ui; QString success; QString fail; QString username = ""; QString password = ""; QTimer time; #ifdef DEBUG const QString LOGIN = "http://192.168.0.102:90/test.html"; #else const QString LOGIN="http://192.168.0.98/user-login-auth"; #endif protected: void closeEvent(QCloseEvent *event);//由於要關閉視窗變為隱藏至托盤圖示,所以要重寫close事件 }; #endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include "jsonxx.h"
#include "jsonxx.cc"
#include <qnetworkproxy.h>
#include <QTextCodec>
#include <QMenu>
#include <QSystemTrayIcon>
#include <QAction>
#include <QSettings>
using namespace std;
using namespace jsonxx;
#define AUTO_RUN_KEY "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
//#define DEBUG
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
success = "color:green";
fail = "color:red";
time.setInterval(15000);//15s自動登入一次
QObject::connect(&time, &QTimer::timeout, [=]()
{
autoLogin(username,password);
});
if(checkFile())
{
//隱藏到托盤
CreateSystemTrayIcon();
}
}
Widget::~Widget()
{
delete ui;
}
//讀取配置檔案
bool Widget::checkFile()
{
QFile file("config.txt");
if(!file.open(QIODevice::ReadOnly|QIODevice::Text))
{
qDebug()<<file.errorString();
return false;
}
else
{
qDebug()<<"openok";
}
QByteArray tt = file.read(1024);
QString tta;
tta = tta.fromLocal8Bit(tt);
string str = tta.toStdString();
Object o;
if(o.parse(str))
{
QString username = "";
QString password = "";
QString tmp = "";
qDebug()<<"success to parse";
if(!o.has<String>("un"))
{
return false;
}
str = o.get<String>("un");
username = QString::fromStdString(str);
ui->lineEdit->setText(username);
if(!o.has<String>("ps"))
{
return false;
}
str = o.get<String>("ps");
password = QString::fromStdString(str);
ui->lineEdit_2->setText(password);
if(!o.has<String>("autoLogin"))
{
qDebug()<<"meiyou";
return false;
}
str = o.get<String>("autoLogin");
tmp = QString::fromStdString(str);
if("true"!=tmp){
return false;
}
ui->checkBox->setCheckState(Qt::Checked);
autoLogin(username,password);
}else{
return false;
}
}
void Widget::autoLogin(QString un, QString ps)
{
QNetworkRequest request;
QNetworkAccessManager* naManager = new QNetworkAccessManager(this);
QMetaObject::Connection connRet = QObject::connect(naManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
Q_ASSERT(connRet);
request.setUrl(QUrl(LOGIN));
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
QByteArray postData;
#ifdef DEBUG
QNetworkProxy proxy;
proxy.setHostName("127.0.0.1");
proxy.setPort(8888);
naManager->setProxy(proxy);
#endif
QString s = QUrl::toPercentEncoding("param[UserName]") + "=" + QUrl::toPercentEncoding(un) + "&" + QUrl::toPercentEncoding("param[UserPswd]") + "=" + QUrl::toPercentEncoding(ps);
postData.append(s);
qDebug()<<s<<endl;
naManager->post(request,postData);
username = un;
password = ps;
}
void Widget::CreateSystemTrayIcon()
{
QAction* show = new QAction(QS("開啟介面"));
QAction* login = new QAction(QS("登入"));
QAction* quit = new QAction(QS("退出"));
connect(show, &QAction::triggered, this, [=]()
{
this->showNormal();
});
connect(login, &QAction::triggered, this, [=]()
{
if(!username.isEmpty()&&!password.isEmpty())
{
this->autoLogin(username,password);
}
else
{
on_pushButton_clicked();
}
});
connect(quit , &QAction::triggered, this, [=]()
{
qDebug()<<"exit";
QApplication::exit(0);
});
QMenu* trayMenu = new QMenu(this);//選單
trayMenu->addAction(show);
trayMenu->addAction(login);
trayMenu->addAction(quit);
//建立一個系統托盤
QSystemTrayIcon* trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(QIcon(QPixmap(":/photo/pic.ico")));
trayIcon->setContextMenu(trayMenu);//設定選單
trayIcon->show();
connect(trayIcon, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason)
{
qDebug()<<reason;
qDebug()<<QApplication::mouseButtons();
if(reason == QSystemTrayIcon::Trigger&&QApplication::mouseButtons()==Qt::LeftButton)
{
this->showNormal();
}
else
{
qDebug()<<"沒到條件";
}
});
}
void Widget::requestFinished(QNetworkReply * reply)
{
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if(statusCode.isValid())
{
qDebug() << "status code=" << statusCode.toInt();
}
QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
if(reason.isValid())
{
qDebug() << "reason=" << reason.toString();
#ifdef DEBUG
if(reason.toString().contains("allowed",Qt::CaseInsensitive))
{
qDebug()<<"success";
ui->label_3->setStyleSheet(success);
ui->label_3->setText(QS("登入成功"));
time.start();
}
else
{
qDebug()<<"fail";
ui->label_3->setStyleSheet(fail);
ui->label_3->setText(QS("登入失敗"));
time.stop();
username = "";
password = "";
this->showNormal();
}
#endif
}
QNetworkReply::NetworkError err = reply->error();
if(err != QNetworkReply::NoError) {
qDebug() << "Failed: " << reply->errorString();//彈出警告框
ui->label_3->setStyleSheet(fail);
ui->label_3->setText(QS("登入失敗"));
username = "";
password = "";
time.stop();
this->showNormal();
return;
}
else {
QString s = reply->readAll();
if(s.contains("success",Qt::CaseInsensitive))//不區分大小寫
{
ui->label_3->setStyleSheet(success);
ui->label_3->setText(QS("登入成功"));
time.start();
}
else
{
ui->label_3->setStyleSheet(fail);
ui->label_3->setText(QS("登入失敗"));
username = "";
password = "";
time.stop();
this->showNormal();
}
}
}
void Widget::on_pushButton_clicked()
{
bool check = ui->checkBox->checkState();
QString username = ui->lineEdit->text();
QString password = ui->lineEdit_2->text();
if(username.isEmpty())
{
QMessageBox::information(NULL,QS("提示"),QS("請輸入賬號"),QMessageBox::Ok);
return;
}
if(password.isEmpty())
{
QMessageBox::information(NULL,QS("提示"),QS("請輸入賬號"),QMessageBox::Ok);
return;
}
qDebug()<<username<<endl;
qDebug()<<password<<endl;
if(check)
{
QString str = "";
str = "{'un':'"+username+"','ps':'"+password+"','autoLogin':'true'}";
QFile file("config.txt");
if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
return;
}
QByteArray data = str.toLocal8Bit();
file.write(data);
qDebug()<<"length = "<<data.length()<<endl;
file.close();
QString application_name = QApplication::applicationName();//獲取應用名稱
QSettings *settings = new QSettings(AUTO_RUN_KEY, QSettings::NativeFormat);//建立QSetting, 需要新增QSetting標頭檔案
QString application_path = QApplication::applicationFilePath();//找到應用的目錄
settings->setValue(application_name, application_path.replace("/", "\\"));//寫入登錄檔
}
autoLogin(username,password);
}
void Widget::on_lineEdit_2_returnPressed()
{
on_pushButton_clicked();
}
void Widget::closeEvent(QCloseEvent *event)
{
hide();//隱藏視窗
event->ignore();//忽略關閉事件
}
jsonxx.h
// -*- mode: c++; c-basic-offset: 4; -*-
// Author: Hong Jiang <[email protected]>
// Contributors:
// Sean Middleditch <[email protected]>
// rlyeh <https://github.com/r-lyeh>
#pragma once
#include <cstddef>
#include <cassert>
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <sstream>
// jsonxx versioning: major.minor-extra where
// major = { number }
// minor = { number }
// extra = { 'a':alpha, 'b':beta, 'rc': release candidate, 'r': release, 's':stable }
#define JSONXX_MAJOR "0"
#define JSONXX_MINOR "22"
#define JSONXX_EXTRA "a"
#define JSONXX_VERSION JSONXX_MAJOR "." JSONXX_MINOR "-" JSONXX_EXTRA
#define JSONXX_XML_TAG "<!-- generated by jsonxx " JSONXX_VERSION " -->"
#if __cplusplus > 199711L
#define JSONXX_COMPILER_HAS_CXX11 1
#elif defined(_MSC_VER) && _MSC_VER > 1700
#define JSONXX_COMPILER_HAS_CXX11 1
#else
#define JSONXX_COMPILER_HAS_CXX11 0
#endif
#ifdef _MSC_VER
// disable the C4127 warning if using VC, see http://stackoverflow.com/a/12042515
#define JSONXX_ASSERT(...) \
do { \
__pragma(warning(push)) __pragma(warning(disable:4127)) \
if( jsonxx::Assertions ) \
__pragma(warning(pop)) \
jsonxx::assertion(__FILE__,__LINE__,#__VA_ARGS__,bool(__VA_ARGS__)); \
__pragma(warning(push)) __pragma(warning(disable:4127)) \
} while(0) \
__pragma(warning(pop))
#else
#define JSONXX_ASSERT(...) do { if( jsonxx::Assertions ) \
jsonxx::assertion(__FILE__,__LINE__,#__VA_ARGS__,bool(__VA_ARGS__)); } while(0)
#endif
namespace jsonxx {
// FIXME(hjiang): Those should really be dynamic.
// Settings
enum Settings {
// constants
Enabled = true,
Disabled = false,
Permissive = true,
Strict = false,
// values
Parser = Permissive, // permissive or strict parsing
UnquotedKeys = Disabled, // support of unquoted keys
Assertions = Enabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds)
};
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4127)
#endif
inline bool parser_is_strict() { return Parser == Strict; }
inline bool parser_is_permissive() { return Parser == Permissive; }
inline bool unquoted_keys_are_enabled() { return UnquotedKeys == Enabled; }
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// Constants for .write() and .xml() methods
enum Format {
JSON = 0, // JSON output
JSONx = 1, // XML output, JSONx format. see http://goo.gl/I3cxs
JXML = 2, // XML output, JXML format. see https://github.com/r-lyeh/JXML
JXMLex = 3, // XML output, JXMLex format. see https://github.com/r-lyeh/JXMLex
TaggedXML = 4 // XML output, tagged XML format. see https://github.com/hjiang/jsonxx/issues/12
};
// Types
typedef long double Number;
typedef bool Boolean;
typedef std::string String;
struct Null {};
class Value;
class Object;
class Array;
// Identity meta-function
template <typename T>
struct identity {
typedef T type;
};
// Tools
bool validate( const std::string &input );
bool validate( std::istream &input );
std::string reformat( const std::string &input );
std::string reformat( std::istream &input );
std::string xml( const std::string &input, unsigned format = JSONx );
std::string xml( std::istream &input, unsigned format = JSONx );
// Detail
void assertion( const char *file, int line, const char *expression, bool result );
// A JSON Object
class Object {
public:
Object();
~Object();
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);
template <typename T>
const T& get(const std::string& key) const;
template <typename T>
const T& get(const std::string& key, const typename identity<T>::type& default_value) const;
size_t size() const;
bool empty() const;
const std::map<std::string, Value*>& kv_map() const;
std::string json() const;
std::string xml( unsigned format = JSONx, const std::string &header = std::string(), const std::string &attrib = std::string() ) const;
std::string write( unsigned format ) const;
void reset();
bool parse(std::istream &input);
bool parse(const std::string &input);
typedef std::map<std::string, Value*> container;
void import( const Object &other );
void import( const std::string &key, const Value &value );
Object &operator<<(const Value &value);
Object &operator<<(const Object &value);
Object &operator=(const Object &value);
Object(const Object &other);
Object(const std::string &key, const Value &value);
template<size_t N>
Object(const char (&key)[N], const Value &value) {
import(key,value);
}
template<typename T>
Object &operator<<(const T &value);
protected:
static bool parse(std::istream& input, Object& object);
container value_map_;
std::string odd;
};
class Array {
public:
Array();
~Array();
size_t size() const;
bool empty() const;
template <typename T>
bool has(unsigned int i) const;
template <typename T>
T& get(unsigned int i);
template <typename T>
const T& get(unsigned int i) const;
template <typename T>
const T& get(unsigned int i, const typename identity<T>::type& default_value) const;
const std::vector<Value*>& values() const {
return values_;
}
std::string json() const;
std::string xml( unsigned format = JSONx, const std::string &header = std::string(), const std::string &attrib = std::string() ) const;
std::string write( unsigned format ) const { return format == JSON ? json() : xml(format); }
void reset();
bool parse(std::istream &input);
bool parse(const std::string &input);
typedef std::vector<Value*> container;
void append(const Array &other);
void append(const Value &value) { import(value); }
void import(const Array &other);
void import(const Value &value);
Array &operator<<(const Array &other);
Array &operator<<(const Value &value);
Array &operator=(const Array &other);
Array &operator=(const Value &value);
Array(const Array &other);
Array(const Value &value);
protected:
static bool parse(std::istream& input, Array& array);
container values_;
};
// A value could be a number, an array, a string, an object, a
// boolean, or null
class Value {
public:
Value();
~Value() { reset(); }
void reset();
template<typename T>
void import( const T & ) {
reset();
type_ = INVALID_;
// debug
// std::cout << "[WARN] No support for " << typeid(t).name() << std::endl;
}
void import( const bool &b ) {
reset();
type_ = BOOL_;
bool_value_ = b;
}
#define $number(TYPE) \
void import( const TYPE &n ) { \
reset(); \
type_ = NUMBER_; \
number_value_ = static_cast<long double>(n); \
}
$number( char )
$number( int )
$number( long )
$number( long long )
$number( unsigned char )
$number( unsigned int )
$number( unsigned long )
$number( unsigned long long )
$number( float )
$number( double )
$number( long double )
#undef $number
#if JSONXX_COMPILER_HAS_CXX11 > 0
void import( const std::nullptr_t & ) {
reset();
type_ = NULL_;
}
#endif
void import( const Null & ) {
reset();
type_ = NULL_;
}
void import( const String &s ) {
reset();
type_ = STRING_;
*( string_value_ = new String() ) = s;
}
void import( const char* s ) {
reset();
type_ = STRING_;
*( string_value_ = new String() ) = s;
}
void import( const Array &a ) {
reset();
type_ = ARRAY_;
*( array_value_ = new Array() ) = a;
}
void import( const Object &o ) {
reset();
type_ = OBJECT_;
*( object_value_ = new Object() ) = o;
}
void import( const Value &other ) {
if (this != &other)
switch (other.type_) {
case NULL_:
import( Null() );
break;
case BOOL_:
import( other.bool_value_ );
break;
case NUMBER_:
import( other.number_value_ );
break;
case STRING_:
import( *other.string_value_ );
break;
case ARRAY_:
import( *other.array_value_ );
break;
case OBJECT_:
import( *other.object_value_ );
break;
case INVALID_:
type_ = INVALID_;
break;
default:
JSONXX_ASSERT( !"not implemented" );
}
}
template<typename T>
Value &operator <<( const T &t ) {
import(t);
return *this;
}
template<typename T>
Value &operator =( const T &t ) {
reset();
import(t);
return *this;
}
Value(const Value &other);
template<typename T>
Value( const T&t ) : type_(INVALID_) { import(t); }
template<size_t N>
Value( const char (&t)[N] ) : type_(INVALID_) { import( std::string(t) ); }
bool parse(std::istream &input);
bool parse(const std::string &input);
template<typename T>
bool is() const;
template<typename T>
T& get();
template<typename T>
const T& get() const;
bool empty() const;
public:
enum {
NUMBER_,
STRING_,
BOOL_,
NULL_,
ARRAY_,
OBJECT_,
INVALID_
} type_;
union {
Number number_value_;
String* string_value_;
Boolean bool_value_;
Array* array_value_;
Object* object_value_;
};
protected:
static bool parse(std::istream& input, Value& 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) {
JSONXX_ASSERT(i < size());
Value* v = values_.at(i);
return v->get<T>();
}
template <typename T>
const T& Array::get(unsigned int i) const {
JSONXX_ASSERT(i < size());
const Value* v = values_.at(i);
return v->get<T>();
}
template <typename T>
const T& Array::get(unsigned int i, const typename identity<T>::type& default_value) const {
if(has<T>(i)) {
const Value* v = values_.at(i);
return v->get<T>();
} else {
return default_value;
}
}
template <typename T>
bool Object::has(const std::string& key) const {
container::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) {
JSONXX_ASSERT(has<T>(key));
return value_map_.find(key)->second->get<T>();
}
template <typename T>
const T& Object::get(const std::string& key) const {
JSONXX_ASSERT(has<T>(key));
return value_map_.find(key)->second->get<T>();
}
template <typename T>
const T& Object::get(const std::string& key, const typename identity<T>::type& default_value) const {
if (has<T>(key)) {
return value_map_.find(key)->second->get<T>();
} else {
return default_value;
}
}
template<>
inline bool Value::is<Value>() const {
return true;
}
template<>
inline bool Value::is<Null>() const {
return type_ == NULL_;
}
template<>
inline bool Value::is<Boolean>() const {
return type_ == BOOL_;
}
template<>
inline bool Value::is<String>() const {
return type_ == STRING_;
}
template<>
inline bool Value::is<Number>() const {
return type_ == NUMBER_;
}
template<>
inline bool Value::is<Array>() const {
return type_ == ARRAY_;
}
template<>
inline bool Value::is<Object>() const {
return type_ == OBJECT_;
}
template<>
inline Value& Value::get<Value>() {
return *this;
}
template<>
inline const Value& Value::get<Value>() const {
return *this;
}
template<>
inline bool& Value::get<Boolean>() {
JSONXX_ASSERT(is<Boolean>());
return bool_value_;
}
template<>
inline std::string& Value::get<String>() {
JSONXX_ASSERT(is<String>());
return *string_value_;
}
template<>
inline Number& Value::get<Number>() {
JSONXX_ASSERT(is<Number>());
return number_value_;
}
template<>
inline Array& Value::get<Array>() {
JSONXX_ASSERT(is<Array>());
return *array_value_;
}
template<>
inline Object& Value::get<Object>() {
JSONXX_ASSERT(is<Object>());
return *object_value_;
}
template<>
inline const Boolean& Value::get<Boolean>() const {
JSONXX_ASSERT(is<Boolean>());
return bool_value_;
}
template<>
inline const String& Value::get<String>() const {
JSONXX_ASSERT(is<String>());
return *string_value_;
}
template<>
inline const Number& Value::get<Number>() const {
JSONXX_ASSERT(is<Number>());
return number_value_;
}
template<>
inline const Array& Value::get<Array>() const {
JSONXX_ASSERT(is<Array>());
return *array_value_;
}
template<>
inline const Object& Value::get<Object>() const {
JSONXX_ASSERT(is<Object>());
return *object_value_;
}
template<typename T>
inline Object &Object::operator<<(const T &value) {
*this << Value(value);
return *this;
}
} // 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);
jsonxx.cc
// -*- mode: c++; c-basic-offset: 4; -*-
// Author: Hong Jiang <[email protected]>
// Contributors:
// Sean Middleditch <[email protected]>
// rlyeh <https://github.com/r-lyeh>
#include "jsonxx.h"
#include <cctype>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <limits>
#include <mutex>
// Snippet that creates an assertion function that works both in DEBUG & RELEASE mode.
// JSONXX_ASSERT(...) macro will redirect to this. assert() macro is kept untouched.
#if defined(NDEBUG) || defined(_NDEBUG)
# define JSONXX_REENABLE_NDEBUG
# undef NDEBUG
# undef _NDEBUG
#endif
#include <stdio.h>
#include <cassert>
void jsonxx::assertion( const char *file, int line, const char *expression, bool result ) {
if( !result ) {
fprintf( stderr, "[JSONXX] expression '%s' failed at %s:%d -> ", expression, file, line );
assert( 0 );
}
}
#if defined(JSONXX_REENABLE_NDEBUG)
# define NDEBUG
# define _NDEBUG
#endif
#include <cassert>
namespace jsonxx {
//static_assert( sizeof(unsigned long long) < sizeof(long double), "'long double' cannot hold 64bit values in this compiler :(");
bool match(const char* pattern, std::istream& input);
bool parse_array(std::istream& input, Array& array);
bool parse_bool(std::istream& input, Boolean& value);
bool parse_comment(std::istream &input);
bool parse_null(std::istream& input);
bool parse_number(std::istream& input, Number& value);
bool parse_object(std::istream& input, Object& object);
bool parse_string(std::istream& input, String& value);
bool parse_identifier(std::istream& input, String& value);
bool parse_value(std::istream& input, Value& value);
// Try to consume characters from the input stream and match the
// pattern string.
bool match(const char* pattern, std::istream& input) {
input >> std::ws;
const char* cur(pattern);
char ch(0);
while(input && !input.eof() && *cur != 0) {
input.get(ch);
if (ch != *cur) {
input.putback(ch);
if( parse_comment(input) )
continue;
while (cur > pattern) {
cur--;
input.putback(*cur);
}
return false;
} else {
cur++;
}
}
return *cur == 0;
}
bool parse_string(std::istream& input, String& value) {
char ch = '\0', delimiter = '"';
if (!match("\"", input)) {
if (parser_is_strict()) {
return false;
}
delimiter = '\'';
if (input.peek() != delimiter) {
return false;
}
input.get(ch);
}
while(!input.eof() && input.good()) {
input.get(ch);
if (ch == delimiter) {
break;
}
if (ch == '\\') {
input.get(ch);
switch(ch) {
case '\\':
case '/':
value.push_back(ch);
break;
case 'b':
value.push_back('\b');
break;
case 'f':
value.push_back('\f');
break;
case 'n':
value.push_back('\n');
break;
case 'r':
value.push_back('\r');
break;
case 't':
value.push_back('\t');
break;
case 'u': {
int i;
std::stringstream ss;
for( i = 0; (!input.eof() && input.good()) && i < 4; ++i ) {
input.get(ch);
ss << std::hex << ch;
}
if( input.good() && (ss >> i) )
value.push_back(static_cast<char>(i));
}
break;
default:
if (ch != delimiter) {
value.push_back('\\');
value.push_back(ch);
} else value.push_back(ch);
break;
}
} else {
value.push_back(ch);
}
}
if (input && ch == delimiter) {
return true;
} else {
return false;
}
}
bool parse_identifier(std::istream& input, String& value) {
input >> std::ws;
char ch = '\0', delimiter = ':';
bool first = true;
while(!input.eof() && input.good()) {
input.get(ch);
if (ch == delimiter) {
input.unget();
break;
}
if(first) {
if ((ch != '_' && ch != '$') &&
(ch < 'a' || ch > 'z') &&
(ch < 'A' || ch > 'Z')) {
return false;
}
first = false;
}
if(ch == '_' || ch == '$' ||
(ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9')) {
value.push_back(ch);
}
else if(ch == '\t' || ch == ' ') {
input >> std::ws;
}
}
if (input && ch == delimiter) {
return true;
} else {
return false;
}
}
class IOStateMasker {
public:
explicit IOStateMasker(std::istream& input): stream(input) {
mask = input.exceptions();
input.exceptions(std::istream::goodbit);
}
~IOStateMasker() {
stream.exceptions(mask);
}
private:
std::istream& stream;
std::istream::iostate mask;
};
bool parse_number(std::istream& input, Number& value) {
input >> std::ws;
std::streampos rollback = input.tellg();
IOStateMasker masker(input);
input >> value;
if (input.fail()) {
input.clear();
input.seekg(rollback);
return false;
}
return true;
}
bool parse_bool(std::istream& input, Boolean& 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;
}
if (parser_is_strict()) {
return false;
}
return (input.peek()==',');
}
bool parse_array(std::istream& input, Array& array) {
return array.parse(input);
}
bool parse_object(std::istream& input, Object& object) {
return object.parse(input);
}
bool parse_comment(std::istream &input) {
if( parser_is_permissive() )
if( !input.eof() && input.peek() == '/' )
{
char ch0(0);
input.get(ch0);
if( !input.eof() )
{
char ch1(0);
input.get(ch1);
if( ch0 == '/' && ch1 == '/' )
{
// trim chars till \r or \n
for( char ch(0); !input.eof() && (input.peek() != '\r' && input.peek() != '\n'); )
input.get(ch);
// consume spaces, tabs, \r or \n, in case no eof is found
if( !input.eof() )
input >> std::ws;
return true;
}
input.unget();
input.clear();
}
input.unget();
input.clear();
}
return false;
}
bool parse_value(std::istream& input, Value& value) {
return value.parse(input);
}
Object::Object() : value_map_() {}
Object::~Object() {
reset();
}
bool Object::parse(std::istream& input, Object& object) {
object.reset();
if (!match("{", input)) {
return false;
}
if (match("}", input)) {
return true;
}
do {
std::string key;
if (unquoted_keys_are_enabled()) {
if (!parse_identifier(input, key)) {
if (parser_is_permissive()) {
if (input.peek() == '}')
break;
}
return false;
}
}
else {
if (!parse_string(input, key)) {
if (parser_is_permissive()) {
if (input.peek() == '}')
break;
}
return false;
}
}
if (!match(":", input)) {
return false;
}
Value* v = new Value();
if (!parse_value(input, *v)) {
delete v;
break;
}
// TODO(hjiang): Add an option to allow duplicated keys?
if (object.value_map_.find(key) == object.value_map_.end()) {
object.value_map_[key] = v;
} else {
if (parser_is_permissive()) {
delete object.value_map_[key];
object.value_map_[key] = v;
} else {
delete v;
return false;
}
}
} while (match(",", input));
if (!match("}", input)) {
return false;
}
return true;
}
Value::Value() : type_(INVALID_) {}
void Value::reset() {
if (type_ == STRING_) {
delete string_value_;
string_value_ = 0;
}
else if (type_ == OBJECT_) {
delete object_value_;
object_value_ = 0;
}
else if (type_ == ARRAY_) {
delete array_value_;
array_value_ = 0;
}
}
bool Value::parse(std::istream& input, Value& value) {
value.reset();
std::string string_value;
if (parse_string(input, string_value)) {
value.string_value_ = new std::string();
value.string_value_->swap(string_value);
value.type_ = STRING_;
return true;
}
if (parse_number(input, value.number_value_)) {
value.type_ = NUMBER_;
return true;
}
if (parse_bool(input, value.bool_value_)) {
value.type_ = BOOL_;
return true;
}
if (parse_null(input)) {
value.type_ = NULL_;
return true;
}
if (input.peek() == '[') {
value.array_value_ = new Array();
if (parse_array(input, *value.array_value_)) {
value.type_ = ARRAY_;
return true;
}
delete value.array_value_;
value.array_value_ = 0;
}
value.object_value_ = new Object();
if (parse_object(input, *value.object_value_)) {
value.type_ = OBJECT_;
return true;
}
delete value.object_value_;
value.object_value_ = 0;
return false;
}
Array::Array() : values_() {}
Array::~Array() {
reset();
}
bool Array::parse(std::istream& input, Array& array) {
array.reset();
if (!match("[", input)) {
return false;
}
if (match("]", input)) {
return true;
}
do {
Value* v = new Value();
if (!parse_value(input, *v)) {
delete v;
break;
}
array.values_.push_back(v);
} while (match(",", input));
if (!match("]", input)) {
return false;
}
return true;
}
static std::ostream& stream_string(std::ostream& stream,
const std::string& string) {
stream << '"';
for (std::string::const_iterator i = string.begin(),
e = string.end(); i != e; ++i) {
switch (*i) {
case '"':
stream << "\\\"";
break;
case '\\':
stream << "\\\\";
break;
case '/':
stream << "\\/";
break;
case '\b':
stream << "\\b";
break;
case '\f':
stream << "\\f";
break;
case '\n':
stream << "\\n";
break;
case '\r':
stream << "\\r";
break;
case '\t':
stream << "\\t";
break;
default:
if (*i < 32) {
stream << "\\u" << std::hex << std::setw(4) <<
std::setfill('0') << static_cast<int>(*i) << std::dec <<
std::setw(0);
} else {
stream << *i;
}
}
}
stream << '"';
return stream;
}
} // namespace jsonxx
std::ostream& operator<<(std::ostream& stream, const jsonxx::Value& v) {
using namespace jsonxx;
if (v.is<Number>()) {
return stream << v.get<Number>();
} else if (v.is<String>()) {
return stream_string(stream, v.get<std::string>());
} else if (v.is<Boolean>()) {
if (v.get<Boolean>()) {
return stream << "true";
} else {
return stream << "false";
}
} else if (v.is<Null>()) {
return stream << "null";
} else if (v.is<Object>()) {
return stream << v.get<Object>();
} else if (v.is<Array>()){
return stream << v.get<Array>();
}
// Shouldn't reach here.
return stream;
}
std::ostream& operator<<(std::ostream& stream, const jsonxx::Array& v) {
stream << "[";
jsonxx::Array::container::const_iterator
it = v.values().begin(),
end = v.values().end();
while (it != end) {
stream << *(*it);
++it;
if (it != end) {
stream << ", ";
}
}
return stream << "]";
}
std::ostream& operator<<(std::ostream& stream, const jsonxx::Object& v) {
stream << "{";
jsonxx::Object::container::const_iterator
it = v.kv_map().begin(),
end = v.kv_map().end();
while (it != end) {
jsonxx::stream_string(stream, it->first);
stream << ": " << *(it->second);
++it;
if (it != end) {
stream << ", ";
}
}
return stream << "}";
}
namespace jsonxx {
namespace {
typedef unsigned char byte;
//template<bool quote>
std::string escape_string( const std::string &input, const bool quote = false ) {
static std::string map[256], *once = 0;
static std::mutex mutex;
if( !once ) {
// The problem here is that, once is initializing at the end of job, but if multithreaded application is starting this for the first time
// it will jump into this part with several threads and cause double free or corruptions.
// To prevent it, it is required to have mutex, to lock other threads while only one of them is constructing the static map.
mutex.lock();
if (!once) {
// base
for( int i = 0; i < 256; ++i ) {
map[ i ] = std::string() + char(i);
}
// non-printable
for( int i = 0; i < 32; ++i ) {
std::stringstream str;
str << "\\u" << std::hex << std::setw(4) << std::setfill('0') << i;
map[ i ] = str.str();
}
// exceptions
map[ byte('"') ] = "\\\"";
map[ byte('\\') ] = "\\\\";
map[ byte('/') ] = "\\/";
map[ byte('\b') ] = "\\b";
map[ byte('\f') ] = "\\f";
map[ byte('\n') ] = "\\n";
map[ byte('\r') ] = "\\r";
map[ byte('\t') ] = "\\t";
once = map;
}
mutex.unlock();
}
std::string output;
output.reserve( input.size() * 2 + 2 ); // worst scenario
if( quote ) output += '"';
for( std::string::const_iterator it = input.begin(), end = input.end(); it != end; ++it )
output += map[ byte(*it) ];
if( quote ) output += '"';
return output;
}
namespace json {
std::string remove_last_comma( const std::string &_input ) {
std::string input( _input );
size_t size = input.size();
if( size > 2 )
if( input[ size - 2 ] == ',' )
input[ size - 2 ] = ' ';
return input;
}
std::string tag( unsigned format, unsigned depth, const std::string &name, const jsonxx::Value &t) {
std::stringstream ss;
const std::string tab(depth, '\t');
if( !name.empty() )
ss << tab << '\"' << escape_string( name ) << '\"' << ':' << ' ';
else
ss << tab;
switch( t.type_ )
{
default:
case jsonxx::Value::NULL_:
ss << "null";
return ss.str() + ",\n";
case jsonxx::Value::BOOL_:
ss << ( t.bool_value_ ? "true" : "false" );
return ss.str() + ",\n";
case jsonxx::Value::ARRAY_:
ss << "[\n";
for(Array::container::const_iterator it = t.array_value_->values().begin(),
end = t.array_value_->values().end(); it != end; ++it )
ss << tag( format, depth+1, std::string(), **it );
return remove_last_comma( ss.str() ) + tab + "]" ",\n";
case jsonxx::Value::STRING_:
ss << '\"' << escape_string( *t.string_value_ ) << '\"';
return ss.str() + ",\n";
case jsonxx::Value::OBJECT_:
ss << "{\n";
for(Object::container::const_iterator it=t.object_value_->kv_map().begin(),
end = t.object_value_->kv_map().end(); it != end ; ++it)
ss << tag( format, depth+1, it->first, *it->second );
return remove_last_comma( ss.str() ) + tab + "}" ",\n";
case jsonxx::Value::NUMBER_:
// max precision
ss << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
ss << t.number_value_;
return ss.str() + ",\n";
}
}
} // namespace jsonxx::anon::json
namespace xml {
std::string escape_attrib( const std::string &input ) {
static std::string map[256], *once = 0;
if( !once ) {
for( int i = 0; i < 256; ++i )
map[ i ] = "_";
for( int i = int('a'); i <= int('z'); ++i )
map[ i ] = std::string() + char(i);
for( int i = int('A'); i <= int('Z'); ++i )
map[ i ] = std::string() + char(i);
for( int i = int('0'); i <= int('9'); ++i )
map[ i ] = std::string() + char(i);
once = map;
}
std::string output;
output.reserve( input.size() ); // worst scenario
for( std::string::const_iterator it = input.begin(), end = input.end(); it != end; ++it )
output += map[ byte(*it) ];
return output;
}
std::string escape_tag( const std::string &input, unsigned format ) {
static std::string map[256], *once = 0;
if( !once ) {
for( int i = 0; i < 256; ++i )
map[ i ] = std::string() + char(i);
map[ byte('<') ] = "<";
map[ byte('>') ] = ">";
switch( format )
{
default:
break;
case jsonxx::JXML:
case jsonxx::JXMLex:
case jsonxx::JSONx:
case jsonxx::TaggedXML:
map[ byte('&') ] = "&";
break;
}
once = map;
}
std::string output;
output.reserve( input.size() * 5 ); // worst scenario
for( std::string::const_iterator it = input.begin(), end = input.end(); it != end; ++it )
output += map[ byte(*it) ];
return output;
}
std::string open_tag( unsigned format, char type, const std::string &name, const std::string &attr = std::string(), const std::string &text = std::string() ) {
std::string tagname;
switch( format )
{
default:
return std::string();
case jsonxx::JXML:
if( name.empty() )
tagname = std::string("j son=\"") + type + '\"';
else
tagname = std::string("j son=\"") + type + ':' + escape_string(name) + '\"';
break;
case jsonxx::JXMLex:
if( name.empty() )
tagname = std::string("j son=\"") + type + '\"';
else
tagname = std::string("j son=\"") + type + ':' + escape_string(name) + "\" " + escape_attrib(name) + "=\"" + escape_string(text) + "\"";
break;
case jsonxx::JSONx:
if( !name.empty() )
tagname = std::string(" name=\"") + escape_string(name) + "\"";
switch( type ) {
default:
case '0': tagname = "json:null" + tagname; break;
case 'b': tagname = "json:boolean" + tagname; break;
case 'a': tagname = "json:array" + tagname; break;
case 's': tagname = "json:string" + tagname; break;
case 'o': tagname = "json:object" + tagname; break;
case 'n': tagname = "json:number" + tagname; break;
}
break;
case jsonxx::TaggedXML: // @TheMadButcher
if( !name.empty() )
tagname = escape_attrib(name);
else
tagname = "JsonItem";
switch( type ) {
default:
case '0': tagname += " type=\"json:null\""; break;
case 'b': tagname += " type=\"json:boolean\""; break;
case 'a': tagname += " type=\"json:array\""; break;
case 's': tagname += " type=\"json:string\""; break;
case 'o': tagname += " type=\"json:object\""; break;
case 'n': tagname += " type=\"json:number\""; break;
}
if( !name.empty() )
tagname += std::string(" name=\"") + escape_string(name) + "\"";
break;
}
return std::string("<") + tagname + attr + ">";
}
std::string close_tag( unsigned format, char type, const std::string &name ) {
switch( format )
{
default:
return std::string();
case jsonxx::JXML:
case jsonxx::JXMLex:
return "</j>";
case jsonxx::JSONx:
switch( type ) {
default:
case '0': return "</json:null>";
case 'b': return "</json:boolean>";
case 'a': return "</json:array>";
case 'o': return "</json:object>";
case 's': return "</json:string>";
case 'n': return "</json:number>";
}
break;
case jsonxx::TaggedXML: // @TheMadButcher
if( !name.empty() )
return "</"+escape_attrib(name)+">";
else
return "</JsonItem>";
}
}
std::string tag( unsigned format, unsigned depth, const std::string &name, const jsonxx::Value &t, const std::string &attr = std::string() ) {
std::stringstream ss;
const std::string tab(depth, '\t');
switch( t.type_ )
{
default:
case jsonxx::Value::NULL_:
return tab + open_tag( format, '0', name, " /" ) + '\n';
case jsonxx::Value::BOOL_:
ss << ( t.bool_value_ ? "true" : "false" );
return tab + open_tag( format, 'b', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string() )
+ ss.str()
+ close_tag( format, 'b', name ) + '\n';
case jsonxx::Value::ARRAY_:
for(Array::container::const_iterator it = t.array_value_->values().begin(),
end = t.array_value_->values().end(); it != end; ++it )
ss << tag( format, depth+1, std::string(), **it );
return tab + open_tag( format, 'a', name, attr ) + '\n'
+ ss.str()
+ tab + close_tag( format, 'a', name ) + '\n';
case jsonxx::Value::STRING_:
ss << escape_tag( *t.string_value_, format );
return tab + open_tag( format, 's', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string() )
+ ss.str()
+ close_tag( format, 's', name ) + '\n';
case jsonxx::Value::OBJECT_:
for(Object::container::const_iterator it=t.object_value_->kv_map().begin(),
end = t.object_value_->kv_map().end(); it != end ; ++it)
ss << tag( format, depth+1, it->first, *it->second );
return tab + open_tag( format, 'o', name, attr ) + '\n'
+ ss.str()
+ tab + close_tag( format, 'o', name ) + '\n';
case jsonxx::Value::NUMBER_:
// max precision
ss << std::setprecision(std::numeric_limits<long double>::digits10 + 1);
ss << t.number_value_;
return tab + open_tag( format, 'n', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string() )
+ ss.str()
+ close_tag( format, 'n', name ) + '\n';
}
}
// order here matches jsonxx::Format enum
const char *defheader[] = {
"",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
JSONXX_XML_TAG "\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
JSONXX_XML_TAG "\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
JSONXX_XML_TAG "\n",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
JSONXX_XML_TAG "\n"
};
// order here matches jsonxx::Format enum
const char *defrootattrib[] = {
"",
" xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
" xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\"",
"",
"",
""
};
} // namespace jsonxx::anon::xml
} // namespace jsonxx::anon
std::string Object::json() const {
using namespace json;
jsonxx::Value v;
v.object_value_ = const_cast<jsonxx::Object*>(this);
v.type_ = jsonxx::Value::OBJECT_;
std::string result = tag( jsonxx::JSON, 0, std::string(), v );
v.object_value_ = 0;
return remove_last_comma( result );
}
std::string Object::xml( unsigned format, const std::string &header, const std::string &attrib ) const {
using namespace xml;
JSONXX_ASSERT( format == jsonxx::JSONx || format == jsonxx::JXML || format == jsonxx::JXMLex || format == jsonxx::TaggedXML );
jsonxx::Value v;
v.object_value_ = const_cast<jsonxx::Object*>(this);
v.type_ = jsonxx::Value::OBJECT_;
std::string result = tag( format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib );
v.object_value_ = 0;
return ( header.empty() ? std::string(defheader[format]) : header ) + result;
}
std::string Array::json() const {
using namespace json;
jsonxx::Value v;
v.array_value_ = const_cast<jsonxx::Array*>(this);
v.type_ = jsonxx::Value::ARRAY_;
std::string result = tag( jsonxx::JSON, 0, std::string(), v );
v.array_value_ = 0;
return remove_last_comma( result );
}
std::string Array::xml( unsigned format, const std::string &header, const std::string &attrib ) const {
using namespace xml;
JSONXX_ASSERT( format == jsonxx::JSONx || format == jsonxx::JXML || format == jsonxx::JXMLex || format == jsonxx::TaggedXML );
jsonxx::Value v;
v.array_value_ = const_cast<jsonxx::Array*>(this);
v.type_ = jsonxx::Value::ARRAY_;
std::string result = tag( format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib );
v.array_value_ = 0;
return ( header.empty() ? std::string(defheader[format]) : header ) + result;
}
bool validate( std::istream &input ) {
// trim non-printable chars
for( char ch(0); !input.eof() && input.peek() <= 32; )
input.get(ch);
// validate json
if( input.peek() == '{' )
{
jsonxx::Object o;
if( parse_object( input, o ) )
return true;
}
else
if( input.peek() == '[' )
{
jsonxx::Array a;
if( parse_array( input, a ) )
return true;
}
// bad json input
return false;
}
bool validate( const std::string &input ) {
std::istringstream is( input );
return jsonxx::validate( is );
}
std::string reformat( std::istream &input ) {
// trim non-printable chars
for( char ch(0); !input.eof() && input.peek() <= 32; )
input.get(ch);
// validate json
if( input.peek() == '{' )
{
jsonxx::Object o;
if( parse_object( input, o ) )
return o.json();
}
else
if( input.peek() == '[' )
{
jsonxx::Array a;
if( parse_array( input, a ) )
return a.json();
}
// bad json input
return std::string();
}
std::string reformat( const std::string &input ) {
std::istringstream is( input );
return jsonxx::reformat( is );
}
std::string xml( std::istream &input, unsigned format ) {
using namespace xml;
JSONXX_ASSERT( format == jsonxx::JSONx || format == jsonxx::JXML || format == jsonxx::JXMLex || format == jsonxx::TaggedXML );
// trim non-printable chars
for( char ch(0); !input.eof() && input.peek() <= 32; )
input.get(ch);
// validate json, then transform
if( input.peek() == '{' )
{
jsonxx::Object o;
if( parse_object( input, o ) )
return o.xml(format);
}
else
if( input.peek() == '[' )
{
jsonxx::Array a;
if( parse_array( input, a ) )
return a.xml(format);
}
// bad json, return empty xml
return defheader[format];
}
std::string xml( const std::string &input, unsigned format ) {
std::istringstream is( input );
return jsonxx::xml( is, format );
}
Object::Object(const Object &other) {
import(other);
}
Object::Object(const std::string &key, const Value &value) {
import(key,value);
}
void Object::import( const Object &other ) {
odd.clear();
if (this != &other) {
// default
container::const_iterator
it = other.value_map_.begin(),
end = other.value_map_.end();
for (/**/ ; it != end ; ++it) {
container::iterator found = value_map_.find(it->first);
if( found != value_map_.end() ) {
delete found->second;
}
value_map_[ it->first ] = new Value( *it->second );
}
} else {
// recursion is supported here
import( Object(*this) );
}
}
void Object::import( const std::string &key, const Value &value ) {
odd.clear();
container::iterator found = value_map_.find(key);
if( found != value_map_.end() ) {
delete found->second;
}
value_map_[ key ] = new Value( value );
}
Object &Object::operator=(const Object &other) {
odd.clear();
if (this != &other) {
reset();
import(other);
}
return *this;
}
Object &Object::operator<<(const Value &value) {
if (odd.empty()) {
odd = value.get<String>();
} else {
import( Object(odd, value) );
odd.clear();
}
return *this;
}
Object &Object::operator<<(const Object &value) {
import( std::string(odd),value);
odd.clear();
return *this;
}
size_t Object::size() const {
return value_map_.size();
}
bool Object::empty() const {
return value_map_.size() == 0;
}
const std::map<std::string, Value*> &Object::kv_map() const {
return value_map_;
}
std::string Object::write( unsigned format ) const {
return format == JSON ? json() : xml(format);
}
void Object::reset() {
container::iterator i;
for (i = value_map_.begin(); i != value_map_.end(); ++i) {
delete i->second;
}
value_map_.clear();
}
bool Object::parse(std::istream &input) {
return parse(input,*this);
}
bool Object::parse(const std::string &input) {
std::istringstream is( input );
return parse(is,*this);
}
Array::Array(const Array &other) {
import(other);
}
Array::Array(const Value &value) {
import(value);
}
void Array::append(const Array &other) {
if (this != &other) {
values_.push_back( new Value(other) );
} else {
append( Array(*this) );
}
}
void Array::import(const Array &other) {
if (this != &other) {
// default
container::const_iterator
it = other.values_.begin(),
end = other.values_.end();
for (/**/ ; it != end; ++it) {
values_.push_back( new Value(**it) );
}
} else {
// recursion is supported here
import( Array(*this) );
}
}
void Array::import(const Value &value) {
values_.push_back( new Value(value) );
}
size_t Array::size() const {
return values_.size();
}
bool Array::empty() const {
return values_.size() == 0;
}
void Array::reset() {
for (container::iterator i = values_.begin(); i != values_.end(); ++i) {
delete *i;
}
values_.clear();
}
bool Array::parse(std::istream &input) {
return parse(input,*this);
}
bool Array::parse(const std::string &input) {
std::istringstream is(input);
return parse(is,*this);
}
Array &Array::operator<<(const Array &other) {
import(other);
return *this;
}
Array &Array::operator<<(const Value &value) {
import(value);
return *this;
}
Array &Array::operator=(const Array &other) {
if( this != &other ) {
reset();
import(other);
}
return *this;
}
Array &Array::operator=(const Value &value) {
reset();
import(value);
return *this;
}
Value::Value(const Value &other) : type_(INVALID_) {
import( other );
}
bool Value::empty() const {
if( type_ == INVALID_ ) return true;
if( type_ == STRING_ && string_value_ == 0 ) return true;
if( type_ == ARRAY_ && array_value_ == 0 ) return true;
if( type_ == OBJECT_ && object_value_ == 0 ) return true;
return false;
}
bool Value::parse(std::istream &input) {
return parse(input,*this);
}
bool Value::parse(const std::string &input) {
std::istringstream is( input );
return parse(is,*this);
}
} // namespace jsonxx
後面的json解析來自於github吧,雖然qt也有json解析,但是哪有我直接從以前工程複製程式碼來得爽快。
也許還有完善的地方吧,反正先用用再說了。