From 5c6b0d39e9db755aaaa2ee38d5f74c5812f194d0 Mon Sep 17 00:00:00 2001 From: reiniero Date: Fri, 5 Apr 2013 13:21:54 +0000 Subject: [PATCH] * fcl-base/dbase: memo definitions clarified git-svn-id: trunk@24159 - --- packages/fcl-db/src/dbase/dbf_dbffile.pas | 9 +++--- packages/fcl-db/src/dbase/dbf_fields.pas | 18 +++++------ packages/fcl-db/src/dbase/dbf_memo.pas | 37 ++++++++++++++--------- packages/fcl-db/src/dbase/dbf_struct.inc | 2 +- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/packages/fcl-db/src/dbase/dbf_dbffile.pas b/packages/fcl-db/src/dbase/dbf_dbffile.pas index 604deb1912..d4e7216892 100644 --- a/packages/fcl-db/src/dbase/dbf_dbffile.pas +++ b/packages/fcl-db/src/dbase/dbf_dbffile.pas @@ -352,7 +352,7 @@ var // http://msdn.microsoft.com/en-US/library/st4a0s68%28v=vs.80%29.aspx case version of $30, $31, $32: FDbfVersion:=xVisualFoxPro; - $F5: FDbfVersion:=xFoxPro; + $F5, $FB: FDbfVersion:=xFoxPro; end; if FDbfVersion = xUnknown then case (version and $07) of @@ -366,11 +366,7 @@ var $02, $05: FDbfVersion := xFoxPro; else - // todo: check visual foxpro, modify - if ((version and $FE) = $30) or (version = $F5) or (version = $FB) then begin - FDbfVersion := xFoxPro; - end else begin // not a valid DBF file raise EDbfError.Create(STRING_INVALID_DBF_FILE); end; @@ -677,6 +673,8 @@ begin {$endif} then begin + // Up to 32kb strings + // Stores high byte of size in precision, low in size lPrec := lSize shr 8; lSize := lSize and $FF; end; @@ -699,6 +697,7 @@ begin lFieldDescIII.FieldPrecision := lPrec; if (FDbfVersion in [xFoxPro,xVisualFoxPro]) then lFieldDescIII.FieldOffset := SwapIntLE(lFieldOffset); + // Adjust the version info if needed for supporting field types used: if (PDbfHdr(Header)^.VerDBF = $02) and (lFieldDef.NativeFieldType in ['0', 'Y', 'T', 'O', '+']) then PDbfHdr(Header)^.VerDBF := $30; {Visual FoxPro} if (PDbfHdr(Header)^.VerDBF = $30) and (lFieldDef.NativeFieldType = '+') then diff --git a/packages/fcl-db/src/dbase/dbf_fields.pas b/packages/fcl-db/src/dbase/dbf_fields.pas index e74e393fc1..773391d6f6 100644 --- a/packages/fcl-db/src/dbase/dbf_fields.pas +++ b/packages/fcl-db/src/dbase/dbf_fields.pas @@ -80,7 +80,7 @@ type // Native dbf field type property NativeFieldType: TDbfFieldType read FNativeFieldType write SetNativeFieldType; property NullPosition: integer read FNullPosition write FNullPosition; - // Size in dbase file (not VCL/LCL) + // Size in memory (not VCL/LCL) property Size: Integer read FSize write SetSize; // Precision in dbase file (not VCL/LCL) property Precision: Integer read FPrecision write SetPrecision; @@ -118,7 +118,7 @@ uses const (* -The theory is: +The theory for Delphi/FPC is: ftSmallint 16 bits = -32768 to 32767 123456 = 6 digit max theorically DIGITS_SMALLINT = 6; @@ -135,15 +135,15 @@ be able to handles fields with 999999 (6 digits). So I oversize the field type in order to accept anything coming from the database. ftSmallint 16 bits = -32768 to 32767 - -999 to 9999 - 4 digits max theorically - DIGITS_SMALLINT = 4; + ... dbf supports: -999 to 9999 + 4 digits max in practice + therefore DIGITS_SMALLINT = 4; ftInteger 32 bits = -2147483648 to 2147483647 - -99999999 to 999999999 12345678901 = 11 digits max - DIGITS_INTEGER = 9; + ... dbf supports: -99999999 to 999999999 12345678901 = 11 digits max + therefore DIGITS_INTEGER = 9; ftLargeInt 64 bits = -9223372036854775808 to 9223372036854775807 - -99999999999999999 to 999999999999999999 - DIGITS_LARGEINT = 18; + ... dbf supports: -99999999999999999 to 999999999999999999 + therefore DIGITS_LARGEINT = 18; *) DIGITS_SMALLINT = 4; DIGITS_INTEGER = 9; diff --git a/packages/fcl-db/src/dbase/dbf_memo.pas b/packages/fcl-db/src/dbase/dbf_memo.pas index 24637f06d7..69daf43366 100644 --- a/packages/fcl-db/src/dbase/dbf_memo.pas +++ b/packages/fcl-db/src/dbase/dbf_memo.pas @@ -101,16 +101,20 @@ uses //=== Memo and binary fields support //==================================================================== type - + // DBase III+ dbt memo file PDbtHdr = ^rDbtHdr; rDbtHdr = record - NextBlock : dword; - Dummy : array [4..7] of Byte; + NextBlock : dword; // 0..3 + // Dummy in DBaseIII; size of blocks in memo file; default 512 bytes + BlockSize : dword; // 4..7 + // DBF file name without extension DbfFile : array [0..7] of Byte; // 8..15 + // DBase III only: version number $03 bVer : Byte; // 16 - Dummy2 : array [17..19] of Byte; + Dummy2 : array [17..19] of Byte; // 17..19 + // Block length in bytes; DBaseIII: always $01 BlockLen : Word; // 20..21 - Dummy3 : array [22..511] of Byte; + Dummy3 : array [22..511] of Byte;// 22..511 First block; garbage contents end; PFptHdr = ^rFptHdr; @@ -121,10 +125,12 @@ type Dummy3 : array [8..511] of Byte; end; + // Header of a memo data block: PBlockHdr = ^rBlockHdr; rBlockHdr = record - MemoType : Cardinal; - MemoSize : Cardinal; + // DBase IV(+) identifier: $FF $FF $08 $00 + MemoType : Cardinal; // 0..4 + MemoSize : Cardinal; // 5..7 end; @@ -184,7 +190,8 @@ begin RecordSize := GetBlockLen; // checking for right blocksize not needed for foxpro? // mod 128 <> 0 <-> and 0x7F <> 0 - if (RecordSize = 0) and ((FDbfVersion in [xFoxPro,xVisualFoxPro]) or ((RecordSize and $7F) <> 0)) then + if (RecordSize = 0) and + ((FDbfVersion in [xFoxPro,xVisualFoxPro]) or ((RecordSize and $7F) <> 0)) then begin SetBlockLen(512); RecordSize := 512; @@ -271,15 +278,15 @@ begin // dbase III memo done := false; repeat - // scan for EOF + // scan for EOF marker endMemo := MemScan(FBuffer, $1A, RecordSize); // EOF found? if endMemo <> nil then begin - // really EOF? - if (endMemo-FBuffer < RecordSize - 1) and ((endMemo[1] = #$1A) or (endMemo[1] = #0)) then + // really EOF? expect another 1A or null character + if (endMemo-FBuffer < RecordSize - 1) and + ((endMemo[1] = #$1A) or (endMemo[1] = #0)) then begin - // yes, EOF found done := true; numBytes := endMemo - FBuffer; end else begin @@ -344,7 +351,7 @@ begin begin bytesBefore := SizeOf(rBlockHdr); bytesAfter := 0; - end else begin // dBase3 type + end else begin // dBase3 type, Clipper? bytesBefore := 0; bytesAfter := 2; end; @@ -383,7 +390,7 @@ begin repeat // read bytes, don't overwrite header readBytes := Src.Read(FBuffer[bytesBefore], RecordSize{PDbtHdr(Header).BlockLen}-bytesBefore); - // end of input data reached ? check if need to write block terminators + // end of input data reached? check if we need to write block terminators while (readBytes < RecordSize - bytesBefore) and (bytesAfter > 0) do begin FBuffer[readBytes] := #$1A; @@ -428,7 +435,7 @@ end; function TDbaseMemoFile.GetMemoSize: Integer; begin - // dBase4 memofiles contain small 'header' + // dBase4 memofiles contain a small 'header' if PInteger(@FBuffer[0])^ = Integer(SwapIntLE($0008FFFF)) then Result := SwapIntLE(PBlockHdr(FBuffer)^.MemoSize)-8 else diff --git a/packages/fcl-db/src/dbase/dbf_struct.inc b/packages/fcl-db/src/dbase/dbf_struct.inc index 7520c15c5f..02a61262d6 100644 --- a/packages/fcl-db/src/dbase/dbf_struct.inc +++ b/packages/fcl-db/src/dbase/dbf_struct.inc @@ -51,9 +51,9 @@ type rFieldDescIII = packed record FieldName : array[0..10] of Char; FieldType : Char; // 11 - FieldOffset : Integer; // 12..15 // FieldOffset only applicable to (visual) foxpro databases // DBase III uses it for address in memory + FieldOffset : Integer; // 12..15 FieldSize : Byte; // 16 FieldPrecision : Byte; // 17, also known as decimal count FoxProFlags : Byte; // 18