From 8bc1e2f652d00a5b85ee13ca90a4d073abf66243 Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Sat, 15 Apr 2006 18:51:38 +0000 Subject: [PATCH] 2006-04-15 20:20 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/Makefile + harbour/include/blob.ch * harbour/include/dbinfo.ch * harbour/include/hbdbferr.h * harbour/include/hbrddfpt.h * harbour/source/rdd/dbf1.c * harbour/source/rdd/workarea.c * harbour/source/rdd/dbffpt/dbffpt1.c + added all CL5.3 BLOB*() functions support + added new RDD DBFBLOB compatible with CL5.3 DBFBLOB It operates on memo files only (.dbv) without tables (.dbf) To create .DBV file use: dbCreate( cFile, {}, "DBFBLOB" ) * harbour/source/rdd/dbcmd.c * do not report error when empty structure table is passed to DBCREATE() CL5.3 allow to create even DBF files without any fields and because I can imagine some valid code which use it as a feature then I also allow it in DBF RDD. Authors of RDDs which do not allow to create tables without fields should add to their low level RDD code necessary RT error. --- harbour/ChangeLog | 24 ++ harbour/include/Makefile | 1 + harbour/include/blob.ch | 83 ++++ harbour/include/dbinfo.ch | 2 +- harbour/include/hbdbferr.h | 1 + harbour/include/hbrddfpt.h | 4 + harbour/source/rdd/dbcmd.c | 12 +- harbour/source/rdd/dbf1.c | 403 ++++++++++--------- harbour/source/rdd/dbffpt/dbffpt1.c | 578 +++++++++++++++++++++++++--- harbour/source/rdd/workarea.c | 8 +- 10 files changed, 868 insertions(+), 248 deletions(-) create mode 100644 harbour/include/blob.ch diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 16a42e30e7..bda6b3aae9 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -7,6 +7,30 @@ For example: 2002-12-01 13:30 UTC+0100 Foo Bar */ + + + + * fixed bug in ParseOptional + * bin/bld.sh + * fixed typo + + * source/pp/ppcore.c + * fixed bug in ParseOptional + <"var"> were not recognized correctly + (This fixes SET RELATION bug reported by David Macias) + + +2006-04-15 20:20 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/Makefile + + harbour/include/blob.ch + * harbour/include/dbinfo.ch + * harbour/include/hbdbferr.h + * harbour/include/hbrddfpt.h + * harbour/source/rdd/dbf1.c + * harbour/source/rdd/workarea.c + * harbour/source/rdd/dbffpt/dbffpt1.c + + added all CL5.3 BLOB*() functions support + + added new RDD DBFBLOB compatible with CL5.3 DBFBLOB It operates on memo files only (.dbv) without tables (.dbf) To create .DBV file use: dbCreate( cFile, {}, "DBFBLOB" ) diff --git a/harbour/include/Makefile b/harbour/include/Makefile index ec146e7ea6..030ad34b9e 100644 --- a/harbour/include/Makefile +++ b/harbour/include/Makefile @@ -57,6 +57,7 @@ PRG_HEADERS=\ assert.ch \ box.ch \ button.ch \ + blob.ch \ color.ch \ common.ch \ dbedit.ch \ diff --git a/harbour/include/blob.ch b/harbour/include/blob.ch new file mode 100644 index 0000000000..6d546cb0e9 --- /dev/null +++ b/harbour/include/blob.ch @@ -0,0 +1,83 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * Header file for the RDD API Index OrderInfo and DBInfo support + * + * Copyright 2004 {list of individual authors and e-mail addresses} + * www - http://www.xharbour.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HB_BLOB_CH_ +#define HB_BLOB_CH_ + + +#ifndef HB_DBINFO_CH + #include "dbinfo.ch" +#endif + +#xtranslate BLOBRootLock() => dbInfo( DBI_BLOB_ROOT_LOCK ) +#xtranslate BLOBRootUnlock() => dbInfo( DBI_BLOB_ROOT_UNLOCK ) +#xtranslate BLOBRootGet() => dbInfo( DBI_BLOB_ROOT_GET ) +#xtranslate BLOBRootPut( ) => dbInfo( DBI_BLOB_ROOT_PUT, ) +#xtranslate BLOBRootDelete() => BLOBRootPut( "" ) + +#xtranslate BLOBDirectExport( , [, ] ) => ; + dbInfo( DBI_BLOB_DIRECT_EXPORT, { , , ; + iif( <.kMode.>, , BLOB_EXPORT_OVERWRITE ) } ) +#xtranslate BLOBDirectGet( [, [, ]] ) => ; + dbInfo( DBI_BLOB_DIRECT_GET, { , , } ) +#xtranslate BLOBDirectImport( , ) => ; + dbInfo( DBI_BLOB_DIRECT_IMPORT, { , } ) +#xtranslate BLOBDirectPut( [], ) => ; + dbInfo( DBI_BLOB_DIRECT_PUT, { , } ) +#xtranslate BLOBGet( [, [, ]] ) => ; + dbFieldInfo( DBS_BLOB_GET, , { , } ) +#xtranslate BLOBExport( , , ) => ; + dbFileGet( , , ) +#xtranslate BLOBImport( , ) => ; + dbFilePut( , ) + +#endif /* HB_BLOB_CH_ */ diff --git a/harbour/include/dbinfo.ch b/harbour/include/dbinfo.ch index dbfd94f90e..e3864160c3 100644 --- a/harbour/include/dbinfo.ch +++ b/harbour/include/dbinfo.ch @@ -99,7 +99,7 @@ #define RDDI_MEMOGCTYPE 34 /* type of garbage collector used by GC */ #define RDDI_MEMOREADLOCK 35 /* use read lock in memo file access */ #define RDDI_MEMOREUSE 36 /* reuse free space on write */ - +#define RDDI_BLOB_SUPPORT 37 /* can support BLOB files directly */ /* Constants for SELF_ORDINFO () diff --git a/harbour/include/hbdbferr.h b/harbour/include/hbdbferr.h index 4adae80887..bde42fda16 100644 --- a/harbour/include/hbdbferr.h +++ b/harbour/include/hbdbferr.h @@ -56,6 +56,7 @@ HB_EXTERN_BEGIN /* DBF errors */ +#define EDBF_UNSUPPORTED 1000 #define EDBF_OPEN_DBF 1001 #define EDBF_OPEN_MEMO 1002 #define EDBF_OPEN_INDEX 1003 diff --git a/harbour/include/hbrddfpt.h b/harbour/include/hbrddfpt.h index 6f5a55ab6c..9464a37e30 100644 --- a/harbour/include/hbrddfpt.h +++ b/harbour/include/hbrddfpt.h @@ -66,6 +66,7 @@ HB_EXTERN_BEGIN #define DBT_MEMOEXT ".dbt" #define FPT_MEMOEXT ".fpt" #define SMT_MEMOEXT ".smt" +#define DBV_MEMOEXT ".dbv" #define DBT_DEFBLOCKSIZE 512 #define FPT_DEFBLOCKSIZE 64 #define SMT_DEFBLOCKSIZE 32 @@ -73,6 +74,8 @@ HB_EXTERN_BEGIN #define FPT_LOCKPOS 0x00000000L #define FPT_LOCKSIZE 0x00000001L +#define FPT_ROOTBLOCK_OFFSET 0x218 /* Clipper 5.3 ROOT data block offset */ + #define SIX_ITEM_BUFSIZE 14 #define FLEX_ITEM_BUFSIZE 8 #define MAX_SIXFREEBLOCKS 82 @@ -177,6 +180,7 @@ HB_EXTERN_BEGIN #define FPTIT_FLEXAR_LONG2 0x20 /* long[4], len, dec */ #define FPTIT_FLEXAR_ULONG2 0x21 /* ulong[4], len, dec */ + /* MEMO file strucutres */ typedef struct _FPTHEADER { diff --git a/harbour/source/rdd/dbcmd.c b/harbour/source/rdd/dbcmd.c index 34155e98c2..d100eeeed0 100644 --- a/harbour/source/rdd/dbcmd.c +++ b/harbour/source/rdd/dbcmd.c @@ -1741,7 +1741,17 @@ HB_FUNC( DBCREATE ) fKeepOpen = ISLOG( 4 ); fCurrArea = fKeepOpen && !hb_parl( 4 ); - if( !pStruct || hb_arrayLen( pStruct ) == 0 || + /* + * Clipper allows to use empty struct array for RDDs which does not + * support fields, f.e.: DBFBLOB in CL5.3 + * In CL5.3 it's also possible to create DBF file without fields. + * if some RDD wants to block it then they should serve it in lower + * level, [druzus] + */ + if( !pStruct || +#ifdef HB_C52_STRICT + hb_arrayLen( pStruct ) == 0 || +#endif !szFileName || !szFileName[ 0 ] ) { hb_errRT_DBCMD( EG_ARG, EDBCMD_DBCMDBADPARAMETER, NULL, "DBCREATE" ); diff --git a/harbour/source/rdd/dbf1.c b/harbour/source/rdd/dbf1.c index 0a2867f110..330f1f96e4 100644 --- a/harbour/source/rdd/dbf1.c +++ b/harbour/source/rdd/dbf1.c @@ -228,8 +228,11 @@ static ULONG hb_dbfCalcRecCount( DBFAREAP pArea ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfCalcRecCount(%p)", pArea)); - return ( ULONG ) ( ( hb_fsSeekLarge( pArea->hDataFile, 0, FS_END ) - - pArea->uiHeaderLen ) / pArea->uiRecordLen ); + if( pArea->hDataFile == FS_ERROR ) + return 0; + else + return ( ULONG ) ( ( hb_fsSeekLarge( pArea->hDataFile, 0, FS_END ) - + pArea->uiHeaderLen ) / pArea->uiRecordLen ); } /* @@ -1928,8 +1931,11 @@ static ERRCODE hb_dbfSetFieldExtent( DBFAREAP pArea, USHORT uiFieldExtent ) return FAILURE; /* Alloc field offsets array */ - pArea->pFieldOffset = ( USHORT * ) hb_xgrab( uiFieldExtent * sizeof( USHORT * ) ); - memset( pArea->pFieldOffset, 0, uiFieldExtent * sizeof( USHORT * ) ); + if( uiFieldExtent ) + { + pArea->pFieldOffset = ( USHORT * ) hb_xgrab( uiFieldExtent * sizeof( USHORT * ) ); + memset( pArea->pFieldOffset, 0, uiFieldExtent * sizeof( USHORT * ) ); + } return SUCCESS; } @@ -2019,9 +2025,9 @@ static ERRCODE hb_dbfClose( DBFAREAP pArea ) */ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) { - ERRCODE errCode; + ERRCODE errCode = SUCCESS; USHORT uiSize, uiCount; - BOOL fRetry, fError; + BOOL fRetry, fError, fRawBlob; DBFFIELD * pBuffer, *pThisField; PHB_FNAME pFileName; PHB_ITEM pItem = NULL, pError; @@ -2036,8 +2042,6 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) SELF_INFO( ( AREAP ) pArea, DBI_TABLEEXT, pItem ); pFileName->szExtension = hb_itemGetCPtr( pItem ); hb_fsFNameMerge( ( char * ) szFileName, pFileName ); - hb_itemRelease( pItem ); - pItem = NULL; } else { @@ -2045,48 +2049,52 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) } hb_xfree( pFileName ); - pError = NULL; - /* Try create */ - do + pItem = hb_itemPutL( pItem, FALSE ); + fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, 0, pItem ) == SUCCESS && + hb_itemGetL( pItem ); + + if( !fRawBlob ) { - pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, - FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | - FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, - NULL, pError ); + pError = NULL; + /* Try create */ + do + { + pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, + FO_READWRITE | FO_EXCLUSIVE | FXO_TRUNCATE | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, pError ); + if( pArea->hDataFile == FS_ERROR ) + { + if( !pError ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_CREATE ); + hb_errPutSubCode( pError, EDBF_CREATE_DBF ); + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); + hb_errPutFileName( pError, ( char * ) szFileName ); + hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); + } + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + } + else + fRetry = FALSE; + } while( fRetry ); + + if( pError ) + { + hb_itemRelease( pError ); + } + if( pArea->hDataFile == FS_ERROR ) { - if( !pError ) - { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_CREATE ); - hb_errPutSubCode( pError, EDBF_CREATE_DBF ); - hb_errPutOsCode( pError, hb_fsError() ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CREATE ) ); - hb_errPutFileName( pError, ( char * ) szFileName ); - hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); - } - fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + if( pItem ) + hb_itemRelease( pItem ); + return FAILURE; } - else - fRetry = FALSE; - } while( fRetry ); - - if( pError ) - { - hb_itemRelease( pError ); - } - - if( pArea->hDataFile == FS_ERROR ) - { - return FAILURE; } pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); - uiSize = pArea->uiFieldCount * sizeof( DBFFIELD ); - - pBuffer = ( DBFFIELD * ) hb_xgrab( uiSize ); - memset( pBuffer, 0, uiSize ); - pThisField = pBuffer; /* Size for deleted flag */ pArea->uiRecordLen = 1; @@ -2117,7 +2125,7 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) } } - if( pArea->bTableType == DB_DBF_VFP ) + if( pArea->bTableType == DB_DBF_VFP && !fRawBlob ) { pArea->bMemoType = DB_MEMO_FPT; } @@ -2140,6 +2148,18 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_itemRelease( pItem ); } + uiSize = pArea->uiFieldCount * sizeof( DBFFIELD ); + if( pArea->uiFieldCount ) + { + pBuffer = ( DBFFIELD * ) hb_xgrab( uiSize ); + memset( pBuffer, 0, uiSize ); + } + else + { + pBuffer = NULL; + } + pThisField = pBuffer; + pArea->fHasMemo = fError = FALSE; for( uiCount = 0; uiCount < pArea->uiFieldCount; uiCount++ ) @@ -2253,7 +2273,6 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) hb_errPutFileName( pError, ( char * ) pCreateInfo->abName ); SELF_ERROR( ( AREAP ) pArea, pError ); hb_itemRelease( pError ); - return FAILURE; } pThisField++ ; @@ -2263,6 +2282,10 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->ulRecCount = 0; pArea->uiHeaderLen = sizeof( DBFHEADER ) + uiSize + ( pArea->bTableType == DB_DBF_VFP ? 1 : 2 ); + if( fRawBlob ) + { + pArea->fHasMemo = TRUE; + } if( !pArea->fHasMemo ) { pArea->bMemoType = DB_MEMO_NONE; @@ -2280,31 +2303,37 @@ static ERRCODE hb_dbfCreate( DBFAREAP pArea, LPDBOPENINFO pCreateInfo ) pArea->cdPage = hb_cdp_page; #endif - /* Force write new header */ - pArea->fUpdateHeader = TRUE; - /* Write header */ - errCode = SELF_WRITEDBHEADER( ( AREAP ) pArea ); - if( errCode != SUCCESS ) + if( !fRawBlob ) { - hb_xfree( pBuffer ); - SELF_CLOSE( ( AREAP ) pArea ); - return errCode; - } + /* Force write new header */ + pArea->fUpdateHeader = TRUE; + /* Write header */ + errCode = SELF_WRITEDBHEADER( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + { + if( pBuffer ) + hb_xfree( pBuffer ); + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; + } - /* Write fields and eof mark */ - if( hb_fsWrite( pArea->hDataFile, ( BYTE * ) pBuffer, uiSize ) != uiSize || - ( pArea->bTableType == DB_DBF_VFP ? - hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\032", 2 ) != 2 : - hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\0\032", 3 ) != 3 ) ) - { - /* TODO: add RT error */ - hb_xfree( pBuffer ); - SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; - } + /* Write fields and eof mark */ + if( hb_fsWrite( pArea->hDataFile, ( BYTE * ) pBuffer, uiSize ) != uiSize || + ( pArea->bTableType == DB_DBF_VFP ? + hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\032", 2 ) != 2 : + hb_fsWrite( pArea->hDataFile, ( BYTE * ) "\r\0\032", 3 ) != 3 ) ) + { + /* TODO: add RT error */ + if( pBuffer ) + hb_xfree( pBuffer ); + SELF_CLOSE( ( AREAP ) pArea ); + return FAILURE; + } - pArea->fDataFlush = TRUE; - hb_xfree( pBuffer ); + pArea->fDataFlush = TRUE; + if( pBuffer ) + hb_xfree( pBuffer ); + } /* Create memo file */ if( pArea->fHasMemo ) @@ -2375,10 +2404,6 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) pArea->dbfHeader.bDay ); break; - case DBI_GETDELIMITER: - case DBI_SETDELIMITER: - break; - case DBI_GETRECSIZE: hb_itemPutNL( pItem, pArea->uiRecordLen ); break; @@ -2413,7 +2438,7 @@ static ERRCODE hb_dbfInfo( DBFAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) break; case DBI_MEMOHANDLE: - hb_itemPutNL( pItem, (LONG)pArea->hMemoFile ); + hb_itemPutNL( pItem, ( LONG ) pArea->hMemoFile ); break; case DBI_SHARED: @@ -2727,8 +2752,8 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) { ERRCODE errCode; USHORT uiFlags, uiFields, uiSize, uiCount; - BOOL fRetry; - PHB_ITEM pError, pFileExt; + BOOL fRetry, fRawBlob; + PHB_ITEM pError, pFileExt, pItem; PHB_FNAME pFileName; BYTE * pBuffer; LPDBFFIELD pField; @@ -2798,126 +2823,143 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) } hb_xfree( pFileName ); - /* Try open */ - do + pItem = hb_itemPutL( NULL, FALSE ); + fRawBlob = SELF_RDDINFO( SELF_RDDNODE( pArea ), RDDI_BLOB_SUPPORT, 0, pItem ) == SUCCESS && + hb_itemGetL( pItem ); + hb_itemRelease( pItem ); + + if( fRawBlob ) { - pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, uiFlags | - FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, - NULL, pError ); + uiFields = 0; + pBuffer = NULL; + pArea->fHasMemo = TRUE; + } + else + { + /* Try open */ + do + { + pArea->hDataFile = hb_fsExtOpen( szFileName, NULL, uiFlags | + FXO_DEFAULTS | FXO_SHARELOCK | FXO_COPYNAME, + NULL, pError ); + if( pArea->hDataFile == FS_ERROR ) + { + if( !pError ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_OPEN ); + hb_errPutSubCode( pError, EDBF_OPEN_DBF ); + hb_errPutOsCode( pError, hb_fsError() ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); + hb_errPutFileName( pError, ( char * ) szFileName ); + hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); + } + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); + } + else + fRetry = FALSE; + } while( fRetry ); + + if( pError ) + { + hb_itemRelease( pError ); + pError = NULL; + } + + /* Exit if error */ if( pArea->hDataFile == FS_ERROR ) { - if( !pError ) + SELF_CLOSE( ( AREAP ) pArea ); + return FAILURE; + } + + /* Allocate only after succesfully open file */ + pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); + + /* Read file header and exit if error */ + errCode = SELF_READDBHEADER( ( AREAP ) pArea ); + if( errCode != SUCCESS ) + { + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; + } + + /* Add fields */ + uiFields = ( pArea->uiHeaderLen - sizeof( DBFHEADER ) ) / sizeof( DBFFIELD ); + uiSize = uiFields * sizeof( DBFFIELD ); + pBuffer = uiFields ? ( BYTE * ) hb_xgrab( uiSize ) : NULL; + + /* Read fields and exit if error */ + do + { + hb_fsSeek( pArea->hDataFile, sizeof( DBFHEADER ), FS_SET ); + if( hb_fsRead( pArea->hDataFile, pBuffer, uiSize ) != uiSize ) { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_OPEN ); - hb_errPutSubCode( pError, EDBF_OPEN_DBF ); - hb_errPutOsCode( pError, hb_fsError() ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_OPEN ) ); - hb_errPutFileName( pError, ( char * ) szFileName ); - hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); + errCode = FAILURE; + if( !pError ) + { + pError = hb_errNew(); + hb_errPutGenCode( pError, EG_CORRUPTION ); + hb_errPutSubCode( pError, EDBF_CORRUPT ); + hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); + hb_errPutFileName( pError, pArea->szDataFileName ); + hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); + } + fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); } - fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); - } - else - fRetry = FALSE; - } while( fRetry ); - - if( pError ) - { - hb_itemRelease( pError ); - pError = NULL; - } - - /* Exit if error */ - if( pArea->hDataFile == FS_ERROR ) - { - SELF_CLOSE( ( AREAP ) pArea ); - return FAILURE; - } - - /* Allocate only after succesfully open file */ - pArea->szDataFileName = hb_strdup( ( char * ) szFileName ); - - /* Read file header and exit if error */ - errCode = SELF_READDBHEADER( ( AREAP ) pArea ); - if( errCode != SUCCESS ) - { - SELF_CLOSE( ( AREAP ) pArea ); - return errCode; - } - - - /* Add fields */ - uiFields = ( pArea->uiHeaderLen - sizeof( DBFHEADER ) ) / sizeof( DBFFIELD ); - uiSize = uiFields * sizeof( DBFFIELD ); - pBuffer = ( BYTE * ) hb_xgrab( uiSize ); - - /* Read fields and exit if error */ - do - { - hb_fsSeek( pArea->hDataFile, sizeof( DBFHEADER ), FS_SET ); - if( hb_fsRead( pArea->hDataFile, pBuffer, uiSize ) != uiSize ) - { - errCode = FAILURE; - if( !pError ) + else { - pError = hb_errNew(); - hb_errPutGenCode( pError, EG_CORRUPTION ); - hb_errPutSubCode( pError, EDBF_CORRUPT ); - hb_errPutDescription( pError, hb_langDGetErrorDesc( EG_CORRUPTION ) ); - hb_errPutFileName( pError, pArea->szDataFileName ); - hb_errPutFlags( pError, EF_CANRETRY | EF_CANDEFAULT ); + errCode = SUCCESS; + break; } - fRetry = ( SELF_ERROR( ( AREAP ) pArea, pError ) == E_RETRY ); - } - else - { - errCode = SUCCESS; - break; - } - } while( fRetry ); + } while( fRetry ); - if( pError ) - { - hb_itemRelease( pError ); - } - - /* Exit if error */ - if( errCode != SUCCESS ) - { - hb_xfree( pBuffer ); - SELF_CLOSE( ( AREAP ) pArea ); - return errCode; - } - - /* some RDDs use the additional space in the header after field arrray - for private data we should check for 0x0D marker to not use this - data as fields description */ - for( uiCount = 0; uiCount < uiFields; uiCount++ ) - { - if( pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x0d ) - { - uiFields = uiCount; - break; - } - /* Peter added it for FVP DBFs but in wrong place, - anyhow I cannot see why it's necessary, FVP private data - in header should be after 0x0d - I disabled this code, [druzus] */ - /* - if( pArea->bTableType == DB_DBF_VFP && - pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x00 ) - { - uiFields = uiCount; - break; - } - */ + if( pError ) + { + hb_itemRelease( pError ); + } + + /* Exit if error */ + if( errCode != SUCCESS ) + { + if( pBuffer ) + hb_xfree( pBuffer ); + SELF_CLOSE( ( AREAP ) pArea ); + return errCode; + } + + /* some RDDs use the additional space in the header after field arrray + for private data we should check for 0x0D marker to not use this + data as fields description */ + for( uiCount = 0; uiCount < uiFields; uiCount++ ) + { + if( pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x0d ) + { + uiFields = uiCount; + break; + } + /* Peter added it for FVP DBFs but in wrong place, + anyhow I cannot see why it's necessary, FVP private data + in header should be after 0x0d - I disabled this code, [druzus] */ + /* + if( pArea->bTableType == DB_DBF_VFP && + pBuffer[ uiCount * sizeof( DBFFIELD ) ] == 0x00 ) + { + uiFields = uiCount; + break; + } + */ + } } + /* CL5.3 allow to create and open DBFs without fields */ +#ifdef HB_C52_STRICT if( uiFields == 0 ) { errCode = FAILURE; } else +#endif { errCode = SELF_SETFIELDEXTENT( ( AREAP ) pArea, uiFields ); if( errCode != SUCCESS ) @@ -3030,7 +3072,8 @@ static ERRCODE hb_dbfOpen( DBFAREAP pArea, LPDBOPENINFO pOpenInfo ) if( errCode != SUCCESS ) break; } - hb_xfree( pBuffer ); + if( pBuffer ) + hb_xfree( pBuffer ); /* Exit if error */ if( errCode != SUCCESS ) diff --git a/harbour/source/rdd/dbffpt/dbffpt1.c b/harbour/source/rdd/dbffpt/dbffpt1.c index aa280bafc1..d743df7540 100644 --- a/harbour/source/rdd/dbffpt/dbffpt1.c +++ b/harbour/source/rdd/dbffpt/dbffpt1.c @@ -77,6 +77,9 @@ # include "hbapicdp.h" #endif +static USHORT s_uiRddIdBLOB = ( USHORT ) -1; +static USHORT s_uiRddIdFPT = ( USHORT ) -1; + static RDDFUNCS fptSuper; static RDDFUNCS fptTable = { @@ -258,8 +261,11 @@ static ERRCODE hb_memoErrorRT( FPTAREAP pArea, USHORT uiGenCode, USHORT uiSubCod } -static char * hb_memoDefaultFileExt( int iType ) +static char * hb_memoDefaultFileExt( int iType, USHORT uiRdd ) { + if( uiRdd == s_uiRddIdBLOB ) + return DBV_MEMOEXT; + switch( iType ) { case DB_MEMO_DBT: @@ -326,6 +332,82 @@ static BOOL hb_fptFileUnLock( FPTAREAP pArea ) return !pArea->fShared || hb_fsLock( pArea->hMemoFile, FPT_LOCKPOS, FPT_LOCKSIZE, FL_UNLOCK ); } +/* + * Check if MEMO file has direct access to data + */ +static BOOL hb_fptHasDirectAccess( FPTAREAP pArea ) +{ + return pArea->bMemoType == DB_MEMO_FPT && + ( pArea->uiMemoVersion == DB_MEMOVER_FLEX || + pArea->uiMemoVersion == DB_MEMOVER_CLIP ); +} + +/* + * Lock root block pointer. + */ +static BOOL hb_fptRootBlockLock( FPTAREAP pArea ) +{ + BOOL fRet; + + if ( !pArea->fShared ) + fRet = TRUE; + else + fRet = hb_fsLock( pArea->hMemoFile, FPT_ROOTBLOCK_OFFSET, 4, + FL_LOCK | FLX_EXCLUSIVE ); + return fRet; +} + +/* + * Unlock root block pointer. + */ +static BOOL hb_fptRootBlockUnLock( FPTAREAP pArea ) +{ + return !pArea->fShared || + hb_fsLock( pArea->hMemoFile, FPT_ROOTBLOCK_OFFSET, 4, FL_UNLOCK ); +} + +/* + * Read root block pointer. + */ +static ERRCODE hb_fptGetRootBlock( FPTAREAP pArea, ULONG * pulBlock ) +{ + *pulBlock = 0; + + if( hb_fptHasDirectAccess( pArea ) ) + { + BYTE buffer[ 4 ]; + + hb_fsSeek( pArea->hMemoFile, FPT_ROOTBLOCK_OFFSET, FS_SET ); + if( hb_fsRead( pArea->hMemoFile, buffer, 4 ) == 4 ) + { + *pulBlock = HB_GET_LE_UINT32( buffer ); + return SUCCESS; + } + else + return EDBF_READ; + } + return EDBF_UNSUPPORTED; +} + +/* + * Write root block pointer. + */ +static ERRCODE hb_fptPutRootBlock( FPTAREAP pArea, ULONG ulBlock ) +{ + if( hb_fptHasDirectAccess( pArea ) ) + { + BYTE buffer[ 4 ]; + + HB_PUT_LE_UINT32( buffer, ulBlock ); + hb_fsSeek( pArea->hMemoFile, FPT_ROOTBLOCK_OFFSET, FS_SET ); + if( hb_fsWrite( pArea->hMemoFile, buffer, 4 ) == 4 ) + return SUCCESS; + else + return EDBF_WRITE; + } + return EDBF_UNSUPPORTED; +} + /* GARBAGE COLLECTOR: I don't have any documentation about it. All I know is reverse engineering @@ -988,7 +1070,7 @@ static ULONG hb_fptGetMemoLen( FPTAREAP pArea, USHORT uiIndex ) HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemoLen(%p, %hu)", pArea, uiIndex)); - if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, &ulBlock, &ulSize, + if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex - 1, &ulBlock, &ulSize, &ulType ) == SUCCESS ) { if( ulBlock != 0 ) @@ -1034,7 +1116,7 @@ static char * hb_fptGetMemoType( FPTAREAP pArea, USHORT uiIndex ) HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemoLen(%p, %hu)", pArea, uiIndex)); - if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, &ulBlock, &ulSize, + if( hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex - 1, &ulBlock, &ulSize, &ulType ) == SUCCESS ) { if( ulBlock != 0 ) @@ -2450,17 +2532,31 @@ ERRCODE hb_fptReadSMTBlock( FPTAREAP pArea, PHB_ITEM pItem, ULONG ulBlock, ULONG /* * Read fpt vartype memos. */ -static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, FHANDLE hFile ) +static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, + FHANDLE hFile, ULONG ulBlock, ULONG ulStart, + ULONG ulCount ) { ERRCODE errCode; - ULONG ulBlock, ulSize, ulBufSize, ulType; + ULONG ulSize, ulType; BYTE * pBuffer, * bMemoBuf; FPTBLOCK fptBlock; - HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemo(%p, %hu, %p, %p)", pArea, uiIndex, pItem)); + HB_TRACE(HB_TR_DEBUG, ("hb_fptGetMemo(%p, %hu, %p, %p, %lu, %lu)", pArea, uiIndex, pItem, hFile, ulStart, ulCount)); - errCode = hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex, - &ulBlock, &ulSize, &ulType ); + if( uiIndex ) + { + errCode = hb_dbfGetMemoData( ( DBFAREAP ) pArea, uiIndex - 1, + &ulBlock, &ulSize, &ulType ); + } + else if( ! hb_fptHasDirectAccess( pArea ) ) + { + errCode = EDBF_UNSUPPORTED; + } + else + { + ulSize = ulType = 0; + errCode = SUCCESS; + } if( errCode != SUCCESS ) return errCode; @@ -2478,7 +2574,6 @@ static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, FH } ulType = HB_GET_BE_UINT32( fptBlock.type ); ulSize = HB_GET_BE_UINT32( fptBlock.size ); - ulBufSize = HB_MAX( ulSize + 1, 8 ); } else { @@ -2489,22 +2584,52 @@ static ERRCODE hb_fptGetMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, FH } hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulBlock * ( HB_FOFFSET ) pArea->uiMemoBlockSize, FS_SET ); - ulBufSize = ulSize + 1; } + if( ulStart || ulCount ) + { + if( pArea->bMemoType == DB_MEMO_FPT ) + { + if( ulType != FPTIT_TEXT && ulType != FPTIT_PICT ) + ulStart = ulCount = 0; + } + else if( pArea->bMemoType == DB_MEMO_SMT ) + { + if( ulType != SMT_IT_CHAR ) + ulStart = ulCount = 0; + } + } + + if( ulStart >= ulSize ) + ulSize = 0; + else + ulSize -= ulStart; + if( ulCount && ulCount < ulSize ) + ulSize = ulCount; + if( ulStart && ulSize ) + hb_fsSeekLarge( pArea->hMemoFile, ( HB_FOFFSET ) ulStart, FS_RELATIVE ); + if( hFile != FS_ERROR ) { return hb_fptExportToFile( pArea, hFile, ulSize ); } - pBuffer = ( BYTE * ) hb_xalloc( ulBufSize ); + if( pArea->bMemoType == DB_MEMO_FPT ) + { + pBuffer = ( BYTE * ) hb_xalloc( HB_MAX( ulSize + 1, 8 ) ); + if( pBuffer ) + memset( pBuffer, '\0', 8 ); + } + else + { + pBuffer = ( BYTE * ) hb_xalloc( ulSize + 1 ); + } + if( !pBuffer ) { /* in most cases this means that file is corrupted */ return EDBF_CORRUPT; } - if( pArea->bMemoType == DB_MEMO_FPT ) - memset( pBuffer, '\0', 8 ); if ( ulSize != 0 && hb_fsReadLarge( pArea->hMemoFile, pBuffer, ulSize ) != ulSize ) { @@ -2764,16 +2889,17 @@ static ERRCODE hb_fptWriteMemo( FPTAREAP pArea, ULONG ulBlock, ULONG ulSize, /* * Assign a value to the specified memo field. */ -static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) +static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem, + ULONG * pulBlock ) { - ULONG ulSize, ulBlock, ulType, ulOldSize, ulOldType, ulArrayCount = 0; + ULONG ulBlock, ulSize, ulType, ulOldSize, ulOldType, ulArrayCount = 0; BYTE itmBuffer[FLEX_ITEM_BUFSIZE]; BYTE *bBufPtr = NULL, *bBufAlloc = NULL; ERRCODE errCode; HB_LONG iVal; LONG lVal; - HB_TRACE(HB_TR_DEBUG, ("hb_fptPutMemo(%p, %hu, %p)", pArea, uiIndex, pItem)); + HB_TRACE(HB_TR_DEBUG, ("hb_fptPutMemo(%p, %hu, %p, %p)", pArea, uiIndex, pItem, pulBlock)); if( HB_IS_STRING( pItem ) ) { @@ -2905,8 +3031,22 @@ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) return EDBF_DATATYPE; } - errCode = hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex, - &ulBlock, &ulOldSize, &ulOldType ); + if( uiIndex ) + { + errCode = hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, + &ulBlock, &ulOldSize, &ulOldType ); + } + else if( !pulBlock || ! hb_fptHasDirectAccess( pArea ) ) + { + errCode = EDBF_UNSUPPORTED; + } + else + { + ulBlock = *pulBlock; + ulOldSize = ulOldType = 0; + errCode = SUCCESS; + } + if( errCode == SUCCESS ) errCode = hb_fptWriteMemo( pArea, ulBlock, ulOldSize, bBufPtr, FS_ERROR, ulType, ulSize, &ulBlock ); @@ -2917,8 +3057,12 @@ static ERRCODE hb_fptPutMemo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) } if( errCode == SUCCESS ) - hb_dbfSetMemoData( (DBFAREAP) pArea, uiIndex, ulBlock, ulSize, ulType ); - + { + if( uiIndex ) + hb_dbfSetMemoData( (DBFAREAP) pArea, uiIndex - 1, ulBlock, ulSize, ulType ); + else + *pulBlock = ulBlock; + } return errCode; } @@ -3172,7 +3316,7 @@ static ERRCODE hb_fptGetVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem if( uiError != SUCCESS ) return uiError; - uiError = hb_fptGetMemo( pArea, uiIndex - 1, pItem, hFile ); + uiError = hb_fptGetMemo( pArea, uiIndex, pItem, hFile, 0, 0, 0 ); } else if( hFile == FS_ERROR ) { @@ -3189,6 +3333,92 @@ static ERRCODE hb_fptGetVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem return uiError; } +static ERRCODE hb_fptGetVarFile( FPTAREAP pArea, ULONG ulBlock, BYTE * szFile, USHORT uiMode ) +{ + USHORT uiError; + FHANDLE hFile; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptGetVarFile(%p, %lu, %s, %hu)", pArea, ulBlock, szFile, uiMode)); + + hFile = hb_fsExtOpen( szFile, NULL, FO_WRITE | FO_EXCLUSIVE | + FXO_DEFAULTS | FXO_SHARELOCK | + ( uiMode == FILEGET_APPEND ? + FXO_APPEND : FXO_TRUNCATE ), + NULL, NULL ); + + if( hFile == FS_ERROR ) + { + uiError = uiMode != FILEGET_APPEND ? EDBF_CREATE : EDBF_OPEN_DBF; + } + else + { + hb_fsSeekLarge( hFile, 0, FS_END ); + uiError = hb_fptGetMemo( pArea, 0, NULL, hFile, ulBlock, 0, 0 ); + hb_fsClose( hFile ); + } + + /* Exit if any error */ + if( uiError != SUCCESS ) + { + if( uiError != FAILURE ) + { + hb_memoErrorRT( pArea, 0, uiError, + uiError == EDBF_OPEN_DBF || uiError == EDBF_CREATE || + uiError == EDBF_WRITE ? ( char * ) szFile : + pArea->szMemoFileName, 0, 0 ); + } + return FAILURE; + } + return SUCCESS; +} + +static ULONG hb_fptPutVarFile( FPTAREAP pArea, ULONG ulBlock, BYTE * szFile ) +{ + USHORT uiError; + FHANDLE hFile; + + HB_TRACE(HB_TR_DEBUG, ("hb_fptPutVarFile(%p, %lu, %s)", pArea, ulBlock, szFile)); + + hFile = hb_fsExtOpen( szFile, NULL, FO_READ | FO_DENYNONE | + FXO_DEFAULTS | FXO_SHARELOCK, NULL, NULL ); + if( hFile == FS_ERROR ) + { + uiError = EDBF_OPEN_DBF; + } + else + { + ULONG ulSize; + HB_FOFFSET size = hb_fsSeekLarge( hFile, 0, FS_END ); + hb_fsSeekLarge( hFile, 0, FS_SET ); + if( ( HB_FOFFSET ) ( size & 0xFFFFFFFFUL ) == size ) + ulSize = HB_MIN( ( ULONG ) size, 0xFFFFFFFFUL - sizeof( FPTBLOCK ) ); + else + ulSize = HB_MIN( size, ( HB_FOFFSET ) ( 0xFFFFFFFFUL - sizeof( FPTBLOCK ) ) ); + + if( hb_fptFileLockEx( pArea, TRUE ) ) + { + uiError = hb_fptWriteMemo( pArea, ulBlock, 0, NULL, hFile, + 0, ulSize, &ulBlock ); + hb_fptFileUnLock( pArea ); + } + else + { + uiError = EDBF_LOCK; + } + hb_fsClose( hFile ); + } + + if( uiError != SUCCESS ) + { + hb_memoErrorRT( pArea, 0, uiError, + uiError == EDBF_OPEN_DBF || uiError == EDBF_READ ? + ( char * ) szFile : pArea->szMemoFileName, 0, 0 ); + ulBlock = 0; + } + + return ulBlock; +} + static ERRCODE hb_fptPutVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) { LPFIELD pField; @@ -3223,7 +3453,7 @@ static ERRCODE hb_fptPutVarField( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem { if( !hb_fptFileLockEx( pArea, TRUE ) ) return EDBF_LOCK; - uiError = hb_fptPutMemo( pArea, uiIndex -1, pItem ); + uiError = hb_fptPutMemo( pArea, uiIndex, pItem, NULL ); #if defined( HB_MEMO_SAFELOCK ) if( uiError == SUCCESS ) { @@ -3462,7 +3692,7 @@ static ERRCODE hb_fptGetVarLen( FPTAREAP pArea, USHORT uiIndex, ULONG * pLength uiError = hb_fptLockForRead( pArea, uiIndex, &fUnLock ); if( uiError == SUCCESS ) - *pLength = hb_fptGetMemoLen( pArea, uiIndex - 1 ); + *pLength = hb_fptGetMemoLen( pArea, uiIndex ); else *pLength = 0; @@ -3644,6 +3874,10 @@ static ERRCODE hb_fptCreateMemFile( FPTAREAP pArea, LPDBOPENINFO pCreateInfo ) { strcpy( ( char *) fptHeader.signature2, "FlexFile3\003" ); ulSize = sizeof( FPTHEADER ); + if( pArea->rddID == s_uiRddIdBLOB ) + { + HB_PUT_LE_UINT16( fptHeader.flexSize, pArea->uiMemoBlockSize ); + } } } ulNextBlock = ( ulSize + pArea->uiMemoBlockSize - 1 ) / pArea->uiMemoBlockSize; @@ -3740,9 +3974,14 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) HB_TRACE(HB_TR_DEBUG, ("hb_fptOpenMemFile(%p, %p)", pArea, pOpenInfo)); - if( pArea->bMemoType != DB_MEMO_DBT && - pArea->bMemoType != DB_MEMO_FPT && - pArea->bMemoType != DB_MEMO_SMT ) + if( pArea->rddID == s_uiRddIdBLOB ) + { + pArea->bMemoType = DB_MEMO_FPT; + pArea->uiMemoVersion = DB_MEMOVER_FLEX; + } + else if( pArea->bMemoType != DB_MEMO_DBT && + pArea->bMemoType != DB_MEMO_FPT && + pArea->bMemoType != DB_MEMO_SMT ) { hb_memoErrorRT( pArea, EG_OPEN, EDBF_MEMOTYPE, ( char * ) pOpenInfo->abName, 0, 0 ); @@ -3815,9 +4054,13 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) if( pArea->uiMemoVersion != DB_MEMOVER_SIX && memcmp( fptHeader.signature2, "FlexFile3\003", 10) == 0 ) { + USHORT usSize = HB_GET_LE_UINT16( fptHeader.flexSize ); pArea->uiMemoVersion = DB_MEMOVER_FLEX; - if ( pArea->uiMemoBlockSize == 0 ) - pArea->uiMemoBlockSize = HB_GET_LE_UINT16( fptHeader.flexSize ); + if( usSize != 0 && ( pArea->uiMemoBlockSize == 0 || + pArea->rddID == s_uiRddIdBLOB ) ) + { + pArea->uiMemoBlockSize = usSize; + } } } hb_fptFileUnLock( pArea ); @@ -3840,14 +4083,18 @@ static ERRCODE hb_fptOpenMemFile( FPTAREAP pArea, LPDBOPENINFO pOpenInfo ) */ static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile, USHORT uiMode ) { + LPFIELD pField; + HB_TRACE(HB_TR_DEBUG, ("hb_fptPutValueFile(%p, %hu, %s, %hu)", pArea, uiIndex, szFile, uiMode)); if( !uiIndex || uiIndex > pArea->uiFieldCount ) return FAILURE; - /* TODO: add "V" field support */ + pField = pArea->lpFields + uiIndex - 1; + if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && - pArea->lpFields[ uiIndex - 1 ].uiType == HB_IT_MEMO ) + ( pField->uiType == HB_IT_MEMO || ( pField->uiType == HB_IT_ANY && + pField->uiLen >= 6 ) ) ) { USHORT uiError; BOOL bDeleted; @@ -3871,6 +4118,29 @@ static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile { uiError = EDBF_OPEN_DBF; } + else if( pField->uiType == HB_IT_ANY ) + { + PHB_ITEM pItem; + BYTE * pAlloc; + ULONG ulSize; + HB_FOFFSET size = hb_fsSeekLarge( hFile, 0, FS_END ); + + hb_fsSeekLarge( hFile, 0, FS_SET ); + ulSize = HB_MIN( size, HB_VF_CHAR ); + pAlloc = ( BYTE * ) hb_xgrab( ulSize + 1 ); + if( hb_fsRead( hFile, pAlloc, ulSize ) != ulSize ) + { + uiError = EDBF_READ; + hb_xfree( pAlloc ); + } + else + { + pAlloc[ ulSize ] = '\0'; + pItem = hb_itemPutCPtr( NULL, ( char * ) pAlloc, ulSize ); + uiError = hb_fptPutVarField( pArea, uiIndex, pItem ); + hb_itemRelease( pItem ); + } + } else if( !hb_fptFileLockEx( pArea, TRUE ) ) { hb_fsClose( hFile ); @@ -3881,13 +4151,14 @@ static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile ULONG ulSize, ulBlock, ulType, ulOldSize, ulOldType; HB_FOFFSET size = hb_fsSeekLarge( hFile, 0, FS_END ); - if( ( HB_FOFFSET ) ( size & 0xFFFFFFFF ) == size ) + hb_fsSeekLarge( hFile, 0, FS_SET ); + if( ( HB_FOFFSET ) ( size & 0xFFFFFFFFUL ) == size ) { ulSize = HB_MIN( ( ULONG ) size, 0xFFFFFFFFUL - sizeof( FPTBLOCK ) ); } else { - ulSize = HB_MIN( size, ( HB_FOFFSET ) ( 0xFFFFFFFF - sizeof( FPTBLOCK ) ) ); + ulSize = HB_MIN( size, ( HB_FOFFSET ) ( 0xFFFFFFFFUL - sizeof( FPTBLOCK ) ) ); } if( pArea->bMemoType == DB_MEMO_SMT ) @@ -3895,7 +4166,7 @@ static ERRCODE hb_fptPutValueFile( FPTAREAP pArea, USHORT uiIndex, BYTE * szFile else ulType = FPTIT_BINARY; - hb_fsSeekLarge( hFile, 0, FS_SET ); + uiError = hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, &ulBlock, &ulOldSize, &ulOldType ); if( uiError == SUCCESS ) @@ -3956,9 +4227,9 @@ static ERRCODE hb_fptInfo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); else { - char * szExt = hb_memoDefaultFileExt( pArea->bMemoType ); + char * szExt = hb_memoDefaultFileExt( pArea->bMemoType, pArea->rddID ); if( !szExt ) - szExt = hb_memoDefaultFileExt( pData->bMemoType ); + szExt = hb_memoDefaultFileExt( pData->bMemoType, pArea->rddID ); hb_itemPutC( pItem, szExt ); } } @@ -4005,21 +4276,141 @@ static ERRCODE hb_fptInfo( FPTAREAP pArea, USHORT uiIndex, PHB_ITEM pItem ) /* case DBI_RDD_VERSION */ - case DBI_BLOB_DIRECT_EXPORT: /* BLOBDirectExport() { , , */ - case DBI_BLOB_DIRECT_GET: /* BLOBDirectGet() { , , } */ - case DBI_BLOB_DIRECT_IMPORT: /* BLOBDirectImport() { , } */ - case DBI_BLOB_DIRECT_PUT: /* BLOBDirectPut() { , } */ + case DBI_BLOB_DIRECT_EXPORT: /* BLOBDirectExport() { , , } */ + { + ERRCODE errCode = FAILURE; - case DBI_BLOB_ROOT_GET: /* BLOBRootGet() */ - case DBI_BLOB_ROOT_PUT: /* BLOBRootPut( ) */ + if( HB_IS_ARRAY( pItem ) ) + { + ULONG ulBlock = hb_arrayGetNL( pItem, 1 ); + BYTE * szFile = ( BYTE * ) hb_arrayGetCPtr( pItem, 2 ); + + if( ulBlock && szFile && *szFile ) + errCode = hb_fptGetVarFile( pArea, ulBlock, szFile, + hb_arrayGetNI( pItem, 3 ) ); + } + hb_itemPutL( pItem, errCode == SUCCESS ); + break; + } + case DBI_BLOB_DIRECT_GET: /* BLOBDirectGet() { , , } */ + { + /* pItem := { , , } */ + ULONG ulBlock, ulStart, ulCount; + USHORT errCode; + + if( HB_IS_ARRAY( pItem ) ) + { + ulBlock = hb_arrayGetNL( pItem, 1 ); + ulStart = hb_arrayGetNL( pItem, 2 ); + if( ulStart ) + --ulStart; + ulCount = hb_arrayGetNL( pItem, 3 ); + } + else + { + ulBlock = ulStart = ulCount = 0; + } + errCode = hb_fptGetMemo( pArea, 0, pItem, FS_ERROR, ulBlock, ulStart, ulCount ); + if( errCode != SUCCESS ) + { + if( errCode != FAILURE ) + hb_memoErrorRT( pArea, 0, errCode, pArea->szMemoFileName, 0, 0 ); + return FAILURE; + } + break; + } + case DBI_BLOB_DIRECT_IMPORT: /* BLOBDirectImport() { , } */ + if( HB_IS_ARRAY( pItem ) ) + hb_itemPutNInt( pItem, hb_fptPutVarFile( pArea, + hb_arrayGetNL( pItem, 1 ), + ( BYTE * ) hb_arrayGetCPtr( pItem, 2 ) ) ); + else + hb_itemPutNI( pItem, 0 ); break; + case DBI_BLOB_DIRECT_PUT: /* BLOBDirectPut() { , } */ + { + /* pItem := { , } */ + USHORT errCode = EDBF_UNSUPPORTED; + ULONG ulBlock = 0; + + if( HB_IS_ARRAY( pItem ) ) + { + PHB_ITEM pValue = hb_arrayGetItemPtr( pItem, 2 ); + ulBlock = hb_arrayGetNL( pItem, 1 ); + if( pValue ) + { + if( hb_fptFileLockEx( pArea, TRUE ) ) + { + errCode = hb_fptPutMemo( pArea, 0, pValue, &ulBlock ); + hb_fptFileUnLock( pArea ); + } + else + errCode = EDBF_LOCK; + } + } + hb_itemPutNInt( pItem, ulBlock ); + if( errCode != SUCCESS ) + { + if( errCode != FAILURE ) + hb_memoErrorRT( pArea, 0, errCode, pArea->szMemoFileName, 0, 0 ); + return FAILURE; + } + break; + } + case DBI_BLOB_ROOT_GET: /* BLOBRootGet() */ + { + ULONG ulBlock; + USHORT errCode; + + errCode = hb_fptGetRootBlock( pArea, &ulBlock ); + if( errCode == SUCCESS ) + { + errCode = hb_fptGetMemo( pArea, 0, pItem, FS_ERROR, ulBlock, 0, 0 ); + } + if( errCode != SUCCESS ) + { + if( errCode != FAILURE ) + hb_memoErrorRT( pArea, 0, errCode, pArea->szMemoFileName, 0, 0 ); + hb_itemClear( pItem ); + return FAILURE; + } + break; + } + case DBI_BLOB_ROOT_PUT: /* BLOBRootPut( ) */ + { + ULONG ulBlock; + USHORT errCode; + + errCode = hb_fptGetRootBlock( pArea, &ulBlock ); + if( errCode == SUCCESS ) + { + if( hb_fptFileLockEx( pArea, TRUE ) ) + { + errCode = hb_fptPutMemo( pArea, 0, pItem, &ulBlock ); + hb_fptFileUnLock( pArea ); + if( errCode == SUCCESS ) + errCode = hb_fptPutRootBlock( pArea, ulBlock ); + } + else + errCode = EDBF_LOCK; + } + if( errCode != SUCCESS ) + { + if( errCode != FAILURE ) + hb_memoErrorRT( pArea, 0, errCode, pArea->szMemoFileName, 0, 0 ); + hb_itemPutL( pItem, FALSE ); + return FAILURE; + } + hb_itemPutL( pItem, TRUE ); + break; + } case DBI_BLOB_ROOT_LOCK: /* BLOBRootLock() */ - hb_itemPutL( pItem, hb_fptFileLockEx( pArea, FALSE ) ); + hb_itemPutL( pItem, hb_fptRootBlockLock( pArea ) ); break; case DBI_BLOB_ROOT_UNLOCK: /* BLOBRootUnlock() */ - hb_itemPutL( pItem, hb_fptFileUnLock( pArea ) ); + hb_itemPutL( pItem, hb_fptRootBlockUnLock( pArea ) ); break; case DBI_BLOB_DIRECT_LEN: @@ -4045,7 +4436,7 @@ static ERRCODE hb_fptFieldInfo( FPTAREAP pArea, USHORT uiIndex, USHORT uiType, P { HB_TRACE(HB_TR_DEBUG, ("hb_fptFieldInfo(%p, %hu, %hu, %p)", pArea, uiIndex, uiType, pItem)); - if( uiIndex > pArea->uiFieldCount ) + if( !uiIndex || uiIndex > pArea->uiFieldCount ) return FAILURE; if( pArea->fHasMemo && pArea->hMemoFile != FS_ERROR && @@ -4058,24 +4449,52 @@ static ERRCODE hb_fptFieldInfo( FPTAREAP pArea, USHORT uiIndex, USHORT uiType, P switch( uiType ) { case DBS_BLOB_GET: /* BLOBGet() { , } */ - /* TODO: !!! pItem := { , } */ + { + /* pItem := { , } */ + ULONG ulStart, ulCount; + USHORT errCode; + + if( HB_IS_ARRAY( pItem ) ) + { + ulStart = hb_arrayGetNL( pItem, 1 ); + if( ulStart ) + --ulStart; + ulCount = hb_arrayGetNL( pItem, 2 ); + } + else + { + ulStart = ulCount = 0; + } + errCode = hb_fptGetMemo( pArea, uiIndex, pItem, FS_ERROR, 0, ulStart, ulCount ); + if( errCode != SUCCESS ) + { + if( errCode != FAILURE ) + hb_memoErrorRT( pArea, 0, errCode, pArea->szMemoFileName, 0, 0 ); + return FAILURE; + } return SUCCESS; + } case DBS_BLOB_LEN: - hb_itemPutNL( pItem, hb_fptGetMemoLen( pArea, uiIndex - 1 ) ); + hb_itemPutNL( pItem, hb_fptGetMemoLen( pArea, uiIndex ) ); return SUCCESS; case DBS_BLOB_OFFSET: + /* Clipper 5.3 does not support it :-( [druzus] */ hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, &ulBlock, &ulSize, &ulType ); hb_itemPutNInt( pItem, ( HB_FOFFSET ) ulBlock * pArea->uiMemoBlockSize + ( pArea->bMemoType == DB_MEMO_FPT ? sizeof( FPTBLOCK ) : 0 ) ); return SUCCESS; case DBS_BLOB_POINTER: + /* + * Clipper 5.3 it returns the same value as DBS_BLOB_OFFSET + * in Harbour - it's a Clipper bug [druzus] + */ hb_dbfGetMemoData( (DBFAREAP) pArea, uiIndex - 1, &ulBlock, &ulSize, &ulType ); hb_itemPutNL( pItem, ulBlock ); return SUCCESS; case DBS_BLOB_TYPE: - hb_itemPutC( pItem, hb_fptGetMemoType( pArea, uiIndex - 1 ) ); + hb_itemPutC( pItem, hb_fptGetMemoType( pArea, uiIndex ) ); return SUCCESS; } } @@ -4107,11 +4526,11 @@ static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P if( pData->szMemoExt[ 0 ] ) hb_itemPutC( pItem, pData->szMemoExt ); - else if( pData->bMemoType == DB_MEMO_FPT && + else if( pData->bMemoType == DB_MEMO_FPT && pRDD->rddID != s_uiRddIdBLOB && hb_set.HB_SET_MFILEEXT && hb_set.HB_SET_MFILEEXT[ 0 ] ) hb_itemPutC( pItem, hb_set.HB_SET_MFILEEXT ); else - hb_itemPutC( pItem, hb_memoDefaultFileExt( pData->bMemoType ) ); + hb_itemPutC( pItem, hb_memoDefaultFileExt( pData->bMemoType, pRDD->rddID ) ); if( szNew ) { @@ -4145,12 +4564,15 @@ static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P hb_itemPutNI( pItem, pData->bMemoType ? pData->bMemoType : DB_MEMO_FPT ); - switch( iType ) + if( pRDD->rddID != s_uiRddIdBLOB ) { - case DB_MEMO_DBT: - case DB_MEMO_FPT: - case DB_MEMO_SMT: - pData->bMemoType = ( BYTE ) iType; + switch( iType ) + { + case DB_MEMO_DBT: + case DB_MEMO_FPT: + case DB_MEMO_SMT: + pData->bMemoType = ( BYTE ) iType; + } } break; } @@ -4174,9 +4596,10 @@ static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P case RDDI_MEMOGCTYPE: hb_itemPutNI( pItem, 0 ); break; + case RDDI_MEMOREADLOCK: #if defined( HB_MEMO_SAFELOCK ) - hb_itemPutL( pItem, TRUE ); + hb_itemPutL( pItem, pRDD->rddID != s_uiRddIdBLOB ); #else hb_itemPutL( pItem, FALSE ); #endif @@ -4185,6 +4608,10 @@ static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P hb_itemPutL( pItem, TRUE ); break; + case RDDI_BLOB_SUPPORT: + hb_itemPutL( pItem, pRDD->rddID == s_uiRddIdBLOB ); + break; + default: return SUPER_RDDINFO( pRDD, uiIndex, ulConnect, pItem ); } @@ -4192,31 +4619,51 @@ static ERRCODE hb_fptRddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnect, P return SUCCESS; } -/* for backward compatibility */ HB_FUNC( DBFDBT ) {;} - +HB_FUNC( DBFSMT ) {;} HB_FUNC( DBFFPT ) {;} +HB_FUNC( DBFBLOB ) {;} -HB_FUNC( DBFFPT_GETFUNCTABLE ) +static void hb_dbffptRegisterRDD( USHORT * pusRddId ) { RDDFUNCS * pTable; - USHORT * uiCount; + USHORT * uiCount, uiRddId; uiCount = ( USHORT * ) hb_itemGetPtr( hb_param( 1, HB_IT_POINTER ) ); pTable = ( RDDFUNCS * ) hb_itemGetPtr( hb_param( 2, HB_IT_POINTER ) ); + uiRddId = hb_parni( 4 ); HB_TRACE(HB_TR_DEBUG, ("DBFFPT_GETFUNCTABLE(%i, %p)", uiCount, pTable)); if( pTable ) { + ERRCODE errCode; + if ( uiCount ) * uiCount = RDDFUNCSCOUNT; - hb_retni( hb_rddInherit( pTable, &fptTable, &fptSuper, ( BYTE * ) "DBF" ) ); + + errCode = hb_rddInherit( pTable, &fptTable, &fptSuper, ( BYTE * ) "DBF" ); + if ( errCode == SUCCESS ) + *pusRddId = uiRddId; + hb_retni( errCode ); } else hb_retni( FAILURE ); } +HB_FUNC( DBFFPT_GETFUNCTABLE ) +{ + HB_TRACE(HB_TR_DEBUG, ("DBFFPT_GETFUNCTABLE()")); + + hb_dbffptRegisterRDD( &s_uiRddIdFPT ); +} + +HB_FUNC( DBFBLOB_GETFUNCTABLE ) +{ + HB_TRACE(HB_TR_DEBUG, ("DBFBLOB_GETFUNCTABLE()")); + + hb_dbffptRegisterRDD( &s_uiRddIdBLOB ); +} #define __PRG_SOURCE__ __FILE__ @@ -4231,8 +4678,9 @@ static void hb_dbffptRddInit( void * cargo ) { HB_SYMBOL_UNUSED( cargo ); - if( hb_rddRegister( "DBF", RDT_FULL ) > 1 || - hb_rddRegister( "DBFFPT", RDT_FULL ) > 1 ) + if( hb_rddRegister( "DBF", RDT_FULL ) > 1 || + hb_rddRegister( "DBFFPT", RDT_FULL ) > 1 || + hb_rddRegister( "DBFBLOB", RDT_FULL ) > 1 ) { hb_errInternal( HB_EI_RDDINVALID, NULL, NULL, NULL ); @@ -4242,8 +4690,10 @@ static void hb_dbffptRddInit( void * cargo ) } HB_INIT_SYMBOLS_BEGIN( dbffpt1__InitSymbols ) -{ "DBFFPT", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFFPT )}, NULL }, -{ "DBFFPT_GETFUNCTABLE", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFFPT_GETFUNCTABLE )}, NULL } +{ "DBFFPT", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFFPT )}, NULL }, +{ "DBFFPT_GETFUNCTABLE", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFFPT_GETFUNCTABLE )}, NULL }, +{ "DBFBLOB", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFBLOB )}, NULL }, +{ "DBFBLOB_GETFUNCTABLE", {HB_FS_PUBLIC}, {HB_FUNCNAME( DBFBLOB_GETFUNCTABLE )}, NULL } HB_INIT_SYMBOLS_END( dbffpt1__InitSymbols ) HB_CALL_ON_STARTUP_BEGIN( _hb_dbffpt_rdd_init_ ) diff --git a/harbour/source/rdd/workarea.c b/harbour/source/rdd/workarea.c index cb663978b1..80f2ca4399 100644 --- a/harbour/source/rdd/workarea.c +++ b/harbour/source/rdd/workarea.c @@ -485,8 +485,11 @@ ERRCODE hb_waSetFieldExtent( AREAP pArea, USHORT uiFieldExtent ) pArea->uiFieldExtent = uiFieldExtent; /* Alloc field array */ - pArea->lpFields = ( LPFIELD ) hb_xgrab( uiFieldExtent * sizeof( FIELD ) ); - memset( pArea->lpFields, 0, uiFieldExtent * sizeof( FIELD ) ); + if( uiFieldExtent ) + { + pArea->lpFields = ( LPFIELD ) hb_xgrab( uiFieldExtent * sizeof( FIELD ) ); + memset( pArea->lpFields, 0, uiFieldExtent * sizeof( FIELD ) ); + } return SUCCESS; } @@ -1557,6 +1560,7 @@ ERRCODE hb_rddInfo( LPRDDNODE pRDD, USHORT uiIndex, ULONG ulConnection, PHB_ITEM case RDDI_MULTITAG: case RDDI_SORTRECNO: case RDDI_MULTIKEY: + case RDDI_BLOB_SUPPORT: hb_itemPutL( pItem, FALSE ); break;