dbf_common.pas 11 KB

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