PasJSON.pas 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976
  1. (* *****************************************************************************
  2. * PasJSON *
  3. ******************************************************************************
  4. * Version 2020-03-04-02-20 *
  5. ******************************************************************************
  6. * zlib license *
  7. *============================================================================*
  8. * *
  9. * Copyright (C) 2016-2020, Benjamin Rosseaux ([email protected]) *
  10. * *
  11. * This software is provided 'as-is', without any express or implied *
  12. * warranty. In no event will the authors be held liable for any damages *
  13. * arising from the use of this software. *
  14. * *
  15. * Permission is granted to anyone to use this software for any purpose, *
  16. * including commercial applications, and to alter it and redistribute it *
  17. * freely, subject to the following restrictions: *
  18. * *
  19. * 1. The origin of this software must not be misrepresented; you must not *
  20. * claim that you wrote the original software. If you use this software *
  21. * in a product, an acknowledgement in the product documentation would be *
  22. * appreciated but is not required. *
  23. * 2. Altered source versions must be plainly marked as such, and must not be *
  24. * misrepresented as being the original software. *
  25. * 3. This notice may not be removed or altered from any source distribution. *
  26. * *
  27. ******************************************************************************
  28. * General guidelines for code contributors *
  29. *============================================================================*
  30. * *
  31. * 1. Make sure you are legally allowed to make a contribution under the zlib *
  32. * license. *
  33. * 2. The zlib license header goes at the top of each source file, with *
  34. * appropriate copyright notice. *
  35. * 3. After a pull request, check the status of your pull request on *
  36. * http://github.com/BeRo1985/pasjson *
  37. * 4. Write code which's compatible with newer modern Delphi versions and *
  38. * FreePascal >= 3.0.0 *
  39. * 5. Don't use Delphi-only, FreePascal-only or Lazarus-only libraries/units, *
  40. * but if needed, make it out-ifdef-able. *
  41. * 6. No use of third-party libraries/units as possible, but if needed, make *
  42. * it out-ifdef-able. *
  43. * 7. Try to use const when possible. *
  44. * 8. Make sure to comment out writeln, used while debugging. *
  45. * 9. Make sure the code compiles on 32-bit and 64-bit platforms (x86-32, *
  46. * x86-64, ARM, ARM64, etc.). *
  47. * *
  48. ***************************************************************************** *)
  49. unit PasJSON;
  50. {$ifdef fpc}
  51. {$mode delphi}
  52. {$ifdef cpui386}
  53. {$define cpu386}
  54. {$endif}
  55. {$ifdef cpu386}
  56. {$asmmode intel}
  57. {$endif}
  58. {$ifdef cpuamd64}
  59. {$asmmode intel}
  60. {$endif}
  61. {$ifdef FPC_LITTLE_ENDIAN}
  62. {$define LITTLE_ENDIAN}
  63. {$else}
  64. {$ifdef FPC_BIG_ENDIAN}
  65. {$define BIG_ENDIAN}
  66. {$endif}
  67. {$endif}
  68. { -$pic off }
  69. {$ifdef fpc_has_internal_sar}
  70. {$define HasSAR}
  71. {$endif}
  72. {$ifdef FPC_HAS_TYPE_EXTENDED}
  73. {$define HAS_TYPE_EXTENDED}
  74. {$else}
  75. {$undef HAS_TYPE_EXTENDED}
  76. {$endif}
  77. {$ifdef FPC_HAS_TYPE_DOUBLE}
  78. {$define HAS_TYPE_DOUBLE}
  79. {$else}
  80. {$undef HAS_TYPE_DOUBLE}
  81. {$endif}
  82. {$ifdef FPC_HAS_TYPE_SINGLE}
  83. {$define HAS_TYPE_SINGLE}
  84. {$else}
  85. {$undef HAS_TYPE_SINGLE}
  86. {$endif}
  87. {$define CAN_INLINE}
  88. {$define HAS_ADVANCED_RECORDS}
  89. {$else}
  90. {$realcompatibility off}
  91. {$localsymbols on}
  92. {$define LITTLE_ENDIAN}
  93. {$ifndef cpu64}
  94. {$define cpu32}
  95. {$endif}
  96. {$define HAS_TYPE_EXTENDED}
  97. {$define HAS_TYPE_DOUBLE}
  98. {$define HAS_TYPE_SINGLE}
  99. {$undef CAN_INLINE}
  100. {$undef HAS_ADVANCED_RECORDS}
  101. {$ifndef BCB}
  102. {$ifdef ver120}
  103. {$define Delphi4or5}
  104. {$endif}
  105. {$ifdef ver130}
  106. {$define Delphi4or5}
  107. {$endif}
  108. {$ifdef ver140}
  109. {$define Delphi6}
  110. {$endif}
  111. {$ifdef ver150}
  112. {$define Delphi7}
  113. {$endif}
  114. {$ifdef ver170}
  115. {$define Delphi2005}
  116. {$endif}
  117. {$else}
  118. {$ifdef ver120}
  119. {$define Delphi4or5}
  120. {$define BCB4}
  121. {$endif}
  122. {$ifdef ver130}
  123. {$define Delphi4or5}
  124. {$endif}
  125. {$endif}
  126. {$ifdef conditionalexpressions}
  127. {$if CompilerVersion>=24.0}
  128. {$legacyifend on}
  129. {$ifend}
  130. {$if CompilerVersion>=14.0}
  131. {$if CompilerVersion=14.0}
  132. {$define Delphi6}
  133. {$ifend}
  134. {$define Delphi6AndUp}
  135. {$ifend}
  136. {$if CompilerVersion>=15.0}
  137. {$if CompilerVersion=15.0}
  138. {$define Delphi7}
  139. {$ifend}
  140. {$define Delphi7AndUp}
  141. {$ifend}
  142. {$if CompilerVersion>=17.0}
  143. {$if CompilerVersion=17.0}
  144. {$define Delphi2005}
  145. {$ifend}
  146. {$define Delphi2005AndUp}
  147. {$ifend}
  148. {$if CompilerVersion>=18.0}
  149. {$if CompilerVersion=18.0}
  150. {$define BDS2006}
  151. {$define Delphi2006}
  152. {$ifend}
  153. {$define Delphi2006AndUp}
  154. {$define CAN_INLINE}
  155. {$define HAS_ADVANCED_RECORDS}
  156. {$ifend}
  157. {$if CompilerVersion>=18.5}
  158. {$if CompilerVersion=18.5}
  159. {$define Delphi2007}
  160. {$ifend}
  161. {$define Delphi2007AndUp}
  162. {$ifend}
  163. {$if CompilerVersion=19.0}
  164. {$define Delphi2007Net}
  165. {$ifend}
  166. {$if CompilerVersion>=20.0}
  167. {$if CompilerVersion=20.0}
  168. {$define Delphi2009}
  169. {$ifend}
  170. {$define Delphi2009AndUp}
  171. {$ifend}
  172. {$if CompilerVersion>=21.0}
  173. {$if CompilerVersion=21.0}
  174. {$define Delphi2010}
  175. {$ifend}
  176. {$define Delphi2010AndUp}
  177. {$ifend}
  178. {$if CompilerVersion>=22.0}
  179. {$if CompilerVersion=22.0}
  180. {$define DelphiXE}
  181. {$ifend}
  182. {$define DelphiXEAndUp}
  183. {$ifend}
  184. {$if CompilerVersion>=23.0}
  185. {$if CompilerVersion=23.0}
  186. {$define DelphiXE2}
  187. {$ifend}
  188. {$define DelphiXE2AndUp}
  189. {$ifend}
  190. {$if CompilerVersion>=24.0}
  191. {$legacyifend on}
  192. {$if CompilerVersion=24.0}
  193. {$define DelphiXE3}
  194. {$ifend}
  195. {$define DelphiXE3AndUp}
  196. {$ifend}
  197. {$if CompilerVersion>=25.0}
  198. {$if CompilerVersion=25.0}
  199. {$define DelphiXE4}
  200. {$ifend}
  201. {$define DelphiXE4AndUp}
  202. {$ifend}
  203. {$if CompilerVersion>=26.0}
  204. {$if CompilerVersion=26.0}
  205. {$define DelphiXE5}
  206. {$ifend}
  207. {$define DelphiXE5AndUp}
  208. {$ifend}
  209. {$if CompilerVersion>=27.0}
  210. {$if CompilerVersion=27.0}
  211. {$define DelphiXE6}
  212. {$ifend}
  213. {$define DelphiXE6AndUp}
  214. {$ifend}
  215. {$if CompilerVersion>=28.0}
  216. {$if CompilerVersion=28.0}
  217. {$define DelphiXE7}
  218. {$ifend}
  219. {$define DelphiXE7AndUp}
  220. {$ifend}
  221. {$if CompilerVersion>=29.0}
  222. {$if CompilerVersion=29.0}
  223. {$define DelphiXE8}
  224. {$ifend}
  225. {$define DelphiXE8AndUp}
  226. {$ifend}
  227. {$if CompilerVersion>=30.0}
  228. {$if CompilerVersion=30.0}
  229. {$define Delphi10Seattle}
  230. {$ifend}
  231. {$define Delphi10SeattleAndUp}
  232. {$ifend}
  233. {$if CompilerVersion>=31.0}
  234. {$if CompilerVersion=31.0}
  235. {$define Delphi10Berlin}
  236. {$ifend}
  237. {$define Delphi10BerlinAndUp}
  238. {$ifend}
  239. {$endif}
  240. {$ifndef Delphi4or5}
  241. {$ifndef BCB}
  242. {$define Delphi6AndUp}
  243. {$endif}
  244. {$ifndef Delphi6}
  245. {$define BCB6OrDelphi7AndUp}
  246. {$ifndef BCB}
  247. {$define Delphi7AndUp}
  248. {$endif}
  249. {$ifndef BCB}
  250. {$ifndef Delphi7}
  251. {$ifndef Delphi2005}
  252. {$define BDS2006AndUp}
  253. {$endif}
  254. {$endif}
  255. {$endif}
  256. {$endif}
  257. {$endif}
  258. {$ifdef Delphi6AndUp}
  259. {$warn symbol_platform off}
  260. {$warn symbol_deprecated off}
  261. {$endif}
  262. {$endif}
  263. {$if defined(Win32) or defined(Win64)}
  264. {$define Windows}
  265. {$ifend}
  266. {$rangechecks off}
  267. {$extendedsyntax on}
  268. {$writeableconst on}
  269. {$hints off}
  270. {$booleval off}
  271. {$typedaddress off}
  272. {$stackframes off}
  273. {$varstringchecks on}
  274. {$typeinfo on}
  275. {$overflowchecks off}
  276. {$longstrings on}
  277. {$openstrings on}
  278. {$ifndef HAS_TYPE_SINGLE}
  279. {$error No single floating point precision}
  280. {$endif}
  281. {$ifndef HAS_TYPE_DOUBLE}
  282. {$error No double floating point precision}
  283. {$endif}
  284. {$scopedenums on}
  285. {$ifndef fpc}
  286. {$ifdef conditionalexpressions}
  287. {$if CompilerVersion>=24.0}
  288. {$legacyifend on}
  289. {$ifend}
  290. {$endif}
  291. {$endif}
  292. interface
  293. uses
  294. System.SysUtils,
  295. System.Classes,
  296. System.Math;
  297. type
  298. PPPasJSONInt8 = ^PPasJSONInt8;
  299. PPasJSONInt8 = ^TPasJSONInt8;
  300. TPasJSONInt8 = {$IFDEF fpc}Int8{$ELSE}shortint{$ENDIF};
  301. PPPasJSONUInt8 = ^PPasJSONUInt8;
  302. PPasJSONUInt8 = ^TPasJSONUInt8;
  303. TPasJSONUInt8 = {$IFDEF fpc}UInt8{$ELSE}byte{$ENDIF};
  304. PPPasJSONUInt8Array = ^PPasJSONUInt8Array;
  305. PPasJSONUInt8Array = ^TPasJSONUInt8Array;
  306. TPasJSONUInt8Array = array [0 .. 65535] of TPasJSONUInt8;
  307. PPPasJSONInt16 = ^PPasJSONInt16;
  308. PPasJSONInt16 = ^TPasJSONInt16;
  309. TPasJSONInt16 = {$IFDEF fpc}Int16{$ELSE}smallint{$ENDIF};
  310. PPPasJSONUInt16 = ^PPasJSONUInt16;
  311. PPasJSONUInt16 = ^TPasJSONUInt16;
  312. TPasJSONUInt16 = {$IFDEF fpc}UInt16{$ELSE}word{$ENDIF};
  313. PPPasJSONInt32 = ^PPasJSONInt32;
  314. PPasJSONInt32 = ^TPasJSONInt32;
  315. TPasJSONInt32 = {$IFDEF fpc}Int32{$ELSE}longint{$ENDIF};
  316. PPPasJSONUInt32 = ^PPasJSONUInt32;
  317. PPasJSONUInt32 = ^TPasJSONUInt32;
  318. TPasJSONUInt32 = {$IFDEF fpc}UInt32{$ELSE}longword{$ENDIF};
  319. PPPasJSONInt64 = ^PPasJSONInt64;
  320. PPasJSONInt64 = ^TPasJSONInt64;
  321. TPasJSONInt64 = Int64;
  322. PPPasJSONUInt64 = ^PPasJSONUInt64;
  323. PPasJSONUInt64 = ^TPasJSONUInt64;
  324. TPasJSONUInt64 = UInt64;
  325. PPPasJSONChar = ^PAnsiChar;
  326. PPasJSONChar = PAnsiChar;
  327. TPasJSONChar = AnsiChar;
  328. PPPasJSONRawByteChar = ^PAnsiChar;
  329. PPasJSONRawByteChar = PAnsiChar;
  330. TPasJSONRawByteChar = AnsiChar;
  331. PPPasJSONUTF16Char = ^PWideChar;
  332. PPasJSONUTF16Char = PWideChar;
  333. TPasJSONUTF16Char = WideChar;
  334. PPPasJSONPointer = ^PPasJSONPointer;
  335. PPasJSONPointer = ^TPasJSONPointer;
  336. TPasJSONPointer = Pointer;
  337. PPPasJSONPointers = ^PPasJSONPointers;
  338. PPasJSONPointers = ^TPasJSONPointers;
  339. TPasJSONPointers = array [0 .. 65535] of TPasJSONPointer;
  340. PPPasJSONVoid = ^PPasJSONVoid;
  341. PPasJSONVoid = TPasJSONPointer;
  342. PPPasJSONFloat = ^PPasJSONFloat;
  343. PPasJSONFloat = ^TPasJSONFloat;
  344. TPasJSONFloat = Single;
  345. TPasJSONFloats = array of TPasJSONFloat;
  346. PPPasJSONDouble = ^PPasJSONDouble;
  347. PPasJSONDouble = ^TPasJSONDouble;
  348. TPasJSONDouble = Double;
  349. PPPasJSONPtrUInt = ^PPasJSONPtrUInt;
  350. PPPasJSONPtrInt = ^PPasJSONPtrInt;
  351. PPasJSONPtrUInt = ^TPasJSONPtrUInt;
  352. PPasJSONPtrInt = ^TPasJSONPtrInt;
  353. {$IFDEF fpc}
  354. TPasJSONPtrUInt = PtrUInt;
  355. TPasJSONPtrInt = PtrInt;
  356. {$UNDEF OldDelphi}
  357. {$ELSE}
  358. {$IFDEF conditionalexpressions}
  359. {$IF CompilerVersion>=23.0}
  360. {$UNDEF OldDelphi}
  361. TPasJSONPtrUInt = NativeUInt;
  362. TPasJSONPtrInt = NativeInt;
  363. {$ELSE}
  364. {$DEFINE OldDelphi}
  365. {$IFEND}
  366. {$ELSE}
  367. {$DEFINE OldDelphi}
  368. {$ENDIF}
  369. {$ENDIF}
  370. {$IFDEF OldDelphi}
  371. {$IFDEF cpu64}
  372. TPasJSONPtrUInt = UInt64;
  373. TPasJSONPtrInt = Int64;
  374. {$ELSE}
  375. TPasJSONPtrUInt = longword;
  376. TPasJSONPtrInt = longint;
  377. {$ENDIF}
  378. {$ENDIF}
  379. PPPasJSONSizeUInt = ^PPasJSONSizeUInt;
  380. PPasJSONSizeUInt = ^TPasJSONSizeUInt;
  381. TPasJSONSizeUInt = TPasJSONPtrUInt;
  382. PPPasJSONSizeInt = ^PPasJSONSizeInt;
  383. PPasJSONSizeInt = ^TPasJSONSizeInt;
  384. TPasJSONSizeInt = TPasJSONPtrInt;
  385. PPPasJSONNativeUInt = ^PPasJSONNativeUInt;
  386. PPasJSONNativeUInt = ^TPasJSONNativeUInt;
  387. TPasJSONNativeUInt = TPasJSONPtrUInt;
  388. PPPasJSONNativeInt = ^PPasJSONNativeInt;
  389. PPasJSONNativeInt = ^TPasJSONNativeInt;
  390. TPasJSONNativeInt = TPasJSONPtrInt;
  391. PPPasJSONSize = ^PPasJSONSizeUInt;
  392. PPasJSONSize = ^TPasJSONSizeUInt;
  393. TPasJSONSize = TPasJSONPtrUInt;
  394. PPPasJSONPtrDiff = ^PPasJSONPtrDiff;
  395. PPasJSONPtrDiff = ^TPasJSONPtrDiff;
  396. TPasJSONPtrDiff = TPasJSONPtrInt;
  397. PPPasJSONRawByteString = ^PPasJSONRawByteString;
  398. PPasJSONRawByteString = ^TPasJSONRawByteString;
  399. TPasJSONRawByteString =
  400. {$IF declared(RawByteString)}RawByteString{$ELSE}AnsiString{$IFEND};
  401. PPPasJSONUTF8String = ^PPasJSONUTF8String;
  402. PPasJSONUTF8String = ^TPasJSONUTF8String;
  403. TPasJSONUTF8String =
  404. {$IF declared(UTF8String)}UTF8String{$ELSE}AnsiString{$IFEND};
  405. PPPasJSONUTF16String = ^PPasJSONUTF16String;
  406. PPasJSONUTF16String = ^TPasJSONUTF16String;
  407. TPasJSONUTF16String =
  408. {$IF declared(UnicodeString)}UnicodeString{$ELSE}WideString{$IFEND};
  409. EPasJSONSyntaxError = class(Exception)
  410. private
  411. fPosition: TPasJSONSizeInt;
  412. public
  413. constructor Create(const aMessage: string;
  414. const aPosition: TPasJSONSizeInt); reintroduce;
  415. published
  416. property Position: TPasJSONSizeInt read fPosition write fPosition;
  417. end;
  418. EPasJSONMergeError = class(Exception);
  419. TPasJSONMergeFlag = (ForceObjectPropertyValueDestinationType);
  420. TPasJSONMergeFlags = set of TPasJSONMergeFlag;
  421. TPasJSONItem = class
  422. public
  423. constructor Create;
  424. destructor Destroy; override;
  425. procedure Merge(const aWith: TPasJSONItem;
  426. const aFlags: TPasJSONMergeFlags = []); virtual;
  427. end;
  428. TPasJSONItems = array of TPasJSONItem;
  429. TPasJSONItemNull = class(TPasJSONItem)
  430. public
  431. constructor Create;
  432. destructor Destroy; override;
  433. procedure Merge(const aWith: TPasJSONItem;
  434. const aFlags: TPasJSONMergeFlags = []); override;
  435. end;
  436. TPasJSONItemBoolean = class(TPasJSONItem)
  437. private
  438. fValue: boolean;
  439. public
  440. constructor Create(const AValue: boolean);
  441. destructor Destroy; override;
  442. procedure Merge(const aWith: TPasJSONItem;
  443. const aFlags: TPasJSONMergeFlags = []); override;
  444. published
  445. property Value: boolean read fValue write fValue;
  446. end;
  447. TPasJSONItemNumber = class(TPasJSONItem)
  448. private
  449. fValue: TPasJSONDouble;
  450. public
  451. constructor Create(const AValue: TPasJSONDouble);
  452. destructor Destroy; override;
  453. procedure Merge(const aWith: TPasJSONItem;
  454. const aFlags: TPasJSONMergeFlags = []); override;
  455. published
  456. property Value: TPasJSONDouble read fValue write fValue;
  457. end;
  458. TPasJSONItemString = class(TPasJSONItem)
  459. private
  460. fValue: TPasJSONUTF8String;
  461. public
  462. constructor Create(const AValue: TPasJSONUTF8String);
  463. destructor Destroy; override;
  464. procedure Merge(const aWith: TPasJSONItem;
  465. const aFlags: TPasJSONMergeFlags = []); override;
  466. published
  467. property Value: TPasJSONUTF8String read fValue write fValue;
  468. end;
  469. TPasJSONItemObjectProperty = class
  470. private
  471. fKey: TPasJSONUTF8String;
  472. fValue: TPasJSONItem;
  473. public
  474. constructor Create; reintroduce;
  475. destructor Destroy; override;
  476. published
  477. property Key: TPasJSONUTF8String read fKey write fKey;
  478. property Value: TPasJSONItem read fValue write fValue;
  479. end;
  480. TPasJSONItemObjectProperties = array of TPasJSONItemObjectProperty;
  481. TPasJSONItemObject = class(TPasJSONItem)
  482. public type
  483. PPasJSONItemObjectEnumerator = ^TPasJSONItemObjectEnumerator;
  484. TPasJSONItemObjectEnumerator = record
  485. private
  486. fOwner: TPasJSONItemObject;
  487. fIndex: TPasJSONSizeInt;
  488. function GetCurrent: TPasJSONItemObjectProperty; inline;
  489. public
  490. constructor Create(const aOwner: TPasJSONItemObject);
  491. function MoveNext: boolean; inline;
  492. property Current: TPasJSONItemObjectProperty read GetCurrent;
  493. end;
  494. private
  495. fProperties: TPasJSONItemObjectProperties;
  496. fCount: TPasJSONSizeInt;
  497. function GetKeyIndex(const aKey: TPasJSONUTF8String): TPasJSONInt32;
  498. function GetKey(const aIndex: TPasJSONSizeInt): TPasJSONUTF8String;
  499. procedure SetKey(const aIndex: TPasJSONSizeInt;
  500. const aKey: TPasJSONUTF8String);
  501. function GetValue(const aIndex: TPasJSONSizeInt): TPasJSONItem;
  502. procedure SetValue(const aIndex: TPasJSONSizeInt;
  503. const aItem: TPasJSONItem);
  504. function GetProperty(const aKey: TPasJSONUTF8String): TPasJSONItem;
  505. procedure SetProperty(const aKey: TPasJSONUTF8String;
  506. const aItem: TPasJSONItem);
  507. public
  508. constructor Create;
  509. destructor Destroy; override;
  510. function GetEnumerator: TPasJSONItemObjectEnumerator; inline;
  511. procedure Clear;
  512. procedure Add(const aKey: TPasJSONUTF8String; const AValue: TPasJSONItem);
  513. procedure Delete(const aIndex: TPasJSONSizeInt); overload;
  514. procedure Delete(const aKey: TPasJSONUTF8String); overload;
  515. procedure Merge(const aWith: TPasJSONItem;
  516. const aFlags: TPasJSONMergeFlags = []); override;
  517. property Count: TPasJSONSizeInt read fCount;
  518. property Indices[const Key: TPasJSONUTF8String]: TPasJSONInt32
  519. read GetKeyIndex;
  520. property Keys[const Index: TPasJSONSizeInt]: TPasJSONUTF8String read GetKey
  521. write SetKey;
  522. property Values[const Index: TPasJSONSizeInt]: TPasJSONItem read GetValue
  523. write SetValue;
  524. property Properties[const Key: TPasJSONUTF8String]: TPasJSONItem
  525. read GetProperty write SetProperty; default;
  526. end;
  527. TPasJSONItemArray = class(TPasJSONItem)
  528. public type
  529. PPasJSONItemArrayEnumerator = ^TPasJSONItemArrayEnumerator;
  530. TPasJSONItemArrayEnumerator = record
  531. private
  532. fOwner: TPasJSONItemArray;
  533. fIndex: TPasJSONSizeInt;
  534. function GetCurrent: TPasJSONItem; inline;
  535. public
  536. constructor Create(const aOwner: TPasJSONItemArray);
  537. function MoveNext: boolean; inline;
  538. property Current: TPasJSONItem read GetCurrent;
  539. end;
  540. private
  541. fItems: TPasJSONItems;
  542. fCount: TPasJSONInt32;
  543. function GetValue(const Index: TPasJSONInt32): TPasJSONItem;
  544. procedure SetValue(const Index: TPasJSONInt32; const Item: TPasJSONItem);
  545. public
  546. constructor Create;
  547. destructor Destroy; override;
  548. function GetEnumerator: TPasJSONItemArrayEnumerator; inline;
  549. procedure Clear;
  550. procedure Add(const AValue: TPasJSONItem);
  551. procedure Delete(const aIndex: TPasJSONSizeInt);
  552. procedure Merge(const aWith: TPasJSONItem;
  553. const aFlags: TPasJSONMergeFlags = []); override;
  554. property Count: TPasJSONInt32 read fCount;
  555. property Items[const Index: TPasJSONInt32]: TPasJSONItem read GetValue
  556. write SetValue; default;
  557. end;
  558. PPasJSONModeFlag = ^TPasJSONModeFlag;
  559. TPasJSONModeFlag = (UnquotedKeys, Comments, ImplicitRootObject,
  560. OptionalCommas, EqualsForColon, MultilineStrings, HexadecimalNumbers);
  561. PPasJSONModeFlags = ^TPasJSONModeFlag;
  562. TPasJSONModeFlags = set of TPasJSONModeFlag;
  563. PPasJSONEncoding = ^TPasJSONEncoding;
  564. TPasJSONEncoding = (AutomaticDetection, Latin1, UTF8, UTF16LE, UTF16BE,
  565. UTF32LE, UTF32BE);
  566. TPasJSON = class
  567. public
  568. // Simplified JSON notation as in http://bitsquid.blogspot.de/2009/10/simplified-json-notation.html
  569. const
  570. SimplifiedJSONModeFlags: TPasJSONModeFlags = [TPasJSONModeFlag.UnquotedKeys,
  571. TPasJSONModeFlag.Comments, TPasJSONModeFlag.ImplicitRootObject,
  572. TPasJSONModeFlag.OptionalCommas, TPasJSONModeFlag.EqualsForColon,
  573. TPasJSONModeFlag.MultilineStrings];
  574. public
  575. class function StringQuote(const aString: TPasJSONUTF8String)
  576. : TPasJSONRawByteString; static;
  577. class function Parse(const aSource: TPasJSONRawByteString;
  578. const aModeFlags: TPasJSONModeFlags = [TPasJSONModeFlag.Comments];
  579. const aEncoding: TPasJSONEncoding = TPasJSONEncoding.AutomaticDetection)
  580. : TPasJSONItem; overload; static;
  581. class function Parse(const aStream: TStream;
  582. const aModeFlags: TPasJSONModeFlags = [TPasJSONModeFlag.Comments];
  583. const aEncoding: TPasJSONEncoding = TPasJSONEncoding.AutomaticDetection)
  584. : TPasJSONItem; overload; static;
  585. class function Stringify(const aJSONItem: TPasJSONItem;
  586. const aFormatting: boolean = false;
  587. const aModeFlags: TPasJSONModeFlags = []; const aLevel: TPasJSONInt32 = 0)
  588. : TPasJSONRawByteString; static;
  589. class procedure StringifyToStream(const aStream: TStream;
  590. const aJSONItem: TPasJSONItem; const aFormatting: boolean = false;
  591. const aModeFlags: TPasJSONModeFlags = [];
  592. const aLevel: TPasJSONInt32 = 0); static;
  593. class function GetNumber(const aItem: TPasJSONItem;
  594. const aDefault: TPasJSONDouble = 0.0): TPasJSONDouble; static;
  595. class function GetInt64(const aItem: TPasJSONItem;
  596. const aDefault: TPasJSONInt64 = 0): TPasJSONInt64; static;
  597. class function GetString(const aItem: TPasJSONItem;
  598. const aDefault: TPasJSONUTF8String = ''): TPasJSONUTF8String; static;
  599. class function GetBoolean(const aItem: TPasJSONItem;
  600. const aDefault: boolean = false): boolean; static;
  601. class function LoadBinaryFromStream(const aStream: TStream)
  602. : TPasJSONItem; static;
  603. class procedure SaveBinaryToStream(const aStream: TStream;
  604. const aJSONItem: TPasJSONItem); static;
  605. end;
  606. implementation
  607. uses
  608. PasDblStrUtils;
  609. // 0 1 2 3 4 5 6 7 8 9 a b c d e f
  610. const { UTF8CharSteps:array[AnsiChar] of byte=(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0
  611. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 1
  612. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 2
  613. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 3
  614. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 4
  615. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 5
  616. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 6
  617. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 7
  618. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 8
  619. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 9
  620. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // a
  621. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // b
  622. 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c
  623. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // d
  624. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // e
  625. 4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1); // f
  626. //0 1 2 3 4 5 6 7 8 9 a b c d e f }
  627. UTF8DFACharClasses: array [AnsiChar] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  628. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  629. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  630. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  631. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  632. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
  633. 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
  634. 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  635. 7, 7, 7, 7, 7, 7, 7, 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  636. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  637. 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8);
  638. UTF8DFATransitions: array [byte] of byte = (0, 16, 32, 48, 80, 128, 112, 16,
  639. 16, 16, 64, 96, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  640. 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 0, 16, 0, 16, 16, 16, 16, 16,
  641. 16, 16, 32, 16, 16, 16, 16, 16, 32, 16, 32, 16, 16, 16, 16, 16, 16, 16, 16,
  642. 16, 16, 16, 16, 16, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 32, 16, 16, 16,
  643. 16, 16, 16, 16, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 48,
  644. 16, 48, 16, 16, 16, 16, 16, 16, 16, 48, 16, 16, 16, 16, 16, 48, 16, 48, 16,
  645. 16, 16, 16, 16, 16, 16, 48, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  646. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  647. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  648. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  649. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  650. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
  651. 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16);
  652. suDONOTKNOW = -1;
  653. suNOUTF8 = 0;
  654. suPOSSIBLEUTF8 = 1;
  655. suISUTF8 = 2;
  656. ucACCEPT = 0;
  657. ucERROR = 16;
  658. function GetNextUTF8Char(const aString: PPasJSONRawByteChar;
  659. const aStringLength: TPasJSONInt32; var aCodeUnit: TPasJSONInt32)
  660. : TPasJSONUInt32;
  661. var
  662. StartCodeUnit, Value, CharClass, State: TPasJSONUInt32;
  663. begin
  664. result := 0;
  665. if (aCodeUnit > 0) and (aCodeUnit <= aStringLength) then
  666. begin
  667. dec(aCodeUnit);
  668. StartCodeUnit := aCodeUnit;
  669. State := ucACCEPT;
  670. while aCodeUnit < aStringLength do
  671. begin
  672. Value := byte(AnsiChar(aString[aCodeUnit]));
  673. inc(aCodeUnit);
  674. CharClass := UTF8DFACharClasses[AnsiChar(Value)];
  675. if State = ucACCEPT then
  676. begin
  677. result := Value and ($FF shr CharClass);
  678. end
  679. else
  680. begin
  681. result := (result shl 6) or (Value and $3F);
  682. end;
  683. State := UTF8DFATransitions[State + CharClass];
  684. if State <= ucERROR then
  685. begin
  686. break;
  687. end;
  688. end;
  689. if State <> ucACCEPT then
  690. begin
  691. result := byte(AnsiChar(aString[StartCodeUnit]));
  692. aCodeUnit := StartCodeUnit + 1;
  693. end;
  694. inc(aCodeUnit);
  695. end;
  696. end;
  697. function ConvertUTF16ToUTF8(const aUTF16String: TPasJSONUTF16String)
  698. : TPasJSONUTF8String;
  699. var
  700. i, j: TPasJSONInt32;
  701. w: UInt16;
  702. u4c: TPasJSONUInt32;
  703. begin
  704. result := '';
  705. j := 0;
  706. i := 1;
  707. while i <= length(aUTF16String) do
  708. begin
  709. w := UInt16(TPasJSONUTF16Char(aUTF16String[i]));
  710. if (w <= $D7FF) or (w >= $E000) then
  711. begin
  712. u4c := w;
  713. inc(i);
  714. end
  715. else if ((i + 1) <= length(aUTF16String)) and ((w >= $D800) and (w <= $DBFF)
  716. ) and ((UInt16(aUTF16String[i + 1]) >= $DC00) and
  717. (UInt16(aUTF16String[i + 1]) <= $DFFF)) then
  718. begin
  719. u4c := (TPasJSONUInt32(TPasJSONUInt32(w and $3FF) shl 10) or
  720. TPasJSONUInt32(UInt16(TPasJSONUTF16Char(aUTF16String[i + 1])) and $3FF)
  721. ) + $10000;
  722. inc(i, 2);
  723. end
  724. else
  725. begin
  726. u4c := $FFFD;
  727. inc(i);
  728. end;
  729. if u4c <= $7F then
  730. begin
  731. inc(j);
  732. end
  733. else if u4c <= $7FF then
  734. begin
  735. inc(j, 2);
  736. end
  737. else if u4c <= $FFFF then
  738. begin
  739. inc(j, 3);
  740. end
  741. else if u4c <= $1FFFFF then
  742. begin
  743. inc(j, 4);
  744. end
  745. else
  746. begin
  747. inc(j, 3);
  748. end;
  749. end;
  750. SetLength(result, j);
  751. j := 1;
  752. i := 1;
  753. while i <= length(aUTF16String) do
  754. begin
  755. w := UInt16(TPasJSONUTF16Char(aUTF16String[i]));
  756. if (w <= $D7FF) or (w >= $E000) then
  757. begin
  758. u4c := w;
  759. inc(i);
  760. end
  761. else if ((i + 1) <= length(aUTF16String)) and ((w >= $D800) and (w <= $DBFF)
  762. ) and ((UInt16(aUTF16String[i + 1]) >= $DC00) and
  763. (UInt16(aUTF16String[i + 1]) <= $DFFF)) then
  764. begin
  765. u4c := (TPasJSONUInt32(TPasJSONUInt32(w and $3FF) shl 10) or
  766. TPasJSONUInt32(UInt16(TPasJSONUTF16Char(aUTF16String[i + 1])) and $3FF)
  767. ) + $10000;
  768. inc(i, 2);
  769. end
  770. else
  771. begin
  772. u4c := $FFFD;
  773. inc(i);
  774. end;
  775. if u4c <= $7F then
  776. begin
  777. result[j] := AnsiChar(byte(u4c));
  778. inc(j);
  779. end
  780. else if u4c <= $7FF then
  781. begin
  782. result[j] := AnsiChar(byte($C0 or ((u4c shr 6) and $1F)));
  783. result[j + 1] := AnsiChar(byte($80 or (u4c and $3F)));
  784. inc(j, 2);
  785. end
  786. else if u4c <= $FFFF then
  787. begin
  788. result[j] := AnsiChar(byte($E0 or ((u4c shr 12) and $0F)));
  789. result[j + 1] := AnsiChar(byte($80 or ((u4c shr 6) and $3F)));
  790. result[j + 2] := AnsiChar(byte($80 or (u4c and $3F)));
  791. inc(j, 3);
  792. end
  793. else if u4c <= $1FFFFF then
  794. begin
  795. result[j] := AnsiChar(byte($F0 or ((u4c shr 18) and $07)));
  796. result[j + 1] := AnsiChar(byte($80 or ((u4c shr 12) and $3F)));
  797. result[j + 2] := AnsiChar(byte($80 or ((u4c shr 6) and $3F)));
  798. result[j + 3] := AnsiChar(byte($80 or (u4c and $3F)));
  799. inc(j, 4);
  800. end
  801. else
  802. begin
  803. u4c := $FFFD;
  804. result[j] := AnsiChar(byte($E0 or (u4c shr 12)));
  805. result[j + 1] := AnsiChar(byte($80 or ((u4c shr 6) and $3F)));
  806. result[j + 2] := AnsiChar(byte($80 or (u4c and $3F)));
  807. inc(j, 3);
  808. end;
  809. end;
  810. end;
  811. constructor EPasJSONSyntaxError.Create(const aMessage: string;
  812. const aPosition: TPasJSONSizeInt);
  813. begin
  814. inherited Create(aMessage);
  815. fPosition := aPosition;
  816. end;
  817. constructor TPasJSONItem.Create;
  818. begin
  819. inherited Create;
  820. end;
  821. destructor TPasJSONItem.Destroy;
  822. begin
  823. inherited Destroy;
  824. end;
  825. procedure TPasJSONItem.Merge(const aWith: TPasJSONItem;
  826. const aFlags: TPasJSONMergeFlags = []);
  827. begin
  828. if not(assigned(aWith) and (aWith is TPasJSONItem)) then
  829. begin
  830. raise EPasJSONMergeError.Create('Incompatible data type');
  831. end;
  832. end;
  833. constructor TPasJSONItemNull.Create;
  834. begin
  835. inherited Create;
  836. end;
  837. destructor TPasJSONItemNull.Destroy;
  838. begin
  839. inherited Destroy;
  840. end;
  841. procedure TPasJSONItemNull.Merge(const aWith: TPasJSONItem;
  842. const aFlags: TPasJSONMergeFlags = []);
  843. begin
  844. if not(assigned(aWith) and (aWith is TPasJSONItemNull)) then
  845. begin
  846. raise EPasJSONMergeError.Create('Incompatible data type');
  847. end;
  848. end;
  849. constructor TPasJSONItemBoolean.Create(const AValue: boolean);
  850. begin
  851. inherited Create;
  852. fValue := AValue;
  853. end;
  854. destructor TPasJSONItemBoolean.Destroy;
  855. begin
  856. inherited Destroy;
  857. end;
  858. procedure TPasJSONItemBoolean.Merge(const aWith: TPasJSONItem;
  859. const aFlags: TPasJSONMergeFlags = []);
  860. begin
  861. if not(assigned(aWith) and (aWith is TPasJSONItemBoolean)) then
  862. begin
  863. raise EPasJSONMergeError.Create('Incompatible data type');
  864. end;
  865. fValue := TPasJSONItemBoolean(aWith).Value;
  866. end;
  867. constructor TPasJSONItemNumber.Create(const AValue: TPasJSONDouble);
  868. begin
  869. inherited Create;
  870. fValue := AValue;
  871. end;
  872. destructor TPasJSONItemNumber.Destroy;
  873. begin
  874. inherited Destroy;
  875. end;
  876. procedure TPasJSONItemNumber.Merge(const aWith: TPasJSONItem;
  877. const aFlags: TPasJSONMergeFlags = []);
  878. begin
  879. if not(assigned(aWith) and (aWith is TPasJSONItemNumber)) then
  880. begin
  881. raise EPasJSONMergeError.Create('Incompatible data type');
  882. end;
  883. fValue := TPasJSONItemNumber(aWith).Value;
  884. end;
  885. constructor TPasJSONItemString.Create(const AValue: TPasJSONUTF8String);
  886. begin
  887. inherited Create;
  888. fValue := AValue;
  889. end;
  890. destructor TPasJSONItemString.Destroy;
  891. begin
  892. fValue := '';
  893. inherited Destroy;
  894. end;
  895. procedure TPasJSONItemString.Merge(const aWith: TPasJSONItem;
  896. const aFlags: TPasJSONMergeFlags = []);
  897. begin
  898. if not(assigned(aWith) and (aWith is TPasJSONItemString)) then
  899. begin
  900. raise EPasJSONMergeError.Create('Incompatible data type');
  901. end;
  902. fValue := TPasJSONItemString(aWith).Value;
  903. end;
  904. constructor TPasJSONItemObjectProperty.Create;
  905. begin
  906. inherited Create;
  907. fKey := '';
  908. fValue := nil;
  909. end;
  910. destructor TPasJSONItemObjectProperty.Destroy;
  911. begin
  912. fKey := '';
  913. FreeAndNil(fValue);
  914. inherited Destroy;
  915. end;
  916. constructor TPasJSONItemObject.TPasJSONItemObjectEnumerator.Create
  917. (const aOwner: TPasJSONItemObject);
  918. begin
  919. fOwner := aOwner;
  920. fIndex := -1;
  921. end;
  922. function TPasJSONItemObject.TPasJSONItemObjectEnumerator.MoveNext: boolean;
  923. begin
  924. inc(fIndex);
  925. result := (fIndex >= 0) and (fIndex < fOwner.fCount);
  926. end;
  927. function TPasJSONItemObject.TPasJSONItemObjectEnumerator.GetCurrent
  928. : TPasJSONItemObjectProperty;
  929. begin
  930. result := fOwner.fProperties[fIndex];
  931. end;
  932. constructor TPasJSONItemObject.Create;
  933. begin
  934. inherited Create;
  935. fProperties := nil;
  936. fCount := 0;
  937. end;
  938. destructor TPasJSONItemObject.Destroy;
  939. var
  940. Index: TPasJSONInt32;
  941. begin
  942. for Index := 0 to fCount - 1 do
  943. begin
  944. FreeAndNil(fProperties[Index]);
  945. end;
  946. SetLength(fProperties, 0);
  947. inherited Destroy;
  948. end;
  949. function TPasJSONItemObject.GetKeyIndex(const aKey: TPasJSONUTF8String)
  950. : TPasJSONInt32;
  951. var
  952. Index: TPasJSONInt32;
  953. begin
  954. for Index := 0 to fCount - 1 do
  955. begin
  956. if fProperties[Index].Key = aKey then
  957. begin
  958. result := Index;
  959. exit;
  960. end;
  961. end;
  962. result := -1;
  963. end;
  964. function TPasJSONItemObject.GetKey(const aIndex: TPasJSONSizeInt)
  965. : TPasJSONUTF8String;
  966. begin
  967. if (aIndex >= 0) and (aIndex < fCount) then
  968. begin
  969. result := fProperties[aIndex].Key;
  970. end
  971. else
  972. begin
  973. result := '';
  974. end;
  975. end;
  976. procedure TPasJSONItemObject.SetKey(const aIndex: TPasJSONSizeInt;
  977. const aKey: TPasJSONUTF8String);
  978. begin
  979. if (aIndex >= 0) and (aIndex < fCount) then
  980. begin
  981. fProperties[aIndex].Key := aKey;
  982. end;
  983. end;
  984. function TPasJSONItemObject.GetValue(const aIndex: TPasJSONSizeInt)
  985. : TPasJSONItem;
  986. begin
  987. if (aIndex >= 0) and (aIndex < fCount) then
  988. begin
  989. result := fProperties[aIndex].Value;
  990. end
  991. else
  992. begin
  993. result := nil;
  994. end;
  995. end;
  996. procedure TPasJSONItemObject.SetValue(const aIndex: TPasJSONSizeInt;
  997. const aItem: TPasJSONItem);
  998. begin
  999. if (aIndex >= 0) and (aIndex < fCount) then
  1000. begin
  1001. fProperties[aIndex].Value := aItem;
  1002. end;
  1003. end;
  1004. function TPasJSONItemObject.GetProperty(const aKey: TPasJSONUTF8String)
  1005. : TPasJSONItem;
  1006. begin
  1007. result := GetValue(GetKeyIndex(aKey));
  1008. end;
  1009. procedure TPasJSONItemObject.SetProperty(const aKey: TPasJSONUTF8String;
  1010. const aItem: TPasJSONItem);
  1011. begin
  1012. SetValue(GetKeyIndex(aKey), aItem);
  1013. end;
  1014. function TPasJSONItemObject.GetEnumerator
  1015. : TPasJSONItemObject.TPasJSONItemObjectEnumerator;
  1016. begin
  1017. result := TPasJSONItemObject.TPasJSONItemObjectEnumerator.Create(self);
  1018. end;
  1019. procedure TPasJSONItemObject.Clear;
  1020. var
  1021. Index: TPasJSONInt32;
  1022. begin
  1023. for Index := 0 to fCount - 1 do
  1024. begin
  1025. FreeAndNil(fProperties[Index]);
  1026. end;
  1027. SetLength(fProperties, 0);
  1028. fCount := 0;
  1029. end;
  1030. procedure TPasJSONItemObject.Add(const aKey: TPasJSONUTF8String;
  1031. const AValue: TPasJSONItem);
  1032. var
  1033. Index: TPasJSONSizeInt;
  1034. ObjectProperty: TPasJSONItemObjectProperty;
  1035. begin
  1036. Index := fCount;
  1037. inc(fCount);
  1038. if fCount >= length(fProperties) then
  1039. begin
  1040. SetLength(fProperties, fCount * 2);
  1041. end;
  1042. ObjectProperty := TPasJSONItemObjectProperty.Create;
  1043. fProperties[Index] := ObjectProperty;
  1044. ObjectProperty.Key := aKey;
  1045. ObjectProperty.Value := AValue;
  1046. end;
  1047. procedure TPasJSONItemObject.Delete(const aIndex: TPasJSONSizeInt);
  1048. begin
  1049. if (aIndex >= 0) and (aIndex < fCount) then
  1050. begin
  1051. FreeAndNil(fProperties[aIndex]);
  1052. dec(fCount);
  1053. Move(fProperties[aIndex + 1], fProperties[aIndex],
  1054. fCount * SizeOf(TPasJSONItemObjectProperty));
  1055. end;
  1056. end;
  1057. procedure TPasJSONItemObject.Delete(const aKey: TPasJSONUTF8String);
  1058. begin
  1059. Delete(GetKeyIndex(aKey));
  1060. end;
  1061. procedure TPasJSONItemObject.Merge(const aWith: TPasJSONItem;
  1062. const aFlags: TPasJSONMergeFlags = []);
  1063. var
  1064. Index, KeyIndex: TPasJSONSizeInt;
  1065. SrcProperty, OurProperty: TPasJSONItemObjectProperty;
  1066. NewItem: TPasJSONItem;
  1067. begin
  1068. if not(assigned(aWith) and (aWith is TPasJSONItemObject)) then
  1069. begin
  1070. raise EPasJSONMergeError.Create('Incompatible data type');
  1071. end;
  1072. for Index := 0 to TPasJSONItemObject(aWith).Count - 1 do
  1073. begin
  1074. SrcProperty := TPasJSONItemObject(aWith).fProperties[Index];
  1075. if assigned(SrcProperty.Value) then
  1076. begin
  1077. KeyIndex := GetKeyIndex(SrcProperty.Key);
  1078. if KeyIndex >= 0 then
  1079. begin
  1080. OurProperty := fProperties[KeyIndex];
  1081. if (TPasJSONMergeFlag.ForceObjectPropertyValueDestinationType in aFlags)
  1082. and ((not assigned(OurProperty.Value)) or
  1083. (assigned(OurProperty.Value) and (OurProperty.Value.ClassType <>
  1084. SrcProperty.Value.ClassType))) then
  1085. begin
  1086. if assigned(OurProperty.Value) then
  1087. begin
  1088. OurProperty.Value.Free;
  1089. end;
  1090. OurProperty.Value := TPasJSONItem(SrcProperty.Value.ClassType.Create);
  1091. end;
  1092. if assigned(OurProperty.Value) and
  1093. (OurProperty.Value.ClassType = SrcProperty.Value.ClassType) then
  1094. begin
  1095. OurProperty.Value.Merge(SrcProperty.Value, aFlags);
  1096. end;
  1097. end
  1098. else
  1099. begin
  1100. NewItem := nil;
  1101. try
  1102. NewItem := TPasJSONItem(SrcProperty.Value.ClassType.Create);
  1103. NewItem.Merge(SrcProperty.Value, aFlags);
  1104. Add(SrcProperty.Key, NewItem);
  1105. except
  1106. NewItem.Free;
  1107. raise;
  1108. end;
  1109. end;
  1110. end;
  1111. end;
  1112. end;
  1113. constructor TPasJSONItemArray.TPasJSONItemArrayEnumerator.Create
  1114. (const aOwner: TPasJSONItemArray);
  1115. begin
  1116. fOwner := aOwner;
  1117. fIndex := -1;
  1118. end;
  1119. function TPasJSONItemArray.TPasJSONItemArrayEnumerator.MoveNext: boolean;
  1120. begin
  1121. inc(fIndex);
  1122. result := (fIndex >= 0) and (fIndex < fOwner.fCount);
  1123. end;
  1124. function TPasJSONItemArray.TPasJSONItemArrayEnumerator.GetCurrent: TPasJSONItem;
  1125. begin
  1126. result := fOwner.fItems[fIndex];
  1127. end;
  1128. constructor TPasJSONItemArray.Create;
  1129. begin
  1130. inherited Create;
  1131. fItems := nil;
  1132. fCount := 0;
  1133. end;
  1134. destructor TPasJSONItemArray.Destroy;
  1135. var
  1136. Index: TPasJSONInt32;
  1137. begin
  1138. for Index := 0 to fCount - 1 do
  1139. begin
  1140. FreeAndNil(fItems[Index]);
  1141. end;
  1142. SetLength(fItems, 0);
  1143. inherited Destroy;
  1144. end;
  1145. function TPasJSONItemArray.GetValue(const Index: TPasJSONInt32): TPasJSONItem;
  1146. begin
  1147. if (Index >= 0) and (Index < fCount) then
  1148. begin
  1149. result := fItems[Index];
  1150. end
  1151. else
  1152. begin
  1153. result := nil;
  1154. end;
  1155. end;
  1156. procedure TPasJSONItemArray.SetValue(const Index: TPasJSONInt32;
  1157. const Item: TPasJSONItem);
  1158. begin
  1159. if (Index >= 0) and (Index < fCount) then
  1160. begin
  1161. fItems[Index] := Item;
  1162. end;
  1163. end;
  1164. function TPasJSONItemArray.GetEnumerator
  1165. : TPasJSONItemArray.TPasJSONItemArrayEnumerator;
  1166. begin
  1167. result := TPasJSONItemArray.TPasJSONItemArrayEnumerator.Create(self);
  1168. end;
  1169. procedure TPasJSONItemArray.Clear;
  1170. var
  1171. Index: TPasJSONInt32;
  1172. begin
  1173. for Index := 0 to fCount - 1 do
  1174. begin
  1175. FreeAndNil(fItems[Index]);
  1176. end;
  1177. SetLength(fItems, 0);
  1178. fCount := 0;
  1179. end;
  1180. procedure TPasJSONItemArray.Add(const AValue: TPasJSONItem);
  1181. var
  1182. Index: TPasJSONSizeInt;
  1183. begin
  1184. Index := fCount;
  1185. inc(fCount);
  1186. if fCount >= length(fItems) then
  1187. begin
  1188. SetLength(fItems, fCount * 2);
  1189. end;
  1190. fItems[Index] := AValue;
  1191. end;
  1192. procedure TPasJSONItemArray.Delete(const aIndex: TPasJSONSizeInt);
  1193. begin
  1194. if (aIndex >= 0) and (aIndex < fCount) then
  1195. begin
  1196. FreeAndNil(fItems[aIndex]);
  1197. dec(fCount);
  1198. Move(fItems[aIndex + 1], fItems[aIndex], fCount * SizeOf(TPasJSONItem));
  1199. end;
  1200. end;
  1201. procedure TPasJSONItemArray.Merge(const aWith: TPasJSONItem;
  1202. const aFlags: TPasJSONMergeFlags = []);
  1203. var
  1204. Index: TPasJSONSizeInt;
  1205. Item, NewItem: TPasJSONItem;
  1206. begin
  1207. if not(assigned(aWith) and (aWith is TPasJSONItemArray)) then
  1208. begin
  1209. raise EPasJSONMergeError.Create('Incompatible data type');
  1210. end;
  1211. for Index := 0 to TPasJSONItemArray(aWith).Count - 1 do
  1212. begin
  1213. Item := TPasJSONItemArray(aWith).Items[Index];
  1214. if assigned(Item) then
  1215. begin
  1216. NewItem := TPasJSONItem(Item.ClassType.Create);
  1217. Add(NewItem);
  1218. NewItem.Merge(Item, aFlags);
  1219. end;
  1220. end;
  1221. end;
  1222. const
  1223. HexChars: array [boolean, 0 .. 15] of AnsiChar = (('0', '1', '2', '3', '4',
  1224. '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'),
  1225. ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
  1226. 'E', 'F'));
  1227. class function TPasJSON.StringQuote(const aString: TPasJSONUTF8String)
  1228. : TPasJSONRawByteString;
  1229. var
  1230. i, l: TPasJSONInt32;
  1231. c, t: TPasJSONUInt32;
  1232. begin
  1233. result := '"';
  1234. i := 1;
  1235. l := length(aString);
  1236. while i <= l do
  1237. begin
  1238. case aString[i] of
  1239. '"', '\':
  1240. begin
  1241. result := result + '\' + AnsiChar(aString[i]);
  1242. inc(i);
  1243. end;
  1244. #$08:
  1245. begin
  1246. result := result + '\b';
  1247. inc(i);
  1248. end;
  1249. #$09:
  1250. begin
  1251. result := result + '\t';
  1252. inc(i);
  1253. end;
  1254. #$0a:
  1255. begin
  1256. result := result + '\n';
  1257. inc(i);
  1258. end;
  1259. #$0b:
  1260. begin
  1261. result := result + '\v';
  1262. inc(i);
  1263. end;
  1264. #$0c:
  1265. begin
  1266. result := result + '\f';
  1267. inc(i);
  1268. end;
  1269. #$0d:
  1270. begin
  1271. result := result + '\r';
  1272. inc(i);
  1273. end;
  1274. #$00 .. #$07, #$0e .. #$1f, #$7e .. #$7f:
  1275. begin
  1276. c := byte(AnsiChar(aString[i]));
  1277. result := result + '\u00' + HexChars[false, (c shr 4) and $F] +
  1278. HexChars[false, c and $F];
  1279. inc(i);
  1280. end;
  1281. #$80 .. #$ff:
  1282. begin
  1283. c := GetNextUTF8Char(PAnsiChar(@aString[1]), l, i);
  1284. case c of
  1285. $0000 .. $D7FF, $F000 .. $FFFC:
  1286. begin
  1287. result := result + '\u' + HexChars[false, (c shr 12) and $F] +
  1288. HexChars[false, (c shr 8) and $F] + HexChars
  1289. [false, (c shr 4) and $F] + HexChars[false, c and $F];
  1290. end;
  1291. $100000 .. $10FFFF:
  1292. begin
  1293. dec(c, $100000);
  1294. t := (c shr 10) or $D800;
  1295. result := result + '\u' + HexChars[false, (t shr 12) and $F] +
  1296. HexChars[false, (t shr 8) and $F] + HexChars
  1297. [false, (t shr 4) and $F] + HexChars[false, t and $F];
  1298. t := (c and $3FF) or $DC00;
  1299. result := result + '\u' + HexChars[false, (t shr 12) and $F] +
  1300. HexChars[false, (t shr 8) and $F] + HexChars
  1301. [false, (t shr 4) and $F] + HexChars[false, t and $F];
  1302. end;
  1303. else { -$d800..$dfff,$fffd..$ffff,$110000..$ffffffff: }
  1304. begin
  1305. result := result + '\ufffd';
  1306. end;
  1307. end;
  1308. end;
  1309. else
  1310. begin
  1311. result := result + AnsiChar(aString[i]);
  1312. inc(i);
  1313. end;
  1314. end;
  1315. end;
  1316. result := result + '"';
  1317. end;
  1318. class function TPasJSON.Parse(const aSource: TPasJSONRawByteString;
  1319. const aModeFlags: TPasJSONModeFlags = [TPasJSONModeFlag.Comments];
  1320. const aEncoding: TPasJSONEncoding = TPasJSONEncoding.AutomaticDetection)
  1321. : TPasJSONItem;
  1322. var
  1323. Position: TPasJSONInt32;
  1324. CurrentChar: TPasJSONUInt32;
  1325. CharEOF: boolean;
  1326. Encoding: TPasJSONEncoding;
  1327. procedure NextChar;
  1328. const
  1329. UTF16Shifts: array [TPasJSONEncoding.UTF16LE .. TPasJSONEncoding.UTF16BE,
  1330. 0 .. 1] of TPasJSONInt32 = ((0, 8), (8, 0));
  1331. var
  1332. Temp: TPasJSONUInt32;
  1333. begin
  1334. if Position <= length(aSource) then
  1335. begin
  1336. case Encoding of
  1337. TPasJSONEncoding.UTF8:
  1338. begin
  1339. CurrentChar := GetNextUTF8Char(PAnsiChar(@aSource[1]),
  1340. length(aSource), Position);
  1341. end;
  1342. TPasJSONEncoding.UTF16LE, TPasJSONEncoding.UTF16BE:
  1343. begin
  1344. if (Position + 1) <= length(aSource) then
  1345. begin
  1346. CurrentChar := (TPasJSONUInt32(byte(AnsiChar(aSource[Position])))
  1347. shl UTF16Shifts[Encoding, 0]) or
  1348. (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 1])))
  1349. shl UTF16Shifts[Encoding, 1]);
  1350. inc(Position, 2);
  1351. if ((CurrentChar >= $D800) and (CurrentChar <= $DBFF)) and
  1352. ((Position + 1) <= length(aSource)) then
  1353. begin
  1354. Temp := (TPasJSONUInt32(byte(AnsiChar(aSource[Position])))
  1355. shl UTF16Shifts[Encoding, 0]) or
  1356. (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 1])))
  1357. shl UTF16Shifts[Encoding, 1]);
  1358. if (Temp >= $DC00) and (Temp <= $DFFF) then
  1359. begin
  1360. CurrentChar :=
  1361. (TPasJSONUInt32(TPasJSONUInt32(CurrentChar and $3FF) shl 10)
  1362. or TPasJSONUInt32(Temp and $3FF)) + $10000;
  1363. inc(Position, 2);
  1364. end
  1365. else
  1366. begin
  1367. CurrentChar := $FFFD;
  1368. end;
  1369. end
  1370. else if not((CurrentChar <= $D7FF) or (CurrentChar >= $E000)) then
  1371. begin
  1372. CurrentChar := $FFFD;
  1373. end;
  1374. end
  1375. else
  1376. begin
  1377. inc(Position);
  1378. CurrentChar := 0;
  1379. CharEOF := true;
  1380. end;
  1381. end;
  1382. TPasJSONEncoding.UTF32LE:
  1383. begin
  1384. if (Position + 3) <= length(aSource) then
  1385. begin
  1386. CurrentChar := (TPasJSONUInt32(byte(AnsiChar(aSource[Position])))
  1387. shl 0) or (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 1])))
  1388. shl 8) or (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 2])))
  1389. shl 16) or
  1390. (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 3]))) shl 24);
  1391. inc(Position, 4);
  1392. end
  1393. else
  1394. begin
  1395. inc(Position);
  1396. CurrentChar := 0;
  1397. CharEOF := true;
  1398. end;
  1399. end;
  1400. TPasJSONEncoding.UTF32BE:
  1401. begin
  1402. if (Position + 3) <= length(aSource) then
  1403. begin
  1404. CurrentChar := (TPasJSONUInt32(byte(AnsiChar(aSource[Position])))
  1405. shl 24) or (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 1]))
  1406. ) shl 16) or
  1407. (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 2]))) shl 8) or
  1408. (TPasJSONUInt32(byte(AnsiChar(aSource[Position + 3]))) shl 0);
  1409. inc(Position, 4);
  1410. end
  1411. else
  1412. begin
  1413. inc(Position);
  1414. CurrentChar := 0;
  1415. CharEOF := true;
  1416. end;
  1417. end;
  1418. else
  1419. begin
  1420. CurrentChar := byte(AnsiChar(aSource[Position]));
  1421. inc(Position);
  1422. end;
  1423. end;
  1424. end
  1425. else
  1426. begin
  1427. CurrentChar := 0;
  1428. CharEOF := true;
  1429. end;
  1430. end;
  1431. procedure JSONError;
  1432. begin
  1433. raise EPasJSONSyntaxError.Create('Parser error at byte position ' +
  1434. IntToStr(Position), Position);
  1435. end;
  1436. procedure SkipWhite;
  1437. var
  1438. LastChar: TPasJSONUInt32;
  1439. begin
  1440. while not CharEOF do
  1441. begin
  1442. case CurrentChar of
  1443. $0009, $000A, $000D, $0020:
  1444. begin
  1445. NextChar;
  1446. end;
  1447. ord('/'):
  1448. begin
  1449. if TPasJSONModeFlag.Comments in aModeFlags then
  1450. begin
  1451. NextChar;
  1452. case CurrentChar of
  1453. ord('/'):
  1454. begin
  1455. NextChar;
  1456. while not(CharEOF or ((CurrentChar = $000A) or
  1457. (CurrentChar = $000D))) do
  1458. begin
  1459. NextChar;
  1460. end;
  1461. end;
  1462. ord('*'):
  1463. begin
  1464. NextChar;
  1465. LastChar := 0;
  1466. while not(CharEOF or ((LastChar = ord('*')) and
  1467. (CurrentChar = ord('/')))) do
  1468. begin
  1469. LastChar := CurrentChar;
  1470. NextChar;
  1471. end;
  1472. if CurrentChar = ord('/') then
  1473. begin
  1474. NextChar;
  1475. end;
  1476. end;
  1477. else
  1478. begin
  1479. JSONError;
  1480. end;
  1481. end;
  1482. end
  1483. else
  1484. begin
  1485. JSONError;
  1486. end;
  1487. end;
  1488. else
  1489. begin
  1490. break;
  1491. end;
  1492. end;
  1493. end;
  1494. end;
  1495. function IsChar(c: TPasJSONUTF16Char): boolean;
  1496. begin
  1497. result := (not CharEOF) and (CurrentChar = UInt16(c));
  1498. end;
  1499. procedure ExpectChar(c: TPasJSONUTF16Char);
  1500. begin
  1501. if IsChar(c) then
  1502. begin
  1503. NextChar;
  1504. end
  1505. else
  1506. begin
  1507. JSONError;
  1508. end;
  1509. end;
  1510. function ParseValue(const ImplicitRootObject: boolean): TPasJSONItem;
  1511. function ParseString: TPasJSONItem;
  1512. var
  1513. w: TPasJSONUTF16String;
  1514. // <= because of easy correct handling of UTF16 surrogates (see ECMAScript and JSON specs)
  1515. wl: TPasJSONInt32;
  1516. wc: TPasJSONUInt32;
  1517. procedure AddChar(c: TPasJSONUInt32);
  1518. var
  1519. cl: TPasJSONInt32;
  1520. begin
  1521. if (c >= $100000) and (c <= $10FFFF) then
  1522. begin
  1523. cl := 2;
  1524. end
  1525. else
  1526. begin
  1527. cl := 1;
  1528. end;
  1529. if (wl + cl) > length(w) then
  1530. begin
  1531. SetLength(w, (wl + cl) shl 1);
  1532. end;
  1533. if c <= $D7FF then
  1534. begin
  1535. inc(wl);
  1536. w[wl] := TPasJSONUTF16Char(UInt16(c));
  1537. end
  1538. else if c <= $DFFF then
  1539. begin
  1540. inc(wl);
  1541. w[wl] := TPasJSONUTF16Char(UInt16($FFFD));
  1542. end
  1543. else if c <= $FFFD then
  1544. begin
  1545. inc(wl);
  1546. w[wl] := TPasJSONUTF16Char(UInt16(c));
  1547. end
  1548. else if c <= $FFFF then
  1549. begin
  1550. inc(wl);
  1551. w[wl] := TPasJSONUTF16Char(UInt16($FFFD));
  1552. end
  1553. else if c <= $10FFFF then
  1554. begin
  1555. dec(c, $10000);
  1556. inc(wl);
  1557. w[wl] := TPasJSONUTF16Char(UInt16((c shr 10) or $D800));
  1558. inc(wl);
  1559. w[wl] := TPasJSONUTF16Char(UInt16((c and $3FF) or $DC00));
  1560. end
  1561. else
  1562. begin
  1563. inc(wl);
  1564. w[wl] := TPasJSONUTF16Char(UInt16($FFFD));
  1565. end;
  1566. end;
  1567. begin
  1568. result := nil;
  1569. w := '';
  1570. try
  1571. try
  1572. SetLength(w, 512);
  1573. wl := 0;
  1574. if IsChar('"') then
  1575. begin
  1576. NextChar;
  1577. while not(CharEOF or IsChar('"')) do
  1578. begin
  1579. case CurrentChar of
  1580. $0000 .. $001F:
  1581. begin
  1582. if TPasJSONModeFlag.MultilineStrings in aModeFlags then
  1583. begin
  1584. AddChar(CurrentChar);
  1585. NextChar;
  1586. end
  1587. else
  1588. begin
  1589. JSONError;
  1590. end;
  1591. end;
  1592. ord('\'):
  1593. begin
  1594. NextChar;
  1595. case CurrentChar of
  1596. ord('"'), ord('\'), ord('/'):
  1597. begin
  1598. AddChar(CurrentChar);
  1599. NextChar;
  1600. end;
  1601. ord('b'):
  1602. begin
  1603. AddChar($0008);
  1604. NextChar;
  1605. end;
  1606. ord('f'):
  1607. begin
  1608. AddChar($000C);
  1609. NextChar;
  1610. end;
  1611. ord('n'):
  1612. begin
  1613. AddChar($000A);
  1614. NextChar;
  1615. end;
  1616. ord('r'):
  1617. begin
  1618. AddChar($000D);
  1619. NextChar;
  1620. end;
  1621. ord('t'):
  1622. begin
  1623. AddChar($0009);
  1624. NextChar;
  1625. end;
  1626. ord('u'):
  1627. begin
  1628. NextChar;
  1629. if (((CurrentChar >= ord('0')) and
  1630. (CurrentChar <= ord('9'))) or
  1631. ((CurrentChar >= ord('a')) and
  1632. (CurrentChar <= ord('f'))) or
  1633. ((CurrentChar >= ord('A')) and
  1634. (CurrentChar <= ord('F')))) and not CharEOF then
  1635. begin
  1636. if (CurrentChar >= ord('0')) and
  1637. (CurrentChar <= ord('9')) then
  1638. begin
  1639. wc := UInt16(CurrentChar) - ord('0');
  1640. end
  1641. else if (CurrentChar >= ord('a')) and
  1642. (CurrentChar <= ord('f')) then
  1643. begin
  1644. wc := (UInt16(CurrentChar) - ord('a')) + $A;
  1645. end
  1646. else if (CurrentChar >= ord('A')) and
  1647. (CurrentChar <= ord('F')) then
  1648. begin
  1649. wc := (UInt16(CurrentChar) - ord('A')) + $A;
  1650. end
  1651. else
  1652. begin
  1653. wc := 0;
  1654. end;
  1655. wc := wc shl 4;
  1656. NextChar;
  1657. if (((CurrentChar >= ord('0')) and
  1658. (CurrentChar <= ord('9'))) or
  1659. ((CurrentChar >= ord('a')) and
  1660. (CurrentChar <= ord('f'))) or
  1661. ((CurrentChar >= ord('A')) and
  1662. (CurrentChar <= ord('F')))) and not CharEOF then
  1663. begin
  1664. if (CurrentChar >= ord('0')) and
  1665. (CurrentChar <= ord('9')) then
  1666. begin
  1667. wc := wc or
  1668. UInt16(UInt16(CurrentChar) - ord('0'));
  1669. end
  1670. else if (CurrentChar >= ord('a')) and
  1671. (CurrentChar <= ord('f')) then
  1672. begin
  1673. wc := wc or
  1674. UInt16((UInt16(CurrentChar) - ord('a')) + $A);
  1675. end
  1676. else if (CurrentChar >= ord('A')) and
  1677. (CurrentChar <= ord('F')) then
  1678. begin
  1679. wc := wc or
  1680. UInt16((UInt16(CurrentChar) - ord('A')) + $A);
  1681. end;
  1682. wc := wc shl 4;
  1683. NextChar;
  1684. if (((CurrentChar >= ord('0')) and
  1685. (CurrentChar <= ord('9'))) or
  1686. ((CurrentChar >= ord('a')) and
  1687. (CurrentChar <= ord('f'))) or
  1688. ((CurrentChar >= ord('A')) and
  1689. (CurrentChar <= ord('F')))) and not CharEOF then
  1690. begin
  1691. if (CurrentChar >= ord('0')) and
  1692. (CurrentChar <= ord('9')) then
  1693. begin
  1694. wc := wc or
  1695. UInt16(UInt16(CurrentChar) - ord('0'));
  1696. end
  1697. else if (CurrentChar >= ord('a')) and
  1698. (CurrentChar <= ord('f')) then
  1699. begin
  1700. wc := wc or
  1701. UInt16((UInt16(CurrentChar) -
  1702. ord('a')) + $A);
  1703. end
  1704. else if (CurrentChar >= ord('A')) and
  1705. (CurrentChar <= ord('F')) then
  1706. begin
  1707. wc := wc or
  1708. UInt16((UInt16(CurrentChar) -
  1709. ord('A')) + $A);
  1710. end;
  1711. wc := wc shl 4;
  1712. NextChar;
  1713. if (((CurrentChar >= ord('0')) and
  1714. (CurrentChar <= ord('9'))) or
  1715. ((CurrentChar >= ord('a')) and
  1716. (CurrentChar <= ord('f'))) or
  1717. ((CurrentChar >= ord('A')) and
  1718. (CurrentChar <= ord('F')))) and not CharEOF
  1719. then
  1720. begin
  1721. if (CurrentChar >= ord('0')) and
  1722. (CurrentChar <= ord('9')) then
  1723. begin
  1724. wc := wc or
  1725. UInt16(UInt16(CurrentChar) - ord('0'));
  1726. end
  1727. else if (CurrentChar >= ord('a')) and
  1728. (CurrentChar <= ord('f')) then
  1729. begin
  1730. wc := wc or
  1731. UInt16((UInt16(CurrentChar) -
  1732. ord('a')) + $A);
  1733. end
  1734. else if (CurrentChar >= ord('A')) and
  1735. (CurrentChar <= ord('F')) then
  1736. begin
  1737. wc := wc or
  1738. UInt16((UInt16(CurrentChar) -
  1739. ord('A')) + $A);
  1740. end;
  1741. AddChar(wc);
  1742. NextChar;
  1743. end
  1744. else
  1745. begin
  1746. JSONError;
  1747. end;
  1748. end
  1749. else
  1750. begin
  1751. JSONError;
  1752. end;
  1753. end
  1754. else
  1755. begin
  1756. JSONError;
  1757. end;
  1758. end
  1759. else
  1760. begin
  1761. JSONError;
  1762. end;
  1763. end;
  1764. else
  1765. begin
  1766. JSONError;
  1767. end;
  1768. end;
  1769. end;
  1770. else
  1771. begin
  1772. AddChar(CurrentChar);
  1773. NextChar;
  1774. end;
  1775. end;
  1776. end;
  1777. ExpectChar('"');
  1778. SetLength(w, wl);
  1779. result := TPasJSONItemString.Create(ConvertUTF16ToUTF8(w));
  1780. end
  1781. else
  1782. begin
  1783. JSONError;
  1784. end;
  1785. SkipWhite;
  1786. except
  1787. FreeAndNil(result);
  1788. raise;
  1789. end;
  1790. finally
  1791. w := '';
  1792. end;
  1793. end;
  1794. function ParseNumber: TPasJSONItem;
  1795. var
  1796. s: TPasJSONRawByteString;
  1797. OK: TPasDblStrUtilsBoolean;
  1798. Value: TPasJSONDouble;
  1799. IsHexadecimal: boolean;
  1800. begin
  1801. result := nil;
  1802. s := '';
  1803. try
  1804. try
  1805. if CharEOF then
  1806. begin
  1807. JSONError;
  1808. end;
  1809. case CurrentChar of
  1810. ord('-'), ord('0') .. ord('9'):
  1811. begin
  1812. if IsChar('-') then
  1813. begin
  1814. s := s + AnsiChar(byte(CurrentChar));
  1815. NextChar;
  1816. if CharEOF or not((CurrentChar >= ord('0')) and
  1817. (CurrentChar <= ord('9'))) then
  1818. begin
  1819. JSONError;
  1820. end;
  1821. end;
  1822. IsHexadecimal := false;
  1823. if (not CharEOF) and (CurrentChar = ord('0')) then
  1824. begin
  1825. s := s + AnsiChar(byte(CurrentChar));
  1826. NextChar;
  1827. if (TPasJSONModeFlag.HexadecimalNumbers in aModeFlags) and
  1828. ((not CharEOF) and (CurrentChar in [ord('x'), ord('X')]))
  1829. then
  1830. begin
  1831. s := s + AnsiChar(byte(CurrentChar));
  1832. NextChar;
  1833. while (not CharEOF) and
  1834. (((CurrentChar >= ord('0')) and (CurrentChar <= ord('9')))
  1835. or ((CurrentChar >= ord('a')) and (CurrentChar <= ord('f')
  1836. )) or ((CurrentChar >= ord('A')) and
  1837. (CurrentChar <= ord('F')))) do
  1838. begin
  1839. s := s + AnsiChar(byte(CurrentChar));
  1840. NextChar;
  1841. end;
  1842. IsHexadecimal := true;
  1843. end
  1844. else
  1845. begin
  1846. if (not CharEOF) and
  1847. ((CurrentChar >= ord('0')) and (CurrentChar <= ord('9')))
  1848. then
  1849. begin
  1850. JSONError;
  1851. end;
  1852. end;
  1853. end
  1854. else
  1855. begin
  1856. while (not CharEOF) and
  1857. ((CurrentChar >= ord('0')) and (CurrentChar <= ord('9'))) do
  1858. begin
  1859. s := s + AnsiChar(byte(CurrentChar));
  1860. NextChar;
  1861. end;
  1862. end;
  1863. if IsChar('.') then
  1864. begin
  1865. s := s + AnsiChar(byte(CurrentChar));
  1866. NextChar;
  1867. if CharEOF or
  1868. not(((CurrentChar >= ord('0')) and (CurrentChar <= ord('9'))
  1869. ) or (IsHexadecimal and (((CurrentChar >= ord('a')) and
  1870. (CurrentChar <= ord('f'))) or ((CurrentChar >= ord('A')) and
  1871. (CurrentChar <= ord('F')))))) then
  1872. begin
  1873. JSONError;
  1874. end;
  1875. while (not CharEOF) and
  1876. (((CurrentChar >= ord('0')) and (CurrentChar <= ord('9')))
  1877. or (IsHexadecimal and (((CurrentChar >= ord('a')) and
  1878. (CurrentChar <= ord('f'))) or ((CurrentChar >= ord('A')) and
  1879. (CurrentChar <= ord('F')))))) do
  1880. begin
  1881. s := s + AnsiChar(byte(CurrentChar));
  1882. NextChar;
  1883. end;
  1884. end;
  1885. if (not CharEOF) and
  1886. ((CurrentChar = ord('e')) or (CurrentChar = ord('E'))) then
  1887. begin
  1888. s := s + AnsiChar(byte(CurrentChar));
  1889. NextChar;
  1890. if (not CharEOF) and
  1891. ((CurrentChar = ord('-')) or (CurrentChar = ord('+'))) then
  1892. begin
  1893. s := s + AnsiChar(byte(CurrentChar));
  1894. NextChar;
  1895. end;
  1896. if CharEOF or not((CurrentChar >= ord('0')) and
  1897. (CurrentChar <= ord('9'))) then
  1898. begin
  1899. JSONError;
  1900. end;
  1901. while (not CharEOF) and
  1902. ((CurrentChar >= ord('0')) and (CurrentChar <= ord('9'))) do
  1903. begin
  1904. s := s + AnsiChar(byte(CurrentChar));
  1905. NextChar;
  1906. end;
  1907. end;
  1908. end
  1909. else
  1910. begin
  1911. JSONError;
  1912. end;
  1913. end;
  1914. if length(s) > 0 then
  1915. begin
  1916. OK := false;
  1917. Value := ConvertStringToDouble(s, rmNearest, @OK);
  1918. if not OK then
  1919. begin
  1920. JSONError;
  1921. end;
  1922. result := TPasJSONItemNumber.Create(Value);
  1923. end;
  1924. except
  1925. FreeAndNil(result);
  1926. raise;
  1927. end;
  1928. finally
  1929. s := '';
  1930. end;
  1931. end;
  1932. procedure ParseObjectProperty(DestinationObject: TPasJSONItemObject);
  1933. var
  1934. Key: TPasJSONUTF8String;
  1935. Value: TPasJSONItem;
  1936. begin
  1937. result := nil;
  1938. try
  1939. if (TPasJSONModeFlag.UnquotedKeys in aModeFlags) and (not CharEOF) and
  1940. ((CurrentChar = UInt16(TPasJSONUTF16Char('_'))) or
  1941. ((CurrentChar >= UInt16(TPasJSONUTF16Char('a'))) and
  1942. (CurrentChar <= UInt16(TPasJSONUTF16Char('z')))) or
  1943. ((CurrentChar >= UInt16(TPasJSONUTF16Char('A'))) and
  1944. (CurrentChar <= UInt16(TPasJSONUTF16Char('Z')))) or
  1945. ((CurrentChar >= UInt16(TPasJSONUTF16Char('0'))) and
  1946. (CurrentChar <= UInt16(TPasJSONUTF16Char('9'))))) then
  1947. begin
  1948. Key := TPasJSONUTF8String(AnsiChar(byte(CurrentChar)));
  1949. NextChar;
  1950. while ((CurrentChar = UInt16(TPasJSONUTF16Char('_'))) or
  1951. ((CurrentChar >= UInt16(TPasJSONUTF16Char('a'))) and
  1952. (CurrentChar <= UInt16(TPasJSONUTF16Char('z')))) or
  1953. ((CurrentChar >= UInt16(TPasJSONUTF16Char('A'))) and
  1954. (CurrentChar <= UInt16(TPasJSONUTF16Char('Z')))) or
  1955. ((CurrentChar >= UInt16(TPasJSONUTF16Char('0'))) and
  1956. (CurrentChar <= UInt16(TPasJSONUTF16Char('9'))))) do
  1957. begin
  1958. Key := Key + TPasJSONUTF8String(AnsiChar(byte(CurrentChar)));
  1959. NextChar;
  1960. end;
  1961. SkipWhite;
  1962. end
  1963. else
  1964. begin
  1965. Value := ParseString;
  1966. if assigned(Value) and (Value is TPasJSONItemString) then
  1967. begin
  1968. Key := TPasJSONItemString(Value).Value;
  1969. FreeAndNil(Value);
  1970. end
  1971. else
  1972. begin
  1973. FreeAndNil(Value);
  1974. JSONError;
  1975. Key := '';
  1976. end;
  1977. end;
  1978. SkipWhite;
  1979. if TPasJSONModeFlag.EqualsForColon in aModeFlags then
  1980. begin
  1981. ExpectChar('=');
  1982. end
  1983. else
  1984. begin
  1985. ExpectChar(':');
  1986. end;
  1987. SkipWhite;
  1988. Value := ParseValue(false);
  1989. DestinationObject.Add(Key, Value);
  1990. except
  1991. FreeAndNil(result);
  1992. raise;
  1993. end;
  1994. end;
  1995. function ParseObject(const ImplicitRootObject: boolean): TPasJSONItem;
  1996. begin
  1997. result := TPasJSONItemObject.Create;
  1998. try
  1999. if not ImplicitRootObject then
  2000. begin
  2001. ExpectChar('{');
  2002. end;
  2003. SkipWhite;
  2004. while not(CharEOF or ((not ImplicitRootObject) and IsChar('}'))) do
  2005. begin
  2006. ParseObjectProperty(TPasJSONItemObject(result));
  2007. SkipWhite;
  2008. if IsChar(',') then
  2009. begin
  2010. NextChar;
  2011. SkipWhite;
  2012. if (not(CharEOF or ImplicitRootObject)) and IsChar('}') then
  2013. begin
  2014. JSONError;
  2015. end;
  2016. end
  2017. else if not(TPasJSONModeFlag.OptionalCommas in aModeFlags) then
  2018. begin
  2019. break;
  2020. end;
  2021. end;
  2022. if not ImplicitRootObject then
  2023. begin
  2024. ExpectChar('}');
  2025. end;
  2026. except
  2027. FreeAndNil(result);
  2028. raise;
  2029. end;
  2030. end;
  2031. function ParseArray: TPasJSONItem;
  2032. begin
  2033. result := TPasJSONItemArray.Create;
  2034. try
  2035. ExpectChar('[');
  2036. SkipWhite;
  2037. while not(CharEOF or IsChar(']')) do
  2038. begin
  2039. TPasJSONItemArray(result).Add(ParseValue(false));
  2040. SkipWhite;
  2041. if IsChar(',') then
  2042. begin
  2043. NextChar;
  2044. SkipWhite;
  2045. if (not CharEOF) and IsChar(']') then
  2046. begin
  2047. JSONError;
  2048. end;
  2049. end
  2050. else if not(TPasJSONModeFlag.OptionalCommas in aModeFlags) then
  2051. begin
  2052. break;
  2053. end;
  2054. end;
  2055. ExpectChar(']');
  2056. except
  2057. FreeAndNil(result);
  2058. raise;
  2059. end;
  2060. end;
  2061. procedure ExpectKeyword(const Keyword: TPasJSONUTF8String);
  2062. var
  2063. i: TPasJSONInt32;
  2064. begin
  2065. for i := 1 to length(Keyword) do
  2066. begin
  2067. ExpectChar(TPasJSONUTF16Char(Keyword[i]));
  2068. end;
  2069. end;
  2070. begin
  2071. result := nil;
  2072. try
  2073. SkipWhite;
  2074. if CharEOF then
  2075. begin
  2076. JSONError;
  2077. end;
  2078. if ImplicitRootObject then
  2079. begin
  2080. result := ParseObject(true);
  2081. end
  2082. else
  2083. begin
  2084. case CurrentChar of
  2085. ord('{'):
  2086. begin
  2087. result := ParseObject(false);
  2088. end;
  2089. ord('['):
  2090. begin
  2091. result := ParseArray;
  2092. end;
  2093. ord('"'):
  2094. begin
  2095. result := ParseString;
  2096. end;
  2097. ord('-'), ord('0') .. ord('9'):
  2098. begin
  2099. result := ParseNumber;
  2100. end;
  2101. ord('t'):
  2102. begin
  2103. ExpectKeyword('true');
  2104. result := TPasJSONItemBoolean.Create(true);
  2105. end;
  2106. ord('f'):
  2107. begin
  2108. ExpectKeyword('false');
  2109. result := TPasJSONItemBoolean.Create(false);
  2110. end;
  2111. ord('n'):
  2112. begin
  2113. ExpectKeyword('null');
  2114. result := TPasJSONItemNull.Create;
  2115. end;
  2116. else
  2117. begin
  2118. JSONError;
  2119. end;
  2120. end;
  2121. end;
  2122. except
  2123. FreeAndNil(result);
  2124. raise;
  2125. end;
  2126. end;
  2127. begin
  2128. result := nil;
  2129. try
  2130. CharEOF := false;
  2131. if aEncoding = TPasJSONEncoding.AutomaticDetection then
  2132. begin
  2133. if (length(aSource) >= 3) and ((byte(AnsiChar(aSource[1])) = $EF) and
  2134. (byte(AnsiChar(aSource[2])) = $BB) and
  2135. (byte(AnsiChar(aSource[3])) = $BF)) then
  2136. begin
  2137. Position := 4;
  2138. Encoding := TPasJSONEncoding.UTF8;
  2139. end
  2140. else if (length(aSource) >= 4) and ((byte(AnsiChar(aSource[1])) = $FF) and
  2141. (byte(AnsiChar(aSource[2])) = $FE) and
  2142. (byte(AnsiChar(aSource[3])) = $00) and
  2143. (byte(AnsiChar(aSource[4])) = $00)) then
  2144. begin
  2145. Position := 5;
  2146. Encoding := TPasJSONEncoding.UTF32LE;
  2147. end
  2148. else if (length(aSource) >= 4) and ((byte(AnsiChar(aSource[1])) = $00) and
  2149. (byte(AnsiChar(aSource[2])) = $00) and
  2150. (byte(AnsiChar(aSource[3])) = $FE) and
  2151. (byte(AnsiChar(aSource[4])) = $FF)) then
  2152. begin
  2153. Position := 5;
  2154. Encoding := TPasJSONEncoding.UTF32BE;
  2155. end
  2156. else if (length(aSource) >= 2) and ((byte(AnsiChar(aSource[1])) = $FF) and
  2157. (byte(AnsiChar(aSource[2])) = $FE)) then
  2158. begin
  2159. Position := 3;
  2160. Encoding := TPasJSONEncoding.UTF16LE;
  2161. end
  2162. else if (length(aSource) >= 2) and ((byte(AnsiChar(aSource[1])) = $FE) and
  2163. (byte(AnsiChar(aSource[2])) = $FF)) then
  2164. begin
  2165. Position := 3;
  2166. Encoding := TPasJSONEncoding.UTF16BE;
  2167. end
  2168. else
  2169. begin
  2170. Position := 1;
  2171. Encoding := TPasJSONEncoding.Latin1;
  2172. end;
  2173. end
  2174. else
  2175. begin
  2176. Position := 1;
  2177. Encoding := aEncoding;
  2178. end;
  2179. NextChar;
  2180. result := ParseValue(TPasJSONModeFlag.ImplicitRootObject in aModeFlags);
  2181. SkipWhite;
  2182. if not CharEOF then
  2183. begin
  2184. JSONError;
  2185. end;
  2186. except
  2187. FreeAndNil(result);
  2188. raise;
  2189. end;
  2190. end;
  2191. class function TPasJSON.Parse(const aStream: TStream;
  2192. const aModeFlags: TPasJSONModeFlags = [TPasJSONModeFlag.Comments];
  2193. const aEncoding: TPasJSONEncoding = TPasJSONEncoding.AutomaticDetection)
  2194. : TPasJSONItem;
  2195. var
  2196. StringValue: TPasJSONRawByteString;
  2197. begin
  2198. StringValue := '';
  2199. try
  2200. SetLength(StringValue, aStream.Size);
  2201. if length(StringValue) > 0 then
  2202. begin
  2203. if aStream.Seek(0, soBeginning) <> 0 then
  2204. begin
  2205. raise EInOutError.Create('Stream seek error');
  2206. end;
  2207. aStream.ReadBuffer(StringValue[1], aStream.Size);
  2208. end;
  2209. result := TPasJSON.Parse(StringValue, aModeFlags, aEncoding);
  2210. finally
  2211. StringValue := '';
  2212. end;
  2213. end;
  2214. class function TPasJSON.Stringify(const aJSONItem: TPasJSONItem;
  2215. const aFormatting: boolean = false; const aModeFlags: TPasJSONModeFlags = [];
  2216. const aLevel: TPasJSONInt32 = 0): TPasJSONRawByteString;
  2217. function IsIdentifier(const pKey: TPasJSONUTF8String): boolean;
  2218. var
  2219. Index: TPasJSONInt32;
  2220. begin
  2221. result := length(pKey) > 0;
  2222. for Index := 1 to length(pKey) do
  2223. begin
  2224. case UInt16(TPasJSONUTF16Char(pKey[Index])) of
  2225. UInt16(TPasJSONUTF16Char('_')), UInt16(TPasJSONUTF16Char('a'))
  2226. .. UInt16(TPasJSONUTF16Char('z')), UInt16(TPasJSONUTF16Char('A'))
  2227. .. UInt16(TPasJSONUTF16Char('Z')), UInt16(TPasJSONUTF16Char('0'))
  2228. .. UInt16(TPasJSONUTF16Char('9')):
  2229. begin
  2230. end;
  2231. else
  2232. begin
  2233. result := false;
  2234. break;
  2235. end;
  2236. end;
  2237. end;
  2238. end;
  2239. var
  2240. Index, Count, Ident, LevelOffset: TPasJSONInt32;
  2241. IntegerValue: Int64;
  2242. Key: TPasJSONUTF8String;
  2243. begin
  2244. if assigned(aJSONItem) then
  2245. begin
  2246. if aJSONItem is TPasJSONItemNull then
  2247. begin
  2248. result := 'null';
  2249. end
  2250. else if aJSONItem is TPasJSONItemBoolean then
  2251. begin
  2252. if TPasJSONItemBoolean(aJSONItem).Value then
  2253. begin
  2254. result := 'true';
  2255. end
  2256. else
  2257. begin
  2258. result := 'false';
  2259. end;
  2260. end
  2261. else if aJSONItem is TPasJSONItemNumber then
  2262. begin
  2263. if IsInfinite(TPasJSONItemNumber(aJSONItem).Value) then
  2264. begin
  2265. if (TPasJSONUInt64(Pointer(@TPasJSONItemNumber(aJSONItem).Value)^)
  2266. shr 63) <> 0 then
  2267. begin
  2268. result := TPasJSON.StringQuote('-Infinity');
  2269. end
  2270. else
  2271. begin
  2272. result := TPasJSON.StringQuote('Infinity');
  2273. end;
  2274. end
  2275. else if IsNaN(TPasJSONItemNumber(aJSONItem).Value) then
  2276. begin
  2277. if (TPasJSONUInt64(Pointer(@TPasJSONItemNumber(aJSONItem).Value)^)
  2278. shr 63) <> 0 then
  2279. begin
  2280. result := TPasJSON.StringQuote('-NaN');
  2281. end
  2282. else
  2283. begin
  2284. result := TPasJSON.StringQuote('NaN');
  2285. end;
  2286. end
  2287. else
  2288. begin
  2289. IntegerValue := trunc(TPasJSONItemNumber(aJSONItem).Value);
  2290. if TPasJSONItemNumber(aJSONItem).Value = IntegerValue then
  2291. begin
  2292. Str(IntegerValue, result);
  2293. end
  2294. else
  2295. begin
  2296. result := ConvertDoubleToString(TPasJSONItemNumber(aJSONItem).Value,
  2297. omStandard, 0);
  2298. end;
  2299. end;
  2300. end
  2301. else if aJSONItem is TPasJSONItemString then
  2302. begin
  2303. result := TPasJSON.StringQuote(TPasJSONItemString(aJSONItem).Value);
  2304. end
  2305. else if aJSONItem is TPasJSONItemArray then
  2306. begin
  2307. result := '[';
  2308. if aFormatting then
  2309. begin
  2310. result := result + #13#10;
  2311. end;
  2312. Count := TPasJSONItemArray(aJSONItem).Count;
  2313. if TPasJSONModeFlag.ImplicitRootObject in aModeFlags then
  2314. begin
  2315. LevelOffset := -1;
  2316. end
  2317. else
  2318. begin
  2319. LevelOffset := 0;
  2320. end;
  2321. for Index := 0 to Count - 1 do
  2322. begin
  2323. if aFormatting then
  2324. begin
  2325. for Ident := 0 to aLevel + LevelOffset do
  2326. begin
  2327. result := result + ' ';
  2328. end;
  2329. end;
  2330. result := result + TPasJSON.Stringify(TPasJSONItemArray(aJSONItem)
  2331. .Items[Index], aFormatting, aModeFlags, aLevel + 1);
  2332. if ((Index + 1) < Count) and not(TPasJSONModeFlag.OptionalCommas
  2333. in aModeFlags) then
  2334. begin
  2335. result := result + ',';
  2336. end;
  2337. if aFormatting then
  2338. begin
  2339. result := result + #13#10;
  2340. end;
  2341. end;
  2342. if aFormatting then
  2343. begin
  2344. for Ident := 1 to aLevel + LevelOffset do
  2345. begin
  2346. result := result + ' ';
  2347. end;
  2348. end;
  2349. result := result + ']';
  2350. end
  2351. else if aJSONItem is TPasJSONItemObject then
  2352. begin
  2353. if (not(TPasJSONModeFlag.ImplicitRootObject in aModeFlags)) or
  2354. (aLevel <> 0) then
  2355. begin
  2356. result := '{';
  2357. if aFormatting then
  2358. begin
  2359. result := result + #13#10;
  2360. end;
  2361. end
  2362. else
  2363. begin
  2364. result := '';
  2365. end;
  2366. if TPasJSONModeFlag.ImplicitRootObject in aModeFlags then
  2367. begin
  2368. LevelOffset := -1;
  2369. end
  2370. else
  2371. begin
  2372. LevelOffset := 0;
  2373. end;
  2374. Count := TPasJSONItemArray(aJSONItem).Count;
  2375. for Index := 0 to Count - 1 do
  2376. begin
  2377. if aFormatting then
  2378. begin
  2379. for Ident := 0 to aLevel + LevelOffset do
  2380. begin
  2381. result := result + ' ';
  2382. end;
  2383. end;
  2384. Key := TPasJSONItemObject(aJSONItem).Keys[Index];
  2385. if (TPasJSONModeFlag.UnquotedKeys in aModeFlags) and IsIdentifier(Key)
  2386. then
  2387. begin
  2388. result := result + TPasJSONRawByteString(Key);
  2389. end
  2390. else
  2391. begin
  2392. result := result + TPasJSON.StringQuote(Key);
  2393. end;
  2394. if TPasJSONModeFlag.EqualsForColon in aModeFlags then
  2395. begin
  2396. if aFormatting then
  2397. begin
  2398. result := result + ' ';
  2399. end;
  2400. result := result + '=';
  2401. end
  2402. else
  2403. begin
  2404. result := result + ':';
  2405. end;
  2406. if aFormatting then
  2407. begin
  2408. result := result + ' ';
  2409. end;
  2410. result := result + TPasJSON.Stringify(TPasJSONItemObject(aJSONItem)
  2411. .Values[Index], aFormatting, aModeFlags, aLevel + 1);
  2412. if ((Index + 1) < Count) and not(TPasJSONModeFlag.OptionalCommas
  2413. in aModeFlags) then
  2414. begin
  2415. result := result + ',';
  2416. end;
  2417. if aFormatting then
  2418. begin
  2419. result := result + #13#10;
  2420. end;
  2421. end;
  2422. if aFormatting then
  2423. begin
  2424. for Ident := 1 to aLevel + LevelOffset do
  2425. begin
  2426. result := result + ' ';
  2427. end;
  2428. end;
  2429. if (not(TPasJSONModeFlag.ImplicitRootObject in aModeFlags)) or
  2430. (aLevel <> 0) then
  2431. begin
  2432. result := result + '}';
  2433. end;
  2434. end
  2435. else
  2436. begin
  2437. result := 'null';
  2438. end;
  2439. end
  2440. else
  2441. begin
  2442. result := 'null';
  2443. end;
  2444. end;
  2445. class procedure TPasJSON.StringifyToStream(const aStream: TStream;
  2446. const aJSONItem: TPasJSONItem; const aFormatting: boolean = false;
  2447. const aModeFlags: TPasJSONModeFlags = []; const aLevel: TPasJSONInt32 = 0);
  2448. var
  2449. StringValue: TPasJSONRawByteString;
  2450. begin
  2451. StringValue := Stringify(aJSONItem, aFormatting, aModeFlags, aLevel);
  2452. try
  2453. if length(StringValue) > 0 then
  2454. begin
  2455. aStream.WriteBuffer(StringValue[1], length(StringValue));
  2456. end;
  2457. finally
  2458. StringValue := '';
  2459. end;
  2460. end;
  2461. class function TPasJSON.GetNumber(const aItem: TPasJSONItem;
  2462. const aDefault: TPasJSONDouble = 0.0): TPasJSONDouble;
  2463. var
  2464. OK: TPasDblStrUtilsBoolean;
  2465. begin
  2466. if assigned(aItem) and (aItem is TPasJSONItemNumber) then
  2467. begin
  2468. result := TPasJSONItemNumber(aItem).Value;
  2469. end
  2470. else if assigned(aItem) and (aItem is TPasJSONItemString) then
  2471. begin
  2472. OK := false;
  2473. result := ConvertStringToDouble(TPasJSONItemString(aItem).Value,
  2474. rmNearest, @OK, -1);
  2475. if not OK then
  2476. begin
  2477. result := aDefault;
  2478. end;
  2479. end
  2480. else if assigned(aItem) and (aItem is TPasJSONItemBoolean) then
  2481. begin
  2482. result := ord(TPasJSONItemBoolean(aItem).Value) and 1;
  2483. end
  2484. else
  2485. begin
  2486. result := aDefault;
  2487. end;
  2488. end;
  2489. class function TPasJSON.GetInt64(const aItem: TPasJSONItem;
  2490. const aDefault: TPasJSONInt64 = 0): TPasJSONInt64;
  2491. begin
  2492. if assigned(aItem) and (aItem is TPasJSONItemNumber) then
  2493. begin
  2494. result := trunc(TPasJSONItemNumber(aItem).Value);
  2495. end
  2496. else if assigned(aItem) and (aItem is TPasJSONItemString) then
  2497. begin
  2498. result := StrToInt64Def(TPasJSONItemString(aItem).Value, aDefault);
  2499. end
  2500. else if assigned(aItem) and (aItem is TPasJSONItemBoolean) then
  2501. begin
  2502. result := ord(TPasJSONItemBoolean(aItem).Value) and 1;
  2503. end
  2504. else
  2505. begin
  2506. result := aDefault;
  2507. end;
  2508. end;
  2509. class function TPasJSON.GetString(const aItem: TPasJSONItem;
  2510. const aDefault: TPasJSONUTF8String = ''): TPasJSONUTF8String;
  2511. begin
  2512. if assigned(aItem) and (aItem is TPasJSONItemString) then
  2513. begin
  2514. result := TPasJSONItemString(aItem).Value;
  2515. end
  2516. else if assigned(aItem) and (aItem is TPasJSONItemNumber) then
  2517. begin
  2518. result := ConvertDoubleToString(TPasJSONItemNumber(aItem).Value,
  2519. omStandard);
  2520. end
  2521. else if assigned(aItem) and (aItem is TPasJSONItemBoolean) then
  2522. begin
  2523. if TPasJSONItemBoolean(aItem).Value then
  2524. begin
  2525. result := 'true';
  2526. end
  2527. else
  2528. begin
  2529. result := 'false';
  2530. end;
  2531. end
  2532. else
  2533. begin
  2534. result := aDefault;
  2535. end;
  2536. end;
  2537. class function TPasJSON.GetBoolean(const aItem: TPasJSONItem;
  2538. const aDefault: boolean = false): boolean;
  2539. begin
  2540. if assigned(aItem) and (aItem is TPasJSONItemBoolean) then
  2541. begin
  2542. result := TPasJSONItemBoolean(aItem).Value;
  2543. end
  2544. else if assigned(aItem) and (aItem is TPasJSONItemNumber) then
  2545. begin
  2546. result := TPasJSONItemNumber(aItem).Value <> 0.0;
  2547. end
  2548. else if assigned(aItem) and (aItem is TPasJSONItemString) then
  2549. begin
  2550. result := (LowerCase(TPasJSONItemString(aItem).Value) <> 'false') and
  2551. (TPasJSONItemString(aItem).Value <> '0');
  2552. end
  2553. else
  2554. begin
  2555. result := aDefault;
  2556. end;
  2557. end;
  2558. class function TPasJSON.LoadBinaryFromStream(const aStream: TStream)
  2559. : TPasJSONItem;
  2560. function LoadJSONItem: TPasJSONItem;
  2561. var
  2562. ItemType, BooleanValue: TPasJSONUInt8;
  2563. Count, Counter, Len: TPasJSONInt32;
  2564. TempString: TPasJSONUTF8String;
  2565. DoubleValue: TPasJSONDouble;
  2566. begin
  2567. result := nil;
  2568. if aStream.Read(ItemType, SizeOf(TPasJSONUInt8)) <> SizeOf(TPasJSONUInt8)
  2569. then
  2570. begin
  2571. raise EInOutError.Create('Stream read error');
  2572. end;
  2573. case ItemType of
  2574. 0:
  2575. begin
  2576. result := TPasJSONItemNull.Create;
  2577. end;
  2578. 1:
  2579. begin
  2580. result := TPasJSONItemArray.Create;
  2581. if aStream.Read(Count, SizeOf(TPasJSONUInt32)) <> SizeOf(TPasJSONInt32)
  2582. then
  2583. begin
  2584. raise EInOutError.Create('Stream read error');
  2585. end;
  2586. for Counter := 0 to Count - 1 do
  2587. begin
  2588. TPasJSONItemArray(result).Add(LoadJSONItem);
  2589. end;
  2590. end;
  2591. 2:
  2592. begin
  2593. TempString := '';
  2594. try
  2595. result := TPasJSONItemObject.Create;
  2596. if aStream.Read(Count, SizeOf(TPasJSONUInt32)) <>
  2597. SizeOf(TPasJSONInt32) then
  2598. begin
  2599. raise EInOutError.Create('Stream read error');
  2600. end;
  2601. for Counter := 0 to Count - 1 do
  2602. begin
  2603. if aStream.Read(Len, SizeOf(TPasJSONUInt32)) <>
  2604. SizeOf(TPasJSONInt32) then
  2605. begin
  2606. raise EInOutError.Create('Stream read error');
  2607. end;
  2608. SetLength(TempString, Len);
  2609. if Len > 0 then
  2610. begin
  2611. if TPasJSONInt64(aStream.Read(TempString[1],
  2612. Len * SizeOf(AnsiChar))) <>
  2613. TPasJSONInt64(Len * SizeOf(AnsiChar)) then
  2614. begin
  2615. raise EInOutError.Create('Stream read error');
  2616. end;
  2617. end;
  2618. TPasJSONItemObject(result).Add(TempString, LoadJSONItem);
  2619. end;
  2620. finally
  2621. TempString := '';
  2622. end;
  2623. end;
  2624. 3:
  2625. begin
  2626. if aStream.Read(BooleanValue, SizeOf(TPasJSONUInt8)) <>
  2627. SizeOf(TPasJSONUInt8) then
  2628. begin
  2629. raise EInOutError.Create('Stream read error');
  2630. end;
  2631. result := TPasJSONItemBoolean.Create(BooleanValue <> 0);
  2632. end;
  2633. 4:
  2634. begin
  2635. if aStream.Read(DoubleValue, SizeOf(TPasJSONDouble)) <>
  2636. SizeOf(TPasJSONDouble) then
  2637. begin
  2638. raise EInOutError.Create('Stream read error');
  2639. end;
  2640. result := TPasJSONItemNumber.Create(DoubleValue);
  2641. end;
  2642. 5:
  2643. begin
  2644. TempString := '';
  2645. try
  2646. if aStream.Read(Len, SizeOf(TPasJSONInt32)) <> SizeOf(TPasJSONInt32)
  2647. then
  2648. begin
  2649. raise EInOutError.Create('Stream read error');
  2650. end;
  2651. SetLength(TempString, Len);
  2652. if Len > 0 then
  2653. begin
  2654. if TPasJSONInt64(aStream.Read(TempString[1],
  2655. Len * SizeOf(AnsiChar))) <> TPasJSONInt64(Len * SizeOf(AnsiChar))
  2656. then
  2657. begin
  2658. raise EInOutError.Create('Stream read error');
  2659. end;
  2660. end;
  2661. result := TPasJSONItemString.Create(TempString);
  2662. finally
  2663. TempString := '';
  2664. end;
  2665. end;
  2666. else
  2667. begin
  2668. raise EInOutError.Create('Stream read error');
  2669. end;
  2670. end;
  2671. end;
  2672. begin
  2673. if assigned(aStream) and (aStream.Position < aStream.Size) then
  2674. begin
  2675. result := LoadJSONItem;
  2676. end
  2677. else
  2678. begin
  2679. result := nil;
  2680. end;
  2681. end;
  2682. class procedure TPasJSON.SaveBinaryToStream(const aStream: TStream;
  2683. const aJSONItem: TPasJSONItem);
  2684. procedure SaveJSONItem(const pCurrentJSONItem: TPasJSONItem);
  2685. var
  2686. ItemType, BooleanValue: TPasJSONUInt8;
  2687. Count, Counter, Len: TPasJSONInt32;
  2688. TempString: TPasJSONUTF8String;
  2689. DoubleValue: TPasJSONDouble;
  2690. begin
  2691. if assigned(pCurrentJSONItem) then
  2692. begin
  2693. if pCurrentJSONItem is TPasJSONItemNull then
  2694. begin
  2695. ItemType := 0;
  2696. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2697. SizeOf(TPasJSONUInt8) then
  2698. begin
  2699. raise EInOutError.Create('Stream write error');
  2700. end;
  2701. end
  2702. else if pCurrentJSONItem is TPasJSONItemArray then
  2703. begin
  2704. ItemType := 1;
  2705. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2706. SizeOf(TPasJSONUInt8) then
  2707. begin
  2708. raise EInOutError.Create('Stream write error');
  2709. end;
  2710. Count := TPasJSONItemArray(pCurrentJSONItem).Count;
  2711. if aStream.Write(Count, SizeOf(TPasJSONInt32)) <> SizeOf(TPasJSONInt32)
  2712. then
  2713. begin
  2714. raise EInOutError.Create('Stream write error');
  2715. end;
  2716. for Counter := 0 to Count - 1 do
  2717. begin
  2718. SaveJSONItem(TPasJSONItemArray(pCurrentJSONItem).Items[Counter]);
  2719. end;
  2720. end
  2721. else if pCurrentJSONItem is TPasJSONItemObject then
  2722. begin
  2723. ItemType := 2;
  2724. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2725. SizeOf(TPasJSONUInt8) then
  2726. begin
  2727. raise EInOutError.Create('Stream write error');
  2728. end;
  2729. Count := TPasJSONItemObject(pCurrentJSONItem).Count;
  2730. if aStream.Write(Count, SizeOf(TPasJSONInt32)) <> SizeOf(TPasJSONInt32)
  2731. then
  2732. begin
  2733. raise EInOutError.Create('Stream write error');
  2734. end;
  2735. try
  2736. for Counter := 0 to Count - 1 do
  2737. begin
  2738. TempString := TPasJSONItemObject(pCurrentJSONItem).Keys[Counter];
  2739. Len := length(TempString);
  2740. if aStream.Write(Len, SizeOf(TPasJSONInt32)) <> SizeOf(TPasJSONInt32)
  2741. then
  2742. begin
  2743. raise EInOutError.Create('Stream write error');
  2744. end;
  2745. if Len > 0 then
  2746. begin
  2747. if TPasJSONInt64(aStream.Write(TempString[1],
  2748. Len * SizeOf(AnsiChar))) <> TPasJSONInt64(Len * SizeOf(AnsiChar))
  2749. then
  2750. begin
  2751. raise EInOutError.Create('Stream write error');
  2752. end;
  2753. end;
  2754. SaveJSONItem(TPasJSONItemObject(pCurrentJSONItem).Values[Counter]);
  2755. end;
  2756. finally
  2757. TempString := '';
  2758. end;
  2759. end
  2760. else if pCurrentJSONItem is TPasJSONItemBoolean then
  2761. begin
  2762. ItemType := 3;
  2763. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2764. SizeOf(TPasJSONUInt8) then
  2765. begin
  2766. raise EInOutError.Create('Stream write error');
  2767. end;
  2768. if TPasJSONItemBoolean(pCurrentJSONItem).fValue then
  2769. begin
  2770. BooleanValue := $FF;
  2771. end
  2772. else
  2773. begin
  2774. BooleanValue := $00;
  2775. end;
  2776. if aStream.Write(BooleanValue, SizeOf(TPasJSONUInt8)) <>
  2777. SizeOf(TPasJSONUInt8) then
  2778. begin
  2779. raise EInOutError.Create('Stream write error');
  2780. end;
  2781. end
  2782. else if pCurrentJSONItem is TPasJSONItemNumber then
  2783. begin
  2784. ItemType := 4;
  2785. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2786. SizeOf(TPasJSONUInt8) then
  2787. begin
  2788. raise EInOutError.Create('Stream write error');
  2789. end;
  2790. DoubleValue := TPasJSONItemNumber(pCurrentJSONItem).fValue;
  2791. if aStream.Write(DoubleValue, SizeOf(TPasJSONDouble)) <>
  2792. SizeOf(TPasJSONDouble) then
  2793. begin
  2794. raise EInOutError.Create('Stream write error');
  2795. end;
  2796. end
  2797. else if pCurrentJSONItem is TPasJSONItemString then
  2798. begin
  2799. ItemType := 5;
  2800. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2801. SizeOf(TPasJSONUInt8) then
  2802. begin
  2803. raise EInOutError.Create('Stream write error');
  2804. end;
  2805. TempString := TPasJSONItemString(pCurrentJSONItem).fValue;
  2806. Len := length(TempString);
  2807. if aStream.Write(Len, SizeOf(TPasJSONInt32)) <> SizeOf(TPasJSONInt32)
  2808. then
  2809. begin
  2810. raise EInOutError.Create('Stream write error');
  2811. end;
  2812. if Len > 0 then
  2813. begin
  2814. if TPasJSONInt64(aStream.Write(TempString[1], Len * SizeOf(AnsiChar)))
  2815. <> TPasJSONInt64(Len * SizeOf(AnsiChar)) then
  2816. begin
  2817. raise EInOutError.Create('Stream write error');
  2818. end;
  2819. end;
  2820. end
  2821. else
  2822. begin
  2823. ItemType := 0;
  2824. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <>
  2825. SizeOf(TPasJSONUInt8) then
  2826. begin
  2827. raise EInOutError.Create('Stream write error');
  2828. end;
  2829. end;
  2830. end
  2831. else
  2832. begin
  2833. ItemType := 0;
  2834. if aStream.Write(ItemType, SizeOf(TPasJSONUInt8)) <> SizeOf(TPasJSONUInt8)
  2835. then
  2836. begin
  2837. raise EInOutError.Create('Stream write error');
  2838. end;
  2839. end;
  2840. end;
  2841. begin
  2842. if assigned(aJSONItem) and assigned(aStream) then
  2843. begin
  2844. SaveJSONItem(aJSONItem);
  2845. end;
  2846. end;
  2847. initialization
  2848. end.