dbf_common.pas 9.7 KB

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