2023-07-21 17:40:49 +08:00
# ifndef QJSON_H
# define QJSON_H
2023-09-19 11:49:20 +08:00
# include "cpp.h"
2023-07-21 17:40:49 +08:00
# include "QtCore/qhashfunctions.h"
2023-10-23 11:44:22 +08:00
# include <QDataStream>
2023-07-21 17:40:49 +08:00
# include <QTextStream>
class JValue ;
using JObj = LinkedMap < QString , JValue > ;
using JArray = Vector < JValue > ;
2023-10-23 11:44:22 +08:00
QDebug operator < < ( QDebug debug , const JValue & val ) ;
2023-07-21 17:40:49 +08:00
class JValue {
public :
2023-09-19 11:49:20 +08:00
long long data = 0 ;
2023-07-21 17:40:49 +08:00
enum Type {
2023-09-19 11:49:20 +08:00
Null , Long , Ulong , Double , Bool , Obj , Array , Str
2023-07-21 17:40:49 +08:00
} ;
2023-09-19 11:49:20 +08:00
Type type = Null ;
2023-07-21 17:40:49 +08:00
JValue ( Type = Null ) { }
2023-09-19 11:49:20 +08:00
JValue ( bool b ) : type ( Bool ) { data = b ; }
JValue ( int n ) : type ( Long ) { data = n ; }
JValue ( qint64 n ) : type ( Long ) { data = n ; }
JValue ( quint64 n ) : type ( Ulong ) { * ( quint64 * ) & data = n ; }
JValue ( double d ) : type ( Double ) { * ( double * ) & data = d ; }
JValue ( const JObj & o ) : type ( Obj ) { new ( & data ) JObj ( o ) ; }
JValue ( const JArray & a ) : type ( Array ) { new ( & data ) JArray ( a ) ; }
JValue ( JObj & & o ) : type ( Obj ) { new ( & data ) JObj ( std : : move ( o ) ) ; }
JValue ( JArray & & a ) : type ( Array ) { new ( & data ) JArray ( std : : move ( a ) ) ; }
JValue ( const QString & s ) : type ( Str ) { * ( SharedData < QString > * * ) & data = new SharedData < QString > { 1 , s } ; }
JValue ( QString & & s ) : type ( Str ) { * ( SharedData < QString > * * ) & data = new SharedData < QString > { 1 , std : : move ( s ) } ; }
2023-07-21 17:40:49 +08:00
JValue ( const char * s ) : JValue ( QString : : fromUtf8 ( s ) ) { }
~ JValue ( ) {
if ( type < Obj ) return ;
2023-09-19 11:49:20 +08:00
else if ( type = = Obj ) ( ( JObj * ) & data ) - > ~ JObj ( ) ;
else if ( type = = Array ) ( ( JArray * ) & data ) - > ~ JArray ( ) ;
2023-07-21 17:40:49 +08:00
else if ( type = = Str ) {
2023-09-19 11:49:20 +08:00
auto ptr = * ( SharedData < QString > * * ) & data ;
2023-07-21 17:40:49 +08:00
if ( ptr - > cnt > 1 ) ptr - > cnt - - ;
else delete ptr ;
}
}
2023-09-19 11:49:20 +08:00
JValue ( const JValue & other ) {
type = other . type ;
if ( type = = Obj ) new ( & data ) JObj ( * ( JObj * ) & other . data ) ;
else if ( type = = Array ) new ( & data ) JArray ( * ( JArray * ) & other . data ) ;
else {
data = other . data ;
if ( type = = Str ) ( * ( SharedData < QString > * * ) & data ) - > cnt + + ;
}
}
2023-07-21 17:40:49 +08:00
JValue & operator = ( const JValue & other ) {
this - > ~ JValue ( ) ;
new ( this ) JValue ( other ) ;
return * this ;
}
2023-09-19 11:49:20 +08:00
JValue ( JValue & & other ) noexcept : data ( other . data ) , type ( other . type ) {
other . data = 0 ;
other . type = Null ;
}
JValue & operator = ( JValue & & other ) noexcept {
std : : swap ( data , other . data ) ;
std : : swap ( type , other . type ) ;
return * this ;
}
2023-07-21 17:40:49 +08:00
bool isNull ( ) const { return type = = Null ; }
2023-09-19 11:49:20 +08:00
bool isStr ( ) const { return type = = Str ; }
2023-07-21 17:40:49 +08:00
bool isObj ( ) const { return type = = Obj ; }
bool isArray ( ) const { return type = = Array ; }
bool toBool ( bool def = false ) const {
2023-09-19 11:49:20 +08:00
return type = = Null ? def : data ;
2023-07-21 17:40:49 +08:00
}
int toInt ( int def = 0 ) const {
2023-09-19 11:49:20 +08:00
return toLong ( def ) ;
2023-07-21 17:40:49 +08:00
}
qint64 toLong ( qint64 def = 0 ) const {
2023-09-19 11:49:20 +08:00
if ( type = = Long | | type = = Bool ) return data ;
if ( type = = Double ) return * ( double * ) & data ;
if ( type = = Ulong ) return * ( quint64 * ) & data ;
return def ;
}
quint64 toULong ( quint64 def = 0 ) const {
if ( type = = Ulong ) return * ( quint64 * ) & data ;
if ( type = = Long | | type = = Bool ) return data ;
if ( type = = Double ) return * ( double * ) & data ;
2023-07-21 17:40:49 +08:00
return def ;
}
double toDouble ( double def = 0 ) const {
2023-09-19 11:49:20 +08:00
if ( type = = Double ) return * ( double * ) & data ;
if ( type = = Long | | type = = Bool ) return data ;
if ( type = = Ulong ) return * ( quint64 * ) & data ;
2023-07-21 17:40:49 +08:00
return def ;
}
QString toStr ( const QString & def = " " ) const {
2023-09-19 11:49:20 +08:00
if ( type = = Str ) return ( * ( SharedData < QString > * * ) & data ) - > data ;
if ( type = = Long ) return QString : : number ( data ) ;
if ( type = = Double ) return QString : : number ( * ( double * ) & data ) ;
if ( type = = Bool ) return data ? " true " : " false " ;
if ( type = = Ulong ) return QString : : number ( * ( quint64 * ) & data ) ;
2023-07-21 17:40:49 +08:00
return def ;
}
2023-09-19 11:49:20 +08:00
QString toString ( const QString & def = " " ) const {
return toStr ( def ) ;
}
2023-07-21 17:40:49 +08:00
JObj toObj ( ) const {
2023-09-19 11:49:20 +08:00
if ( type = = Obj ) return * ( JObj * ) & data ;
2023-07-21 17:40:49 +08:00
return JObj ( ) ;
}
JArray toArray ( ) const {
2023-09-19 11:49:20 +08:00
if ( type = = Array ) return * ( JArray * ) & data ;
2023-07-21 17:40:49 +08:00
return JArray ( ) ;
}
2023-09-19 11:49:20 +08:00
2023-08-07 09:04:53 +08:00
const JValue operator [ ] ( const QString & key ) const {
2023-09-19 11:49:20 +08:00
return type = = Obj ? ( * ( const JObj * ) & data ) [ key ] : JValue ( ) ;
2023-08-07 09:04:53 +08:00
}
const JValue operator [ ] ( int i ) const {
2023-09-19 11:49:20 +08:00
return type = = Array ? ( * ( const JArray * ) & data ) [ i ] : JValue ( ) ;
}
JArray : : iterator begin ( ) const noexcept {
return type = = Array ? ( ( const JArray * ) & data ) - > begin ( ) : JArray : : iterator ( ) ;
}
JArray : : iterator end ( ) const noexcept {
return type = = Array ? ( ( const JArray * ) & data ) - > end ( ) : JArray : : iterator ( ) ;
}
2023-10-23 11:44:22 +08:00
bool empty ( ) const noexcept {
if ( type = = Array ) return ( ( const JArray * ) & data ) - > empty ( ) ;
else if ( type = = Obj ) return ( ( const JObj * ) & data ) - > empty ( ) ;
return 0 ;
}
2023-09-19 11:49:20 +08:00
size_t size ( ) const noexcept {
if ( type = = Array ) return ( ( const JArray * ) & data ) - > size ( ) ;
else if ( type = = Obj ) return ( ( const JObj * ) & data ) - > size ( ) ;
return 0 ;
}
bool operator = = ( const JValue & other ) const {
if ( type = = other . type ) {
if ( data = = other . data ) return true ;
if ( type = = Null ) return true ;
if ( type < = Double ) return false ;
if ( type = = Bool ) return ( ( bool ) data ) = = ( bool ) other . data ;
if ( type = = Str ) return ( * ( SharedData < QString > * * ) & data ) - > data = = ( * ( SharedData < QString > * * ) & other . data ) - > data ;
if ( type = = Obj ) return * ( JObj * ) & data = = * ( JObj * ) & other . data ;
if ( type = = Array ) return * ( JArray * ) & data = = * ( JArray * ) & other . data ;
} else {
if ( type > Double | | other . type > Double | | type = = Null | | other . type = = Null ) return false ;
if ( type = = Double | | other . type = = Double ) return toDouble ( ) = = other . toDouble ( ) ;
if ( type = = Long ) return data = = other . toLong ( ) ;
else return toLong ( ) = = other . data ;
}
return false ;
}
bool operator ! = ( const JValue & other ) const {
return ! ( * this = = other ) ;
2023-08-07 09:04:53 +08:00
}
2023-07-21 17:40:49 +08:00
private :
JValue ( const void * ) = delete ; // avoid implicit conversions from char * to bool
} ;
class JParser {
public :
2023-10-23 11:44:22 +08:00
JParser ( QDataStream & in ) : in ( in ) { }
JValue read ( ) {
in > > ch ;
if ( ch = = 0 ) throw " Unexpected end-of-input " ;
if ( ch = = 0xEF & & ( readOne ( ) ! = 0xBB | | readOne ( ) ! = 0xBF ) ) throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting an UTF-8 BOM " ;
if ( ch < 33 ) skipSpace ( ) ;
2023-07-21 17:40:49 +08:00
return readValue ( ) ;
}
protected :
JValue readValue ( ) ;
QString readStr ( ) ;
void skipSpace ( ) ;
2023-10-23 11:44:22 +08:00
unsigned char readOne ( ) {
in > > ch ;
return ch ;
}
QDataStream & in ;
unsigned char ch { 0 } , bk { 0 } ;
2023-07-21 17:40:49 +08:00
} ;
inline JValue JFrom ( const QByteArray & json , QString * err = 0 ) {
2023-10-23 11:44:22 +08:00
QDataStream in ( json ) ;
2023-07-21 17:40:49 +08:00
try {
return JParser ( in ) . read ( ) ;
} catch ( QString anerr ) {
if ( err ) * err = anerr ;
} catch ( const char * anerr ) {
if ( err ) * err = anerr ;
} catch ( . . . ) {
if ( err ) * err = " unknow error " ;
}
return JValue ( ) ;
}
inline JValue JFrom ( QIODevice * device , QString * err = 0 ) {
2023-10-23 11:44:22 +08:00
QDataStream in ( device ) ;
2023-07-21 17:40:49 +08:00
try {
return JParser ( in ) . read ( ) ;
} catch ( QString anerr ) {
if ( err ) * err = anerr ;
} catch ( const char * anerr ) {
if ( err ) * err = anerr ;
} catch ( . . . ) {
if ( err ) * err = " unknow error " ;
}
return JValue ( ) ;
}
class JOut {
public :
2023-08-07 09:04:53 +08:00
JOut ( QTextStream & out , QString indent = " " ) : out ( out ) , indent ( indent ) {
# if(QT_VERSION_MAJOR < 6)
out . setCodec ( " UTF-8 " ) ;
# endif
}
2023-07-21 17:40:49 +08:00
2023-09-19 11:49:20 +08:00
void write ( const JValue & value ) ;
2023-07-21 17:40:49 +08:00
void writeStr ( const QString & str ) ;
void writeMap ( const JObj & map ) ;
void writeList ( const JArray & objs ) ;
protected :
QTextStream & out ;
QString indent ;
int cnt { 0 } ;
} ;
2023-09-19 11:49:20 +08:00
inline QString JToStr ( const JValue & value , QString indent = " " ) {
2023-07-21 17:40:49 +08:00
QString json ;
QTextStream out ( & json ) ;
2023-09-19 11:49:20 +08:00
JOut ( out , indent ) . write ( value ) ;
2023-07-21 17:40:49 +08:00
return json ;
}
2023-09-19 11:49:20 +08:00
inline QByteArray JToBytes ( const JValue & value , QString indent = " " ) {
2023-07-21 17:40:49 +08:00
QByteArray json ;
QTextStream out ( & json ) ;
2023-09-19 11:49:20 +08:00
JOut ( out , indent ) . write ( value ) ;
2023-07-21 17:40:49 +08:00
return json ;
}
2023-09-19 11:49:20 +08:00
inline QTextStream : : Status JWrite ( const JValue & value , QIODevice * device , QString indent = " " ) {
2023-07-21 17:40:49 +08:00
QTextStream out ( device ) ;
2023-09-19 11:49:20 +08:00
JOut ( out , indent ) . write ( value ) ;
2023-07-21 17:40:49 +08:00
return out . status ( ) ;
}
# endif // QJSON_H