diff --git a/harbour/ChangeLog.txt b/harbour/ChangeLog.txt index c8876de807..879c49445d 100644 --- a/harbour/ChangeLog.txt +++ b/harbour/ChangeLog.txt @@ -10,6 +10,30 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2013-01-23 08:56 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * harbour/src/vm/classes.c + * updated some comments + * renamed hb_setClsHandle() to __objSetClassHandle() + old function name covered by HB_LEGACY_LEVEL5 macro + + * harbour/src/rtl/itemseri.c + + added support for deserialization xHarbour HB_SERIALIZE() output. + All types except codeblocks are supported. I haven't added support + for xHarbour serialized data with cyclic references. If it will be + really necessary then I can implement it. + I also added workaround for bug in xHarbour serialization code so + now Harbour correctly decodes data with LONGLONG numbers though + xHarbour cannot correctly decode its own stream. + Now Harbour can deserialize xHarbour data encoded by HB_SERIALIZE() + and stored somewhere. It can be important in migration process, i.e. + SQLRDD uses HB_SERIALIZE() to encode data in memos so now SQLRDD + port for Harbour should read old tables and decode xHarbour items + correctly. The same is for any other tool which saved HB_SERIALIZE() + output in xHarbour. + + * harbour/ChangeLog.txt + * minor update + 2013-01-23 00:59 UTC+0100 Viktor Szakats (harbour syenar.net) * utils/hbmk2/hbmk2.prg ! FindInPath(): fixed for filenames with an empty @@ -21719,12 +21743,12 @@ serialized by default serialization code used by both compilers to generate expressions. In Harbour it's done by hb_valToExp() function and - in xHarbour it's ValToPrg() is used. + in xHarbour ValToPrg() is used. ValToPrg() does not create valid macrocompiler expressions for arrays and objects so HBPersistent files created by xHarbour are broken and cannot be correctly deserialized. - It happens if objects has hash arrays in instance variables - and these hash arrays contain normal arrays or object + It happens if object has hash arrays in instance variables + and these hash arrays contain normal arrays or objects. If Harbour application restores such xHarbour HBPersistent file then RTE "Syntax error: &" is generated. ; xHarbour encapsulates deserialization code inside TRY/CATCH/END @@ -21749,6 +21773,7 @@ HBPersistent:LoadFromFile(): If necessary we can implement it though it's usable only if we want to ignore some wrong lines and process others. + [Update: support for have been added] ; Warning: Neither Harbour nor xHarbour supports arrays and objects with cyclic references in HBPersistent code - infinite loop appears in such case. diff --git a/harbour/src/rtl/itemseri.c b/harbour/src/rtl/itemseri.c index d74588a059..e42691e38c 100644 --- a/harbour/src/rtl/itemseri.c +++ b/harbour/src/rtl/itemseri.c @@ -55,6 +55,9 @@ #include "hbapicls.h" #include "hbapicdp.h" +#include "hbvm.h" +#include "hbstack.h" + /* HB_UCHAR [ 1 ] - item type @@ -67,7 +70,7 @@ HB_UCHAR [ 1 ] - item type 6. INT24 3 7. INT32 4 8. INT64 8 - 9. DOUBLE IEE754 LE 8 + 9. DOUBLE IEEE754 LE 8 10. DATE 3 11. STRING8 1+n 12. STRING16 2+n @@ -100,6 +103,27 @@ HB_UCHAR [ 1 ] - item type 39. TIMESTAMP 8 40. HASHFLAGS 2 41. HASHDEFAULT VALUE 0 + +xHarbour types HB_SERIAL_XHB_*: + 67. 'C' 8+n + 76. 'L' 'T'|'F' 1 + 78. 'N' 'I' 1+8 + 78. 'N' 'L' 1+8 + 78. 'N' 'X' 1+8 + 78. 'N' 'D'1+8 + 68. 'D' 8 + 84. 'T' 8 + 90. 'Z' 0 +complex ones: + 65. 'A' 8+n ,... + 66. 'B' 1+n (HB_SaveBlock()) + 72. 'H' 8+n ,... + 79. 'O' 8+n ,,... (__ClsGetPropertiesAndValues()) + 81. 'Q' 8+n ,HBPersistent:SaveToText(raw) + 82. 'R' 'A' 1+8 (index to array of arrays) + 82. 'R' 'O' 1+8 (index to array of objects) + 82. 'R' 'H' 1+8 (index to array of hashes) + 82. 'R' 'B' 1+8 (index to array of codeblock) */ #define HB_SERIAL_NIL 0 @@ -144,6 +168,20 @@ HB_UCHAR [ 1 ] - item type #define HB_SERIAL_TIMESTAMP 39 #define HB_SERIAL_HASHFLAGS 40 #define HB_SERIAL_HASHDEFVAL 41 +/* xHarbour types */ +#define HB_SERIAL_XHB_A 65 +#define HB_SERIAL_XHB_B 66 +#define HB_SERIAL_XHB_C 67 +#define HB_SERIAL_XHB_D 68 +#define HB_SERIAL_XHB_H 72 +#define HB_SERIAL_XHB_L 76 +#define HB_SERIAL_XHB_O 79 +#define HB_SERIAL_XHB_Q 81 +#define HB_SERIAL_XHB_R 82 +#define HB_SERIAL_XHB_N 78 +#define HB_SERIAL_XHB_T 84 +#define HB_SERIAL_XHB_Z 90 + #define HB_SERIAL_DUMMYOFFSET ( ( HB_SIZE ) -1 ) @@ -825,7 +863,7 @@ static HB_SIZE hb_deserializeItem( PHB_ITEM pItem, const HB_UCHAR * pBuffer, HB_SIZE nOffset, PHB_CYCLIC_REF pRef ) { - HB_SIZE nLen, ulPad, nSize; + HB_SIZE nLen, nPad, nSize; char * szVal; switch( pBuffer[ nOffset++ ] ) @@ -958,42 +996,42 @@ static HB_SIZE hb_deserializeItem( PHB_ITEM pItem, break; case HB_SERIAL_STRPAD8: nSize = pBuffer[ nOffset++ ]; - ulPad = pBuffer[ nOffset++ ]; + nPad = pBuffer[ nOffset++ ]; nLen = hb_cdpnDupLen( ( const char * ) &pBuffer[ nOffset ], nSize, cdpIn, cdpOut ); - szVal = ( char * ) hb_xgrab( nLen + ulPad + 1 ); + szVal = ( char * ) hb_xgrab( nLen + nPad + 1 ); hb_cdpnDup2( ( const char * ) &pBuffer[ nOffset ], nSize, szVal, &nLen, cdpIn, cdpOut ); - memset( szVal + nLen, ' ', ulPad ); - hb_itemPutCLPtr( pItem, szVal, nLen + ulPad ); + memset( szVal + nLen, ' ', nPad ); + hb_itemPutCLPtr( pItem, szVal, nLen + nPad ); nOffset += nSize; break; case HB_SERIAL_STRPAD16: nSize = HB_GET_LE_UINT16( &pBuffer[ nOffset ] ); nOffset += 2; - ulPad = HB_GET_LE_UINT16( &pBuffer[ nOffset ] ); + nPad = HB_GET_LE_UINT16( &pBuffer[ nOffset ] ); nOffset += 2; nLen = hb_cdpnDupLen( ( const char * ) &pBuffer[ nOffset ], nSize, cdpIn, cdpOut ); - szVal = ( char * ) hb_xgrab( nLen + ulPad + 1 ); + szVal = ( char * ) hb_xgrab( nLen + nPad + 1 ); hb_cdpnDup2( ( const char * ) &pBuffer[ nOffset ], nSize, szVal, &nLen, cdpIn, cdpOut ); - memset( szVal + nLen, ' ', ulPad ); - hb_itemPutCLPtr( pItem, szVal, nLen + ulPad ); + memset( szVal + nLen, ' ', nPad ); + hb_itemPutCLPtr( pItem, szVal, nLen + nPad ); nOffset += nSize; break; case HB_SERIAL_STRPAD32: nSize = HB_GET_LE_UINT32( &pBuffer[ nOffset ] ); nOffset += 4; - ulPad = HB_GET_LE_UINT32( &pBuffer[ nOffset ] ); + nPad = HB_GET_LE_UINT32( &pBuffer[ nOffset ] ); nOffset += 4; nLen = hb_cdpnDupLen( ( const char * ) &pBuffer[ nOffset ], nSize, cdpIn, cdpOut ); - szVal = ( char * ) hb_xgrab( nLen + ulPad + 1 ); + szVal = ( char * ) hb_xgrab( nLen + nPad + 1 ); hb_cdpnDup2( ( const char * ) &pBuffer[ nOffset ], nSize, szVal, &nLen, cdpIn, cdpOut ); - hb_xmemset( szVal + nLen, ' ', ulPad ); - hb_itemPutCLPtr( pItem, szVal, nLen + ulPad ); + hb_xmemset( szVal + nLen, ' ', nPad ); + hb_itemPutCLPtr( pItem, szVal, nLen + nPad ); nOffset += nSize; break; @@ -1077,6 +1115,153 @@ static HB_SIZE hb_deserializeItem( PHB_ITEM pItem, break; } + /* xHarbour types */ + case HB_SERIAL_XHB_C: + nSize = nLen = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ); + nOffset += 8; + szVal = hb_cdpnDup( ( const char * ) &pBuffer[ nOffset ], &nLen, + cdpIn, cdpOut ); + hb_itemPutCLPtr( pItem, szVal, nLen ); + nOffset += nSize; + break; + case HB_SERIAL_XHB_L: + hb_itemPutL( pItem, pBuffer[ nOffset++ ] == 'T' ); + break; + case HB_SERIAL_XHB_N: + switch( pBuffer[ nOffset++ ] ) + { + case 'I': + hb_itemPutNI( pItem, ( int ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ) ); + break; + case 'L': + hb_itemPutNL( pItem, ( long ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ) ); + break; + case 'X': + hb_itemPutNInt( pItem, ( HB_MAXINT ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ) ); + /* this is workaround for bug in xHarbour serialization code */ + nOffset += 10; + break; + case 'D': + hb_itemPutND( pItem, HB_GET_LE_DOUBLE( &pBuffer[ nOffset ] ) ); + break; + default: + hb_itemClear( pItem ); + break; + } + nOffset += 8; + break; + case HB_SERIAL_XHB_D: + hb_itemPutDL( pItem, ( long ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ) ); + nOffset += 8; + break; + case HB_SERIAL_XHB_T: + hb_itemPutTD( pItem, HB_GET_LE_DOUBLE( &pBuffer[ nOffset ] ) ); + nOffset += 8; + break; + case HB_SERIAL_XHB_Z: + hb_itemClear( pItem ); + break; + case HB_SERIAL_XHB_A: + nLen = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ); + nOffset = hb_deserializeArray( pItem, cdpIn, cdpOut, pBuffer, + nOffset + 8, nLen, pRef ); + break; + case HB_SERIAL_XHB_B: + nOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + nOffset, pRef ); + /* we do not support codeblock deserialization: HB_RestoreBlock( pItem ) */ + hb_itemClear( pItem ); + break; + case HB_SERIAL_XHB_H: + nLen = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ); + nOffset = hb_deserializeHash( pItem, cdpIn, cdpOut, pBuffer, + nOffset + 8, nLen, pRef ); + hb_hashSetFlags( pItem, HB_HASH_KEEPORDER | HB_HASH_RESORT ); + break; + case HB_SERIAL_XHB_O: + { + HB_USHORT uiClass; + + nLen = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ); + /* deserialize :className */ + nOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + nOffset + 8, pRef ); + /* find class handle */ + uiClass = hb_clsFindClass( hb_itemGetCPtr( pItem ), NULL ); + if( uiClass && hb_vmRequestReenter() ) + { + PHB_ITEM pMsg = hb_stackAllocItem(), + pVal = hb_stackAllocItem(); + + hb_clsAssociate( uiClass ); + hb_itemMove( pItem, hb_stackReturnItem() ); + + while( nLen-- ) + { + nOffset = hb_deserializeItem( pMsg, cdpIn, cdpOut, pBuffer, + nOffset, pRef ); + nOffset = hb_deserializeItem( pVal, cdpIn, cdpOut, pBuffer, + nOffset, pRef ); + if( hb_vmRequestQuery() == 0 ) + { + char szMsg[ HB_SYMBOL_NAME_LEN ]; + hb_snprintf( szMsg, sizeof( szMsg ), "_%s", hb_itemGetCPtr( pMsg ) ); + hb_objSendMsg( pItem, szMsg, 1, pVal ); + } + } + hb_stackPop(); + hb_stackPop(); + hb_vmRequestRestore(); + } + else + { + while( nLen-- ) + { + nOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + nOffset, pRef ); + nOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + nOffset, pRef ); + } + hb_itemClear( pItem ); + } + break; + } + case HB_SERIAL_XHB_Q: + { + HB_USHORT uiClass; + + nPad = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ) + nOffset + 8; + /* deserialize :className */ + nOffset = hb_deserializeItem( pItem, cdpIn, cdpOut, pBuffer, + nOffset + 8, pRef ); + nLen = nPad - nOffset; + /* get serialized HBPERSISTENT text */ + szVal = hb_cdpnDup( ( const char * ) &pBuffer[ nOffset ], &nLen, + cdpIn, cdpOut ); + nOffset = nPad; + /* find class handle */ + uiClass = hb_clsFindClass( hb_itemGetCPtr( pItem ), NULL ); + hb_itemPutCLPtr( pItem, szVal, nLen ); + if( uiClass && hb_vmRequestReenter() ) + { + hb_clsAssociate( uiClass ); + hb_vmPushDynSym( hb_dynsymGetCase( "LOADFROMTEXT" ) ); + hb_vmPush( hb_stackReturnItem() ); + hb_vmPush( pItem ); + hb_vmPushLogical( HB_TRUE ); + hb_itemMove( pItem, hb_stackReturnItem() ); + hb_vmSend( 2 ); + hb_vmRequestRestore(); + } + else + hb_itemClear( pItem ); + break; + } + case HB_SERIAL_XHB_R: + /* nIndex = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ nOffset ] ); */ + /* TODO: add support for references */ + nOffset =+ 9; + default: hb_itemClear( pItem ); break; @@ -1251,6 +1436,84 @@ static HB_BOOL hb_deserializeTest( const HB_UCHAR ** pBufferPtr, HB_SIZE * pnSiz nSize = 1; nLen = 2; break; + + /* xHarbour types */ + case HB_SERIAL_XHB_C: + nSize = 9 + ( nSize >= 9 ? ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ) : nSize ); + break; + case HB_SERIAL_XHB_L: + nSize = 2; + break; + case HB_SERIAL_XHB_N: + if( nSize >= 2 && *pBuffer == 'X' ) + /* this is workaround for bug in xHarbour serialization code */ + nSize = 20; + else + nSize = 10; + break; + case HB_SERIAL_XHB_D: + case HB_SERIAL_XHB_T: + nSize = 9; + break; + case HB_SERIAL_XHB_Z: + nSize = 1; + break; + case HB_SERIAL_XHB_A: + if( nSize >= 9 ) + { + nSize = 9; + nLen = ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ); + } + else + nSize++; + break; + case HB_SERIAL_XHB_B: + nSize = 1; + nLen = 1; + break; + case HB_SERIAL_XHB_H: + if( nSize >= 9 ) + { + nSize = 9; + nLen = ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ) << 1; + } + else + nSize++; + break; + case HB_SERIAL_XHB_O: + if( nSize >= 9 ) + { + nSize = 9; + nLen = ( ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ) << 1 ) + 1; + } + else + nSize++; + break; + case HB_SERIAL_XHB_Q: + if( nSize >= 18 && pBuffer[ 8 ] == HB_SERIAL_XHB_C ) + { + HB_SIZE nData = ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ); + if( nData >= 9 && nData - 9 >= + ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ 9 ] ) ) + nSize = 9 + nData; + else + nSize++; + } + else + nSize++; + nSize = 9 + ( nSize >= 9 ? ( HB_SIZE ) HB_GET_BE_UINT64( pBuffer ) : nSize ); + break; + case HB_SERIAL_XHB_R: + if( nSize >= 10 ) + { + nSize = 10; + /* nIndex = ( HB_SIZE ) HB_GET_BE_UINT64( &pBuffer[ 1 ] ); */ + /* TODO: add support for references */ + } + else + nSize++; + break; + default: nSize = 1; break; diff --git a/harbour/src/vm/classes.c b/harbour/src/vm/classes.c index b623af50c2..8066d711d7 100644 --- a/harbour/src/vm/classes.c +++ b/harbour/src/vm/classes.c @@ -3566,9 +3566,7 @@ static HB_USHORT hb_clsNew( const char * szClassName, HB_USHORT uiDatas, } /* - * hb_clsNew( , < ) -> - * - * := __clsNew( , , [], [], [] ) + * __clsNew( , , [], [], [] ) -> * * Create a new class * @@ -3618,9 +3616,9 @@ HB_FUNC( __CLSNEW ) } /* - * __clsAddFriend( , ) + * __clsAddFriend( , ) * - * Add friend function + * Add friend function */ HB_FUNC( __CLSADDFRIEND ) { @@ -4112,7 +4110,7 @@ HB_FUNC( __CLSASSOCTYPE ) } /* - * __ClsCntClasses() -> + * __clsCntClasses() -> * * Return number of classes */ @@ -4274,7 +4272,7 @@ HB_FUNC( __CLSPARENT ) hb_clsIsParent( ( HB_USHORT ) hb_parni( 1 ), szParentName ) ); } -/* __Sender() -> | NIL +/* __sender() -> | NIL * returns sender object */ HB_FUNC( __SENDER ) @@ -4356,7 +4354,7 @@ HB_FUNC( __CLSSYNCWAIT ) } /* - * __ClassH( ) -> + * __classH( ) -> * * Returns class handle of */ @@ -5035,7 +5033,7 @@ void hb_mthAddTime( HB_ULONG ulClockTicks ) } #endif -/* ( nClass, cMsg ) --> aMethodInfo { nTimes, nTime } */ +/* __getMsgPrf( nClass, cMsg ) --> aMethodInfo { nTimes, nTime } */ HB_FUNC( __GETMSGPRF ) /* profiler: returns a method called and consumed times */ { HB_STACK_TLS_PRELOAD @@ -5067,7 +5065,7 @@ HB_FUNC( __GETMSGPRF ) /* profiler: returns a method called and consumed times * hb_storvnl( 0, -1, 2 ); } -/* __ClsGetProperties( nClassHandle, [ lAllExported ] ) --> aPropertiesNames +/* __clsGetProperties( , [ ] ) --> * Notice that this function works quite similar to __CLASSSEL() * except that just returns the name of the datas and methods * that have been declared as PROPERTY (PERSISTENT) or also EXPORTED @@ -5168,6 +5166,7 @@ HB_FUNC( __CLSMSGTYPE ) * for MT programs which will allocate dynamically at runtime * more then 16386 classes. In practice rather impossible though * who knows ;-) + * __clsPreAllocate( [] ) -> */ HB_FUNC( __CLSPREALLOCATE ) { @@ -5191,6 +5190,8 @@ HB_FUNC( __CLSPREALLOCATE ) hb_retnl( s_uiClsSize ); } +/* __clsLockDef( ) -> + */ HB_FUNC( __CLSLOCKDEF ) { HB_STACK_TLS_PRELOAD @@ -5210,6 +5211,8 @@ HB_FUNC( __CLSLOCKDEF ) hb_retl( fLocked ); } +/* __clsUnlockDef( @, ) + */ HB_FUNC( __CLSUNLOCKDEF ) { PHB_ITEM pClsDst = hb_param( 1, HB_IT_BYREF ), @@ -5227,13 +5230,31 @@ HB_FUNC( __CLSUNLOCKDEF ) hb_threadMutexUnlock( s_pClassMtx ); } +/* Dirty functions which converts array to object of given class + * __objSetClass( , [, ] ) -> + */ +HB_FUNC( __OBJSETCLASS ) +{ + PHB_ITEM pObject = hb_param( 1, HB_IT_ARRAY ); + + if( pObject && pObject->item.asArray.value->uiClass == 0 ) + { + const char * szClass = hb_parc( 2 ); + + if( szClass ) + hb_objSetClass( pObject, szClass, hb_parc( 3 ) ); + } + + hb_itemReturn( pObject ); +} + /* Real dirty function, though very usefull under certain circunstances: * It allows to change the class handle of an object into another class handle, * so the object behaves like a different Class of object. * Based on objects.lib SetClsHandle() + * __objSetClassHandle( , ) --> */ - -HB_FUNC( HB_SETCLSHANDLE ) /* ( oObject, nClassHandle ) --> nPrevClassHandle */ +HB_FUNC( __OBJSETCLASSHANDLE ) { HB_STACK_TLS_PRELOAD PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); @@ -5251,23 +5272,9 @@ HB_FUNC( HB_SETCLSHANDLE ) /* ( oObject, nClassHandle ) --> nPrevClassHandle */ hb_retnl( uiPrevClassHandle ); } -/* Dirty functions which converts array to object of given class - * __OBJSETCLASS( , [, ] ) -> - */ -HB_FUNC( __OBJSETCLASS ) -{ - PHB_ITEM pObject = hb_param( 1, HB_IT_ARRAY ); - - if( pObject && pObject->item.asArray.value->uiClass == 0 ) - { - const char * szClass = hb_parc( 2 ); - - if( szClass ) - hb_objSetClass( pObject, szClass, hb_parc( 3 ) ); - } - - hb_itemReturn( pObject ); -} +#if defined( HB_LEGACY_LEVEL5 ) +HB_FUNC_TRANSLATE( HB_SETCLSHANDLE, __OBJSETCLASSHANDLE ) +#endif /* Harbour equivalent for Clipper internal __mdCreate() */ HB_USHORT hb_clsCreate( HB_USHORT usSize, const char * szClassName )