dbf_common.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. unit dbf_common;
  2. interface
  3. {$I dbf_common.inc}
  4. uses
  5. SysUtils, Classes, DB
  6. {$ifndef WIN32}
  7. , Types, dbf_wtil
  8. {$ifdef KYLIX}
  9. , Libc
  10. {$endif}
  11. {$endif}
  12. ;
  13. const
  14. TDBF_MAJOR_VERSION = 6;
  15. TDBF_MINOR_VERSION = 45;
  16. TDBF_SUB_MINOR_VERSION = 0;
  17. TDBF_TABLELEVEL_FOXPRO = 25;
  18. type
  19. EDbfError = class (EDatabaseError);
  20. EDbfWriteError = class (EDbfError);
  21. TDbfFieldType = char;
  22. TXBaseVersion = (xUnknown, xClipper, xBaseIII, xBaseIV, xBaseV, xFoxPro, xBaseVII);
  23. TSearchKeyType = (stEqual, stGreaterEqual, stGreater);
  24. TDateTimeHandling = (dtDateTime, dtBDETimeStamp);
  25. //-------------------------------------
  26. PDateTime = ^TDateTime;
  27. {$ifdef FPC_VERSION}
  28. TDateTimeAlias = type TDateTime;
  29. TDateTimeRec = record
  30. case TFieldType of
  31. ftDate: (Date: Longint);
  32. ftTime: (Time: Longint);
  33. ftDateTime: (DateTime: TDateTimeAlias);
  34. end;
  35. {$endif}
  36. PSmallInt = ^SmallInt;
  37. PCardinal = ^Cardinal;
  38. PDouble = ^Double;
  39. PString = ^String;
  40. PDateTimeRec = ^TDateTimeRec;
  41. {$ifdef SUPPORT_INT64}
  42. PLargeInt = ^Int64;
  43. {$endif}
  44. //-------------------------------------
  45. {$ifndef SUPPORT_FREEANDNIL}
  46. // some procedures for the less lucky who don't have newer versions yet :-)
  47. procedure FreeAndNil(var v);
  48. {$endif}
  49. procedure FreeMemAndNil(var P: Pointer);
  50. //-------------------------------------
  51. {$ifndef SUPPORT_PATHDELIM}
  52. const
  53. {$ifdef WIN32}
  54. PathDelim = '\';
  55. {$else}
  56. PathDelim = '/';
  57. {$endif}
  58. {$endif}
  59. {$ifndef SUPPORT_INCLTRAILPATHDELIM}
  60. function IncludeTrailingPathDelimiter(const Path: string): string;
  61. {$endif}
  62. //-------------------------------------
  63. function GetCompletePath(const Base, Path: string): string;
  64. function GetCompleteFileName(const Base, FileName: string): string;
  65. function IsFullFilePath(const Path: string): Boolean; // full means not relative
  66. function DateTimeToBDETimeStamp(aDT: TDateTime): double;
  67. function BDETimeStampToDateTime(aBT: double): TDateTime;
  68. function GetStrFromInt(Val: Integer; const Dst: PChar): Integer;
  69. procedure GetStrFromInt_Width(Val: Integer; const Width: Integer; const Dst: PChar; const PadChar: Char);
  70. {$ifdef SUPPORT_INT64}
  71. function GetStrFromInt64(Val: Int64; const Dst: PChar): Integer;
  72. procedure GetStrFromInt64_Width(Val: Int64; const Width: Integer; const Dst: PChar; const PadChar: Char);
  73. {$endif}
  74. procedure FindNextName(BaseName: string; var OutName: string; var Modifier: Integer);
  75. {$ifdef USE_CACHE}
  76. function GetFreeMemory: Integer;
  77. {$endif}
  78. // OH 2000-11-15 dBase7 support. Swap Byte order for 4 and 8 Byte Integer
  79. function SwapInt(const Value: Cardinal): Cardinal;
  80. { SwapInt64 NOTE: do not call with same value for Value and Result ! }
  81. procedure SwapInt64(Value, Result: Pointer); register;
  82. function TranslateString(FromCP, ToCP: Cardinal; Src, Dest: PChar; Length: Integer): Integer;
  83. // Returns a pointer to the first occurence of Chr in Str within the first Length characters
  84. // Does not stop at null (#0) terminator!
  85. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  86. // Delphi 3 does not have a Min function
  87. {$ifdef DELPHI_3}
  88. {$ifndef DELPHI_4}
  89. function Min(x, y: integer): integer;
  90. {$endif}
  91. {$endif}
  92. implementation
  93. {$ifdef WIN32}
  94. uses
  95. Windows;
  96. {$endif}
  97. //====================================================================
  98. function GetCompletePath(const Base, Path: string): string;
  99. begin
  100. if IsFullFilePath(Path)
  101. then begin
  102. Result := Path;
  103. end else begin
  104. if Length(Base) > 0 then
  105. Result := ExpandFileName(IncludeTrailingPathDelimiter(Base) + Path)
  106. else
  107. Result := ExpandFileName(Path);
  108. end;
  109. // add last backslash if not present
  110. if Length(Result) > 0 then
  111. Result := IncludeTrailingPathDelimiter(Result);
  112. end;
  113. function IsFullFilePath(const Path: string): Boolean; // full means not relative
  114. begin
  115. {$ifdef WIN32}
  116. Result := Length(Path) > 1;
  117. if Result then
  118. // check for 'x:' or '\\' at start of path
  119. Result := ((Path[2]=':') and (upcase(Path[1]) in ['A'..'Z']))
  120. or ((Path[1]='\') and (Path[2]='\'));
  121. {$else} // Linux
  122. Result := Length(Path) > 0;
  123. if Result then
  124. Result := Path[1]='/';
  125. {$endif}
  126. end;
  127. //====================================================================
  128. function GetCompleteFileName(const Base, FileName: string): string;
  129. var
  130. lpath: string;
  131. lfile: string;
  132. begin
  133. lpath := GetCompletePath(Base, ExtractFilePath(FileName));
  134. lfile := ExtractFileName(FileName);
  135. lpath := lpath + lfile;
  136. result := lpath;
  137. end;
  138. // it seems there is no pascal function to convert an integer into a PChar???
  139. procedure GetStrFromInt_Width(Val: Integer; const Width: Integer; const Dst: PChar; const PadChar: Char);
  140. var
  141. Temp: array[0..10] of Char;
  142. I, J: Integer;
  143. NegSign: boolean;
  144. begin
  145. {$I getstrfromint.inc}
  146. end;
  147. {$ifdef SUPPORT_INT64}
  148. procedure GetStrFromInt64_Width(Val: Int64; const Width: Integer; const Dst: PChar; const PadChar: Char);
  149. var
  150. Temp: array[0..19] of Char;
  151. I, J: Integer;
  152. NegSign: boolean;
  153. begin
  154. {$I getstrfromint.inc}
  155. end;
  156. {$endif}
  157. // it seems there is no pascal function to convert an integer into a PChar???
  158. // NOTE: in dbf_dbffile.pas there is also a convert routine, but is slightly different
  159. function GetStrFromInt(Val: Integer; const Dst: PChar): Integer;
  160. var
  161. Temp: array[0..10] of Char;
  162. I, J: Integer;
  163. begin
  164. Val := Abs(Val);
  165. // we'll have to store characters backwards first
  166. I := 0;
  167. J := 0;
  168. repeat
  169. Temp[I] := Chr((Val mod 10) + Ord('0'));
  170. Val := Val div 10;
  171. Inc(I);
  172. until Val = 0;
  173. // remember number of digits
  174. Result := I;
  175. // copy value, remember: stored backwards
  176. repeat
  177. Dst[J] := Temp[I-1];
  178. Inc(J);
  179. Dec(I);
  180. until I = 0;
  181. // done!
  182. end;
  183. {$ifdef SUPPORT_INT64}
  184. function GetStrFromInt64(Val: Int64; const Dst: PChar): Integer;
  185. var
  186. Temp: array[0..19] of Char;
  187. I, J: Integer;
  188. begin
  189. Val := Abs(Val);
  190. // we'll have to store characters backwards first
  191. I := 0;
  192. J := 0;
  193. repeat
  194. Temp[I] := Chr((Val mod 10) + Ord('0'));
  195. Val := Val div 10;
  196. Inc(I);
  197. until Val = 0;
  198. // remember number of digits
  199. Result := I;
  200. // copy value, remember: stored backwards
  201. repeat
  202. Dst[J] := Temp[I-1];
  203. inc(J);
  204. dec(I);
  205. until I = 0;
  206. // done!
  207. end;
  208. {$endif}
  209. function DateTimeToBDETimeStamp(aDT: TDateTime): double;
  210. var
  211. aTS: TTimeStamp;
  212. begin
  213. aTS := DateTimeToTimeStamp(aDT);
  214. Result := TimeStampToMSecs(aTS);
  215. end;
  216. function BDETimeStampToDateTime(aBT: double): TDateTime;
  217. var
  218. aTS: TTimeStamp;
  219. begin
  220. aTS := MSecsToTimeStamp(aBT);
  221. Result := TimeStampToDateTime(aTS);
  222. end;
  223. //====================================================================
  224. {$ifndef SUPPORT_FREEANDNIL}
  225. procedure FreeAndNil(var v);
  226. var
  227. Temp: TObject;
  228. begin
  229. Temp := TObject(v);
  230. TObject(v) := nil;
  231. Temp.Free;
  232. end;
  233. {$endif}
  234. procedure FreeMemAndNil(var P: Pointer);
  235. var
  236. Temp: Pointer;
  237. begin
  238. Temp := P;
  239. P := nil;
  240. FreeMem(Temp);
  241. end;
  242. //====================================================================
  243. {$ifndef SUPPORT_INCLTRAILPATHDELIM}
  244. {$ifndef SUPPORT_INCLTRAILBACKSLASH}
  245. function IncludeTrailingPathDelimiter(const Path: string): string;
  246. var
  247. len: Integer;
  248. begin
  249. Result := Path;
  250. len := Length(Result);
  251. if len = 0 then
  252. Result := PathDelim
  253. else
  254. if Result[len] <> PathDelim then
  255. Result := Result + PathDelim;
  256. end;
  257. {$else}
  258. function IncludeTrailingPathDelimiter(const Path: string): string;
  259. begin
  260. {$ifdef WIN32}
  261. Result := IncludeTrailingBackslash(Path);
  262. {$else}
  263. Result := IncludeTrailingSlash(Path);
  264. {$endif}
  265. end;
  266. {$endif}
  267. {$endif}
  268. {$ifdef USE_CACHE}
  269. function GetFreeMemory: Integer;
  270. var
  271. MemStatus: TMemoryStatus;
  272. begin
  273. GlobalMemoryStatus(MemStatus);
  274. Result := MemStatus.dwAvailPhys;
  275. end;
  276. {$endif}
  277. //====================================================================
  278. // Utility routines
  279. //====================================================================
  280. {$ifdef USE_ASSEMBLER_486_UP}
  281. function SwapInt(const Value: Cardinal): Cardinal; register; assembler;
  282. asm
  283. BSWAP EAX;
  284. end;
  285. procedure SwapInt64(Value {EAX}, Result {EDX}: Pointer); register; assembler;
  286. asm
  287. MOV ECX, dword ptr [EAX]
  288. MOV EAX, dword ptr [EAX + 4]
  289. BSWAP ECX
  290. BSWAP EAX
  291. MOV dword ptr [EDX+4], ECX
  292. MOV dword ptr [EDX], EAX
  293. end;
  294. {$else}
  295. function SwapInt(const Value: Cardinal): Cardinal;
  296. begin
  297. PByteArray(@Result)[0] := PByteArray(@Value)[3];
  298. PByteArray(@Result)[1] := PByteArray(@Value)[2];
  299. PByteArray(@Result)[2] := PByteArray(@Value)[1];
  300. PByteArray(@Result)[3] := PByteArray(@Value)[0];
  301. end;
  302. procedure SwapInt64(Value, Result: Pointer); register;
  303. var
  304. PtrResult: PByteArray;
  305. PtrSource: PByteArray;
  306. begin
  307. // temporary storage is actually not needed, but otherwise compiler crashes (?)
  308. PtrResult := PByteArray(Result);
  309. PtrSource := PByteArray(Value);
  310. PtrResult[0] := PtrSource[7];
  311. PtrResult[1] := PtrSource[6];
  312. PtrResult[2] := PtrSource[5];
  313. PtrResult[3] := PtrSource[4];
  314. PtrResult[4] := PtrSource[3];
  315. PtrResult[5] := PtrSource[2];
  316. PtrResult[6] := PtrSource[1];
  317. PtrResult[7] := PtrSource[0];
  318. end;
  319. {$endif}
  320. function TranslateString(FromCP, ToCP: Cardinal; Src, Dest: PChar; Length: Integer): Integer;
  321. var
  322. WideCharStr: array[0..1023] of WideChar;
  323. wideBytes: Cardinal;
  324. begin
  325. if Length = -1 then
  326. Length := StrLen(Src);
  327. Result := Length;
  328. if (FromCP = GetOEMCP) and (ToCP = GetACP) then
  329. OemToCharBuff(Src, Dest, Length)
  330. else
  331. if (FromCP = GetACP) and (ToCP = GetOEMCP) then
  332. CharToOemBuff(Src, Dest, Length)
  333. else
  334. if FromCP = ToCP then
  335. begin
  336. if Src <> Dest then
  337. Move(Src^, Dest^, Length);
  338. end else begin
  339. // does this work on Win95/98/ME?
  340. wideBytes := MultiByteToWideChar(FromCP, MB_PRECOMPOSED, Src, Length, LPWSTR(@WideCharStr[0]), 1024);
  341. WideCharToMultiByte(ToCP, 0, LPWSTR(@WideCharStr[0]), wideBytes, Dest, Length, nil, nil);
  342. end;
  343. end;
  344. procedure FindNextName(BaseName: string; var OutName: string; var Modifier: Integer);
  345. var
  346. Extension: string;
  347. begin
  348. Extension := ExtractFileExt(BaseName);
  349. BaseName := Copy(BaseName, 1, Length(BaseName)-Length(Extension));
  350. repeat
  351. Inc(Modifier);
  352. OutName := ChangeFileExt(BaseName+'_'+IntToStr(Modifier), Extension);
  353. until not FileExists(OutName);
  354. end;
  355. {$ifdef FPC}
  356. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  357. var
  358. I: Integer;
  359. begin
  360. I := System.IndexByte(Buffer, Length, Chr);
  361. if I = -1 then
  362. Result := nil
  363. else
  364. Result := Buffer+I;
  365. end;
  366. {$else}
  367. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  368. asm
  369. PUSH EDI
  370. MOV EDI,Buffer
  371. MOV AL, Chr
  372. MOV ECX,Length
  373. REPNE SCASB
  374. MOV EAX,0
  375. JNE @@1
  376. MOV EAX,EDI
  377. DEC EAX
  378. @@1: POP EDI
  379. end;
  380. {$endif}
  381. {$ifdef DELPHI_3}
  382. {$ifndef DELPHI_4}
  383. function Min(x, y: integer): integer;
  384. begin
  385. if x < y then
  386. result := x
  387. else
  388. result := y;
  389. end;
  390. {$endif}
  391. {$endif}
  392. end.