PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/src/superobject/superobject.pas

http://delphionrails.googlecode.com/
Pascal | 2085 lines | 1721 code | 147 blank | 217 comment | 99 complexity | 3551683f44083aa75b2ebf1be939b466 MD5 | raw file

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

Large files files are truncated, but you can click here to view the full file