dbf_common.pas 10 KB

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