📄 dbf_dbffile.pas
字号:
ftString:
if Dst <> nil then
PChar(Dst)[0] := #0;
end;
end;
end;
end;
procedure TDbfFile.UpdateNullField(Buffer: Pointer; AFieldDef: TDbfFieldDef;
Action: TUpdateNullField);
var
NullDst: pbyte;
Mask: byte;
begin
// this field has null setting capability
NullDst := PByte(PChar(Buffer) + FNullField.Offset + (AFieldDef.NullPosition shr 3));
Mask := 1 shl (AFieldDef.NullPosition and $7);
if Action = unSet then
begin
// clear the field, set null flag
NullDst^ := NullDst^ or Mask;
end else begin
// set field data, clear null flag
NullDst^ := NullDst^ and not Mask;
end;
end;
procedure TDbfFile.SetFieldData(Column: Integer; DataType: TFieldType;
Src, Dst: Pointer; NativeFormat: boolean);
const
IsBlobFieldToPadChar: array[Boolean] of Char = (#32, '0');
SrcNilToUpdateNullField: array[boolean] of TUpdateNullField = (unClear, unSet);
var
FieldSize,FieldPrec: Integer;
TempFieldDef: TDbfFieldDef;
Len: Integer;
IntValue: dword;
year, month, day: Word;
hour, minute, sec, msec: Word;
date: TDateTime;
timeStamp: TTimeStamp;
asciiContents: boolean;
procedure LoadDateFromSrc;
begin
if not NativeFormat then
begin
// Delphi 5, new format, passes a TDateTime
date := PDateTime(Src)^;
end else begin
// Delphi 3 and 4, old "native" format, pass a TDateTimeRec with a time stamp
// date = integer
// datetime = msecs == BDETimeStampToDateTime as we implemented it
if DataType = ftDateTime then
begin
date := PDouble(Src)^;
end else begin
timeStamp.Time := 0;
timeStamp.Date := PLongInt(Src)^;
date := TimeStampToDateTime(timeStamp);
end;
end;
end;
begin
TempFieldDef := TDbfFieldDef(FFieldDefs.Items[Column]);
FieldSize := TempFieldDef.Size;
FieldPrec := TempFieldDef.Precision;
// if src = nil then write empty field
// symmetry with above
// foxpro has special _nullfield for flagging fields as `null'
if (FNullField <> nil) and (TempFieldDef.NullPosition >= 0) then
UpdateNullField(Dst, TempFieldDef, SrcNilToUpdateNullField[Src = nil]);
// copy field data to record buffer
Dst := PChar(Dst) + TempFieldDef.Offset;
asciiContents := false;
case TempFieldDef.NativeFieldType of
'+', 'I':
begin
if FDbfVersion <> xFoxPro then
begin
if Src = nil then
IntValue := 0
else
IntValue := PDWord(Src)^ xor $80000000;
PDWord(Dst)^ := SwapIntBE(IntValue);
end else begin
if Src = nil then
PDWord(Dst)^ := 0
else
PDWord(Dst)^ := SwapIntLE(PDWord(Src)^);
end;
end;
'O':
begin
{$ifdef SUPPORT_INT64}
if Src = nil then
begin
PInt64(Dst)^ := 0;
end else begin
if PDouble(Src)^ < 0 then
PInt64(Dst)^ := not PInt64(Src)^
else
PDouble(Dst)^ := (PDouble(Src)^) * -1;
SwapInt64BE(Dst, Dst);
end;
{$endif}
end;
'@':
begin
if Src = nil then
begin
{$ifdef SUPPORT_INT64}
PInt64(Dst)^ := 0;
{$else}
PInteger(Dst)^ := 0;
PInteger(PChar(Dst)+4)^ := 0;
{$endif}
end else begin
LoadDateFromSrc;
if FDateTimeHandling = dtBDETimeStamp then
date := DateTimeToBDETimeStamp(date);
SwapInt64BE(@date, Dst);
end;
end;
'T':
begin
// all binary zeroes -> empty datetime
if Src = nil then
begin
{$ifdef SUPPORT_INT64}
PInt64(Dst)^ := 0;
{$else}
PInteger(Dst)^ := 0;
PInteger(PChar(Dst)+4)^ := 0;
{$endif}
end else begin
LoadDateFromSrc;
timeStamp := DateTimeToTimeStamp(date);
PInteger(Dst)^ := SwapIntLE(timeStamp.Date + JulianDateDelta);
PInteger(PChar(Dst)+4)^ := SwapIntLE(timeStamp.Time);
end;
end;
'Y':
begin
{$ifdef SUPPORT_INT64}
if Src = nil then
begin
PInt64(Dst)^ := 0;
end else begin
case DataType of
ftCurrency:
PInt64(Dst)^ := Trunc(PDouble(Src)^ * 10000);
ftBCD:
PCurrency(Dst)^ := PCurrency(Src)^;
end;
SwapInt64LE(Dst, Dst);
end;
{$endif}
end;
'B':
begin
if DbfVersion = xFoxPro then
begin
if Src = nil then
PDouble(Dst)^ := 0
else
SwapInt64LE(Src, Dst);
end else
asciiContents := true;
end;
'M':
begin
if FieldSize = 4 then
begin
if Src = nil then
PInteger(Dst)^ := 0
else
PInteger(Dst)^ := SwapIntLE(PInteger(Src)^);
end else
asciiContents := true;
end;
else
asciiContents := true;
end;
if asciiContents then
begin
if Src = nil then
begin
FillChar(Dst^, FieldSize, ' ');
end else begin
case DataType of
ftBoolean:
begin
if PWord(Src)^ <> 0 then
PChar(Dst)^ := 'T'
else
PChar(Dst)^ := 'F';
end;
ftSmallInt:
GetStrFromInt_Width(PSmallInt(Src)^, FieldSize, PChar(Dst), #32);
{$ifdef SUPPORT_INT64}
ftLargeInt:
GetStrFromInt64_Width(PLargeInt(Src)^, FieldSize, PChar(Dst), #32);
{$endif}
ftFloat, ftCurrency:
FloatToDbfStr(PDouble(Src)^, FieldSize, FieldPrec, PChar(Dst));
ftInteger:
GetStrFromInt_Width(PInteger(Src)^, FieldSize, PChar(Dst),
IsBlobFieldToPadChar[TempFieldDef.IsBlob]);
ftDate, ftDateTime:
begin
LoadDateFromSrc;
// decode
DecodeDate(date, year, month, day);
// format is yyyymmdd
GetStrFromInt_Width(year, 4, PChar(Dst), '0');
GetStrFromInt_Width(month, 2, PChar(Dst)+4, '0');
GetStrFromInt_Width(day, 2, PChar(Dst)+6, '0');
// do time too if datetime
if DataType = ftDateTime then
begin
DecodeTime(date, hour, minute, sec, msec);
// format is hhmmss
GetStrFromInt_Width(hour, 2, PChar(Dst)+8, '0');
GetStrFromInt_Width(minute, 2, PChar(Dst)+10, '0');
GetStrFromInt_Width(sec, 2, PChar(Dst)+12, '0');
end;
end;
ftString:
begin
// copy data
Len := StrLen(Src);
if Len > FieldSize then
Len := FieldSize;
Move(Src^, Dst^, Len);
// fill remaining space with spaces
FillChar((PChar(Dst)+Len)^, FieldSize - Len, ' ');
end;
end; // case datatype
end;
end;
end;
procedure TDbfFile.InitDefaultBuffer;
var
lRecordSize: integer;
TempFieldDef: TDbfFieldDef;
I: Integer;
begin
lRecordSize := PDbfHdr(Header)^.RecordSize;
// clear buffer (assume all string, fix specific fields later)
// note: Self.RecordSize is used for reading fielddefs too
GetMem(FDefaultBuffer, lRecordSize+1);
FillChar(FDefaultBuffer^, lRecordSize, ' ');
// set nullflags field so that all fields are null
if FNullField <> nil then
FillChar(PChar(FDefaultBuffer+FNullField.Offset)^, FNullField.Size, $FF);
// check binary and default fields
for I := 0 to FFieldDefs.Count-1 do
begin
TempFieldDef := FFieldDefs.Items[I];
// binary field? (foxpro memo fields are binary, but dbase not)
if (TempFieldDef.NativeFieldType in ['I', 'O', '@', '+', '0', 'Y'])
or ((TempFieldDef.NativeFieldType = 'M') and (TempFieldDef.Size = 4)) then
FillChar(PChar(FDefaultBuffer+TempFieldDef.Offset)^, TempFieldDef.Size, 0);
// copy default value?
if TempFieldDef.HasDefault then
begin
Move(TempFieldDef.DefaultBuf[0], FDefaultBuffer[TempFieldDef.Offset], TempFieldDef.Size);
// clear the null flag, this field has a value
if FNullField <> nil then
UpdateNullField(FDefaultBuffer, TempFieldDef, unClear);
end;
end;
end;
procedure TDbfFile.InitRecord(DestBuf: PChar);
begin
if FDefaultBuffer = nil then
InitDefaultBuffer;
Move(FDefaultBuffer^, DestBuf^, RecordSize);
end;
procedure TDbfFile.ApplyAutoIncToBuffer(DestBuf: PChar);
var
TempFieldDef: TDbfFieldDef;
I, NextVal, lAutoIncOffset: {LongWord} Cardinal; {Delphi 3 does not know LongWord?}
begin
if FAutoIncPresent then
begin
// if shared, reread header to find new autoinc values
if NeedLocks then
begin
// lock header so nobody else can use this value
LockPage(0, true);
end;
// find autoinc fields
for I := 0 to FFieldDefs.Count-1 do
begin
TempFieldDef := FFieldDefs.Items[I];
if (TempFieldDef.NativeFieldType = '+') then
begin
// read current auto inc, from header or field, depending on sharing
lAutoIncOffset := sizeof(rDbfHdr) + sizeof(rAfterHdrVII) +
FieldDescVII_AutoIncOffset + I * sizeof(rFieldDescVII);
if NeedLocks then
begin
ReadBlock(@NextVal, 4, lAutoIncOffset);
NextVal := SwapIntLE(NextVal);
end else
NextVal := TempFieldDef.AutoInc;
// store to buffer, positive = high bit on, so flip it
PCardinal(DestBuf+TempFieldDef.Offset)^ := SwapIntBE(NextVal or $80000000);
// increase
Inc(NextVal);
TempFieldDef.AutoInc := NextVal;
// write new value to header buffer
PCardinal(FHeader+lAutoIncOffset)^ := SwapIntLE(NextVal);
end;
end;
// write modified header (new autoinc values) to file
WriteHeader;
// release lock if locked
if NeedLocks then
UnlockPage(0);
end;
end;
procedure TDbfFile.TryExclusive;
var
I: Integer;
begin
inherited;
// exclusive succeeded? open index & memo exclusive too
if Mode in [pfMemoryCreate..pfExclusiveOpen] then
begin
// indexes
for I := 0 to FIndexFiles.Count - 1 do
TPagedFile(FIndexFiles[I]).TryExclusive;
// memo
if FMemoFile <> nil then
FMemoFile.TryExclusive;
end;
end;
procedure TDbfFile.EndExclusive;
var
I: Integer;
begin
// end exclusive on index & memo too
for I := 0 to FIndexFiles.Count - 1 do
TPagedFile(FIndexFiles[I]).EndExclusive;
// memo
if FMemoFile <> nil then
FMemoFile.EndExclusive;
// dbf file
inherited;
end;
procedure TDbfFile.OpenIndex(IndexName, IndexField: string; CreateIndex: Boolean; Options: TIndexOptions);
//
// assumes IndexName is not empty
//
const
// memcr, memop, excr, exopen, rwcr, rwopen, rdonly
IndexOpenMode: array[boolean, pfMemoryCreate..pfReadOnly] of TPagedFileMode =
((pfMemoryCreate, pfMemoryCreate, pfExclusiveOpen, pfExclusiveOpen, pfReadWriteOpen, pfReadWriteOpen,
pfReadOnly),
(pfMemoryCreate, pfMemoryCreate, pfExclusiveCreate, pfExclusiveCreate, pfReadWriteCreate, pfReadWriteCreate,
pfReadOnly));
var
lIndexFile: TIndexFile;
lIndexFileName: string;
createMdxFile: Boolean;
tempExclusive: boolean;
addedIndexFile: Integer;
addedIndexName: Integer;
begin
// init
addedIndexFile := -1;
addedIndexName := -1;
createMdxFile := false;
// index already opened?
lIndexFile := GetIndexByName(IndexName);
if (lIndexFile <> nil) and (lIndexFile = FMdxFile) and CreateIndex then
begin
// index already exists in MDX file
// delete it to save space, this causes a repage
FMdxFile.DeleteIndex(IndexName);
// index no longer exists
lIndexFile := nil;
end;
if (lIndexFile = nil) and (IndexName <> EmptyStr) then
begin
// check if no extension, then create MDX index
if Length(ExtractFileExt(IndexName)) = 0 then
begin
// check if mdx index already opened
if FMdxFile <> nil then
begin
lIn
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -