2023-07-21 17:40:49 +08:00
# include "qjson.h"
2023-09-19 11:49:20 +08:00
# include "qdebug.h"
QDebug operator < < ( QDebug debug , const JValue & val ) {
auto old = debug . autoInsertSpaces ( ) ;
debug . noquote ( ) . nospace ( ) < < JToBytes ( val , " \t " ) ;
debug . setAutoInsertSpaces ( old ) ;
return debug ;
}
2023-07-21 17:40:49 +08:00
JValue JParser : : readValue ( ) {
if ( ch = = ' { ' ) {
JObj obj ;
while ( true ) {
do skipSpace ( ) ; //ch有三种可能
while ( ch = = ' , ' ) ;
if ( ch = = ' } ' ) return obj ;
QString key ;
if ( ch = = ' " ' ) key = readStr ( ) ;
2023-10-23 11:44:22 +08:00
else if ( ch ! = ' n ' | | readOne ( ) ! = ' u ' | | readOne ( ) ! = ' l ' | | readOne ( ) ! = ' l ' ) throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting double-quote to start field name or null " ;
2023-07-21 17:40:49 +08:00
skipSpace ( ) ;
2023-10-23 11:44:22 +08:00
if ( ch ! = ' : ' ) throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting a colon to separate field name and value " ;
2023-07-21 17:40:49 +08:00
skipSpace ( ) ;
obj . insert ( key , readValue ( ) ) ;
skipSpace ( ) ; //ch有两种可能
if ( ch = = ' } ' ) return obj ;
2023-10-23 11:44:22 +08:00
if ( ch ! = ' , ' ) throw QString ( " Unexpected char " ) + ( char ) ch + " ' (code " + QString : : number ( ch ) + " ): was expecting } to end Object or comma to separate Object entries " ;
2023-07-21 17:40:49 +08:00
}
}
if ( ch = = ' [ ' ) {
JArray list ;
while ( true ) {
do skipSpace ( ) ; //ch有三种可能
while ( ch = = ' , ' ) ;
if ( ch = = ' ] ' ) return list ;
list - > push_back ( readValue ( ) ) ;
skipSpace ( ) ; //ch有两种可能
if ( ch = = ' ] ' ) return list ;
2023-10-23 11:44:22 +08:00
if ( ch ! = ' , ' ) throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting ] to end Array or comma to separate Array entries " ;
2023-07-21 17:40:49 +08:00
}
}
if ( ch = = ' " ' ) return readStr ( ) ;
if ( ( ch > = ' 0 ' & & ch < = ' 9 ' ) | | ch = = ' - ' ) {
2023-10-23 11:44:22 +08:00
QByteArray buf ;
2023-07-21 17:40:49 +08:00
buf + = ch ;
bool isInt = true ;
2023-10-23 11:44:22 +08:00
while ( readOne ( ) ) {
2023-07-21 17:40:49 +08:00
if ( ( ch > ' * ' & & ch < ' : ' & & ch ! = ' , ' & & ch ! = ' / ' ) | | ch = = ' e ' | | ch = = ' E ' ) {
buf . append ( ch ) ;
if ( isInt & & ch = = ' . ' ) isInt = false ;
} else {
bk = ch ;
break ;
}
}
bool ok ;
if ( isInt ) {
auto num = buf . toLongLong ( & ok ) ;
if ( ! ok ) throw " Illegal number: " + buf ;
return num ;
} else {
auto num = buf . toDouble ( & ok ) ;
if ( ! ok ) throw " Illegal number: " + buf ;
return num ;
}
}
if ( ch = = ' n ' ) {
2023-10-23 11:44:22 +08:00
if ( readOne ( ) = = ' u ' & & readOne ( ) = = ' l ' & & readOne ( ) = = ' l ' ) return JValue ( ) ;
else throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting null " ;
2023-07-21 17:40:49 +08:00
}
if ( ch = = ' t ' ) {
2023-10-23 11:44:22 +08:00
if ( readOne ( ) = = ' r ' & & readOne ( ) = = ' u ' & & readOne ( ) = = ' e ' ) return true ;
else throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting true " ;
2023-07-21 17:40:49 +08:00
}
if ( ch = = ' f ' ) {
2023-10-23 11:44:22 +08:00
if ( readOne ( ) = = ' a ' & & readOne ( ) = = ' l ' & & readOne ( ) = = ' s ' & & readOne ( ) = = ' e ' ) return false ;
else throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting false " ;
2023-07-21 17:40:49 +08:00
}
2023-10-23 11:44:22 +08:00
throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ): was expecting { } , [ ] , \ " string \" , number, null, true or false " ;
}
inline int toHex ( unsigned char ch ) {
if ( ch < ' 0 ' ) return - 1 ;
if ( ch < = ' 9 ' ) return ch - ' 0 ' ;
if ( ch < ' A ' ) return - 1 ;
if ( ch < = ' F ' ) return ch - 55 ;
if ( ch < ' a ' ) return - 1 ;
if ( ch < = ' f ' ) return ch - 87 ;
return - 1 ;
2023-07-21 17:40:49 +08:00
}
QString JParser : : readStr ( ) {
2023-10-23 11:44:22 +08:00
QByteArray buf ;
while ( readOne ( ) ! = ' " ' ) {
2023-07-21 17:40:49 +08:00
if ( ch = = 0 ) throw " Unexpected end-of-input: was expecting closing quote for string " ;
if ( ch = = ' \\ ' ) {
2023-10-23 11:44:22 +08:00
if ( readOne ( ) = = 0 ) throw " Unexpected end-of-input in char escape sequence " ;
2023-07-21 17:40:49 +08:00
if ( ch = = ' " ' | | ch = = ' \\ ' | | ch = = ' / ' ) buf . append ( ch ) ;
else if ( ch = = ' n ' ) buf . append ( ' \n ' ) ;
else if ( ch = = ' r ' ) buf . append ( ' \r ' ) ;
else if ( ch = = ' t ' ) buf . append ( ' \t ' ) ;
else if ( ch = = ' f ' ) buf . append ( ' \f ' ) ;
else if ( ch = = ' b ' ) buf . append ( ' \b ' ) ;
else if ( ch = = ' u ' ) {
2023-10-23 11:44:22 +08:00
uint hex = 0 ;
for ( int i = 3 ; i > = 0 ; i - - ) {
if ( readOne ( ) = = 0 ) throw " Unexpected end-of-input in char escape sequence " ;
auto h = toHex ( ch ) ;
if ( h = = - 1 ) throw " Illegal hex-digits in char escape sequence: \\ u " + ( hex = = 0 ? " " : QString : : number ( hex , 16 ) + ( char ) ch ) ;
hex | = h < < ( i < < 2 ) ;
}
buf . append ( QString ( QChar ( hex ) ) . toUtf8 ( ) ) ;
} else throw QString ( " Unrecognized char-escape " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ) after ' \\ ' " ;
2023-07-21 17:40:49 +08:00
} else buf . append ( ch ) ;
}
2023-10-23 11:44:22 +08:00
return QString : : fromUtf8 ( buf ) ;
2023-07-21 17:40:49 +08:00
}
void JParser : : skipSpace ( ) {
2023-10-23 11:44:22 +08:00
if ( bk ) {
bk = 0 ;
if ( ch > = 33 ) return ;
}
do {
in > > ch ;
if ( ch = = 0 ) throw " Unexpected end-of-input " ;
} while ( ch < 33 ) ; // || ch==65279
if ( ch = = ' / ' ) {
in > > ch ;
if ( ch = = ' / ' ) { //skipComment
do {
in > > ch ;
if ( ch = = 0 ) throw " Unexpected end-of-input " ;
} while ( ch ! = ' \n ' & & ch ! = ' \r ' ) ;
skipSpace ( ) ;
return ;
}
if ( ch = = ' * ' ) { //skipMultiComment
int last ;
do {
last = ch ;
in > > ch ;
if ( ch = = 0 ) throw " Unexpected end-of-input " ;
} while ( ch ! = ' / ' | | last ! = ' * ' ) ;
skipSpace ( ) ;
return ;
}
throw QString ( " Unexpected char " ) + ( char ) ch + " (code " + QString : : number ( ch ) + " ) " ;
2023-07-21 17:40:49 +08:00
}
}
void JOut : : write ( const JValue & value ) {
if ( value . type = = JValue : : Null ) out < < " null " ;
else if ( value . type = = JValue : : Str ) writeStr ( value . toStr ( ) ) ;
else if ( value . type = = JValue : : Obj ) writeMap ( value . toObj ( ) ) ;
else if ( value . type = = JValue : : Array ) writeList ( value . toArray ( ) ) ;
else out < < value . toStr ( ) ;
out . flush ( ) ;
}
void JOut : : writeStr ( const QString & str ) {
out < < ' " ' ;
QChar ch ;
for ( int i = 0 ; i < str . length ( ) ; i + + ) {
ch = str [ i ] ;
if ( ch = = ' " ' | | ch = = ' \\ ' ) out < < ' \\ ' < < ch ;
else if ( ch < ' ' ) {
if ( ch = = ' \n ' ) out < < " \\ n " ;
else if ( ch = = ' \r ' ) out < < " \\ r " ;
else if ( ch = = ' \t ' ) out < < " \\ t " ;
else if ( ch = = ' \f ' ) out < < " \\ f " ;
else if ( ch = = ' \b ' ) out < < " \\ b " ;
else {
out < < " \\ u00 " ;
auto aa = QString : : number ( ch . unicode ( ) , 16 ) ;
if ( aa . size ( ) = = 1 ) out < < ' 0 ' ;
out < < aa ;
}
} else out < < ch ;
}
out < < ' " ' ;
}
void JOut : : writeMap ( const JObj & map ) {
out < < ' { ' ;
if ( ! map . empty ( ) ) {
if ( indent . size ( ) ) {
out < < ' \n ' ;
cnt + + ;
for ( int c = 0 ; c < cnt ; c + + ) out < < indent ;
}
bool addSep = false ;
for ( const auto & pair : map ) {
if ( addSep ) {
out < < ' , ' ;
if ( indent . size ( ) ) {
out < < ' \n ' ;
for ( int c = 0 ; c < cnt ; c + + ) out < < indent ;
}
}
else addSep = true ;
out < < ' " ' < < pair . first < < " \" : " ;
if ( indent . size ( ) ) out < < ' ' ;
write ( pair . second ) ;
}
if ( indent . size ( ) ) {
out < < ' \n ' ;
cnt - - ;
for ( int c = 0 ; c < cnt ; c + + ) out < < indent ;
}
}
out < < ' } ' ;
}
void JOut : : writeList ( const JArray & vals ) {
out < < ' [ ' ;
auto iter = vals . begin ( ) ;
auto end = vals . end ( ) ;
if ( iter ! = end ) write ( * iter + + ) ;
while ( iter ! = end ) {
out < < ' , ' ;
if ( indent . size ( ) ) out < < ' ' ;
write ( * iter + + ) ;
}
out < < ' ] ' ;
}