diff --git a/ChangeLog.txt b/ChangeLog.txt index be4b322478..d32cfb7ad6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,35 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2015-11-30 14:56 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * include/hbjson.h + * src/rtl/hbjson.c + + added new C function: + char * hb_jsonEncodeCP( PHB_ITEM pValue, HB_SIZE * pnLen, + HB_BOOL fHuman, PHB_CODEPAGE cdp ); + It allows to pass explicitly codepage in which strings inside pValue + are encoded. If cdp parameter is not NULL then it's used to extract + unicode character values from passed strings and this values is used + to encode to encode non ASCII characters as "\uXXXX" where XXXX is + unicode character value. Data serialized in such way is 7bit clean. + If this parameter is NULL then strings are encoded in raw form just + like in hb_jsonEncode(). + + added new C function: + HB_SIZE hb_jsonDecodeCP( const char * szSource, PHB_ITEM pValue, + PHB_CODEPAGE cdp ); + It allows to pass explicitly codepage used for strings decoded from + JSON data. If this parameter is NULL then strings are decoded in raw + form and unicode character with code over 255 are converted to '?' + char. + + added optional 3-rd parameter with codepage ID to PRG functions + hb_jsonEncode() and hb_jsonDecode(). If this parameter is not given + then above functions works like before this modification: + hb_jsonEncode() uses raw string encoding and hb_jsonDecode() uses + current HVM CP to decode characters encoded as \uXXXX. + + modified PRG function hb_jsonDecode() to return decoded data + instead of length of decoded data when second parameter is not + passed by reference. + 2015-11-25 15:06 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * include/harbour.hbx * src/rtl/dateshb.c diff --git a/include/hbjson.h b/include/hbjson.h index 16c0d70dc4..7586089708 100644 --- a/include/hbjson.h +++ b/include/hbjson.h @@ -50,11 +50,14 @@ #define HB_JSON_H_ #include "hbapi.h" +#include "hbapicdp.h" HB_EXTERN_BEGIN extern HB_EXPORT char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ); +extern HB_EXPORT char * hb_jsonEncodeCP( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman, PHB_CODEPAGE cdp ); extern HB_EXPORT HB_SIZE hb_jsonDecode( const char * szSource, PHB_ITEM pValue ); +extern HB_EXPORT HB_SIZE hb_jsonDecodeCP( const char * szSource, PHB_ITEM pValue, PHB_CODEPAGE cdp ); HB_EXTERN_END diff --git a/src/rtl/hbjson.c b/src/rtl/hbjson.c index d71c69b227..92c11ff782 100644 --- a/src/rtl/hbjson.c +++ b/src/rtl/hbjson.c @@ -142,7 +142,7 @@ static void _hb_jsonCtxAddIndent( PHB_JSON_ENCODE_CTX pCtx, HB_SIZE nCount ) } static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, - HB_SIZE nLevel, HB_BOOL fEOL ) + HB_SIZE nLevel, HB_BOOL fEOL, PHB_CODEPAGE cdp ) { /* Protection against recursive structures */ if( ( HB_IS_ARRAY( pValue ) || HB_IS_HASH( pValue ) ) && hb_itemSize( pValue ) > 0 ) @@ -176,57 +176,102 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, if( HB_IS_STRING( pValue ) ) { - const char * szString = hb_itemGetCPtr( pValue ); HB_SIZE nPos, nPos2, nLen = hb_itemGetCLen( pValue ); + const char * szString = hb_itemGetCPtr( pValue ); + char buf[ 8 ]; _hb_jsonCtxAdd( pCtx, "\"", 1 ); - nPos = 0; - while( nPos < nLen ) + if( cdp ) { - nPos2 = nPos; - while( *( ( const unsigned char * ) szString + nPos2 ) >= ' ' && - szString[ nPos2 ] != '\\' && szString[ nPos2 ] != '\"' ) - nPos2++; - if( nPos2 > nPos ) - { - _hb_jsonCtxAdd( pCtx, szString + nPos, nPos2 - nPos ); - nPos = nPos2; - continue; - } + HB_WCHAR wc; - switch( szString[ nPos ] ) + nPos = 0; + while( HB_CDPCHAR_GET( cdp, szString, nLen, &nPos, &wc ) ) { - case '\\': - _hb_jsonCtxAdd( pCtx, "\\\\", 2 ); - break; - case '\"': - _hb_jsonCtxAdd( pCtx, "\\\"", 2 ); - break; - case '\b': - _hb_jsonCtxAdd( pCtx, "\\b", 2 ); - break; - case '\f': - _hb_jsonCtxAdd( pCtx, "\\f", 2 ); - break; - case '\n': - _hb_jsonCtxAdd( pCtx, "\\n", 2 ); - break; - case '\r': - _hb_jsonCtxAdd( pCtx, "\\r", 2 ); - break; - case '\t': - _hb_jsonCtxAdd( pCtx, "\\t", 2 ); - break; - default: + if( wc >= ' ' && wc < 0x7F && wc != '\\' && wc != '\"' ) { - char buf[ 8 ]; - hb_snprintf( buf, sizeof( buf ), "\\u00%02X", ( unsigned char ) szString[ nPos ] ); - _hb_jsonCtxAdd( pCtx, buf, 6 ); - break; + buf[ 0 ] = ( char ) wc; + _hb_jsonCtxAdd( pCtx, buf, 1 ); + continue; + } + switch( wc ) + { + case '\\': + _hb_jsonCtxAdd( pCtx, "\\\\", 2 ); + break; + case '\"': + _hb_jsonCtxAdd( pCtx, "\\\"", 2 ); + break; + case '\b': + _hb_jsonCtxAdd( pCtx, "\\b", 2 ); + break; + case '\f': + _hb_jsonCtxAdd( pCtx, "\\f", 2 ); + break; + case '\n': + _hb_jsonCtxAdd( pCtx, "\\n", 2 ); + break; + case '\r': + _hb_jsonCtxAdd( pCtx, "\\r", 2 ); + break; + case '\t': + _hb_jsonCtxAdd( pCtx, "\\t", 2 ); + break; + default: + hb_snprintf( buf, sizeof( buf ), "\\u%04X", wc ); + _hb_jsonCtxAdd( pCtx, buf, 6 ); + break; } } - nPos++; + } + else + { + nPos = 0; + while( nPos < nLen ) + { + unsigned char uch = szString[ nPos ]; + nPos2 = nPos; + while( uch >= ' ' && uch != '\\' && uch != '\"' ) + uch = szString[ ++nPos2 ]; + if( nPos2 > nPos ) + { + _hb_jsonCtxAdd( pCtx, szString + nPos, nPos2 - nPos ); + if( nPos2 >= nLen ) + break; + nPos = nPos2; + } + + switch( uch ) + { + case '\\': + _hb_jsonCtxAdd( pCtx, "\\\\", 2 ); + break; + case '\"': + _hb_jsonCtxAdd( pCtx, "\\\"", 2 ); + break; + case '\b': + _hb_jsonCtxAdd( pCtx, "\\b", 2 ); + break; + case '\f': + _hb_jsonCtxAdd( pCtx, "\\f", 2 ); + break; + case '\n': + _hb_jsonCtxAdd( pCtx, "\\n", 2 ); + break; + case '\r': + _hb_jsonCtxAdd( pCtx, "\\r", 2 ); + break; + case '\t': + _hb_jsonCtxAdd( pCtx, "\\t", 2 ); + break; + default: + hb_snprintf( buf, sizeof( buf ), "\\u00%02X", uch ); + _hb_jsonCtxAdd( pCtx, buf, 6 ); + break; + } + nPos++; + } } _hb_jsonCtxAdd( pCtx, "\"", 1 ); } @@ -312,7 +357,7 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, hb_itemSize( pItem ) > 0 ) ) _hb_jsonCtxAddIndent( pCtx, ( nLevel + 1 ) * INDENT_SIZE ); - _hb_jsonEncode( pItem, pCtx, nLevel + 1, HB_FALSE ); + _hb_jsonEncode( pItem, pCtx, nLevel + 1, HB_FALSE, cdp ); } if( pCtx->fHuman ) { @@ -353,7 +398,7 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, _hb_jsonCtxAdd( pCtx, pCtx->szEol, pCtx->iEolLen ); _hb_jsonCtxAddIndent( pCtx, ( nLevel + 1 ) * INDENT_SIZE ); } - _hb_jsonEncode( pKey, pCtx, nLevel + 1, HB_FALSE ); + _hb_jsonEncode( pKey, pCtx, nLevel + 1, HB_FALSE, cdp ); if( pCtx->fHuman ) { @@ -366,7 +411,7 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, fEOL = HB_FALSE; } - _hb_jsonEncode( pItem, pCtx, nLevel + 1, fEOL ); + _hb_jsonEncode( pItem, pCtx, nLevel + 1, fEOL, cdp ); } } if( pCtx->fHuman ) @@ -394,7 +439,7 @@ static const char * _skipws( const char * szSource ) return szSource; } -static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) +static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue, PHB_CODEPAGE cdp ) { if( *szSource == '\"' ) { @@ -462,9 +507,14 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) return NULL; } } - szHead += hb_cdpU16ToStr( hb_vmCDP(), HB_CDP_ENDIAN_NATIVE, - &wc, 1, - szHead, szDest + nAlloc - szHead ); + if( cdp ) + szHead += hb_cdpU16ToStr( cdp, HB_CDP_ENDIAN_NATIVE, + &wc, 1, + szHead, szDest + nAlloc - szHead ); + else if( wc <= 0xFF ) + *szHead++ = ( char ) wc; + else + *szHead++ = '?'; break; } default: @@ -574,7 +624,7 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) for( ;; ) { - szSource = _hb_jsonDecode( szSource, pItem ); + szSource = _hb_jsonDecode( szSource, pItem, cdp ); if( ! szSource ) { hb_itemRelease( pItem ); @@ -612,10 +662,10 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) for( ;; ) { /* Do we need to check if key does not exist yet? */ - if( ( szSource = _hb_jsonDecode( szSource, pItemKey ) ) == NULL || + if( ( szSource = _hb_jsonDecode( szSource, pItemKey, cdp ) ) == NULL || ! HB_IS_STRING( pItemKey ) || * ( szSource = _skipws( szSource ) ) != ':' || - ( szSource = _hb_jsonDecode( _skipws( szSource + 1 ), pItemValue ) ) == NULL) + ( szSource = _hb_jsonDecode( _skipws( szSource + 1 ), pItemValue, cdp ) ) == NULL) { hb_itemRelease( pItemKey ); hb_itemRelease( pItemValue ); @@ -648,7 +698,7 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) /* C level API functions */ -char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ) +char * hb_jsonEncodeCP( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman, PHB_CODEPAGE cdp ) { PHB_JSON_ENCODE_CTX pCtx; char * szRet; @@ -665,7 +715,7 @@ char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ) pCtx->szEol = hb_conNewLine(); pCtx->iEolLen = ( int ) strlen( pCtx->szEol ); - _hb_jsonEncode( pValue, pCtx, 0, HB_FALSE ); + _hb_jsonEncode( pValue, pCtx, 0, HB_FALSE, cdp ); if( fHuman ) _hb_jsonCtxAdd( pCtx, pCtx->szEol, pCtx->iEolLen ); @@ -679,12 +729,17 @@ char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ) return szRet; } -HB_SIZE hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) +char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ) +{ + return hb_jsonEncodeCP( pValue, pnLen, fHuman, NULL ); +} + +HB_SIZE hb_jsonDecodeCP( const char * szSource, PHB_ITEM pValue, PHB_CODEPAGE cdp ) { PHB_ITEM pItem = pValue ? pValue : hb_itemNew( NULL ); const char * sz; - sz = szSource ? _hb_jsonDecode( _skipws( szSource ), pItem ) : NULL; + sz = szSource ? _hb_jsonDecode( _skipws( szSource ), pItem, cdp ) : NULL; if( ! pValue ) hb_itemRelease( pItem ); if( sz ) @@ -692,9 +747,28 @@ HB_SIZE hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) return 0; } +HB_SIZE hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) +{ + return hb_jsonDecodeCP( szSource, pValue, hb_vmCDP() ); +} /* Harbour level API functions */ +static PHB_CODEPAGE _hb_jsonCdpPar( int iParam, HB_BOOL lVmCp ) +{ + if( hb_pcount() >= iParam ) + { + const char * szCdp = hb_parc( iParam ); + + if( szCdp ) + return hb_cdpFindExt( szCdp ); + } + else if( lVmCp ) + return hb_vmCDP(); + + return NULL; +} + HB_FUNC( HB_JSONENCODE ) { PHB_ITEM pItem = hb_param( 1, HB_IT_ANY ); @@ -702,8 +776,10 @@ HB_FUNC( HB_JSONENCODE ) if( pItem ) { HB_SIZE nLen; + char * szRet; - char * szRet = hb_jsonEncode( pItem, &nLen, hb_parl( 2 ) ); + szRet = hb_jsonEncodeCP( pItem, &nLen, hb_parl( 2 ), + _hb_jsonCdpPar( 3, HB_FALSE ) ); hb_retclen_buffer( szRet, nLen ); } } @@ -711,8 +787,15 @@ HB_FUNC( HB_JSONENCODE ) HB_FUNC( HB_JSONDECODE ) { PHB_ITEM pItem = hb_itemNew( NULL ); + HB_SIZE nSize = hb_jsonDecodeCP( hb_parc( 1 ), pItem, + _hb_jsonCdpPar( 3, HB_TRUE ) ); - hb_retns( ( HB_ISIZ ) hb_jsonDecode( hb_parc( 1 ), pItem ) ); - hb_itemParamStoreForward( 2, pItem ); - hb_itemRelease( pItem ); + if( HB_ISBYREF( 2 ) ) + { + hb_retns( ( HB_ISIZ ) nSize ); + hb_itemParamStoreForward( 2, pItem ); + hb_itemRelease( pItem ); + } + else + hb_itemReturnRelease( pItem ); }