From c7c5d14460abfb2aaf0f801a842285f4a99e064b Mon Sep 17 00:00:00 2001 From: Mindaugas Kavaliauskas Date: Fri, 22 Oct 2010 23:10:37 +0000 Subject: [PATCH] 2010-10-24 02:10 UTC+0300 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt) * harbour/rtl/hbjson.c + added human readable JSON encoding support char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ); hb_jsonEncode( xValue [, lHuman = .F. ] ) --> cJSON ! removed UTF8 encoding from JSON functions. These function should return/accept data in VM codepage, just like any other string function. If JSON string is to be stored as some binary stream (ex., file), HB_StrToUTF8() should be applied on the hb_jsonEncode() result. This conversion removal fixes code when returned JSON string is used not as a binary stream. Ex.: oIE:document:getElementById("data_div"):innerHtml := hb_jsonEncode(xValue) --- harbour/ChangeLog | 13 ++++ harbour/src/rtl/hbjson.c | 148 ++++++++++++++++++++++++++++++--------- 2 files changed, 127 insertions(+), 34 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 811e41fed4..e0678df01c 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,19 @@ The license applies to all entries newer than 2009-04-28. */ +2010-10-24 02:10 UTC+0300 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt) + * harbour/rtl/hbjson.c + + added human readable JSON encoding support + char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ); + hb_jsonEncode( xValue [, lHuman = .F. ] ) --> cJSON + ! removed UTF8 encoding from JSON functions. These function should + return/accept data in VM codepage, just like any other string + function. If JSON string is to be stored as some binary stream + (ex., file), HB_StrToUTF8() should be applied on the hb_jsonEncode() + result. This conversion removal fixes code when returned JSON string is used + not as a binary stream. Ex.: + oIE:document:getElementById("data_div"):innerHtml := hb_jsonEncode(xValue) + 2010-10-23 21:15 UTC+0300 Mindaugas Kavaliauskas (dbtopas/at/dbtopas.lt) - harbour/include/hbnsctp.ch - harbour/include/hbnsctp.h diff --git a/harbour/src/rtl/hbjson.c b/harbour/src/rtl/hbjson.c index f0ddb2cfd1..795ff0a2aa 100644 --- a/harbour/src/rtl/hbjson.c +++ b/harbour/src/rtl/hbjson.c @@ -60,10 +60,11 @@ http://www.ietf.org/rfc/rfc4627.txt C level functions: - char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen ); + char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ); pValue - value to encode; pnLen - if pnLen is not NULL, length of returned buffer is stored to *pnLen; + fHuman - format to be human redable; returns pointer to encoded JSON buffer. buffer must be fried by the caller. @@ -77,7 +78,7 @@ Harbour level functions: hb_jsonDecode( cJSON, @xValue ) --> nLengthDecoded - hb_jsonEncode( xValue ) --> cJSON + hb_jsonEncode( xValue [, lHuman = .F. ] ) --> cJSON Note: - Harbour types unsupported by JSON (date, timestamp, etc.) are @@ -104,9 +105,20 @@ typedef struct HB_SIZE nAlloc; void ** pId; HB_SIZE nAllocId; + HB_BOOL fHuman; } HB_JSON_ENCODE_CTX, * PHB_JSON_ENCODE_CTX; +#if defined( HB_OS_UNIX ) && !defined( HB_EOL_CRLF ) + static const char s_szEol[ 2 ] = { HB_CHAR_LF, 0 }; + static const int s_iEolLen = 1; +#else + static const char s_szEol[ 3 ] = { HB_CHAR_CR, HB_CHAR_LF, 0 }; + static const int s_iEolLen = 2; +#endif + +#define INDENT_SIZE 2 + static void _hb_jsonCtxAdd( PHB_JSON_ENCODE_CTX pCtx, const char * szString, HB_SIZE nLen ) { if( pCtx->pHead + nLen >= pCtx->pBuffer + pCtx->nAlloc ) @@ -124,6 +136,23 @@ static void _hb_jsonCtxAdd( PHB_JSON_ENCODE_CTX pCtx, const char * szString, HB_ } } +static void _hb_jsonCtxAddIndent( PHB_JSON_ENCODE_CTX pCtx, HB_SIZE nCount ) +{ + if( nCount <= 0 ) + return; + + if( pCtx->pHead + nCount >= pCtx->pBuffer + pCtx->nAlloc ) + { + HB_SIZE nSize = pCtx->pHead - pCtx->pBuffer; + + pCtx->nAlloc += ( pCtx->nAlloc << 1 ) + nCount; + pCtx->pBuffer = ( char * ) hb_xrealloc( pCtx->pBuffer, pCtx->nAlloc ); + pCtx->pHead = pCtx->pBuffer + nSize; + } + hb_xmemset( pCtx->pHead, ' ', nCount ); + pCtx->pHead += nCount; +} + static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, HB_SIZE nLevel ) { if( nLevel >= pCtx->nAllocId ) @@ -151,10 +180,8 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, HB_SIZE n if( HB_IS_STRING( pValue ) ) { - void * hText; - HB_SIZE nLen; - const char * szString = hb_itemGetStrUTF8( pValue, &hText, &nLen ); - HB_SIZE nPos, nPos2; + const char * szString = hb_itemGetCPtr( pValue ); + HB_SIZE nPos, nPos2, nLen = hb_itemGetCLen( pValue ); _hb_jsonCtxAdd( pCtx, "\"", 1 ); @@ -206,7 +233,6 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, HB_SIZE n nPos++; } _hb_jsonCtxAdd( pCtx, "\"", 1 ); - hb_strfree( hText ); } else if( HB_IS_NUMINT( pValue ) ) { @@ -238,38 +264,94 @@ static void _hb_jsonEncode( PHB_ITEM pValue, PHB_JSON_ENCODE_CTX pCtx, HB_SIZE n } else if( HB_IS_ARRAY( pValue ) ) { - HB_SIZE nIndex, nLen = hb_itemSize( pValue ); + HB_SIZE nLen = hb_itemSize( pValue ); - _hb_jsonCtxAdd( pCtx, "[", 1 ); - for( nIndex = 1; nIndex <= nLen; nIndex++ ) + if( nLen ) { - if( nIndex > 1 ) - _hb_jsonCtxAdd( pCtx, ",", 1 ); - _hb_jsonEncode( hb_arrayGetItemPtr( pValue, nIndex ), pCtx, nLevel + 1 ); + HB_SIZE nIndex; + + if( pCtx->fHuman ) + _hb_jsonCtxAddIndent( pCtx, nLevel * INDENT_SIZE ); + + _hb_jsonCtxAdd( pCtx, "[", 1 ); + + for( nIndex = 1; nIndex <= nLen; nIndex++ ) + { + PHB_ITEM pItem = hb_arrayGetItemPtr( pValue, nIndex ); + + if( nIndex > 1 ) + _hb_jsonCtxAdd( pCtx, ",", 1 ); + + if( pCtx->fHuman ) + _hb_jsonCtxAdd( pCtx, s_szEol, s_iEolLen ); + + if( pCtx->fHuman && ( ! HB_IS_ARRAY( pItem ) && ! HB_IS_HASH( pItem ) || + hb_itemSize( pItem ) == 0 ) ) + _hb_jsonCtxAddIndent( pCtx, ( nLevel + 1 ) * INDENT_SIZE ); + + _hb_jsonEncode( pItem, pCtx, nLevel + 1 ); + } + if( pCtx->fHuman ) + { + _hb_jsonCtxAdd( pCtx, s_szEol, s_iEolLen ); + _hb_jsonCtxAddIndent( pCtx, nLevel * INDENT_SIZE ); + } + _hb_jsonCtxAdd( pCtx, "]", 1 ); } - _hb_jsonCtxAdd( pCtx, "]", 1 ); + else + _hb_jsonCtxAdd( pCtx, "[]", 2 ); } else if( HB_IS_HASH( pValue ) ) { - HB_SIZE nIndex, nLen = hb_hashLen( pValue ); - HB_BOOL fComma = HB_FALSE; + HB_SIZE nLen = hb_hashLen( pValue ); - _hb_jsonCtxAdd( pCtx, "{", 1 ); - for( nIndex = 1; nIndex <= nLen; nIndex++ ) + if( nLen ) { - PHB_ITEM pItem = hb_hashGetKeyAt( pValue, nIndex ); + HB_SIZE nIndex; - if( HB_IS_STRING( pItem ) ) + if( pCtx->fHuman ) + _hb_jsonCtxAddIndent( pCtx, nLevel * INDENT_SIZE ); + + _hb_jsonCtxAdd( pCtx, "{", 1 ); + + for( nIndex = 1; nIndex <= nLen; nIndex++ ) { - if( fComma ) - _hb_jsonCtxAdd( pCtx, ",", 1 ); - _hb_jsonEncode( pItem, pCtx, nLevel + 1 ); - _hb_jsonCtxAdd( pCtx, ":", 1 ); - _hb_jsonEncode( hb_hashGetValueAt( pValue, nIndex ), pCtx, nLevel + 1 ); - fComma = HB_TRUE; + PHB_ITEM pKey = hb_hashGetKeyAt( pValue, nIndex ); + + if( HB_IS_STRING( pKey ) ) + { + PHB_ITEM pItem = hb_hashGetValueAt( pValue, nIndex ); + if( nIndex > 1 ) + _hb_jsonCtxAdd( pCtx, ",", 1 ); + + if( pCtx->fHuman ) + { + _hb_jsonCtxAdd( pCtx, s_szEol, s_iEolLen ); + _hb_jsonCtxAddIndent( pCtx, ( nLevel + 1 ) * INDENT_SIZE ); + } + _hb_jsonEncode( pKey, pCtx, nLevel + 1 ); + + if( pCtx->fHuman ) + { + _hb_jsonCtxAdd( pCtx, " : ", 3 ); + if( ( HB_IS_ARRAY( pItem ) || HB_IS_HASH( pItem ) ) && hb_itemSize( pItem ) > 0 ) + _hb_jsonCtxAdd( pCtx, s_szEol, s_iEolLen ); + } + else + _hb_jsonCtxAdd( pCtx, ":", 1 ); + + _hb_jsonEncode( pItem, pCtx, nLevel + 1 ); + } } + if( pCtx->fHuman ) + { + _hb_jsonCtxAdd( pCtx, s_szEol, s_iEolLen ); + _hb_jsonCtxAddIndent( pCtx, nLevel * INDENT_SIZE ); + } + _hb_jsonCtxAdd( pCtx, "}", 1 ); } - _hb_jsonCtxAdd( pCtx, "}", 1 ); + else + _hb_jsonCtxAdd( pCtx, "{}", 2 ); } else { @@ -334,7 +416,6 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) break; case 'u': { - char utf8buf[ 6 ]; int i, val = 0; szSource++; @@ -354,9 +435,7 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) hb_xfree( szDest ); return NULL; } - i = hb_cdpU16CharToUTF8( utf8buf, ( HB_WCHAR ) val ); - hb_xmemcpy( szHead, utf8buf, i ); - szHead += i; + *szHead = hb_cdpGetChar( hb_vmCDP(), HB_TRUE, ( HB_WCHAR ) val ); szSource += 3; break; } @@ -376,7 +455,7 @@ static const char * _hb_jsonDecode( const char * szSource, PHB_ITEM pValue ) return NULL; } } - hb_itemPutStrLenUTF8( pValue, szDest, szHead - szDest ); + hb_itemPutCL( pValue, szDest, szHead - szDest ); hb_xfree( szDest ); return szSource + 1; } @@ -540,7 +619,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 ) +char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen, HB_BOOL fHuman ) { PHB_JSON_ENCODE_CTX pCtx; char * szRet; @@ -551,6 +630,7 @@ char * hb_jsonEncode( PHB_ITEM pValue, HB_SIZE * pnLen ) pCtx->pHead = pCtx->pBuffer = ( char * ) hb_xgrab( pCtx->nAlloc ); pCtx->nAllocId = 8; pCtx->pId = ( void ** ) hb_xgrab( sizeof( void * ) * pCtx->nAllocId ); + pCtx->fHuman = fHuman; _hb_jsonEncode( pValue, pCtx, 0 ); @@ -588,7 +668,7 @@ HB_FUNC( HB_JSONENCODE ) { HB_SIZE nLen; - char * szRet = hb_jsonEncode( pItem, &nLen ); + char * szRet = hb_jsonEncode( pItem, &nLen, hb_parl( 2 ) ); hb_retclen_buffer( szRet, nLen ); } }