/superobject.pas

http://delphi-wordfeud.googlecode.com/ · Pascal · 2085 lines · 1716 code · 148 blank · 221 comment · 99 complexity · 4a5dc44975f120aba2b5c880b5b74807 MD5 · raw file

Large files are truncated click here to view the full file

  1. (*
  2. * Super Object Toolkit
  3. *
  4. * Usage allowed under the restrictions of the Lesser GNU General Public License
  5. * or alternatively the restrictions of the Mozilla Public License 1.1
  6. *
  7. * Software distributed under the License is distributed on an "AS IS" basis,
  8. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
  9. * the specific language governing rights and limitations under the License.
  10. *
  11. * Embarcadero Technologies Inc is not permitted to use or redistribute
  12. * this source code without explicit permission.
  13. *
  14. * Unit owner : Henri Gourvest <hgourvest@gmail.com>
  15. * Web site : http://www.progdigy.com
  16. *
  17. * This unit is inspired from the json c lib:
  18. * Michael Clark <michael@metaparadigm.com>
  19. * http://oss.metaparadigm.com/json-c/
  20. *
  21. * CHANGES:
  22. * v1.2.1 (Wouter van Nifterick)
  23. * - Removed console logging
  24. * + Skip nested records during RTTI marshalling (instead of failing the entire operation)
  25. * v1.2
  26. * + support of currency data type
  27. * + right trim unquoted string
  28. * + read Unicode Files and streams (Litle Endian with BOM)
  29. * + Fix bug on javadate functions + windows nt compatibility
  30. * + Now you can force to parse only the canonical syntax of JSON using the stric parameter
  31. * + Delphi 2010 RTTI marshalling
  32. * v1.1
  33. * + Double licence MPL or LGPL.
  34. * + Delphi 2009 compatibility & Unicode support.
  35. * + AsString return a string instead of PChar.
  36. * + Escaped and Unascaped JSON serialiser.
  37. * + Missed FormFeed added \f
  38. * - Removed @ trick, uses forcepath() method instead.
  39. * + Fixed parse error with uppercase E symbol in numbers.
  40. * + Fixed possible buffer overflow when enlarging array.
  41. * + Added "delete", "pack", "insert" methods for arrays and/or objects
  42. * + Multi parametters when calling methods
  43. * + Delphi Enumerator (for obj1 in obj2 do ...)
  44. * + Format method ex: obj.format('<%name%>%tab[1]%</%name%>')
  45. * + ParseFile and ParseStream methods
  46. * + Parser now understand hexdecimal c syntax ex: \xFF
  47. * + Null Object Design Patern (ex: for obj in values.N['path'] do ...)
  48. * v1.0
  49. * + renamed class
  50. * + interfaced object
  51. * + added a new data type: the method
  52. * + parser can now evaluate properties and call methods
  53. * - removed obselet rpc class
  54. * - removed "find" method, now you can use "parse" method instead
  55. * v0.6
  56. * + refactoring
  57. * v0.5
  58. * + new find method to get or set value using a path syntax
  59. * ex: obj.s['obj.prop[1]'] := 'string value';
  60. * obj.a['@obj.array'].b[n] := true; // @ -> create property if necessary
  61. * v0.4
  62. * + bug corrected: AVL tree badly balanced.
  63. * v0.3
  64. * + New validator partially based on the Kwalify syntax.
  65. * + extended syntax to parse unquoted fields.
  66. * + Freepascal compatibility win32/64 Linux32/64.
  67. * + JavaToDelphiDateTime and DelphiToJavaDateTime improved for UTC.
  68. * + new TJsonObject.Compare function.
  69. * v0.2
  70. * + Hashed string list replaced with a faster AVL tree
  71. * + JsonInt data type can be changed to int64
  72. * + JavaToDelphiDateTime and DelphiToJavaDateTime helper fonctions
  73. * + from json-c v0.7
  74. * + Add escaping of backslash to json output
  75. * + Add escaping of foward slash on tokenizing and output
  76. * + Changes to internal tokenizer from using recursion to
  77. * using a depth state structure to allow incremental parsing
  78. * v0.1
  79. * + first release
  80. *)
  81. {$IFDEF FPC}
  82. {$MODE OBJFPC}{$H+}
  83. {$ENDIF}
  84. {$DEFINE SUPER_METHOD}
  85. {$DEFINE WINDOWSNT_COMPATIBILITY}
  86. {.$DEFINE DEBUG} // track memory leack
  87. {$if defined(FPC) or defined(VER170) or defined(VER180) or defined(VER190) or defined(VER200) or defined(VER210)}
  88. {$DEFINE HAVE_INLINE}
  89. {$ifend}
  90. {$if defined(VER210) or defined(VER220) or defined(VER230)}
  91. {$define HAVE_RTTI}
  92. {$ifend}
  93. {$if defined(VER230)}
  94. {$define NEED_FORMATSETTINGS}
  95. {$ifend}
  96. {$if defined(FPC) and defined(VER2_6)}
  97. {$define NEED_FORMATSETTINGS}
  98. {$ifend}
  99. {$OVERFLOWCHECKS OFF}
  100. {$RANGECHECKS OFF}
  101. unit superobject;
  102. interface
  103. uses
  104. Classes
  105. {$IFDEF HAVE_RTTI}
  106. ,Generics.Collections, RTTI, TypInfo
  107. {$ENDIF}
  108. ;
  109. type
  110. {$IFNDEF FPC}
  111. {$IFDEF CPUX64}
  112. PtrInt = Int64;
  113. PtrUInt = UInt64;
  114. {$ELSE}
  115. PtrInt = longint;
  116. PtrUInt = Longword;
  117. {$ENDIF}
  118. {$ENDIF}
  119. SuperInt = Int64;
  120. {$if (sizeof(Char) = 1)}
  121. SOChar = WideChar;
  122. SOIChar = Word;
  123. PSOChar = PWideChar;
  124. {$IFDEF FPC}
  125. SOString = UnicodeString;
  126. {$ELSE}
  127. SOString = WideString;
  128. {$ENDIF}
  129. {$else}
  130. SOChar = Char;
  131. SOIChar = Word;
  132. PSOChar = PChar;
  133. SOString = string;
  134. {$ifend}
  135. const
  136. SUPER_ARRAY_LIST_DEFAULT_SIZE = 32;
  137. SUPER_TOKENER_MAX_DEPTH = 32;
  138. SUPER_AVL_MAX_DEPTH = sizeof(longint) * 8;
  139. SUPER_AVL_MASK_HIGH_BIT = not ((not longword(0)) shr 1);
  140. type
  141. // forward declarations
  142. TSuperObject = class;
  143. ISuperObject = interface;
  144. TSuperArray = class;
  145. (* AVL Tree
  146. * This is a "special" autobalanced AVL tree
  147. * It use a hash value for fast compare
  148. *)
  149. {$IFDEF SUPER_METHOD}
  150. TSuperMethod = procedure(const This, Params: ISuperObject; var Result: ISuperObject);
  151. {$ENDIF}
  152. TSuperAvlBitArray = set of 0..SUPER_AVL_MAX_DEPTH - 1;
  153. TSuperAvlSearchType = (stEQual, stLess, stGreater);
  154. TSuperAvlSearchTypes = set of TSuperAvlSearchType;
  155. TSuperAvlIterator = class;
  156. TSuperAvlEntry = class
  157. private
  158. FGt, FLt: TSuperAvlEntry;
  159. FBf: integer;
  160. FHash: Cardinal;
  161. FName: SOString;
  162. FPtr: Pointer;
  163. function GetValue: ISuperObject;
  164. procedure SetValue(const val: ISuperObject);
  165. public
  166. class function Hash(const k: SOString): Cardinal; virtual;
  167. constructor Create(const AName: SOString; Obj: Pointer); virtual;
  168. property Name: SOString read FName;
  169. property Ptr: Pointer read FPtr;
  170. property Value: ISuperObject read GetValue write SetValue;
  171. end;
  172. TSuperAvlTree = class
  173. private
  174. FRoot: TSuperAvlEntry;
  175. FCount: Integer;
  176. function balance(bal: TSuperAvlEntry): TSuperAvlEntry;
  177. protected
  178. procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); virtual;
  179. function CompareNodeNode(node1, node2: TSuperAvlEntry): integer; virtual;
  180. function CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; virtual;
  181. function Insert(h: TSuperAvlEntry): TSuperAvlEntry; virtual;
  182. function Search(const k: SOString; st: TSuperAvlSearchTypes = [stEqual]): TSuperAvlEntry; virtual;
  183. public
  184. constructor Create; virtual;
  185. destructor Destroy; override;
  186. function IsEmpty: boolean;
  187. procedure Clear(all: boolean = false); virtual;
  188. procedure Pack(all: boolean);
  189. function Delete(const k: SOString): ISuperObject;
  190. function GetEnumerator: TSuperAvlIterator;
  191. property count: Integer read FCount;
  192. end;
  193. TSuperTableString = class(TSuperAvlTree)
  194. protected
  195. procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); override;
  196. procedure PutO(const k: SOString; const value: ISuperObject);
  197. function GetO(const k: SOString): ISuperObject;
  198. procedure PutS(const k: SOString; const value: SOString);
  199. function GetS(const k: SOString): SOString;
  200. procedure PutI(const k: SOString; value: SuperInt);
  201. function GetI(const k: SOString): SuperInt;
  202. procedure PutD(const k: SOString; value: Double);
  203. function GetD(const k: SOString): Double;
  204. procedure PutB(const k: SOString; value: Boolean);
  205. function GetB(const k: SOString): Boolean;
  206. {$IFDEF SUPER_METHOD}
  207. procedure PutM(const k: SOString; value: TSuperMethod);
  208. function GetM(const k: SOString): TSuperMethod;
  209. {$ENDIF}
  210. procedure PutN(const k: SOString; const value: ISuperObject);
  211. function GetN(const k: SOString): ISuperObject;
  212. procedure PutC(const k: SOString; value: Currency);
  213. function GetC(const k: SOString): Currency;
  214. public
  215. property O[const k: SOString]: ISuperObject read GetO write PutO; default;
  216. property S[const k: SOString]: SOString read GetS write PutS;
  217. property I[const k: SOString]: SuperInt read GetI write PutI;
  218. property D[const k: SOString]: Double read GetD write PutD;
  219. property B[const k: SOString]: Boolean read GetB write PutB;
  220. {$IFDEF SUPER_METHOD}
  221. property M[const k: SOString]: TSuperMethod read GetM write PutM;
  222. {$ENDIF}
  223. property N[const k: SOString]: ISuperObject read GetN write PutN;
  224. property C[const k: SOString]: Currency read GetC write PutC;
  225. function GetValues: ISuperObject;
  226. function GetNames: ISuperObject;
  227. function Find(const k: SOString; var value: ISuperObject): Boolean;
  228. end;
  229. TSuperAvlIterator = class
  230. private
  231. FTree: TSuperAvlTree;
  232. FBranch: TSuperAvlBitArray;
  233. FDepth: LongInt;
  234. FPath: array[0..SUPER_AVL_MAX_DEPTH - 2] of TSuperAvlEntry;
  235. public
  236. constructor Create(tree: TSuperAvlTree); virtual;
  237. procedure Search(const k: SOString; st: TSuperAvlSearchTypes = [stEQual]);
  238. procedure First;
  239. procedure Last;
  240. function GetIter: TSuperAvlEntry;
  241. procedure Next;
  242. procedure Prior;
  243. // delphi enumerator
  244. function MoveNext: Boolean;
  245. property Current: TSuperAvlEntry read GetIter;
  246. end;
  247. TSuperObjectArray = array[0..(high(Integer) div sizeof(TSuperObject))-1] of ISuperObject;
  248. PSuperObjectArray = ^TSuperObjectArray;
  249. TSuperArray = class
  250. private
  251. FArray: PSuperObjectArray;
  252. FLength: Integer;
  253. FSize: Integer;
  254. procedure Expand(max: Integer);
  255. protected
  256. function GetO(const index: integer): ISuperObject;
  257. procedure PutO(const index: integer; const Value: ISuperObject);
  258. function GetB(const index: integer): Boolean;
  259. procedure PutB(const index: integer; Value: Boolean);
  260. function GetI(const index: integer): SuperInt;
  261. procedure PutI(const index: integer; Value: SuperInt);
  262. function GetD(const index: integer): Double;
  263. procedure PutD(const index: integer; Value: Double);
  264. function GetC(const index: integer): Currency;
  265. procedure PutC(const index: integer; Value: Currency);
  266. function GetS(const index: integer): SOString;
  267. procedure PutS(const index: integer; const Value: SOString);
  268. {$IFDEF SUPER_METHOD}
  269. function GetM(const index: integer): TSuperMethod;
  270. procedure PutM(const index: integer; Value: TSuperMethod);
  271. {$ENDIF}
  272. function GetN(const index: integer): ISuperObject;
  273. procedure PutN(const index: integer; const Value: ISuperObject);
  274. public
  275. constructor Create; virtual;
  276. destructor Destroy; override;
  277. function Add(const Data: ISuperObject): Integer;
  278. function Delete(index: Integer): ISuperObject;
  279. procedure Insert(index: Integer; const value: ISuperObject);
  280. procedure Clear(all: boolean = false);
  281. procedure Pack(all: boolean);
  282. property Length: Integer read FLength;
  283. property N[const index: integer]: ISuperObject read GetN write PutN;
  284. property O[const index: integer]: ISuperObject read GetO write PutO; default;
  285. property B[const index: integer]: boolean read GetB write PutB;
  286. property I[const index: integer]: SuperInt read GetI write PutI;
  287. property D[const index: integer]: Double read GetD write PutD;
  288. property C[const index: integer]: Currency read GetC write PutC;
  289. property S[const index: integer]: SOString read GetS write PutS;
  290. {$IFDEF SUPER_METHOD}
  291. property M[const index: integer]: TSuperMethod read GetM write PutM;
  292. {$ENDIF}
  293. end;
  294. TSuperWriter = class
  295. public
  296. // abstact methods to overide
  297. function Append(buf: PSOChar; Size: Integer): Integer; overload; virtual; abstract;
  298. function Append(buf: PSOChar): Integer; overload; virtual; abstract;
  299. procedure Reset; virtual; abstract;
  300. end;
  301. TSuperWriterString = class(TSuperWriter)
  302. private
  303. FBuf: PSOChar;
  304. FBPos: integer;
  305. FSize: integer;
  306. public
  307. function Append(buf: PSOChar; Size: Integer): Integer; overload; override;
  308. function Append(buf: PSOChar): Integer; overload; override;
  309. procedure Reset; override;
  310. procedure TrimRight;
  311. constructor Create; virtual;
  312. destructor Destroy; override;
  313. function GetString: SOString;
  314. property Data: PSOChar read FBuf;
  315. property Size: Integer read FSize;
  316. property Position: integer read FBPos;
  317. end;
  318. TSuperWriterStream = class(TSuperWriter)
  319. private
  320. FStream: TStream;
  321. public
  322. function Append(buf: PSOChar): Integer; override;
  323. procedure Reset; override;
  324. constructor Create(AStream: TStream); reintroduce; virtual;
  325. end;
  326. TSuperAnsiWriterStream = class(TSuperWriterStream)
  327. public
  328. function Append(buf: PSOChar; Size: Integer): Integer; override;
  329. end;
  330. TSuperUnicodeWriterStream = class(TSuperWriterStream)
  331. public
  332. function Append(buf: PSOChar; Size: Integer): Integer; override;
  333. end;
  334. TSuperWriterFake = class(TSuperWriter)
  335. private
  336. FSize: Integer;
  337. public
  338. function Append(buf: PSOChar; Size: Integer): Integer; override;
  339. function Append(buf: PSOChar): Integer; override;
  340. procedure Reset; override;
  341. constructor Create; reintroduce; virtual;
  342. property size: integer read FSize;
  343. end;
  344. TSuperWriterSock = class(TSuperWriter)
  345. private
  346. FSocket: longint;
  347. FSize: Integer;
  348. public
  349. function Append(buf: PSOChar; Size: Integer): Integer; override;
  350. function Append(buf: PSOChar): Integer; override;
  351. procedure Reset; override;
  352. constructor Create(ASocket: longint); reintroduce; virtual;
  353. property Socket: longint read FSocket;
  354. property Size: Integer read FSize;
  355. end;
  356. TSuperTokenizerError = (
  357. teSuccess,
  358. teContinue,
  359. teDepth,
  360. teParseEof,
  361. teParseUnexpected,
  362. teParseNull,
  363. teParseBoolean,
  364. teParseNumber,
  365. teParseArray,
  366. teParseObjectKeyName,
  367. teParseObjectKeySep,
  368. teParseObjectValueSep,
  369. teParseString,
  370. teParseComment,
  371. teEvalObject,
  372. teEvalArray,
  373. teEvalMethod,
  374. teEvalInt
  375. );
  376. TSuperTokenerState = (
  377. tsEatws,
  378. tsStart,
  379. tsFinish,
  380. tsNull,
  381. tsCommentStart,
  382. tsComment,
  383. tsCommentEol,
  384. tsCommentEnd,
  385. tsString,
  386. tsStringEscape,
  387. tsIdentifier,
  388. tsEscapeUnicode,
  389. tsEscapeHexadecimal,
  390. tsBoolean,
  391. tsNumber,
  392. tsArray,
  393. tsArrayAdd,
  394. tsArraySep,
  395. tsObjectFieldStart,
  396. tsObjectField,
  397. tsObjectUnquotedField,
  398. tsObjectFieldEnd,
  399. tsObjectValue,
  400. tsObjectValueAdd,
  401. tsObjectSep,
  402. tsEvalProperty,
  403. tsEvalArray,
  404. tsEvalMethod,
  405. tsParamValue,
  406. tsParamPut,
  407. tsMethodValue,
  408. tsMethodPut
  409. );
  410. PSuperTokenerSrec = ^TSuperTokenerSrec;
  411. TSuperTokenerSrec = record
  412. state, saved_state: TSuperTokenerState;
  413. obj: ISuperObject;
  414. current: ISuperObject;
  415. field_name: SOString;
  416. parent: ISuperObject;
  417. gparent: ISuperObject;
  418. end;
  419. TSuperTokenizer = class
  420. public
  421. str: PSOChar;
  422. pb: TSuperWriterString;
  423. depth, is_double, floatcount, st_pos, char_offset: Integer;
  424. err: TSuperTokenizerError;
  425. ucs_char: Word;
  426. quote_char: SOChar;
  427. stack: array[0..SUPER_TOKENER_MAX_DEPTH-1] of TSuperTokenerSrec;
  428. line, col: Integer;
  429. public
  430. constructor Create; virtual;
  431. destructor Destroy; override;
  432. procedure ResetLevel(adepth: integer);
  433. procedure Reset;
  434. end;
  435. // supported object types
  436. TSuperType = (
  437. stNull,
  438. stBoolean,
  439. stDouble,
  440. stCurrency,
  441. stInt,
  442. stObject,
  443. stArray,
  444. stString
  445. {$IFDEF SUPER_METHOD}
  446. ,stMethod
  447. {$ENDIF}
  448. );
  449. TSuperValidateError = (
  450. veRuleMalformated,
  451. veFieldIsRequired,
  452. veInvalidDataType,
  453. veFieldNotFound,
  454. veUnexpectedField,
  455. veDuplicateEntry,
  456. veValueNotInEnum,
  457. veInvalidLength,
  458. veInvalidRange
  459. );
  460. TSuperFindOption = (
  461. foCreatePath,
  462. foPutValue,
  463. foDelete
  464. {$IFDEF SUPER_METHOD}
  465. ,foCallMethod
  466. {$ENDIF}
  467. );
  468. TSuperFindOptions = set of TSuperFindOption;
  469. TSuperCompareResult = (cpLess, cpEqu, cpGreat, cpError);
  470. TSuperOnValidateError = procedure(sender: Pointer; error: TSuperValidateError; const objpath: SOString);
  471. TSuperEnumerator = class
  472. private
  473. FObj: ISuperObject;
  474. FObjEnum: TSuperAvlIterator;
  475. FCount: Integer;
  476. public
  477. constructor Create(const obj: ISuperObject); virtual;
  478. destructor Destroy; override;
  479. function MoveNext: Boolean;
  480. function GetCurrent: ISuperObject;
  481. property Current: ISuperObject read GetCurrent;
  482. end;
  483. ISuperObject = interface
  484. ['{4B86A9E3-E094-4E5A-954A-69048B7B6327}']
  485. function GetEnumerator: TSuperEnumerator;
  486. function GetDataType: TSuperType;
  487. function GetProcessing: boolean;
  488. procedure SetProcessing(value: boolean);
  489. function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject;
  490. function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString;
  491. function GetO(const path: SOString): ISuperObject;
  492. procedure PutO(const path: SOString; const Value: ISuperObject);
  493. function GetB(const path: SOString): Boolean;
  494. procedure PutB(const path: SOString; Value: Boolean);
  495. function GetI(const path: SOString): SuperInt;
  496. procedure PutI(const path: SOString; Value: SuperInt);
  497. function GetD(const path: SOString): Double;
  498. procedure PutC(const path: SOString; Value: Currency);
  499. function GetC(const path: SOString): Currency;
  500. procedure PutD(const path: SOString; Value: Double);
  501. function GetS(const path: SOString): SOString;
  502. procedure PutS(const path: SOString; const Value: SOString);
  503. {$IFDEF SUPER_METHOD}
  504. function GetM(const path: SOString): TSuperMethod;
  505. procedure PutM(const path: SOString; Value: TSuperMethod);
  506. {$ENDIF}
  507. function GetA(const path: SOString): TSuperArray;
  508. // Null Object Design patern
  509. function GetN(const path: SOString): ISuperObject;
  510. procedure PutN(const path: SOString; const Value: ISuperObject);
  511. // Writers
  512. function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer;
  513. function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload;
  514. function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload;
  515. function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload;
  516. function CalcSize(indent: boolean = false; escape: boolean = true): integer;
  517. // convert
  518. function AsBoolean: Boolean;
  519. function AsInteger: SuperInt;
  520. function AsDouble: Double;
  521. function AsCurrency: Currency;
  522. function AsString: SOString;
  523. function AsArray: TSuperArray;
  524. function AsObject: TSuperTableString;
  525. {$IFDEF SUPER_METHOD}
  526. function AsMethod: TSuperMethod;
  527. {$ENDIF}
  528. function AsJSon(indent: boolean = false; escape: boolean = true): SOString;
  529. procedure Clear(all: boolean = false);
  530. procedure Pack(all: boolean = false);
  531. property N[const path: SOString]: ISuperObject read GetN write PutN;
  532. property O[const path: SOString]: ISuperObject read GetO write PutO; default;
  533. property B[const path: SOString]: boolean read GetB write PutB;
  534. property I[const path: SOString]: SuperInt read GetI write PutI;
  535. property D[const path: SOString]: Double read GetD write PutD;
  536. property C[const path: SOString]: Currency read GetC write PutC;
  537. property S[const path: SOString]: SOString read GetS write PutS;
  538. {$IFDEF SUPER_METHOD}
  539. property M[const path: SOString]: TSuperMethod read GetM write PutM;
  540. {$ENDIF}
  541. property A[const path: SOString]: TSuperArray read GetA;
  542. {$IFDEF SUPER_METHOD}
  543. function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload;
  544. function call(const path, param: SOString): ISuperObject; overload;
  545. {$ENDIF}
  546. // clone a node
  547. function Clone: ISuperObject;
  548. function Delete(const path: SOString): ISuperObject;
  549. // merges tow objects of same type, if reference is true then nodes are not cloned
  550. procedure Merge(const obj: ISuperObject; reference: boolean = false); overload;
  551. procedure Merge(const str: SOString); overload;
  552. // validate methods
  553. function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload;
  554. function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload;
  555. // compare
  556. function Compare(const obj: ISuperObject): TSuperCompareResult; overload;
  557. function Compare(const str: SOString): TSuperCompareResult; overload;
  558. // the data type
  559. function IsType(AType: TSuperType): boolean;
  560. property DataType: TSuperType read GetDataType;
  561. property Processing: boolean read GetProcessing write SetProcessing;
  562. function GetDataPtr: Pointer;
  563. procedure SetDataPtr(const Value: Pointer);
  564. property DataPtr: Pointer read GetDataPtr write SetDataPtr;
  565. end;
  566. TSuperObject = class(TObject, ISuperObject)
  567. private
  568. FRefCount: Integer;
  569. FProcessing: boolean;
  570. FDataType: TSuperType;
  571. FDataPtr: Pointer;
  572. {.$if true}
  573. FO: record
  574. case TSuperType of
  575. stBoolean: (c_boolean: boolean);
  576. stDouble: (c_double: double);
  577. stCurrency: (c_currency: Currency);
  578. stInt: (c_int: SuperInt);
  579. stObject: (c_object: TSuperTableString);
  580. stArray: (c_array: TSuperArray);
  581. {$IFDEF SUPER_METHOD}
  582. stMethod: (c_method: TSuperMethod);
  583. {$ENDIF}
  584. end;
  585. {.$ifend}
  586. FOString: SOString;
  587. function GetDataType: TSuperType;
  588. function GetDataPtr: Pointer;
  589. procedure SetDataPtr(const Value: Pointer);
  590. protected
  591. {$IFDEF FPC}
  592. function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid: tguid; out obj): longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
  593. {$ELSE}
  594. function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
  595. {$ENDIF}
  596. function _AddRef: Integer; virtual; stdcall;
  597. function _Release: Integer; virtual; stdcall;
  598. function GetO(const path: SOString): ISuperObject;
  599. procedure PutO(const path: SOString; const Value: ISuperObject);
  600. function GetB(const path: SOString): Boolean;
  601. procedure PutB(const path: SOString; Value: Boolean);
  602. function GetI(const path: SOString): SuperInt;
  603. procedure PutI(const path: SOString; Value: SuperInt);
  604. function GetD(const path: SOString): Double;
  605. procedure PutD(const path: SOString; Value: Double);
  606. procedure PutC(const path: SOString; Value: Currency);
  607. function GetC(const path: SOString): Currency;
  608. function GetS(const path: SOString): SOString;
  609. procedure PutS(const path: SOString; const Value: SOString);
  610. {$IFDEF SUPER_METHOD}
  611. function GetM(const path: SOString): TSuperMethod;
  612. procedure PutM(const path: SOString; Value: TSuperMethod);
  613. {$ENDIF}
  614. function GetA(const path: SOString): TSuperArray;
  615. function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; virtual;
  616. public
  617. function GetEnumerator: TSuperEnumerator;
  618. procedure AfterConstruction; override;
  619. procedure BeforeDestruction; override;
  620. class function NewInstance: TObject; override;
  621. property RefCount: Integer read FRefCount;
  622. function GetProcessing: boolean;
  623. procedure SetProcessing(value: boolean);
  624. // Writers
  625. function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload;
  626. function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload;
  627. function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload;
  628. function CalcSize(indent: boolean = false; escape: boolean = true): integer;
  629. function AsJSon(indent: boolean = false; escape: boolean = true): SOString;
  630. // parser ... owned!
  631. class function ParseString(s: PSOChar; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = [];
  632. const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject;
  633. class function ParseStream(stream: TStream; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = [];
  634. const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject;
  635. class function ParseFile(const FileName: string; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = [];
  636. const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject;
  637. class function ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; strict: Boolean; const this: ISuperObject = nil;
  638. options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject;
  639. // constructors / destructor
  640. constructor Create(jt: TSuperType = stObject); overload; virtual;
  641. constructor Create(b: boolean); overload; virtual;
  642. constructor Create(i: SuperInt); overload; virtual;
  643. constructor Create(d: double); overload; virtual;
  644. constructor CreateCurrency(c: Currency); overload; virtual;
  645. constructor Create(const s: SOString); overload; virtual;
  646. {$IFDEF SUPER_METHOD}
  647. constructor Create(m: TSuperMethod); overload; virtual;
  648. {$ENDIF}
  649. destructor Destroy; override;
  650. // convert
  651. function AsBoolean: Boolean; virtual;
  652. function AsInteger: SuperInt; virtual;
  653. function AsDouble: Double; virtual;
  654. function AsCurrency: Currency; virtual;
  655. function AsString: SOString; virtual;
  656. function AsArray: TSuperArray; virtual;
  657. function AsObject: TSuperTableString; virtual;
  658. {$IFDEF SUPER_METHOD}
  659. function AsMethod: TSuperMethod; virtual;
  660. {$ENDIF}
  661. procedure Clear(all: boolean = false); virtual;
  662. procedure Pack(all: boolean = false); virtual;
  663. function GetN(const path: SOString): ISuperObject;
  664. procedure PutN(const path: SOString; const Value: ISuperObject);
  665. function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject;
  666. function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString;
  667. property N[const path: SOString]: ISuperObject read GetN write PutN;
  668. property O[const path: SOString]: ISuperObject read GetO write PutO; default;
  669. property B[const path: SOString]: boolean read GetB write PutB;
  670. property I[const path: SOString]: SuperInt read GetI write PutI;
  671. property D[const path: SOString]: Double read GetD write PutD;
  672. property C[const path: SOString]: Currency read GetC write PutC;
  673. property S[const path: SOString]: SOString read GetS write PutS;
  674. {$IFDEF SUPER_METHOD}
  675. property M[const path: SOString]: TSuperMethod read GetM write PutM;
  676. {$ENDIF}
  677. property A[const path: SOString]: TSuperArray read GetA;
  678. {$IFDEF SUPER_METHOD}
  679. function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; virtual;
  680. function call(const path, param: SOString): ISuperObject; overload; virtual;
  681. {$ENDIF}
  682. // clone a node
  683. function Clone: ISuperObject; virtual;
  684. function Delete(const path: SOString): ISuperObject;
  685. // merges tow objects of same type, if reference is true then nodes are not cloned
  686. procedure Merge(const obj: ISuperObject; reference: boolean = false); overload;
  687. procedure Merge(const str: SOString); overload;
  688. // validate methods
  689. function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload;
  690. function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload;
  691. // compare
  692. function Compare(const obj: ISuperObject): TSuperCompareResult; overload;
  693. function Compare(const str: SOString): TSuperCompareResult; overload;
  694. // the data type
  695. function IsType(AType: TSuperType): boolean;
  696. property DataType: TSuperType read GetDataType;
  697. // a data pointer to link to something ele, a treeview for example
  698. property DataPtr: Pointer read GetDataPtr write SetDataPtr;
  699. property Processing: boolean read GetProcessing;
  700. end;
  701. {$IFDEF HAVE_RTTI}
  702. TSuperRttiContext = class;
  703. TSerialFromJson = function(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean;
  704. TSerialToJson = function(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject;
  705. TSuperAttribute = class(TCustomAttribute)
  706. private
  707. FName: string;
  708. public
  709. constructor Create(const AName: string);
  710. property Name: string read FName;
  711. end;
  712. SOName = class(TSuperAttribute);
  713. SODefault = class(TSuperAttribute);
  714. TSuperRttiContext = class
  715. private
  716. class function GetFieldName(r: TRttiField): string;
  717. class function GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject;
  718. public
  719. Context: TRttiContext;
  720. SerialFromJson: TDictionary<PTypeInfo, TSerialFromJson>;
  721. SerialToJson: TDictionary<PTypeInfo, TSerialToJson>;
  722. constructor Create; virtual;
  723. destructor Destroy; override;
  724. function FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; var Value: TValue): Boolean; virtual;
  725. function ToJson(var value: TValue; const index: ISuperObject): ISuperObject; virtual;
  726. function AsType<T>(const obj: ISuperObject): T;
  727. function AsJson<T>(const obj: T; const index: ISuperObject = nil): ISuperObject;
  728. end;
  729. TSuperObjectHelper = class helper for TObject
  730. public
  731. function ToJson(ctx: TSuperRttiContext = nil): ISuperObject;
  732. constructor FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); overload;
  733. constructor FromJson(const str: string; ctx: TSuperRttiContext = nil); overload;
  734. end;
  735. {$ENDIF}
  736. TSuperObjectIter = record
  737. key: SOString;
  738. val: ISuperObject;
  739. Ite: TSuperAvlIterator;
  740. end;
  741. function ObjectIsError(obj: TSuperObject): boolean;
  742. function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean;
  743. function ObjectGetType(const obj: ISuperObject): TSuperType;
  744. function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean;
  745. function ObjectFindNext(var F: TSuperObjectIter): boolean;
  746. procedure ObjectFindClose(var F: TSuperObjectIter);
  747. function SO(const s: SOString = '{}'): ISuperObject; overload;
  748. function SO(const value: Variant): ISuperObject; overload;
  749. function SO(const Args: array of const): ISuperObject; overload;
  750. function SA(const Args: array of const): ISuperObject; overload;
  751. function JavaToDelphiDateTime(const dt: int64): TDateTime;
  752. function DelphiToJavaDateTime(const dt: TDateTime): int64;
  753. function TryObjectToDate(const obj: ISuperObject; var dt: TDateTime): Boolean;
  754. function ISO8601DateToJavaDateTime(const str: SOString; var ms: Int64): Boolean;
  755. function ISO8601DateToDelphiDateTime(const str: SOString; var dt: TDateTime): Boolean;
  756. function DelphiDateTimeToISO8601Date(dt: TDateTime): SOString;
  757. function UUIDToString(const g: TGUID): string;
  758. function StringToUUID(const str: string; var g: TGUID): Boolean;
  759. {$IFDEF HAVE_RTTI}
  760. type
  761. TSuperInvokeResult = (
  762. irSuccess,
  763. irMethothodError, // method don't exist
  764. irParamError, // invalid parametters
  765. irError // other error
  766. );
  767. function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; const method: string; const params: ISuperObject; var Return: ISuperObject): TSuperInvokeResult; overload;
  768. function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext = nil): ISuperObject; overload;
  769. function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext = nil): ISuperObject; overload;
  770. {$ENDIF}
  771. implementation
  772. uses sysutils,
  773. {$IFDEF UNIX}
  774. baseunix, unix, DateUtils
  775. {$ELSE}
  776. Windows
  777. {$ENDIF}
  778. {$IFDEF FPC}
  779. ,sockets
  780. {$ELSE}
  781. ,WinSock
  782. {$ENDIF};
  783. {$IFDEF DEBUG}
  784. var
  785. debugcount: integer = 0;
  786. {$ENDIF}
  787. const
  788. super_number_chars_set = ['0'..'9','.','+','-','e','E'];
  789. super_hex_chars: PSOChar = '0123456789abcdef';
  790. super_hex_chars_set = ['0'..'9','a'..'f','A'..'F'];
  791. ESC_BS: PSOChar = '\b';
  792. ESC_LF: PSOChar = '\n';
  793. ESC_CR: PSOChar = '\r';
  794. ESC_TAB: PSOChar = '\t';
  795. ESC_FF: PSOChar = '\f';
  796. ESC_QUOT: PSOChar = '\"';
  797. ESC_SL: PSOChar = '\\';
  798. ESC_SR: PSOChar = '\/';
  799. ESC_ZERO: PSOChar = '\u0000';
  800. TOK_CRLF: PSOChar = #13#10;
  801. TOK_SP: PSOChar = #32;
  802. TOK_BS: PSOChar = #8;
  803. TOK_TAB: PSOChar = #9;
  804. TOK_LF: PSOChar = #10;
  805. TOK_FF: PSOChar = #12;
  806. TOK_CR: PSOChar = #13;
  807. // TOK_SL: PSOChar = '\';
  808. // TOK_SR: PSOChar = '/';
  809. TOK_NULL: PSOChar = 'null';
  810. TOK_CBL: PSOChar = '{'; // curly bracket left
  811. TOK_CBR: PSOChar = '}'; // curly bracket right
  812. TOK_ARL: PSOChar = '[';
  813. TOK_ARR: PSOChar = ']';
  814. TOK_ARRAY: PSOChar = '[]';
  815. TOK_OBJ: PSOChar = '{}'; // empty object
  816. TOK_COM: PSOChar = ','; // Comma
  817. TOK_DQT: PSOChar = '"'; // Double Quote
  818. TOK_TRUE: PSOChar = 'true';
  819. TOK_FALSE: PSOChar = 'false';
  820. {$if (sizeof(Char) = 1)}
  821. function StrLComp(const Str1, Str2: PSOChar; MaxLen: Cardinal): Integer;
  822. var
  823. P1, P2: PWideChar;
  824. I: Cardinal;
  825. C1, C2: WideChar;
  826. begin
  827. P1 := Str1;
  828. P2 := Str2;
  829. I := 0;
  830. while I < MaxLen do
  831. begin
  832. C1 := P1^;
  833. C2 := P2^;
  834. if (C1 <> C2) or (C1 = #0) then
  835. begin
  836. Result := Ord(C1) - Ord(C2);
  837. Exit;
  838. end;
  839. Inc(P1);
  840. Inc(P2);
  841. Inc(I);
  842. end;
  843. Result := 0;
  844. end;
  845. function StrComp(const Str1, Str2: PSOChar): Integer;
  846. var
  847. P1, P2: PWideChar;
  848. C1, C2: WideChar;
  849. begin
  850. P1 := Str1;
  851. P2 := Str2;
  852. while True do
  853. begin
  854. C1 := P1^;
  855. C2 := P2^;
  856. if (C1 <> C2) or (C1 = #0) then
  857. begin
  858. Result := Ord(C1) - Ord(C2);
  859. Exit;
  860. end;
  861. Inc(P1);
  862. Inc(P2);
  863. end;
  864. end;
  865. function StrLen(const Str: PSOChar): Cardinal;
  866. var
  867. p: PSOChar;
  868. begin
  869. Result := 0;
  870. if Str <> nil then
  871. begin
  872. p := Str;
  873. while p^ <> #0 do inc(p);
  874. Result := (p - Str);
  875. end;
  876. end;
  877. {$ifend}
  878. function FloatToJson(const value: Double): SOString;
  879. var
  880. p: PSOChar;
  881. begin
  882. Result := FloatToStr(value);
  883. if {$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator <> '.' then
  884. begin
  885. p := PSOChar(Result);
  886. while p^ <> #0 do
  887. if p^ <> SOChar({$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator) then
  888. inc(p) else
  889. begin
  890. p^ := '.';
  891. Exit;
  892. end;
  893. end;
  894. end;
  895. function CurrToJson(const value: Currency): SOString;
  896. var
  897. p: PSOChar;
  898. begin
  899. Result := CurrToStr(value);
  900. if {$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator <> '.' then
  901. begin
  902. p := PSOChar(Result);
  903. while p^ <> #0 do
  904. if p^ <> SOChar({$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator) then
  905. inc(p) else
  906. begin
  907. p^ := '.';
  908. Exit;
  909. end;
  910. end;
  911. end;
  912. {$IFDEF UNIX}
  913. function GetTimeBias: integer;
  914. var
  915. TimeVal: TTimeVal;
  916. TimeZone: TTimeZone;
  917. begin
  918. fpGetTimeOfDay(@TimeVal, @TimeZone);
  919. Result := TimeZone.tz_minuteswest;
  920. end;
  921. {$ELSE}
  922. function GetTimeBias: integer;
  923. var
  924. tzi : TTimeZoneInformation;
  925. begin
  926. case GetTimeZoneInformation(tzi) of
  927. TIME_ZONE_ID_UNKNOWN : Result := tzi.Bias;
  928. TIME_ZONE_ID_STANDARD: Result := tzi.Bias + tzi.StandardBias;
  929. TIME_ZONE_ID_DAYLIGHT: Result := tzi.Bias + tzi.DaylightBias;
  930. else
  931. Result := 0;
  932. end;
  933. end;
  934. {$ENDIF}
  935. {$IFDEF UNIX}
  936. type
  937. ptm = ^tm;
  938. tm = record
  939. tm_sec: Integer; (* Seconds: 0-59 (K&R says 0-61?) *)
  940. tm_min: Integer; (* Minutes: 0-59 *)
  941. tm_hour: Integer; (* Hours since midnight: 0-23 *)
  942. tm_mday: Integer; (* Day of the month: 1-31 *)
  943. tm_mon: Integer; (* Months *since* january: 0-11 *)
  944. tm_year: Integer; (* Years since 1900 *)
  945. tm_wday: Integer; (* Days since Sunday (0-6) *)
  946. tm_yday: Integer; (* Days since Jan. 1: 0-365 *)
  947. tm_isdst: Integer; (* +1 Daylight Savings Time, 0 No DST, -1 don't know *)
  948. end;
  949. function mktime(p: ptm): LongInt; cdecl; external;
  950. function gmtime(const t: PLongint): ptm; cdecl; external;
  951. function localtime (const t: PLongint): ptm; cdecl; external;
  952. function DelphiToJavaDateTime(const dt: TDateTime): Int64;
  953. var
  954. p: ptm;
  955. l, ms: Integer;
  956. v: Int64;
  957. begin
  958. v := Round((dt - 25569) * 86400000);
  959. ms := v mod 1000;
  960. l := v div 1000;
  961. p := localtime(@l);
  962. Result := Int64(mktime(p)) * 1000 + ms;
  963. end;
  964. function JavaToDelphiDateTime(const dt: int64): TDateTime;
  965. var
  966. p: ptm;
  967. l, ms: Integer;
  968. begin
  969. l := dt div 1000;
  970. ms := dt mod 1000;
  971. p := gmtime(@l);
  972. Result := EncodeDateTime(p^.tm_year+1900, p^.tm_mon+1, p^.tm_mday, p^.tm_hour, p^.tm_min, p^.tm_sec, ms);
  973. end;
  974. {$ELSE}
  975. {$IFDEF WINDOWSNT_COMPATIBILITY}
  976. function DayLightCompareDate(const date: PSystemTime;
  977. const compareDate: PSystemTime): Integer;
  978. var
  979. limit_day, dayinsecs, weekofmonth: Integer;
  980. First: Word;
  981. begin
  982. if (date^.wMonth < compareDate^.wMonth) then
  983. begin
  984. Result := -1; (* We are in a month before the date limit. *)
  985. Exit;
  986. end;
  987. if (date^.wMonth > compareDate^.wMonth) then
  988. begin
  989. Result := 1; (* We are in a month after the date limit. *)
  990. Exit;
  991. end;
  992. (* if year is 0 then date is in day-of-week format, otherwise
  993. * it's absolute date.
  994. *)
  995. if (compareDate^.wYear = 0) then
  996. begin
  997. (* compareDate.wDay is interpreted as number of the week in the month
  998. * 5 means: the last week in the month *)
  999. weekofmonth := compareDate^.wDay;
  1000. (* calculate the day of the first DayOfWeek in the month *)
  1001. First := (6 + compareDate^.wDayOfWeek - date^.wDayOfWeek + date^.wDay) mod 7 + 1;
  1002. limit_day := First + 7 * (weekofmonth - 1);
  1003. (* check needed for the 5th weekday of the month *)
  1004. if (limit_day > MonthDays[(date^.wMonth=2) and IsLeapYear(date^.wYear)][date^.wMonth]) then
  1005. dec(limit_day, 7);
  1006. end
  1007. else
  1008. limit_day := compareDate^.wDay;
  1009. (* convert to seconds *)
  1010. limit_day := ((limit_day * 24 + compareDate^.wHour) * 60 + compareDate^.wMinute ) * 60;
  1011. dayinsecs := ((date^.wDay * 24 + date^.wHour) * 60 + date^.wMinute ) * 60 + date^.wSecond;
  1012. (* and compare *)
  1013. if dayinsecs < limit_day then
  1014. Result := -1 else
  1015. if dayinsecs > limit_day then
  1016. Result := 1 else
  1017. Result := 0; (* date is equal to the date limit. *)
  1018. end;
  1019. function CompTimeZoneID(const pTZinfo: PTimeZoneInformation;
  1020. lpFileTime: PFileTime; islocal: Boolean): LongWord;
  1021. var
  1022. ret: Integer;
  1023. beforeStandardDate, afterDaylightDate: Boolean;
  1024. llTime: Int64;
  1025. SysTime: TSystemTime;
  1026. ftTemp: TFileTime;
  1027. begin
  1028. llTime := 0;
  1029. if (pTZinfo^.DaylightDate.wMonth <> 0) then
  1030. begin
  1031. (* if year is 0 then date is in day-of-week format, otherwise
  1032. * it's absolute date.
  1033. *)
  1034. if ((pTZinfo^.StandardDate.wMonth = 0) or
  1035. ((pTZinfo^.StandardDate.wYear = 0) and
  1036. ((pTZinfo^.StandardDate.wDay < 1) or
  1037. (pTZinfo^.StandardDate.wDay > 5) or
  1038. (pTZinfo^.DaylightDate.wDay < 1) or
  1039. (pTZinfo^.DaylightDate.wDay > 5)))) then
  1040. begin
  1041. SetLastError(ERROR_INVALID_PARAMETER);
  1042. Result := TIME_ZONE_ID_INVALID;
  1043. Exit;
  1044. end;
  1045. if (not islocal) then
  1046. begin
  1047. llTime := PInt64(lpFileTime)^;
  1048. dec(llTime, Int64(pTZinfo^.Bias + pTZinfo^.DaylightBias) * 600000000);
  1049. PInt64(@ftTemp)^ := llTime;
  1050. lpFileTime := @ftTemp;
  1051. end;
  1052. FileTimeToSystemTime(lpFileTime^, SysTime);
  1053. (* check for daylight savings *)
  1054. ret := DayLightCompareDate(@SysTime, @pTZinfo^.StandardDate);
  1055. if (ret = -2) then
  1056. begin
  1057. Result := TIME_ZONE_ID_INVALID;
  1058. Exit;
  1059. end;
  1060. beforeStandardDate := ret < 0;
  1061. if (not islocal) then
  1062. begin
  1063. dec(llTime, Int64(pTZinfo^.StandardBias - pTZinfo^.DaylightBias) * 600000000);
  1064. PInt64(@ftTemp)^ := llTime;
  1065. FileTimeToSystemTime(lpFileTime^, SysTime);
  1066. end;
  1067. ret := DayLightCompareDate(@SysTime, @pTZinfo^.DaylightDate);
  1068. if (ret = -2) then
  1069. begin
  1070. Result := TIME_ZONE_ID_INVALID;
  1071. Exit;
  1072. end;
  1073. afterDaylightDate := ret >= 0;
  1074. Result := TIME_ZONE_ID_STANDARD;
  1075. if( pTZinfo^.DaylightDate.wMonth < pTZinfo^.StandardDate.wMonth ) then
  1076. begin
  1077. (* Northern hemisphere *)
  1078. if( beforeStandardDate and afterDaylightDate) then
  1079. Result := TIME_ZONE_ID_DAYLIGHT;
  1080. end else (* Down south *)
  1081. if( beforeStandardDate or afterDaylightDate) then
  1082. Result := TIME_ZONE_ID_DAYLIGHT;
  1083. end else
  1084. (* No transition date *)
  1085. Result := TIME_ZONE_ID_UNKNOWN;
  1086. end;
  1087. function GetTimezoneBias(const pTZinfo: PTimeZoneInformation;
  1088. lpFileTime: PFileTime; islocal: Boolean; pBias: PLongint): Boolean;
  1089. var
  1090. bias: LongInt;
  1091. tzid: LongWord;
  1092. begin
  1093. bias := pTZinfo^.Bias;
  1094. tzid := CompTimeZoneID(pTZinfo, lpFileTime, islocal);
  1095. if( tzid = TIME_ZONE_ID_INVALID) then
  1096. begin
  1097. Result := False;
  1098. Exit;
  1099. end;
  1100. if (tzid = TIME_ZONE_ID_DAYLIGHT) then
  1101. inc(bias, pTZinfo^.DaylightBias)
  1102. else if (tzid = TIME_ZONE_ID_STANDARD) then
  1103. inc(bias, pTZinfo^.StandardBias);
  1104. pBias^ := bias;
  1105. Result := True;
  1106. end;
  1107. function SystemTimeToTzSpecificLocalTime(
  1108. lpTimeZoneInformation: PTimeZoneInformation;
  1109. lpUniversalTime, lpLocalTime: PSystemTime): BOOL;
  1110. var
  1111. ft: TFileTime;
  1112. lBias: LongInt;
  1113. llTime: Int64;
  1114. tzinfo: TTimeZoneInformation;
  1115. begin
  1116. if (lpTimeZoneInformation <> nil) then
  1117. tzinfo := lpTimeZoneInformation^ else
  1118. if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then
  1119. begin
  1120. Result := False;
  1121. Exit;
  1122. end;
  1123. if (not SystemTimeToFileTime(lpUniversalTime^, ft)) then
  1124. begin
  1125. Result := False;
  1126. Exit;
  1127. end;
  1128. llTime := PInt64(@ft)^;
  1129. if (not GetTimezoneBias(@tzinfo, @ft, False, @lBias)) then
  1130. begin
  1131. Result := False;
  1132. Exit;
  1133. end;
  1134. (* convert minutes to 100-nanoseconds-ticks *)
  1135. dec(llTime, Int64(lBias) * 600000000);
  1136. PInt64(@ft)^ := llTime;
  1137. Result := FileTimeToSystemTime(ft, lpLocalTime^);
  1138. end;
  1139. function TzSpecificLocalTimeToSystemTime(
  1140. const lpTimeZoneInformation: PTimeZoneInformation;
  1141. const lpLocalTime: PSystemTime; lpUniversalTime: PSystemTime): BOOL;
  1142. var
  1143. ft: TFileTime;
  1144. lBias: LongInt;
  1145. t: Int64;
  1146. tzinfo: TTimeZoneInformation;
  1147. begin
  1148. if (lpTimeZoneInformation <> nil) then
  1149. tzinfo := lpTimeZoneInformation^
  1150. else
  1151. if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then
  1152. begin
  1153. Result := False;
  1154. Exit;
  1155. end;
  1156. if (not SystemTimeToFileTime(lpLocalTime^, ft)) then
  1157. begin
  1158. Result := False;
  1159. Exit;
  1160. end;
  1161. t := PInt64(@ft)^;
  1162. if (not GetTimezoneBias(@tzinfo, @ft, True, @lBias)) then
  1163. begin
  1164. Result := False;
  1165. Exit;
  1166. end;
  1167. (* convert minutes to 100-nanoseconds-ticks *)
  1168. inc(t, Int64(lBias) * 600000000);
  1169. PInt64(@ft)^ := t;
  1170. Result := FileTimeToSystemTime(ft, lpUniversalTime^);
  1171. end;
  1172. {$ELSE}
  1173. function TzSpecificLocalTimeToSystemTime(
  1174. lpTimeZoneInformation: PTimeZoneInformation;
  1175. lpLocalTime, lpUniversalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll';
  1176. function SystemTimeToTzSpecificLocalTime(
  1177. lpTimeZoneInformation: PTimeZoneInformation;
  1178. lpUniversalTime, lpLocalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll';
  1179. {$ENDIF}
  1180. function JavaToDelphiDateTime(const dt: int64): TDateTime;
  1181. var
  1182. t: TSystemTime;
  1183. begin
  1184. DateTimeToSystemTime(25569 + (dt / 86400000), t);
  1185. SystemTimeToTzSpecificLocalTime(nil, @t, @t);
  1186. Result := SystemTimeToDateTime(t);
  1187. end;
  1188. function DelphiToJavaDateTime(const dt: TDateTime): int64;
  1189. var
  1190. t: TSystemTime;
  1191. begin
  1192. DateTimeToSystemTime(dt, t);
  1193. TzSpecificLocalTimeToSystemTime(nil, @t, @t);
  1194. Result := Round((SystemTimeToDateTime(t) - 25569) * 86400000)
  1195. end;
  1196. {$ENDIF}
  1197. function ISO8601DateToJavaDateTime(const str: SOString; var ms: Int64): Boolean;
  1198. type
  1199. TState = (
  1200. stStart, stYear, stMonth, stWeek, stWeekDay, stDay, stDayOfYear,
  1201. stHour, stMin, stSec, stMs, stUTC, stGMTH, stGMTM,
  1202. stGMTend, stEnd);
  1203. TPerhaps = (yes, no, perhaps);
  1204. TDateTimeInfo = record
  1205. year: Word;
  1206. month: Word;
  1207. week: Word;
  1208. weekday: Word;
  1209. day: Word;
  1210. dayofyear: Integer;
  1211. hour: Word;
  1212. minute: Word;
  1213. second: Word;
  1214. ms: Word;
  1215. bias: Integer;
  1216. end;
  1217. var
  1218. p: PSOChar;
  1219. state: TState;
  1220. pos, v: Word;
  1221. sep: TPerhaps;
  1222. inctz, havetz, havedate: Boolean;
  1223. st: TDateTimeInfo;
  1224. DayTable: PDayTable;
  1225. function get(var v: Word; c: SOChar): Boolean; {$IFDEF HAVE_INLINE} inline;{$ENDIF}
  1226. begin
  1227. if (c < #256) and (AnsiChar(c) in ['0'..'9']) then
  1228. begin
  1229. Result := True;
  1230. v := v * 10 + Ord(c) - Ord('0');
  1231. end else
  1232. Result := False;
  1233. end;
  1234. label
  1235. error;
  1236. begin
  1237. p := PSOChar(str);
  1238. sep := perhaps;
  1239. state := stStart;
  1240. pos := 0;
  1241. FillChar(st, SizeOf(st), 0);
  1242. havedate := True;
  1243. inctz := False;
  1244. havetz := False;
  1245. while true do
  1246. case state of
  1247. stStart:
  1248. case p^ of
  1249. '0'..'9': state := stYear;
  1250. 'T', 't':
  1251. begin
  1252. state := stHour;
  1253. pos := 0;
  1254. inc(p);
  1255. havedate := False;
  1256. end;
  1257. else
  1258. goto error;
  1259. end;
  1260. stYear:
  1261. case pos of
  1262. 0..1,3:
  1263. if get(st.year, p^) then
  1264. begin
  1265. Inc(pos);
  1266. Inc(p);
  1267. end else
  1268. goto error;
  1269. 2: case p^ of
  1270. '0'..'9':
  1271. begin
  1272. st.year := st.year * 10 + ord(p^) - ord('0');
  1273. Inc(pos);
  1274. Inc(p);
  1275. end;
  1276. ':':
  1277. begin
  1278. havedate := false;
  1279. st.hour := st.year;
  1280. st.year := 0;
  1281. inc(p);
  1282. pos := 0;
  1283. state := stMin;
  1284. sep := yes;
  1285. end;
  1286. else
  1287. goto error;
  1288. end;
  1289. 4: case p^ of
  1290. '-': begin
  1291. pos := 0;
  1292. Inc(p);
  1293. sep := yes;
  1294. state := stMonth;
  1295. end;
  1296. '0'..'9':
  1297. begin
  1298. sep := no;
  1299. pos := 0;
  1300. state := stMonth;
  1301. end;
  1302. 'W', 'w' :
  1303. begin
  1304. pos := 0;
  1305. Inc(p);
  1306. state := stWeek;
  1307. end;
  1308. 'T', 't', ' ':
  1309. begin
  1310. state := stHour;
  1311. pos := 0;
  1312. inc(p);
  1313. st.month := 1;
  1314. st.day := 1;
  1315. end;
  1316. #0:
  1317. begin
  1318. st.month := 1;
  1319. st.day := 1;
  1320. state := stEnd;
  1321. end;
  1322. else
  1323. goto error;
  1324. end;
  1325. end;
  1326. stMonth:
  1327. case pos of
  1328. 0: case p^ of
  1329. '0'..'9':
  1330. begin
  1331. st.month := ord(p^) - ord('0');
  1332. Inc(pos);
  1333. Inc(p);
  1334. end;
  1335. 'W', 'w':
  1336. begin
  1337. pos := 0;
  1338. Inc(p);
  1339. state := stWeek;
  1340. end;
  1341. else
  1342. goto error;
  1343. end;
  1344. 1: if get(st.month, p^) then
  1345. begin
  1346. Inc(pos);
  1347. Inc(p);
  1348. end else
  1349. goto error;
  1350. 2: case p^ of
  1351. '-':
  1352. if (sep in [yes, perhaps]) then
  1353. begin
  1354. pos := 0;
  1355. Inc(p);
  1356. state := stDay;
  1357. sep := yes;
  1358. end else
  1359. goto error;
  1360. '0'..'9':
  1361. if sep in [no, perhaps] then
  1362. begin
  1363. pos := 0;
  1364. state := stDay;
  1365. sep := no;
  1366. end else
  1367. begin
  1368. st.dayofyear := st.month * 10 + Ord(p^) - Ord('0');
  1369. st.month := 0;
  1370. inc(p);
  1371. pos := 3;
  1372. state := stDayOfYear;
  1373. end;
  1374. 'T', 't', ' ':
  1375. begin
  1376. state := stHour;
  1377. pos := 0;
  1378. inc(p);
  1379. st.day := 1;
  1380. end;
  1381. #0:
  1382. begin
  1383. st.day := 1;
  1384. state := stEnd;
  1385. end;
  1386. else
  1387. goto error;
  1388. end;
  1389. end;
  1390. stDay:
  1391. case pos of
  1392. 0: if get(st.day, p^) then
  1393. begin
  1394. Inc(pos);
  1395. Inc(p);
  1396. end else
  1397. goto error;
  1398. 1: if get(st.day, p^) then
  1399. begin
  1400. Inc(pos);
  1401. Inc(p);
  1402. end else