dbf_common.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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 = 41;
  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. implementation
  87. {$ifdef WIN32}
  88. uses
  89. Windows;
  90. {$endif}
  91. //====================================================================
  92. function GetCompletePath(const Base, Path: string): string;
  93. begin
  94. if IsFullFilePath(Path)
  95. then begin
  96. Result := Path;
  97. end else begin
  98. if Length(Base) > 0 then
  99. Result := ExpandFileName(IncludeTrailingPathDelimiter(Base) + Path)
  100. else
  101. Result := ExpandFileName(Path);
  102. end;
  103. // add last backslash if not present
  104. if Length(Result) > 0 then
  105. Result := IncludeTrailingPathDelimiter(Result);
  106. end;
  107. function IsFullFilePath(const Path: string): Boolean; // full means not relative
  108. begin
  109. {$ifdef WIN32}
  110. Result := Length(Path) > 1;
  111. if Result then
  112. // check for 'x:' or '\\' at start of path
  113. Result := ((Path[2]=':') and (upcase(Path[1]) in ['A'..'Z']))
  114. or ((Path[1]='\') and (Path[2]='\'));
  115. {$else} // Linux
  116. Result := Length(Path) > 0;
  117. if Result then
  118. Result := Path[1]='/';
  119. {$endif}
  120. end;
  121. //====================================================================
  122. function GetCompleteFileName(const Base, FileName: string): string;
  123. var
  124. lpath: string;
  125. lfile: string;
  126. begin
  127. lpath := GetCompletePath(Base, ExtractFilePath(FileName));
  128. lfile := ExtractFileName(FileName);
  129. lpath := lpath + lfile;
  130. result := lpath;
  131. end;
  132. // it seems there is no pascal function to convert an integer into a PChar???
  133. procedure GetStrFromInt_Width(Val: Integer; const Width: Integer; const Dst: PChar; const PadChar: Char);
  134. var
  135. Temp: array[0..10] of Char;
  136. I, J, K: Integer;
  137. NegSign: boolean;
  138. begin
  139. if Width <= 0 then
  140. exit;
  141. NegSign := Val < 0;
  142. Val := Abs(Val);
  143. // we'll have to store characters backwards first
  144. I := 0;
  145. J := 0;
  146. repeat
  147. Temp[I] := Chr((Val mod 10) + Ord('0'));
  148. Val := Val div 10;
  149. Inc(I);
  150. until Val = 0;
  151. // add sign
  152. if NegSign then
  153. begin
  154. Dst[J] := '-';
  155. Inc(J);
  156. end;
  157. // add spaces
  158. for K := 0 to Width - I - J - 1 do
  159. begin
  160. Dst[J] := PadChar;
  161. Inc(J);
  162. end;
  163. // if field too long, cut off
  164. if J + I > Width then
  165. I := Width - J;
  166. // copy value, remember: stored backwards
  167. repeat
  168. Dst[J] := Temp[I-1];
  169. Inc(J);
  170. Dec(I);
  171. until I = 0;
  172. // done!
  173. end;
  174. {$ifdef SUPPORT_INT64}
  175. procedure GetStrFromInt64_Width(Val: Int64; const Width: Integer; const Dst: PChar; const PadChar: Char);
  176. var
  177. Temp: array[0..19] of Char;
  178. I, J, K: Integer;
  179. NegSign: boolean;
  180. begin
  181. if Width <= 0 then
  182. exit;
  183. NegSign := Val < 0;
  184. Val := Abs(Val);
  185. // we'll have to store characters backwards first
  186. I := 0;
  187. J := 0;
  188. repeat
  189. Temp[I] := Chr((Val mod 10) + Ord('0'));
  190. Val := Val div 10;
  191. inc(I);
  192. until Val = 0;
  193. // add sign
  194. if NegSign then
  195. begin
  196. Dst[J] := '-';
  197. inc(J);
  198. end;
  199. // add spaces
  200. for K := 0 to Width - I - J - 1 do
  201. begin
  202. Dst[J] := PadChar;
  203. inc(J);
  204. end;
  205. // if field too long, cut off
  206. if J + I > Width then
  207. I := Width - J;
  208. // copy value, remember: stored backwards
  209. repeat
  210. Dst[J] := Temp[I-1];
  211. inc(J);
  212. dec(I);
  213. until I = 0;
  214. // done!
  215. end;
  216. {$endif}
  217. // it seems there is no pascal function to convert an integer into a PChar???
  218. // NOTE: in dbf_dbffile.pas there is also a convert routine, but is slightly different
  219. function GetStrFromInt(Val: Integer; const Dst: PChar): Integer;
  220. var
  221. Temp: array[0..10] of Char;
  222. I, J: Integer;
  223. begin
  224. Val := Abs(Val);
  225. // we'll have to store characters backwards first
  226. I := 0;
  227. J := 0;
  228. repeat
  229. Temp[I] := Chr((Val mod 10) + Ord('0'));
  230. Val := Val div 10;
  231. Inc(I);
  232. until Val = 0;
  233. // remember number of digits
  234. Result := I;
  235. // copy value, remember: stored backwards
  236. repeat
  237. Dst[J] := Temp[I-1];
  238. Inc(J);
  239. Dec(I);
  240. until I = 0;
  241. // done!
  242. end;
  243. {$ifdef SUPPORT_INT64}
  244. function GetStrFromInt64(Val: Int64; const Dst: PChar): Integer;
  245. var
  246. Temp: array[0..19] of Char;
  247. I, J: Integer;
  248. begin
  249. Val := Abs(Val);
  250. // we'll have to store characters backwards first
  251. I := 0;
  252. J := 0;
  253. repeat
  254. Temp[I] := Chr((Val mod 10) + Ord('0'));
  255. Val := Val div 10;
  256. Inc(I);
  257. until Val = 0;
  258. // remember number of digits
  259. Result := I;
  260. // copy value, remember: stored backwards
  261. repeat
  262. Dst[J] := Temp[I-1];
  263. inc(J);
  264. dec(I);
  265. until I = 0;
  266. // done!
  267. end;
  268. {$endif}
  269. function DateTimeToBDETimeStamp(aDT: TDateTime): double;
  270. var
  271. aTS: TTimeStamp;
  272. begin
  273. aTS := DateTimeToTimeStamp(aDT);
  274. Result := TimeStampToMSecs(aTS);
  275. end;
  276. function BDETimeStampToDateTime(aBT: double): TDateTime;
  277. var
  278. aTS: TTimeStamp;
  279. begin
  280. aTS := MSecsToTimeStamp(aBT);
  281. Result := TimeStampToDateTime(aTS);
  282. end;
  283. //====================================================================
  284. {$ifndef SUPPORT_FREEANDNIL}
  285. procedure FreeAndNil(var v);
  286. var
  287. Temp: TObject;
  288. begin
  289. Temp := TObject(v);
  290. TObject(v) := nil;
  291. Temp.Free;
  292. end;
  293. {$endif}
  294. procedure FreeMemAndNil(var P: Pointer);
  295. var
  296. Temp: Pointer;
  297. begin
  298. Temp := P;
  299. P := nil;
  300. FreeMem(Temp);
  301. end;
  302. //====================================================================
  303. {$ifndef SUPPORT_INCLTRAILPATHDELIM}
  304. {$ifndef SUPPORT_INCLTRAILBACKSLASH}
  305. function IncludeTrailingPathDelimiter(const Path: string): string;
  306. var
  307. len: Integer;
  308. begin
  309. Result := Path;
  310. len := Length(Result);
  311. if len = 0 then
  312. Result := PathDelim
  313. else
  314. if Result[len] <> PathDelim then
  315. Result := Result + PathDelim;
  316. end;
  317. {$else}
  318. function IncludeTrailingPathDelimiter(const Path: string): string;
  319. begin
  320. {$ifdef WIN32}
  321. Result := IncludeTrailingBackslash(Path);
  322. {$else}
  323. Result := IncludeTrailingSlash(Path);
  324. {$endif}
  325. end;
  326. {$endif}
  327. {$endif}
  328. {$ifdef USE_CACHE}
  329. function GetFreeMemory: Integer;
  330. var
  331. MemStatus: TMemoryStatus;
  332. begin
  333. GlobalMemoryStatus(MemStatus);
  334. Result := MemStatus.dwAvailPhys;
  335. end;
  336. {$endif}
  337. //====================================================================
  338. // Utility routines
  339. //====================================================================
  340. {$ifdef USE_ASSEMBLER_486_UP}
  341. function SwapInt(const Value: Cardinal): Cardinal; register;
  342. asm
  343. BSWAP EAX;
  344. end;
  345. procedure SwapInt64(Value {EAX}, Result {EDX}: Pointer); register;
  346. asm
  347. MOV ECX, dword ptr [EAX]
  348. MOV EAX, dword ptr [EAX + 4]
  349. BSWAP ECX
  350. BSWAP EAX
  351. MOV dword ptr [EDX+4], ECX
  352. MOV dword ptr [EDX], EAX
  353. end;
  354. {$else}
  355. function SwapInt(const Value: Cardinal): Cardinal;
  356. begin
  357. PByteArray(@Result)[0] := PByteArray(@Value)[3];
  358. PByteArray(@Result)[1] := PByteArray(@Value)[2];
  359. PByteArray(@Result)[2] := PByteArray(@Value)[1];
  360. PByteArray(@Result)[3] := PByteArray(@Value)[0];
  361. end;
  362. procedure SwapInt64(Value, Result: Pointer); register;
  363. var
  364. PtrResult: PByteArray;
  365. PtrSource: PByteArray;
  366. begin
  367. // temporary storage is actually not needed, but otherwise compiler crashes (?)
  368. PtrResult := PByteArray(Result);
  369. PtrSource := PByteArray(Value);
  370. PtrResult[0] := PtrSource[7];
  371. PtrResult[1] := PtrSource[6];
  372. PtrResult[2] := PtrSource[5];
  373. PtrResult[3] := PtrSource[4];
  374. PtrResult[4] := PtrSource[3];
  375. PtrResult[5] := PtrSource[2];
  376. PtrResult[6] := PtrSource[1];
  377. PtrResult[7] := PtrSource[0];
  378. end;
  379. {$endif}
  380. function TranslateString(FromCP, ToCP: Cardinal; Src, Dest: PChar; Length: Integer): Integer;
  381. var
  382. WideCharStr: array[0..1023] of WideChar;
  383. wideBytes: Cardinal;
  384. begin
  385. if Length = -1 then
  386. Length := StrLen(Src);
  387. Result := Length;
  388. if (FromCP = GetOEMCP) and (ToCP = GetACP) then
  389. OemToCharBuff(Src, Dest, Length)
  390. else
  391. if (FromCP = GetACP) and (ToCP = GetOEMCP) then
  392. CharToOemBuff(Src, Dest, Length)
  393. else
  394. if FromCP = ToCP then
  395. begin
  396. if Src <> Dest then
  397. Move(Src^, Dest^, Length);
  398. end else begin
  399. // does this work on Win95/98/ME?
  400. wideBytes := MultiByteToWideChar(FromCP, MB_PRECOMPOSED, Src, Length, LPWSTR(@WideCharStr[0]), 1024);
  401. WideCharToMultiByte(ToCP, 0, LPWSTR(@WideCharStr[0]), wideBytes, Dest, Length, nil, nil);
  402. end;
  403. end;
  404. procedure FindNextName(BaseName: string; var OutName: string; var Modifier: Integer);
  405. var
  406. Extension: string;
  407. begin
  408. Extension := ExtractFileExt(BaseName);
  409. BaseName := Copy(BaseName, 1, Length(BaseName)-Length(Extension));
  410. repeat
  411. Inc(Modifier);
  412. OutName := ChangeFileExt(BaseName+'_'+IntToStr(Modifier), Extension);
  413. until not FileExists(OutName);
  414. end;
  415. {$ifdef FPC}
  416. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  417. var
  418. I: Integer;
  419. begin
  420. I := System.IndexByte(Buffer, Length, Chr);
  421. if I = -1 then
  422. Result := nil
  423. else
  424. Result := Buffer+I;
  425. end;
  426. {$else}
  427. function MemScan(const Buffer: Pointer; Chr: Byte; Length: Integer): Pointer;
  428. asm
  429. PUSH EDI
  430. MOV EDI,Buffer
  431. MOV AL, Chr
  432. MOV ECX,Length
  433. REPNE SCASB
  434. MOV EAX,0
  435. JNE @@1
  436. MOV EAX,EDI
  437. DEC EAX
  438. @@1: POP EDI
  439. end;
  440. {$endif}
  441. end.