1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626 |
- {
- LkJSON v1.07
- 06 november 2009
- * Copyright (c) 2006,2007,2008,2009 Leonid Koninin
- * leon_kon@users.sourceforge.net
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the <organization> nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Leonid Koninin ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL Leonid Koninin BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- changes:
- v1.07 06/11/2009 * fixed a bug in js_string - thanks to Andrew G. Khodotov
- * fixed error with double-slashes - thanks to anonymous user
- * fixed a BOM bug in parser, thanks to jasper_dale
- v1.06 13/03/2009 * fixed a bug in string parsing routine
- * looked routine from the Adrian M. Jones, and get some
- ideas from it; thanks a lot, Adrian!
- * checked error reported by phpop and fix it in the string
- routine; also, thanks for advice.
- v1.05 26/01/2009 + added port to D2009 by Daniele Teti, thanx a lot! really,
- i haven't the 2009 version, so i can't play with it. I was
- add USE_D2009 directive below, disabled by default
- * fixed two small bugs in parsing object: errors with empty
- object and list; thanx to RSDN's delphi forum members
- * fixed "[2229135] Value deletion is broken" tracker
- issue, thanx to anonymous sender provided code for
- tree version
- * fixed js_string according to "[1917047] (much) faster
- js_string Parse" tracker issue by Joao Inacio; a lot of
- thanx, great speedup!
- v1.04 05/04/2008 + a declaration of Field property moved from TlkJSONobject
- to TlkJSONbase; thanx for idea to Andrey Lukyanov; this
- improve objects use, look the bottom of SAMPLE2.DPR
- * fixed field name in TlkJSONobject to WideString
- v1.03 14/03/2008 + added a code for generating readable JSON text, sended to
- me by Kusnassriyanto Saiful Bahri, thanx to him!
- * from this version, library distributed with BSD
- license, more pleasure for commercial programmers :)
- * was rewritten internal storing of objects, repacing
- hash tables with balanced trees (AA tree, by classic
- author's variant). On mine machine, with enabled fastmm,
- tree variant is about 30% slower in from-zero creation,
- but about 50% faster in parsing; also deletion of
- objects will be much faster than a hash-one.
- Hashes (old-style) can be switched on by enabling
- USE_HASH directive below
- v1.02 14/09/2007 * fix mistypes in diffrent places; thanx for reports
- to Aleksandr Fedorov and Tobias Wrede
- v1.01 18/05/2007 * fix small bug in new text generation routine, check
- library for leaks by fastmm4; thanx for idea and comments
- for Glynn Owen
- v1.00 12/05/2007 * some fixes in new code (mistypes, mistypes...)
- * also many fixes by ideas of Henri Gourvest - big thanx
- for him again; he send me code for thread-safe initializing
- of hash table, some FPC-compatible issues (not tested by
- myself) and better code for localization in latest
- delphi versions; very, very big thanx!
- * rewritten procedure of json text generating, with wich
- work of it speeds up 4-5 times (on test) its good for
- a large objects
- * started a large work for making source code self-doc
- (not autodoc!)
- v0.99 10/05/2007 + add functions to list and object:
- function getInt(idx: Integer): Integer;
- function getString(idx: Integer): String;
- function getWideString(idx: Integer):WideString;
- function getDouble(idx: Integer): Double;
- function getBoolean(idx: Integer): Boolean;
- + add overloaded functions to object:
- function getDouble(nm: String): Double; overload;
- function getInt(nm: String): Integer; overload;
- function getString(nm: String): String; overload;
- function getWideString(nm: String): WideString; overload;
- function getBoolean(nm: String): Boolean; overload;
- * changed storing mech of TlkJSONcustomlist descendants from
- dynamic array to TList; this gives us great speedup with
- lesser changes; thanx for idea to Henri Gourvest
- * also reworked hashtable to work with TList, so it also
- increase speed of work
- v0.98 09/05/2007 * fix small bug in work with WideStrings(UTF8), thanx to
- IVO GELOV to description and sources
- v0.97 10/04/2007 + add capabilities to work with KOL delphi projects; for
- this will define KOL variable in begin of text; of course,
- in this case object TlkJSONstreamed is not compiled.
- v0.96 03/30/2007 + add TlkJSONFuncEnum and method ForEach in all
- TlkJSONcustomlist descendants
- + add property UseHash(r/o) to TlkJSONobject, and parameter
- UseHash:Boolean to object constructors; set it to false
- allow to disable using of hash-table, what can increase
- speed of work in case of objects with low number of
- methods(fields); [by default it is true]
- + added conditional compile directive DOTNET for use in .Net
- based delphi versions; remove dot in declaration below
- (thanx for idea and sample code to Tim Radford)
- + added property HashOf to TlkHashTable to allow use of
- users hash functions; on enter is widestring, on exit is
- cardinal (32 bit unsigned). Original HashOf renamed to
- DefaultHashOf
- * hash table object of TlkJSONobject wrapped by property called
- HashTable
- * fixed some minor bugs
- v0.95 03/29/2007 + add object TlkJSONstreamed what descendant of TlkJSON and
- able to load/save JSON objects from/to streams/files.
- * fixed small bug in generating of unicode strings representation
- v0.94 03/27/2007 + add properties NameOf and FieldByIndex to TlkJSONobject
- * fix small error in parsing unicode chars
- * small changes in hashing code (try to speed up)
- v0.93 03/05/2007 + add overloaded functions to list and object
- + add enum type TlkJSONtypes
- + add functions: SelfType:TlkJSONtypes and
- SelfTypeName: String to every TlkJSONbase child
- * fix mistype 'IndefOfName' to 'IndexOfName'
- * fix mistype 'IndefOfObject' to 'IndexOfObject'
- v0.92 03/02/2007 + add some fix to TlkJSON.ParseText to fix bug with parsing
- objects - object methods not always added properly
- to hash array (thanx to Chris Matheson)
- ...
- }
- unit uLkJSON;
- {$IFDEF fpc}
- {$MODE objfpc}
- {$H+}
- {.$DEFINE HAVE_FORMATSETTING}
- {$ELSE}
- {$IF RTLVersion > 14.00}
- {$DEFINE HAVE_FORMATSETTING}
- {$IF RTLVersion > 19.00}
- {$DEFINE USE_D2009}
- {$IFEND}
- {$IFEND}
- {$ENDIF}
- interface
- {.$DEFINE USE_D2009}
- {.$DEFINE KOL}
- {.$define DOTNET}
- {$DEFINE THREADSAFE}
- {$DEFINE NEW_STYLE_GENERATE}
- {.$DEFINE USE_HASH}
- {.$DEFINE TCB_EXT}
- uses windows,
- SysUtils,
- {$IFNDEF KOL}
- classes,
- {$ELSE}
- kol,
- {$ENDIF}
- variants;
- type
- TlkJSONtypes = (jsBase, jsNumber, jsString, jsBoolean, jsNull,
- jsList, jsObject);
- {$IFDEF DOTNET}
- TlkJSONdotnetclass = class
- public
- constructor Create;
- destructor Destroy; override;
- procedure AfterConstruction; virtual;
- procedure BeforeDestruction; virtual;
- end;
- {$ENDIF DOTNET}
- TlkJSONbase = class{$IFDEF DOTNET}(TlkJSONdotnetclass){$ENDIF}
- protected
- function GetValue: variant; virtual;
- procedure SetValue(const AValue: variant); virtual;
- function GetChild(idx: Integer): TlkJSONbase; virtual;
- procedure SetChild(idx: Integer; const AValue: TlkJSONbase);
- virtual;
- function GetCount: Integer; virtual;
- function GetField(AName: Variant):TlkJSONbase; virtual;
- public
- property Field[AName: Variant]: TlkJSONbase read GetField;
- property Count: Integer read GetCount;
- property Child[idx: Integer]: TlkJSONbase read GetChild write SetChild;
- property Value: variant read GetValue write SetValue;
- class function SelfType: TlkJSONtypes; virtual;
- class function SelfTypeName: string; virtual;
- end;
- TlkJSONnumber = class(TlkJSONbase)
- protected
- FValue: extended;
- function GetValue: Variant; override;
- procedure SetValue(const AValue: Variant); override;
- public
- procedure AfterConstruction; override;
- class function Generate(AValue: extended = 0): TlkJSONnumber;
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- end;
- TlkJSONstring = class(TlkJSONbase)
- protected
- FValue: WideString;
- function GetValue: Variant; override;
- procedure SetValue(const AValue: Variant); override;
- public
- procedure AfterConstruction; override;
- class function Generate(const wsValue: WideString = ''):
- TlkJSONstring;
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- end;
- TlkJSONboolean = class(TlkJSONbase)
- protected
- FValue: Boolean;
- function GetValue: Variant; override;
- procedure SetValue(const AValue: Variant); override;
- public
- procedure AfterConstruction; override;
- class function Generate(AValue: Boolean = true): TlkJSONboolean;
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- end;
- TlkJSONnull = class(TlkJSONbase)
- protected
- function GetValue: Variant; override;
- function Generate: TlkJSONnull;
- public
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- end;
- TlkJSONFuncEnum = procedure(ElName: string; Elem: TlkJSONbase;
- data: pointer; var Continue: Boolean) of object;
- TlkJSONcustomlist = class(TlkJSONbase)
- protected
- // FValue: array of TlkJSONbase;
- fList: TList;
- function GetCount: Integer; override;
- function GetChild(idx: Integer): TlkJSONbase; override;
- procedure SetChild(idx: Integer; const AValue: TlkJSONbase);
- override;
- function ForEachElement(idx: Integer; var nm: string):
- TlkJSONbase; virtual;
- function GetField(AName: Variant):TlkJSONbase; override;
- function _Add(obj: TlkJSONbase): Integer; virtual;
- procedure _Delete(iIndex: Integer); virtual;
- function _IndexOf(obj: TlkJSONbase): Integer; virtual;
- public
- procedure ForEach(fnCallBack: TlkJSONFuncEnum; pUserData:
- pointer);
- procedure AfterConstruction; override;
- procedure BeforeDestruction; override;
- function getInt(idx: Integer): Integer; virtual;
- function getString(idx: Integer): string; virtual;
- function getWideString(idx: Integer): WideString; virtual;
- function getDouble(idx: Integer): Double; virtual;
- function getBoolean(idx: Integer): Boolean; virtual;
- end;
- TlkJSONlist = class(TlkJSONcustomlist)
- protected
- public
- function Add(obj: TlkJSONbase): Integer; overload;
- function Add(aboolean: Boolean): Integer; overload;
- function Add(nmb: double): Integer; overload;
- function Add(s: string): Integer; overload;
- function Add(const ws: WideString): Integer; overload;
- function Add(inmb: Integer): Integer; overload;
- procedure Delete(idx: Integer);
- function IndexOf(obj: TlkJSONbase): Integer;
- class function Generate: TlkJSONlist;
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- end;
- TlkJSONobjectmethod = class(TlkJSONbase)
- protected
- FValue: TlkJSONbase;
- FName: WideString;
- procedure SetName(const AValue: WideString);
- public
- property ObjValue: TlkJSONbase read FValue;
- procedure AfterConstruction; override;
- procedure BeforeDestruction; override;
- property Name: WideString read FName write SetName;
- class function Generate(const aname: WideString; aobj: TlkJSONbase):
- TlkJSONobjectmethod;
- end;
- {$IFDEF USE_HASH}
- PlkHashItem = ^TlkHashItem;
- TlkHashItem = packed record
- hash: cardinal;
- index: Integer;
- end;
- TlkHashFunction = function(const ws: WideString): cardinal of
- object;
- TlkHashTable = class
- private
- FParent: TObject; // TCB:parent for check chaining op.
- FHashFunction: TlkHashFunction;
- procedure SetHashFunction(const AValue: TlkHashFunction);
- protected
- a_x: array[0..255] of TList;
- procedure hswap(j, k, l: Integer);
- function InTable(const ws: WideString; var i, j, k: cardinal):
- Boolean;
- public
- function counters: string;
- function DefaultHashOf(const ws: WideString): cardinal;
- function SimpleHashOf(const ws: WideString): cardinal;
- property HashOf: TlkHashFunction read FHashFunction write
- SetHashFunction;
- function IndexOf(const ws: WideString): Integer;
- procedure AddPair(const ws: WideString; idx: Integer);
- procedure Delete(const ws: WideString);
- constructor Create;
- destructor Destroy; override;
- end;
- {$ELSE}
- // implementation based on "Arne Andersson, Balanced Search Trees Made Simpler"
- PlkBalNode = ^TlkBalNode;
- TlkBalNode = packed record
- left,right: PlkBalNode;
- level: byte;
- key: Integer;
- nm: WideString;
- end;
- TlkBalTree = class
- protected
- fdeleted,flast,fbottom,froot: PlkBalNode;
- procedure skew(var t:PlkBalNode);
- procedure split(var t:PlkBalNode);
- public
- function counters: string;
- procedure Clear;
- function Insert(const ws: WideString; x: Integer): Boolean;
- function Delete(const ws: WideString): Boolean;
- function IndexOf(const ws: WideString): Integer;
- constructor Create;
- destructor Destroy; override;
- end;
- {$ENDIF USE_HASH}
- TlkJSONobject = class(TlkJSONcustomlist)
- protected
- {$IFDEF USE_HASH}
- ht: TlkHashTable;
- {$ELSE}
- ht: TlkBalTree;
- {$ENDIF USE_HASH}
- FUseHash: Boolean;
- function GetFieldByIndex(idx: Integer): TlkJSONbase;
- function GetNameOf(idx: Integer): WideString;
- procedure SetFieldByIndex(idx: Integer; const AValue: TlkJSONbase);
- {$IFDEF USE_HASH}
- function GetHashTable: TlkHashTable;
- {$ELSE}
- function GetHashTable: TlkBalTree;
- {$ENDIF USE_HASH}
- function ForEachElement(idx: Integer; var nm: string): TlkJSONbase;
- override;
- function GetField(AName: Variant):TlkJSONbase; override;
- public
- property UseHash: Boolean read FUseHash;
- {$IFDEF USE_HASH}
- property HashTable: TlkHashTable read GetHashTable;
- {$ELSE}
- property HashTable: TlkBalTree read GetHashTable;
- {$ENDIF USE_HASH}
- function Add(const aname: WideString; aobj: TlkJSONbase): Integer;
- overload;
- function OldGetField(nm: WideString): TlkJSONbase;
- procedure OldSetField(nm: WideString; const AValue: TlkJSONbase);
- function Add(const aname: WideString; aboolean: Boolean): Integer; overload;
- function Add(const aname: WideString; nmb: double): Integer; overload;
- function Add(const aname: WideString; s: string): Integer; overload;
- function Add(const aname: WideString; const ws: WideString): Integer;
- overload;
- function Add(const aname: WideString; inmb: Integer): Integer; overload;
- procedure Delete(idx: Integer);
- function IndexOfName(const aname: WideString): Integer;
- function IndexOfObject(aobj: TlkJSONbase): Integer;
- property Field[nm: WideString]: TlkJSONbase read OldGetField
- write OldSetField; default;
- constructor Create(bUseHash: Boolean = true);
- destructor Destroy; override;
- class function Generate(AUseHash: Boolean = true): TlkJSONobject;
- class function SelfType: TlkJSONtypes; override;
- class function SelfTypeName: string; override;
- property FieldByIndex[idx: Integer]: TlkJSONbase read GetFieldByIndex
- write SetFieldByIndex;
- property NameOf[idx: Integer]: WideString read GetNameOf;
- function getDouble(idx: Integer): Double; overload; override;
- function getInt(idx: Integer): Integer; overload; override;
- function getString(idx: Integer): string; overload; override;
- function getWideString(idx: Integer): WideString; overload; override;
- function getBoolean(idx: Integer): Boolean; overload; override;
- function {$ifdef TCB_EXT}getDoubleFromName{$else}getDouble{$endif}
- (nm: string): Double; overload;
- function {$ifdef TCB_EXT}getIntFromName{$else}getInt{$endif}
- (nm: string): Integer; overload;
- function {$ifdef TCB_EXT}getStringFromName{$else}getString{$endif}
- (nm: string): string; overload;
- function {$ifdef TCB_EXT}getWideStringFromName{$else}getWideString{$endif}
- (nm: string): WideString; overload;
- function {$ifdef TCB_EXT}getBooleanFromName{$else}getBoolean{$endif}
- (nm: string): Boolean; overload;
- end;
- TlkJSON = class
- public
- class function ParseText(const txt: string): TlkJSONbase;
- class function GenerateText(obj: TlkJSONbase): string;
- end;
- {$IFNDEF KOL}
- TlkJSONstreamed = class(TlkJSON)
- class function LoadFromStream(src: TStream): TlkJSONbase;
- class procedure SaveToStream(obj: TlkJSONbase; dst: TStream);
- class function LoadFromFile(srcname: string): TlkJSONbase;
- class procedure SaveToFile(obj: TlkJSONbase; dstname: string);
- end;
- {$ENDIF}
- function GenerateReadableText(vObj: TlkJSONbase; var vLevel:
- Integer): string;
- implementation
- uses math,strutils;
- type
- ElkIntException = class(Exception)
- public
- idx: Integer;
- constructor Create(idx: Integer; msg: string);
- end;
- // author of next two functions is Kusnassriyanto Saiful Bahri
- function Indent(vTab: Integer): string;
- begin
- result := DupeString(' ', vTab);
- end;
- function GenerateReadableText(vObj: TlkJSONbase; var vLevel:
- Integer): string;
- var
- i: Integer;
- vStr: string;
- xs: TlkJSONstring;
- begin
- vLevel := vLevel + 1;
- if vObj is TlkJSONObject then
- begin
- vStr := '';
- for i := 0 to TlkJSONobject(vObj).Count - 1 do
- begin
- if vStr <> '' then
- begin
- vStr := vStr + ','#13#10;
- end;
- vStr := vStr + Indent(vLevel) +
- GenerateReadableText(TlkJSONobject(vObj).Child[i], vLevel);
- end;
- if vStr <> '' then
- begin
- vStr := '{'#13#10 + vStr + #13#10 + Indent(vLevel - 1) + '}';
- end
- else
- begin
- vStr := '{}';
- end;
- result := vStr;
- end
- else if vObj is TlkJSONList then
- begin
- vStr := '';
- for i := 0 to TlkJSONList(vObj).Count - 1 do
- begin
- if vStr <> '' then
- begin
- vStr := vStr + ','#13#10;
- end;
- vStr := vStr + Indent(vLevel) +
- GenerateReadableText(TlkJSONList(vObj).Child[i], vLevel);
- end;
- if vStr <> '' then
- begin
- vStr := '['#13#10 + vStr + #13#10 + Indent(vLevel - 1) + ']';
- end
- else
- begin
- vStr := '[]';
- end;
- result := vStr;
- end
- else if vObj is TlkJSONobjectmethod then
- begin
- vStr := '';
- xs := TlkJSONstring.Create;
- try
- xs.Value := TlkJSONobjectMethod(vObj).Name;
- vStr := GenerateReadableText(xs, vLevel);
- vLevel := vLevel - 1;
- vStr := vStr + ':' + GenerateReadableText(TlkJSONbase(
- TlkJSONobjectmethod(vObj).ObjValue), vLevel);
- //vStr := vStr + ':' + GenerateReadableText(TlkJSONbase(vObj), vLevel);
- vLevel := vLevel + 1;
- result := vStr;
- finally
- xs.Free;
- end;
- end
- else
- begin
- if vObj is TlkJSONobjectmethod then
- begin
- if TlkJSONobjectMethod(vObj).Name <> '' then
- begin
- end;
- end;
- result := TlkJSON.GenerateText(vObj);
- end;
- vLevel := vLevel - 1;
- end;
- // author of this routine is IVO GELOV
- function code2utf(iNumber: Integer): UTF8String;
- begin
- if iNumber < 128 then Result := chr(iNumber)
- else if iNumber < 2048 then
- Result := chr((iNumber shr 6) + 192) + chr((iNumber and 63) + 128)
- else if iNumber < 65536 then
- Result := chr((iNumber shr 12) + 224) + chr(((iNumber shr 6) and
- 63) + 128) + chr((iNumber and 63) + 128)
- else if iNumber < 2097152 then
- Result := chr((iNumber shr 18) + 240) + chr(((iNumber shr 12) and
- 63) + 128) + chr(((iNumber shr 6) and 63) + 128) +
- chr((iNumber and 63) + 128);
- end;
- { TlkJSONbase }
- function TlkJSONbase.GetChild(idx: Integer): TlkJSONbase;
- begin
- result := nil;
- end;
- function TlkJSONbase.GetCount: Integer;
- begin
- result := 0;
- end;
- function TlkJSONbase.GetField(AName: Variant):TlkJSONbase;
- begin
- result := self;
- end;
- function TlkJSONbase.GetValue: variant;
- begin
- result := variants.Null;
- end;
- class function TlkJSONbase.SelfType: TlkJSONtypes;
- begin
- result := jsBase;
- end;
- class function TlkJSONbase.SelfTypeName: string;
- begin
- result := 'jsBase';
- end;
- procedure TlkJSONbase.SetChild(idx: Integer; const AValue:
- TlkJSONbase);
- begin
- end;
- procedure TlkJSONbase.SetValue(const AValue: variant);
- begin
- end;
- { TlkJSONnumber }
- procedure TlkJSONnumber.AfterConstruction;
- begin
- inherited;
- FValue := 0;
- end;
- class function TlkJSONnumber.Generate(AValue: extended):
- TlkJSONnumber;
- begin
- result := TlkJSONnumber.Create;
- result.FValue := AValue;
- end;
- function TlkJSONnumber.GetValue: Variant;
- begin
- result := FValue;
- end;
- class function TlkJSONnumber.SelfType: TlkJSONtypes;
- begin
- result := jsNumber;
- end;
- class function TlkJSONnumber.SelfTypeName: string;
- begin
- result := 'jsNumber';
- end;
- procedure TlkJSONnumber.SetValue(const AValue: Variant);
- begin
- FValue := VarAsType(AValue, varDouble);
- end;
- { TlkJSONstring }
- procedure TlkJSONstring.AfterConstruction;
- begin
- inherited;
- FValue := '';
- end;
- class function TlkJSONstring.Generate(const wsValue: WideString):
- TlkJSONstring;
- begin
- result := TlkJSONstring.Create;
- result.FValue := wsValue;
- end;
- function TlkJSONstring.GetValue: Variant;
- begin
- result := FValue;
- end;
- class function TlkJSONstring.SelfType: TlkJSONtypes;
- begin
- result := jsString;
- end;
- class function TlkJSONstring.SelfTypeName: string;
- begin
- result := 'jsString';
- end;
- procedure TlkJSONstring.SetValue(const AValue: Variant);
- begin
- FValue := VarToWideStr(AValue);
- end;
- { TlkJSONboolean }
- procedure TlkJSONboolean.AfterConstruction;
- begin
- FValue := false;
- end;
- class function TlkJSONboolean.Generate(AValue: Boolean):
- TlkJSONboolean;
- begin
- result := TlkJSONboolean.Create;
- result.Value := AValue;
- end;
- function TlkJSONboolean.GetValue: Variant;
- begin
- result := FValue;
- end;
- class function TlkJSONboolean.SelfType: TlkJSONtypes;
- begin
- Result := jsBoolean;
- end;
- class function TlkJSONboolean.SelfTypeName: string;
- begin
- Result := 'jsBoolean';
- end;
- procedure TlkJSONboolean.SetValue(const AValue: Variant);
- begin
- FValue := boolean(AValue);
- end;
- { TlkJSONnull }
- function TlkJSONnull.Generate: TlkJSONnull;
- begin
- result := TlkJSONnull.Create;
- end;
- function TlkJSONnull.GetValue: Variant;
- begin
- result := variants.Null;
- end;
- class function TlkJSONnull.SelfType: TlkJSONtypes;
- begin
- result := jsNull;
- end;
- class function TlkJSONnull.SelfTypeName: string;
- begin
- result := 'jsNull';
- end;
- { TlkJSONcustomlist }
- function TlkJSONcustomlist._Add(obj: TlkJSONbase): Integer;
- begin
- if not Assigned(obj) then
- begin
- result := -1;
- exit;
- end;
- result := fList.Add(obj);
- end;
- procedure TlkJSONcustomlist.AfterConstruction;
- begin
- inherited;
- fList := TList.Create;
- end;
- procedure TlkJSONcustomlist.BeforeDestruction;
- var
- i: Integer;
- begin
- for i := (Count - 1) downto 0 do _Delete(i);
- fList.Free;
- inherited;
- end;
- // renamed
- procedure TlkJSONcustomlist._Delete(iIndex: Integer);
- var
- idx: Integer;
- begin
- if not ((iIndex < 0) or (iIndex >= Count)) then
- begin
- if fList.Items[iIndex] <> nil then
- TlkJSONbase(fList.Items[iIndex]).Free;
- idx := pred(fList.Count);
- if iIndex<idx then
- begin
- fList.Items[iIndex] := fList.Items[idx];
- fList.Delete(idx);
- end
- else
- begin
- fList.Delete(iIndex);
- end;
- end;
- end;
- function TlkJSONcustomlist.GetChild(idx: Integer): TlkJSONbase;
- begin
- if (idx < 0) or (idx >= Count) then
- begin
- result := nil;
- end
- else
- begin
- result := fList.Items[idx];
- end;
- end;
- function TlkJSONcustomlist.GetCount: Integer;
- begin
- result := fList.Count;
- end;
- function TlkJSONcustomlist._IndexOf(obj: TlkJSONbase): Integer;
- begin
- result := fList.IndexOf(obj);
- end;
- procedure TlkJSONcustomlist.SetChild(idx: Integer; const AValue:
- TlkJSONbase);
- begin
- if not ((idx < 0) or (idx >= Count)) then
- begin
- if fList.Items[idx] <> nil then
- TlkJSONbase(fList.Items[idx]).Free;
- fList.Items[idx] := AValue;
- end;
- end;
- procedure TlkJSONcustomlist.ForEach(fnCallBack: TlkJSONFuncEnum;
- pUserData:
- pointer);
- var
- iCount: Integer;
- IsContinue: Boolean;
- anJSON: TlkJSONbase;
- wsObject: string;
- begin
- if not assigned(fnCallBack) then exit;
- IsContinue := true;
- for iCount := 0 to GetCount - 1 do
- begin
- anJSON := ForEachElement(iCount, wsObject);
- if assigned(anJSON) then
- fnCallBack(wsObject, anJSON, pUserData, IsContinue);
- if not IsContinue then break;
- end;
- end;
- ///---- renamed to here
- function TlkJSONcustomlist.GetField(AName: Variant):TlkJSONbase;
- var
- index: Integer;
- begin
- if VarIsNumeric(AName) then
- begin
- index := integer(AName);
- result := GetChild(index);
- end
- else
- begin
- result := inherited GetField(AName);
- end;
- end;
- function TlkJSONcustomlist.ForEachElement(idx: Integer; var nm:
- string): TlkJSONbase;
- begin
- nm := inttostr(idx);
- result := GetChild(idx);
- end;
- function TlkJSONcustomlist.getDouble(idx: Integer): Double;
- var
- jn: TlkJSONnumber;
- begin
- jn := Child[idx] as TlkJSONnumber;
- if not assigned(jn) then result := 0
- else result := jn.Value;
- end;
- function TlkJSONcustomlist.getInt(idx: Integer): Integer;
- var
- jn: TlkJSONnumber;
- begin
- jn := Child[idx] as TlkJSONnumber;
- if not assigned(jn) then result := 0
- else result := round(int(jn.Value));
- end;
- function TlkJSONcustomlist.getString(idx: Integer): string;
- var
- js: TlkJSONstring;
- begin
- js := Child[idx] as TlkJSONstring;
- if not assigned(js) then result := ''
- else result := VarToStr(js.Value);
- end;
- function TlkJSONcustomlist.getWideString(idx: Integer): WideString;
- var
- js: TlkJSONstring;
- begin
- js := Child[idx] as TlkJSONstring;
- if not assigned(js) then result := ''
- else result := VarToWideStr(js.Value);
- end;
- function TlkJSONcustomlist.getBoolean(idx: Integer): Boolean;
- var
- jb: TlkJSONboolean;
- begin
- jb := Child[idx] as TlkJSONboolean;
- if not assigned(jb) then result := false
- else result := jb.Value;
- end;
- { TlkJSONobjectmethod }
- procedure TlkJSONobjectmethod.AfterConstruction;
- begin
- inherited;
- FValue := nil;
- FName := '';
- end;
- procedure TlkJSONobjectmethod.BeforeDestruction;
- begin
- FName := '';
- if FValue <> nil then
- begin
- FValue.Free;
- FValue := nil;
- end;
- inherited;
- end;
- class function TlkJSONobjectmethod.Generate(const aname: WideString;
- aobj: TlkJSONbase): TlkJSONobjectmethod;
- begin
- result := TlkJSONobjectmethod.Create;
- result.FName := aname;
- result.FValue := aobj;
- end;
- procedure TlkJSONobjectmethod.SetName(const AValue: WideString);
- begin
- FName := AValue;
- end;
- { TlkJSONlist }
- function TlkJSONlist.Add(obj: TlkJSONbase): Integer;
- begin
- result := _Add(obj);
- end;
- function TlkJSONlist.Add(nmb: double): Integer;
- begin
- Result := self.Add(TlkJSONnumber.Generate(nmb));
- end;
- function TlkJSONlist.Add(aboolean: Boolean): Integer;
- begin
- Result := self.Add(TlkJSONboolean.Generate(aboolean));
- end;
- function TlkJSONlist.Add(inmb: Integer): Integer;
- begin
- Result := self.Add(TlkJSONnumber.Generate(inmb));
- end;
- function TlkJSONlist.Add(const ws: WideString): Integer;
- begin
- Result := self.Add(TlkJSONstring.Generate(ws));
- end;
- function TlkJSONlist.Add(s: string): Integer;
- begin
- Result := self.Add(TlkJSONstring.Generate(s));
- end;
- procedure TlkJSONlist.Delete(idx: Integer);
- begin
- _Delete(idx);
- end;
- class function TlkJSONlist.Generate: TlkJSONlist;
- begin
- result := TlkJSONlist.Create;
- end;
- function TlkJSONlist.IndexOf(obj: TlkJSONbase): Integer;
- begin
- result := _IndexOf(obj);
- end;
- class function TlkJSONlist.SelfType: TlkJSONtypes;
- begin
- result := jsList;
- end;
- class function TlkJSONlist.SelfTypeName: string;
- begin
- result := 'jsList';
- end;
- { TlkJSONobject }
- function TlkJSONobject.Add(const aname: WideString; aobj:
- TlkJSONbase):
- Integer;
- var
- mth: TlkJSONobjectmethod;
- begin
- if not assigned(aobj) then
- begin
- result := -1;
- exit;
- end;
- mth := TlkJSONobjectmethod.Create;
- mth.FName := aname;
- mth.FValue := aobj;
- result := self._Add(mth);
- if FUseHash then
- {$IFDEF USE_HASH}
- ht.AddPair(aname, result);
- {$ELSE}
- ht.Insert(aname, result);
- {$ENDIF USE_HASH}
- end;
- procedure TlkJSONobject.Delete(idx: Integer);
- var
- i,j,k:cardinal;
- mth: TlkJSONobjectmethod;
- begin
- if (idx >= 0) and (idx < Count) then
- begin
- // mth := FValue[idx] as TlkJSONobjectmethod;
- mth := TlkJSONobjectmethod(fList.Items[idx]);
- if FUseHash then
- begin
- ht.Delete(mth.FName);
- end;
- end;
- _Delete(idx);
- {$ifdef USE_HASH}
- if (idx<Count) and (FUseHash) then
- begin
- mth := TlkJSONobjectmethod(fList.Items[idx]);
- ht.AddPair(mth.FName,idx);
- end;
- {$endif}
- end;
- class function TlkJSONobject.Generate(AUseHash: Boolean = true):
- TlkJSONobject;
- begin
- result := TlkJSONobject.Create(AUseHash);
- end;
- function TlkJSONobject.OldGetField(nm: WideString): TlkJSONbase;
- var
- mth: TlkJSONobjectmethod;
- i: Integer;
- begin
- i := IndexOfName(nm);
- if i = -1 then
- begin
- result := nil;
- end
- else
- begin
- // mth := TlkJSONobjectmethod(FValue[i]);
- mth := TlkJSONobjectmethod(fList.Items[i]);
- result := mth.FValue;
- end;
- end;
- function TlkJSONobject.IndexOfName(const aname: WideString): Integer;
- var
- mth: TlkJSONobjectmethod;
- i: Integer;
- begin
- if not FUseHash then
- begin
- result := -1;
- for i := 0 to Count - 1 do
- begin
- // mth := TlkJSONobjectmethod(FValue[i]);
- mth := TlkJSONobjectmethod(fList.Items[i]);
- if mth.Name = aname then
- begin
- result := i;
- break;
- end;
- end;
- end
- else
- begin
- result := ht.IndexOf(aname);
- end;
- end;
- function TlkJSONobject.IndexOfObject(aobj: TlkJSONbase): Integer;
- var
- mth: TlkJSONobjectmethod;
- i: Integer;
- begin
- result := -1;
- for i := 0 to Count - 1 do
- begin
- // mth := TlkJSONobjectmethod(FValue[i]);
- mth := TlkJSONobjectmethod(fList.Items[i]);
- if mth.FValue = aobj then
- begin
- result := i;
- break;
- end;
- end;
- end;
- procedure TlkJSONobject.OldSetField(nm: WideString; const AValue:
- TlkJSONbase);
- var
- mth: TlkJSONobjectmethod;
- i: Integer;
- begin
- i := IndexOfName(nm);
- if i <> -1 then
- begin
- // mth := TlkJSONobjectmethod(FValue[i]);
- mth := TlkJSONobjectmethod(fList.Items[i]);
- mth.FValue := AValue;
- end;
- end;
- function TlkJSONobject.Add(const aname: WideString; nmb: double):
- Integer;
- begin
- Result := self.Add(aname, TlkJSONnumber.Generate(nmb));
- end;
- function TlkJSONobject.Add(const aname: WideString; aboolean: Boolean):
- Integer;
- begin
- Result := self.Add(aname, TlkJSONboolean.Generate(aboolean));
- end;
- function TlkJSONobject.Add(const aname: WideString; s: string):
- Integer;
- begin
- Result := self.Add(aname, TlkJSONstring.Generate(s));
- end;
- function TlkJSONobject.Add(const aname: WideString; inmb: Integer):
- Integer;
- begin
- Result := self.Add(aname, TlkJSONnumber.Generate(inmb));
- end;
- function TlkJSONobject.Add(const aname, ws: WideString): Integer;
- begin
- Result := self.Add(aname, TlkJSONstring.Generate(ws));
- end;
- class function TlkJSONobject.SelfType: TlkJSONtypes;
- begin
- Result := jsObject;
- end;
- class function TlkJSONobject.SelfTypeName: string;
- begin
- Result := 'jsObject';
- end;
- function TlkJSONobject.GetFieldByIndex(idx: Integer): TlkJSONbase;
- var
- nm: WideString;
- begin
- nm := GetNameOf(idx);
- if nm <> '' then
- begin
- result := Field[nm];
- end
- else
- begin
- result := nil;
- end;
- end;
- function TlkJSONobject.GetNameOf(idx: Integer): WideString;
- var
- mth: TlkJSONobjectmethod;
- begin
- if (idx < 0) or (idx >= Count) then
- begin
- result := '';
- end
- else
- begin
- mth := Child[idx] as TlkJSONobjectmethod;
- result := mth.Name;
- end;
- end;
- procedure TlkJSONobject.SetFieldByIndex(idx: Integer;
- const AValue: TlkJSONbase);
- var
- nm: WideString;
- begin
- nm := GetNameOf(idx);
- if nm <> '' then
- begin
- Field[nm] := AValue;
- end;
- end;
- function TlkJSONobject.ForEachElement(idx: Integer;
- var nm: string): TlkJSONbase;
- begin
- nm := GetNameOf(idx);
- result := GetFieldByIndex(idx);
- end;
- function TlkJSONobject.GetField(AName: Variant):TlkJSONbase;
- begin
- if VarIsStr(AName) then
- result := OldGetField(VarToWideStr(AName))
- else
- result := inherited GetField(AName);
- end;
- {$IFDEF USE_HASH}
- function TlkJSONobject.GetHashTable: TlkHashTable;
- {$ELSE}
- function TlkJSONobject.GetHashTable: TlkBalTree;
- {$ENDIF USE_HASH}
- begin
- result := ht;
- end;
- constructor TlkJSONobject.Create(bUseHash: Boolean);
- begin
- inherited Create;
- FUseHash := bUseHash;
- {$IFDEF USE_HASH}
- ht := TlkHashTable.Create;
- ht.FParent := self;
- {$ELSE}
- ht := TlkBalTree.Create;
- {$ENDIF}
- end;
- destructor TlkJSONobject.Destroy;
- begin
- if assigned(ht) then FreeAndNil(ht);
- inherited;
- end;
- function TlkJSONobject.getDouble(idx: Integer): Double;
- var
- jn: TlkJSONnumber;
- begin
- jn := FieldByIndex[idx] as TlkJSONnumber;
- if not assigned(jn) then result := 0
- else result := jn.Value;
- end;
- function TlkJSONobject.getInt(idx: Integer): Integer;
- var
- jn: TlkJSONnumber;
- begin
- jn := FieldByIndex[idx] as TlkJSONnumber;
- if not assigned(jn) then result := 0
- else result := round(int(jn.Value));
- end;
- function TlkJSONobject.getString(idx: Integer): string;
- var
- js: TlkJSONstring;
- begin
- js := FieldByIndex[idx] as TlkJSONstring;
- if not assigned(js) then result := ''
- else result := vartostr(js.Value);
- end;
- function TlkJSONobject.getWideString(idx: Integer): WideString;
- var
- js: TlkJSONstring;
- begin
- js := FieldByIndex[idx] as TlkJSONstring;
- if not assigned(js) then result := ''
- else result := VarToWideStr(js.Value);
- end;
- {$ifdef TCB_EXT}
- function TlkJSONobject.getDoubleFromName(nm: string): Double;
- {$else}
- function TlkJSONobject.getDouble(nm: string): Double;
- {$endif}
- begin
- result := getDouble(IndexOfName(nm));
- end;
- {$ifdef TCB_EXT}
- function TlkJSONobject.getIntFromName(nm: string): Integer;
- {$else}
- function TlkJSONobject.getInt(nm: string): Integer;
- {$endif}
- begin
- result := getInt(IndexOfName(nm));
- end;
- {$ifdef TCB_EXT}
- function TlkJSONobject.getStringFromName(nm: string): string;
- {$else}
- function TlkJSONobject.getString(nm: string): string;
- {$endif}
- begin
- result := getString(IndexOfName(nm));
- end;
- {$ifdef TCB_EXT}
- function TlkJSONobject.getWideStringFromName(nm: string): WideString;
- {$else}
- function TlkJSONobject.getWideString(nm: string): WideString;
- {$endif}
- begin
- result := getWideString(IndexOfName(nm));
- end;
- function TlkJSONobject.getBoolean(idx: Integer): Boolean;
- var
- jb: TlkJSONboolean;
- begin
- jb := FieldByIndex[idx] as TlkJSONboolean;
- if not assigned(jb) then result := false
- else result := jb.Value;
- end;
- {$ifdef TCB_EXT}
- function TlkJSONobject.getBooleanFromName(nm: string): Boolean;
- {$else}
- function TlkJSONobject.getBoolean(nm: string): Boolean;
- {$endif}
- begin
- result := getBoolean(IndexOfName(nm));
- end;
- { TlkJSON }
- class function TlkJSON.GenerateText(obj: TlkJSONbase): string;
- var
- {$IFDEF HAVE_FORMATSETTING}
- fs: TFormatSettings;
- {$ENDIF}
- pt1, pt0, pt2: PChar;
- ptsz: cardinal;
- {$IFNDEF NEW_STYLE_GENERATE}
- function gn_base(obj: TlkJSONbase): string;
- var
- ws: string;
- i, j: Integer;
- xs: TlkJSONstring;
- begin
- result := '';
- if not assigned(obj) then exit;
- if obj is TlkJSONnumber then
- begin
- {$IFDEF HAVE_FORMATSETTING}
- result := FloatToStr(TlkJSONnumber(obj).FValue, fs);
- {$ELSE}
- result := FloatToStr(TlkJSONnumber(obj).FValue);
- i := pos(DecimalSeparator, result);
- if (DecimalSeparator <> '.') and (i > 0) then
- result[i] := '.';
- {$ENDIF}
- end
- else if obj is TlkJSONstring then
- begin
- ws := UTF8Encode(TlkJSONstring(obj).FValue);
- i := 1;
- result := '"';
- while i <= length(ws) do
- begin
- case ws[i] of
- '/', '\', '"': result := result + '\' + ws[i];
- #8: result := result + '\b';
- #9: result := result + '\t';
- #10: result := result + '\n';
- #13: result := result + '\r';
- #12: result := result + '\f';
- else
- if ord(ws[i]) < 32 then
- result := result + '\u' + inttohex(ord(ws[i]), 4)
- else
- result := result + ws[i];
- end;
- inc(i);
- end;
- result := result + '"';
- end
- else if obj is TlkJSONboolean then
- begin
- if TlkJSONboolean(obj).FValue then
- result := 'true'
- else
- result := 'false';
- end
- else if obj is TlkJSONnull then
- begin
- result := 'null';
- end
- else if obj is TlkJSONlist then
- begin
- result := '[';
- j := TlkJSONobject(obj).Count - 1;
- for i := 0 to j do
- begin
- if i > 0 then result := result + ',';
- result := result + gn_base(TlkJSONlist(obj).Child[i]);
- end;
- result := result + ']';
- end
- else if obj is TlkJSONobjectmethod then
- begin
- try
- xs := TlkJSONstring.Create;
- xs.FValue := TlkJSONobjectmethod(obj).FName;
- result := gn_base(TlkJSONbase(xs)) + ':';
- result := result +
- gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue));
- finally
- if assigned(xs) then FreeAndNil(xs);
- end;
- end
- else if obj is TlkJSONobject then
- begin
- result := '{';
- j := TlkJSONobject(obj).Count - 1;
- for i := 0 to j do
- begin
- if i > 0 then result := result + ',';
- result := result + gn_base(TlkJSONobject(obj).Child[i]);
- end;
- result := result + '}';
- end;
- end;
- {$ELSE}
- procedure get_more_memory;
- var
- delta: cardinal;
- begin
- delta := 50000;
- if pt0 = nil then
- begin
- pt0 := AllocMem(delta);
- ptsz := 0;
- pt1 := pt0;
- end
- else
- begin
- ReallocMem(pt0, ptsz + delta);
- pt1 := pointer(cardinal(pt0) + ptsz);
- end;
- ptsz := ptsz + delta;
- pt2 := pointer(cardinal(pt1) + delta);
- end;
- procedure mem_ch(ch: char);
- begin
- if pt1 >= pt2 then get_more_memory;
- pt1^ := ch;
- inc(pt1);
- end;
- procedure mem_write(rs: string);
- var
- i: Integer;
- begin
- for i := 1 to length(rs) do
- begin
- if pt1 >= pt2 then get_more_memory;
- pt1^ := rs[i];
- inc(pt1);
- end;
- end;
- procedure gn_base(obj: TlkJSONbase);
- var
- ws: string;
- i, j: Integer;
- xs: TlkJSONstring;
- begin
- if not assigned(obj) then exit;
- if obj is TlkJSONnumber then
- begin
- {$IFDEF HAVE_FORMATSETTING}
- mem_write(FloatToStr(TlkJSONnumber(obj).FValue, fs));
- {$ELSE}
- ws := FloatToStr(TlkJSONnumber(obj).FValue);
- i := pos(DecimalSeparator, ws);
- if (DecimalSeparator <> '.') and (i > 0) then ws[i] := '.';
- mem_write(ws);
- {$ENDIF}
- end
- else if obj is TlkJSONstring then
- begin
- ws := UTF8Encode(TlkJSONstring(obj).FValue);
- i := 1;
- mem_ch('"');
- while i <= length(ws) do
- begin
- case ws[i] of
- '/', '\', '"':
- begin
- mem_ch('\');
- mem_ch(ws[i]);
- end;
- #8: mem_write('\b');
- #9: mem_write('\t');
- #10: mem_write('\n');
- #13: mem_write('\r');
- #12: mem_write('\f');
- else
- if ord(ws[i]) < 32 then
- mem_write('\u' + inttohex(ord(ws[i]), 4))
- else
- mem_ch(ws[i]);
- end;
- inc(i);
- end;
- mem_ch('"');
- end
- else if obj is TlkJSONboolean then
- begin
- if TlkJSONboolean(obj).FValue then
- mem_write('true')
- else
- mem_write('false');
- end
- else if obj is TlkJSONnull then
- begin
- mem_write('null');
- end
- else if obj is TlkJSONlist then
- begin
- mem_ch('[');
- j := TlkJSONobject(obj).Count - 1;
- for i := 0 to j do
- begin
- if i > 0 then mem_ch(',');
- gn_base(TlkJSONlist(obj).Child[i]);
- end;
- mem_ch(']');
- end
- else if obj is TlkJSONobjectmethod then
- begin
- try
- xs := TlkJSONstring.Create;
- xs.FValue := TlkJSONobjectmethod(obj).FName;
- gn_base(TlkJSONbase(xs));
- mem_ch(':');
- gn_base(TlkJSONbase(TlkJSONobjectmethod(obj).FValue));
- finally
- if assigned(xs) then FreeAndNil(xs);
- end;
- end
- else if obj is TlkJSONobject then
- begin
- mem_ch('{');
- j := TlkJSONobject(obj).Count - 1;
- for i := 0 to j do
- begin
- if i > 0 then mem_ch(',');
- gn_base(TlkJSONobject(obj).Child[i]);
- end;
- mem_ch('}');
- end;
- end;
- {$ENDIF NEW_STYLE_GENERATE}
- begin
- {$IFDEF HAVE_FORMATSETTING}
- GetLocaleFormatSettings(GetThreadLocale, fs);
- fs.DecimalSeparator := '.';
- {$ENDIF}
- {$IFDEF NEW_STYLE_GENERATE}
- pt0 := nil;
- get_more_memory;
- gn_base(obj);
- mem_ch(#0);
- result := string(pt0);
- freemem(pt0);
- {$ELSE}
- result := gn_base(obj);
- {$ENDIF}
- end;
- class function TlkJSON.ParseText(const txt: string): TlkJSONbase;
- {$IFDEF HAVE_FORMATSETTING}
- var
- fs: TFormatSettings;
- {$ENDIF}
- function js_base(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean; forward;
- function xe(idx: Integer): Boolean;
- {$IFDEF FPC}inline;
- {$ENDIF}
- begin
- result := idx <= length(txt);
- end;
- procedure skip_spc(var idx: Integer);
- {$IFDEF FPC}inline;
- {$ENDIF}
- begin
- while (xe(idx)) and (ord(txt[idx]) < 33) do
- inc(idx);
- end;
- procedure add_child(var o, c: TlkJSONbase);
- var
- i: Integer;
- begin
- if o = nil then
- begin
- o := c;
- end
- else
- begin
- if o is TlkJSONobjectmethod then
- begin
- TlkJSONobjectmethod(o).FValue := c;
- end
- else if o is TlkJSONlist then
- begin
- TlkJSONlist(o)._Add(c);
- end
- else if o is TlkJSONobject then
- begin
- i := TlkJSONobject(o)._Add(c);
- if TlkJSONobject(o).UseHash then
- {$IFDEF USE_HASH}
- TlkJSONobject(o).ht.AddPair(TlkJSONobjectmethod(c).Name, i);
- {$ELSE}
- TlkJSONobject(o).ht.Insert(TlkJSONobjectmethod(c).Name, i);
- {$ENDIF USE_HASH}
- end;
- end;
- end;
- function js_boolean(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- js: TlkJSONboolean;
- begin
- skip_spc(idx);
- if copy(txt, idx, 4) = 'true' then
- begin
- result := true;
- ridx := idx + 4;
- js := TlkJSONboolean.Create;
- js.FValue := true;
- add_child(o, TlkJSONbase(js));
- end
- else if copy(txt, idx, 5) = 'false' then
- begin
- result := true;
- ridx := idx + 5;
- js := TlkJSONboolean.Create;
- js.FValue := false;
- add_child(o, TlkJSONbase(js));
- end
- else
- begin
- result := false;
- end;
- end;
- function js_null(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- js: TlkJSONnull;
- begin
- skip_spc(idx);
- if copy(txt, idx, 4) = 'null' then
- begin
- result := true;
- ridx := idx + 4;
- js := TlkJSONnull.Create;
- add_child(o, TlkJSONbase(js));
- end
- else
- begin
- result := false;
- end;
- end;
- function js_integer(idx: Integer; var ridx: Integer): Boolean;
- begin
- result := false;
- while (xe(idx)) and (txt[idx] in ['0'..'9']) do
- begin
- result := true;
- inc(idx);
- end;
- if result then ridx := idx;
- end;
- function js_number(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- js: TlkJSONnumber;
- ws: string;
- {$IFNDEF HAVE_FORMATSETTING}
- i: Integer;
- {$ENDIF}
- begin
- skip_spc(idx);
- result := xe(idx);
- if not result then exit;
- if txt[idx] in ['+', '-'] then
- begin
- inc(idx);
- result := xe(idx);
- end;
- if not result then exit;
- result := js_integer(idx, idx);
- if not result then exit;
- if (xe(idx)) and (txt[idx] = '.') then
- begin
- inc(idx);
- result := js_integer(idx, idx);
- if not result then exit;
- end;
- if (xe(idx)) and (txt[idx] in ['e', 'E']) then
- begin
- inc(idx);
- if (xe(idx)) and (txt[idx] in ['+', '-']) then inc(idx);
- result := js_integer(idx, idx);
- if not result then exit;
- end;
- if not result then exit;
- js := TlkJSONnumber.Create;
- ws := copy(txt, ridx, idx - ridx);
- {$IFDEF HAVE_FORMATSETTING}
- js.FValue := StrToFloat(ws, fs);
- {$ELSE}
- i := pos('.', ws);
- if (DecimalSeparator <> '.') and (i > 0) then
- ws[pos('.', ws)] := DecimalSeparator;
- js.FValue := StrToFloat(ws);
- {$ENDIF}
- add_child(o, TlkJSONbase(js));
- ridx := idx;
- end;
- {
- }
- function js_string(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- function strSpecialChars(const s: string): string;
- var
- i, j : integer;
- begin
- i := Pos('\', s);
- if (i = 0) then
- Result := s
- else
- begin
- Result := Copy(s, 1, i-1);
- j := i;
- repeat
- if (s[j] = '\') then
- begin
- inc(j);
- case s[j] of
- '\': Result := Result + '\';
- '"': Result := Result + '"';
- '''': Result := Result + '''';
- '/': Result := Result + '/';
- 'b': Result := Result + #8;
- 'f': Result := Result + #12;
- 'n': Result := Result + #10;
- 'r': Result := Result + #13;
- 't': Result := Result + #9;
- 'u':
- begin
- Result := Result + code2utf(strtoint('$' + copy(s, j + 1, 4)));
- inc(j, 4);
- end;
- end;
- end
- else
- Result := Result + s[j];
- inc(j);
- until j > length(s);
- end;
- end;
- var
- js: TlkJSONstring;
- fin: Boolean;
- ws: String;
- i,j,widx: Integer;
- begin
- skip_spc(idx);
- result := xe(idx) and (txt[idx] = '"');
- if not result then exit;
- inc(idx);
- widx := idx;
- fin:=false;
- REPEAT
- i := 0;
- j := 0;
- while (widx<=length(txt)) and (j=0) do
- begin
- if (i=0) and (txt[widx]='\') then i:=widx;
- if (j=0) and (txt[widx]='"') then j:=widx;
- inc(widx);
- end;
- // incorrect string!!!
- if j=0 then
- begin
- result := false;
- exit;
- end;
- // if we have no slashed chars in string
- if (i=0) or (j<i) then
- begin
- ws := copy(txt,idx,j-idx);
- idx := j;
- fin := true;
- end
- // if i>0 and j>=i - skip slashed char
- else
- begin
- widx:=i+2;
- end;
- UNTIL fin;
- ws := strSpecialChars(ws);
- inc(idx);
- js := TlkJSONstring.Create;
- {$ifdef USE_D2009}
- js.FValue := UTF8ToString(ws);
- {$else}
- js.FValue := UTF8Decode(ws);
- {$endif}
- add_child(o, TlkJSONbase(js));
- ridx := idx;
- end;
- function js_list(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- js: TlkJSONlist;
- begin
- result := false;
- try
- js := TlkJSONlist.Create;
- skip_spc(idx);
- result := xe(idx);
- if not result then exit;
- result := txt[idx] = '[';
- if not result then exit;
- inc(idx);
- while js_base(idx, idx, TlkJSONbase(js)) do
- begin
- skip_spc(idx);
- if (xe(idx)) and (txt[idx] = ',') then inc(idx);
- end;
- skip_spc(idx);
- result := (xe(idx)) and (txt[idx] = ']');
- if not result then exit;
- inc(idx);
- finally
- if not result then
- begin
- js.Free;
- end
- else
- begin
- add_child(o, TlkJSONbase(js));
- ridx := idx;
- end;
- end;
- end;
- function js_method(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- mth: TlkJSONobjectmethod;
- ws: TlkJSONstring;
- begin
- result := false;
- try
- ws := nil;
- mth := TlkJSONobjectmethod.Create;
- skip_spc(idx);
- result := xe(idx);
- if not result then exit;
- result := js_string(idx, idx, TlkJSONbase(ws));
- if not result then exit;
- skip_spc(idx);
- result := xe(idx) and (txt[idx] = ':');
- if not result then exit;
- inc(idx);
- mth.FName := ws.FValue;
- result := js_base(idx, idx, TlkJSONbase(mth));
- finally
- if ws <> nil then ws.Free;
- if result then
- begin
- add_child(o, TlkJSONbase(mth));
- ridx := idx;
- end
- else
- begin
- mth.Free;
- end;
- end;
- end;
- function js_object(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- var
- js: TlkJSONobject;
- begin
- result := false;
- try
- js := TlkJSONobject.Create;
- skip_spc(idx);
- result := xe(idx);
- if not result then exit;
- result := txt[idx] = '{';
- if not result then exit;
- inc(idx);
- while js_method(idx, idx, TlkJSONbase(js)) do
- begin
- skip_spc(idx);
- if (xe(idx)) and (txt[idx] = ',') then inc(idx);
- end;
- skip_spc(idx);
- result := (xe(idx)) and (txt[idx] = '}');
- if not result then exit;
- inc(idx);
- finally
- if not result then
- begin
- js.Free;
- end
- else
- begin
- add_child(o, TlkJSONbase(js));
- ridx := idx;
- end;
- end;
- end;
- function js_base(idx: Integer; var ridx: Integer; var o:
- TlkJSONbase): Boolean;
- begin
- skip_spc(idx);
- result := js_boolean(idx, idx, o);
- if not result then result := js_null(idx, idx, o);
- if not result then result := js_number(idx, idx, o);
- if not result then result := js_string(idx, idx, o);
- if not result then result := js_list(idx, idx, o);
- if not result then result := js_object(idx, idx, o);
- if result then ridx := idx;
- end;
- var
- idx: Integer;
- begin
- {$IFDEF HAVE_FORMATSETTING}
- GetLocaleFormatSettings(GetThreadLocale, fs);
- fs.DecimalSeparator := '.';
- {$ENDIF}
- result := nil;
- if txt = '' then exit;
- try
- idx := 1;
- // skip a BOM utf8 marker
- if copy(txt,idx,3)=#239#187#191 then
- begin
- inc(idx,3);
- // if there are only a BOM - exit;
- if idx>length(txt) then exit;
- end;
- if not js_base(idx, idx, result) then FreeAndNil(result);
- except
- if assigned(result) then FreeAndNil(result);
- end;
- end;
- { ElkIntException }
- constructor ElkIntException.Create(idx: Integer; msg: string);
- begin
- self.idx := idx;
- inherited Create(msg);
- end;
- { TlkHashTable }
- {$IFDEF USE_HASH}
- procedure TlkHashTable.AddPair(const ws: WideString; idx: Integer);
- var
- i, j, k: cardinal;
- p: PlkHashItem;
- find: boolean;
- begin
- find := false;
- if InTable(ws, i, j, k) then
- begin
- // if string is already in table, changing index
- if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) = ws then
- begin
- PlkHashItem(a_x[j].Items[k])^.index := idx;
- find := true;
- end;
- end;
- if find = false then
- begin
- GetMem(p,sizeof(TlkHashItem));
- k := a_x[j].Add(p);
- p^.hash := i;
- p^.index := idx;
- while (k>0) and (PlkHashItem(a_x[j].Items[k])^.hash < PlkHashItem(a_x[j].Items[k-1])^.hash) do
- begin
- a_x[j].Exchange(k,k-1);
- dec(k);
- end;
- end;
- end;
- function TlkHashTable.counters: string;
- var
- i, j: Integer;
- ws: string;
- begin
- ws := '';
- for i := 0 to 15 do
- begin
- for j := 0 to 15 do
- // ws := ws + format('%.3d ', [length(a_h[i * 16 + j])]);
- ws := ws + format('%.3d ', [a_x[i * 16 + j].Count]);
- ws := ws + #13#10;
- end;
- result := ws;
- end;
- procedure TlkHashTable.Delete(const ws: WideString);
- var
- i, j, k: cardinal;
- begin
- if InTable(ws, i, j, k) then
- begin
- // while k < high(a_h[j]) do
- // begin
- // hswap(j, k, k + 1);
- // inc(k);
- // end;
- // SetLength(a_h[j], k);
- FreeMem(a_x[j].Items[k]);
- a_x[j].Delete(k);
- end;
- end;
- {$IFDEF THREADSAFE}
- const
- rnd_table: array[0..255] of byte =
- (216, 191, 234, 201, 12, 163, 190, 205, 128, 199, 210, 17, 52, 43,
- 38, 149, 40, 207, 186, 89, 92, 179, 142, 93, 208, 215, 162,
- 161, 132, 59, 246, 37, 120, 223, 138, 233, 172, 195, 94, 237, 32,
- 231, 114, 49, 212, 75, 198, 181, 200, 239, 90, 121, 252, 211,
- 46, 125, 112, 247, 66, 193, 36, 91, 150, 69, 24, 255, 42, 9, 76,
- 227, 254, 13, 192, 7, 18, 81, 116, 107, 102, 213, 104, 15, 250,
- 153, 156, 243, 206, 157, 16, 23, 226, 225, 196, 123, 54, 101,
- 184, 31, 202, 41, 236, 3, 158, 45, 96, 39, 178, 113, 20, 139, 6,
- 245, 8, 47, 154, 185, 60, 19, 110, 189, 176, 55, 130, 1, 100,
- 155, 214, 133, 88, 63, 106, 73, 140, 35, 62, 77, 0, 71, 82, 145,
- 180,
- 171, 166, 21, 168, 79, 58, 217, 220, 51, 14, 221, 80, 87, 34, 33,
- 4, 187, 118, 165, 248, 95, 10, 105, 44, 67, 222, 109, 160, 103,
- 242, 177, 84, 203, 70, 53, 72, 111, 218, 249, 124, 83, 174, 253,
- 240, 119, 194, 65, 164, 219, 22, 197, 152, 127, 170, 137, 204,
- 99, 126, 141, 64, 135, 146, 209, 244, 235, 230, 85, 232, 143,
- 122, 25, 28, 115, 78, 29, 144, 151, 98, 97, 68, 251, 182, 229,
- 56,
- 159, 74, 169, 108, 131, 30, 173, 224, 167, 50, 241, 148, 11, 134,
- 117, 136, 175, 26, 57, 188, 147, 238, 61, 48, 183, 2, 129,
- 228, 27, 86, 5);
- {$ELSE}
- var
- rnd_table: array[0..255] of byte;
- {$ENDIF}
- function TlkHashTable.DefaultHashOf(const ws: WideString): cardinal;
- {$IFDEF DOTNET}
- var
- i, j: Integer;
- x1, x2, x3, x4: byte;
- begin
- result := 0;
- // result := 0;
- x1 := 0;
- x2 := 1;
- for i := 1 to length(ws) do
- begin
- j := ord(ws[i]);
- // first version of hashing
- x1 := (x1 + j) {and $FF};
- x2 := (x2 + 1 + (j shr 8)) {and $FF};
- x3 := rnd_table[x1];
- x4 := rnd_table[x3];
- result := ((x1 * x4) + (x2 * x3)) xor result;
- end;
- end;
- {$ELSE}
- var
- x1, x2, x3, x4: byte;
- p: PWideChar;
- begin
- result := 0;
- x1 := 0;
- x2 := 1;
- p := PWideChar(ws);
- while p^ <> #0 do
- begin
- inc(x1, ord(p^)) {and $FF};
- inc(x2, 1 + (ord(p^) shr 8)) {and $FF};
- x3 := rnd_table[x1];
- x4 := rnd_table[x3];
- result := ((x1 * x4) + (x2 * x3)) xor result;
- inc(p);
- end;
- end;
- {$ENDIF}
- procedure TlkHashTable.hswap(j, k, l: Integer);
- //var
- // h: TlkHashItem;
- begin
- // h := a_h[j, k];
- // a_h[j, k] := a_h[j, l];
- // a_h[j, l] := h;
- a_x[j].Exchange(k, l);
- end;
- function TlkHashTable.IndexOf(const ws: WideString): Integer;
- var
- i, j, k: Cardinal;
- begin
- if not InTable(ws, i, j, k) then
- begin
- result := -1;
- end
- else
- begin
- // result := a_h[j, k].index;
- result := PlkHashItem(a_x[j].Items[k])^.index;
- end;
- end;
- function TlkHashTable.InTable(const ws: WideString; var i, j, k:
- cardinal):
- Boolean;
- var
- l, wu, wl: Integer;
- x: Cardinal;
- fin: Boolean;
- begin
- i := HashOf(ws);
- j := i and $FF;
- result := false;
- {using "binary" search always, because array is sorted}
- if a_x[j].Count-1 >= 0 then
- begin
- wl := 0;
- wu := a_x[j].Count-1;
- repeat
- fin := true;
- if PlkHashItem(a_x[j].Items[wl])^.hash = i then
- begin
- k := wl;
- result := true;
- end
- else if PlkHashItem(a_x[j].Items[wu])^.hash = i then
- begin
- k := wu;
- result := true;
- end
- else if (wu - wl) > 1 then
- begin
- fin := false;
- x := (wl + wu) shr 1;
- if PlkHashItem(a_x[j].Items[x])^.hash > i then
- begin
- wu := x;
- end
- else
- begin
- wl := x;
- end;
- end;
- until fin;
- end;
- // verify k index in chain
- if result = true then
- begin
- while (k > 0) and (PlkHashItem(a_x[j].Items[k])^.hash = PlkHashItem(a_x[j].Items[k-1])^.hash) do dec(k);
- repeat
- fin := true;
- if TlkJSONobject(FParent).GetNameOf(PlkHashItem(a_x[j].Items[k])^.index) <> ws then
- begin
- if k < a_x[j].Count-1 then
- begin
- inc(k);
- fin := false;
- end
- else
- begin
- result := false;
- end;
- end
- else
- begin
- result := true;
- end;
- until fin;
- end;
- end;
- {$IFNDEF THREADSAFE}
- procedure init_rnd;
- var
- x0: Integer;
- i: Integer;
- begin
- x0 := 5;
- for i := 0 to 255 do
- begin
- x0 := (x0 * 29 + 71) and $FF;
- rnd_table[i] := x0;
- end;
- end;
- {$ENDIF}
- procedure TlkHashTable.SetHashFunction(const AValue:
- TlkHashFunction);
- begin
- FHashFunction := AValue;
- end;
- constructor TlkHashTable.Create;
- var
- i: Integer;
- begin
- inherited;
- // for i := 0 to 255 do SetLength(a_h[i], 0);
- for i := 0 to 255 do a_x[i] := TList.Create;
- HashOf := {$IFDEF FPC}@{$ENDIF}DefaultHashOf;
- end;
- destructor TlkHashTable.Destroy;
- var
- i, j: Integer;
- begin
- // for i := 0 to 255 do SetLength(a_h[i], 0);
- for i := 0 to 255 do
- begin
- for j := 0 to a_x[i].Count - 1 do Freemem(a_x[i].Items[j]);
- a_x[i].Free;
- end;
- inherited;
- end;
- function TlkHashTable.SimpleHashOf(const ws: WideString): cardinal;
- var
- i: Integer;
- begin
- result := length(ws);
- for i := 1 to length(ws) do result := result + ord(ws[i]);
- end;
- {$ENDIF USE_HASH}
- { TlkJSONstreamed }
- {$IFNDEF KOL}
- class function TlkJSONstreamed.LoadFromFile(srcname: string):
- TlkJSONbase;
- var
- fs: TFileStream;
- begin
- result := nil;
- if not FileExists(srcname) then exit;
- try
- fs := TFileStream.Create(srcname, fmOpenRead);
- result := LoadFromStream(fs);
- finally
- if Assigned(fs) then FreeAndNil(fs);
- end;
- end;
- class function TlkJSONstreamed.LoadFromStream(src: TStream):
- TlkJSONbase;
- var
- ws: string;
- len: int64;
- begin
- result := nil;
- if not assigned(src) then exit;
- len := src.Size - src.Position;
- SetLength(ws, len);
- src.Read(pchar(ws)^, len);
- result := ParseText(ws);
- end;
- class procedure TlkJSONstreamed.SaveToFile(obj: TlkJSONbase;
- dstname: string);
- var
- fs: TFileStream;
- begin
- if not assigned(obj) then exit;
- try
- fs := TFileStream.Create(dstname, fmCreate);
- SaveToStream(obj, fs);
- finally
- if Assigned(fs) then FreeAndNil(fs);
- end;
- end;
- class procedure TlkJSONstreamed.SaveToStream(obj: TlkJSONbase;
- dst: TStream);
- var
- ws: string;
- begin
- if not assigned(obj) then exit;
- if not assigned(dst) then exit;
- ws := GenerateText(obj);
- dst.Write(pchar(ws)^, length(ws));
- end;
- {$ENDIF}
- { TlkJSONdotnetclass }
- {$IFDEF DOTNET}
- procedure TlkJSONdotnetclass.AfterConstruction;
- begin
- end;
- procedure TlkJSONdotnetclass.BeforeDestruction;
- begin
- end;
- constructor TlkJSONdotnetclass.Create;
- begin
- inherited;
- AfterConstruction;
- end;
- destructor TlkJSONdotnetclass.Destroy;
- begin
- BeforeDestruction;
- inherited;
- end;
- {$ENDIF DOTNET}
- { TlkBalTree }
- {$IFNDEF USE_HASH}
- procedure TlkBalTree.Clear;
- procedure rec(t: PlkBalNode);
- begin
- if t.left<>fbottom then rec(t.left);
- if t.right<>fbottom then rec(t.right);
- t.nm := '';
- dispose(t);
- end;
- begin
- if froot<>fbottom then rec(froot);
- froot := fbottom;
- fdeleted := fbottom;
- end;
- function TlkBalTree.counters: string;
- begin
- result := format('Balanced tree root node level is %d',[froot.level]);
- end;
- constructor TlkBalTree.Create;
- begin
- inherited Create;
- new(fbottom);
- fbottom.left := fbottom;
- fbottom.right := fbottom;
- fbottom.level := 0;
- fdeleted := fbottom;
- froot := fbottom;
- end;
- function TlkBalTree.Delete(const ws: WideString): Boolean;
- procedure UpdateKeys(t: PlkBalNode; idx: integer);
- begin
- if t <> fbottom then begin
- if t.key > idx then
- t.key := t.key - 1;
- UpdateKeys(t.left, idx);
- UpdateKeys(t.right, idx);
- end;
- end;
- function del(var t: PlkBalNode): Boolean;
- begin
- result := false;
- if t<>fbottom then begin
- flast := t;
- if ws<t.nm then
- result := del(t.left)
- else begin
- fdeleted := t;
- result := del(t.right);
- end;
- if (t = flast) and (fdeleted <> fbottom) and (ws = fdeleted.nm) then begin
- UpdateKeys(froot, fdeleted.key);
- fdeleted.key := t.key;
- fdeleted.nm := t.nm;
- t := t.right;
- flast.nm := '';
- dispose(flast);
- result := true;
- end
- else if (t.left.level < (t.level - 1)) or (t.right.level < (t.level - 1)) then begin
- t.level := t.level - 1;
- if t.right.level > t.level then
- t.right.level := t.level;
- skew(t);
- skew(t.right);
- skew(t.right.right);
- split(t);
- split(t.right);
- end;
- end;
- end;
- {
- // mine version, buggy, see tracker message
- // [ 2229135 ] Value deletion is broken by "Nobody/Anonymous - nobody"
- function del(var t: PlkBalNode): Boolean;
- begin
- result := false;
- if t<>fbottom then
- begin
- flast := t;
- if ws<t.nm then
- result := del(t.left)
- else
- begin
- fdeleted := t;
- result := del(t.right);
- end;
- if (t = flast) and (fdeleted<>fbottom) and (ws = t.nm) then
- begin
- fdeleted.key := t.key;
- fdeleted.nm := t.nm;
- t := t.right;
- flast.nm := '';
- dispose(flast);
- result := true;
- end
- else if (t.left.level<(t.level-1)) or (t.right.level<(t.level-1)) then
- begin
- t.level := t.level-1;
- if t.right.level>t.level then t.right.level := t.level;
- skew(t);
- skew(t.right);
- skew(t.right.right);
- split(t);
- split(t.right);
- end;
- end;
- end;
- }
- begin
- result := del(froot);
- end;
- destructor TlkBalTree.Destroy;
- begin
- Clear;
- dispose(fbottom);
- inherited;
- end;
- function TlkBalTree.IndexOf(const ws: WideString): Integer;
- var
- tk: PlkBalNode;
- begin
- result := -1;
- tk := froot;
- while (result=-1) and (tk<>fbottom) do
- begin
- if tk.nm = ws then result := tk.key
- else if ws<tk.nm then tk := tk.left
- else tk := tk.right;
- end;
- end;
- function TlkBalTree.Insert(const ws: WideString; x: Integer): Boolean;
- function ins(var t: PlkBalNode): Boolean;
- begin
- if t = fbottom then
- begin
- new(t);
- t.key := x;
- t.nm := ws;
- t.left := fbottom;
- t.right := fbottom;
- t.level := 1;
- result := true;
- end
- else
- begin
- if ws < t.nm then
- result := ins(t.left)
- else if ws > t.nm then
- result := ins(t.right)
- else result := false;
- skew(t);
- split(t);
- end;
- end;
- begin
- result := ins(froot);
- end;
- procedure TlkBalTree.skew(var t: PlkBalNode);
- var
- temp: PlkBalNode;
- begin
- if t.left.level = t.level then
- begin
- temp := t;
- t := t.left;
- temp.left := t.right;
- t.right := temp;
- end;
- end;
- procedure TlkBalTree.split(var t: PlkBalNode);
- var
- temp: PlkBalNode;
- begin
- if t.right.right.level = t.level then
- begin
- temp := t;
- t := t.right;
- temp.right := t.left;
- t.left := temp;
- t.level := t.level+1;
- end;
- end;
- {$ENDIF USE_HASH}
- initialization
- {$IFNDEF THREADSAFE}
- {$IFDEF USE_HASH}
- init_rnd;
- {$ENDIF USE_HASH}
- {$ENDIF THREADSAFE}
- end.
|