helper.pas 141 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959
  1. { Unicode parser helper unit.
  2. Copyright (c) 2012-2015 by Inoussa OUEDRAOGO
  3. The source code is distributed under the Library GNU
  4. General Public License with the following modification:
  5. - object files and libraries linked into an application may be
  6. distributed without source code.
  7. If you didn't receive a copy of the file COPYING, contact:
  8. Free Software Foundation
  9. 675 Mass Ave
  10. Cambridge, MA 02139
  11. USA
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
  15. unit helper;
  16. {$mode delphi}
  17. {$H+}
  18. {$PACKENUM 1}
  19. {$pointermath on}
  20. {$typedaddress on}
  21. {$warn 4056 off} //Conversion between ordinals and pointers is not portable
  22. {$macro on}
  23. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  24. {$define X_PACKED:=}
  25. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  26. {$define X_PACKED:=packed}
  27. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  28. interface
  29. uses
  30. Classes, SysUtils, StrUtils;
  31. const
  32. SLicenseText =
  33. ' { Unicode implementation tables. ' + sLineBreak +
  34. ' ' + sLineBreak +
  35. ' Copyright (c) 2013 - 2017 by Inoussa OUEDRAOGO ' + sLineBreak +
  36. ' ' + sLineBreak +
  37. ' Permission is hereby granted, free of charge, to any person ' + sLineBreak +
  38. ' obtaining a copy of the Unicode data files and any associated ' + sLineBreak +
  39. ' documentation (the "Data Files") or Unicode software and any ' + sLineBreak +
  40. ' associated documentation (the "Software") to deal in the Data ' + sLineBreak +
  41. ' Files or Software without restriction, including without ' + sLineBreak +
  42. ' limitation the rights to use, copy, modify, merge, publish, ' + sLineBreak +
  43. ' distribute, and/or sell copies of the Data Files or Software, ' + sLineBreak +
  44. ' and to permit persons to whom the Data Files or Software are ' + sLineBreak +
  45. ' furnished to do so, provided that (a) the above copyright ' + sLineBreak +
  46. ' notice(s) and this permission notice appear with all copies ' + sLineBreak +
  47. ' of the Data Files or Software, (b) both the above copyright ' + sLineBreak +
  48. ' notice(s) and this permission notice appear in associated ' + sLineBreak +
  49. ' documentation, and (c) there is clear notice in each modified ' + sLineBreak +
  50. ' Data File or in the Software as well as in the documentation ' + sLineBreak +
  51. ' associated with the Data File(s) or Software that the data or ' + sLineBreak +
  52. ' software has been modified. ' + sLineBreak +
  53. ' ' + sLineBreak +
  54. ' ' + sLineBreak +
  55. ' This program is distributed in the hope that it will be useful, ' + sLineBreak +
  56. ' but WITHOUT ANY WARRANTY; without even the implied warranty of ' + sLineBreak +
  57. ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }';
  58. WEIGHT_LEVEL_COUNT = 3;
  59. type
  60. // Unicode General Category
  61. TUnicodeCategory = (
  62. ucUppercaseLetter, // Lu = Letter, uppercase
  63. ucLowercaseLetter, // Ll = Letter, lowercase
  64. ucTitlecaseLetter, // Lt = Letter, titlecase
  65. ucModifierLetter, // Lm = Letter, modifier
  66. ucOtherLetter, // Lo = Letter, other
  67. ucNonSpacingMark, // Mn = Mark, nonspacing
  68. ucCombiningMark, // Mc = Mark, spacing combining
  69. ucEnclosingMark, // Me = Mark, enclosing
  70. ucDecimalNumber, // Nd = Number, decimal digit
  71. ucLetterNumber, // Nl = Number, letter
  72. ucOtherNumber, // No = Number, other
  73. ucConnectPunctuation, // Pc = Punctuation, connector
  74. ucDashPunctuation, // Pd = Punctuation, dash
  75. ucOpenPunctuation, // Ps = Punctuation, open
  76. ucClosePunctuation, // Pe = Punctuation, close
  77. ucInitialPunctuation, // Pi = Punctuation, initial quote (may behave like Ps or Pe depending on usage)
  78. ucFinalPunctuation, // Pf = Punctuation, final quote (may behave like Ps or Pe depending on usage)
  79. ucOtherPunctuation, // Po = Punctuation, other
  80. ucMathSymbol, // Sm = Symbol, math
  81. ucCurrencySymbol, // Sc = Symbol, currency
  82. ucModifierSymbol, // Sk = Symbol, modifier
  83. ucOtherSymbol, // So = Symbol, other
  84. ucSpaceSeparator, // Zs = Separator, space
  85. ucLineSeparator, // Zl = Separator, line
  86. ucParagraphSeparator, // Zp = Separator, paragraph
  87. ucControl, // Cc = Other, control
  88. ucFormat, // Cf = Other, format
  89. ucSurrogate, // Cs = Other, surrogate
  90. ucPrivateUse, // Co = Other, private use
  91. ucUnassigned // Cn = Other, not assigned (including noncharacters)
  92. );
  93. TUInt24Rec = packed record
  94. public
  95. {$ifdef FPC_LITTLE_ENDIAN}
  96. byte0, byte1, byte2 : Byte;
  97. {$else FPC_LITTLE_ENDIAN}
  98. byte2, byte1, byte0 : Byte;
  99. {$endif FPC_LITTLE_ENDIAN}
  100. public
  101. class operator Implicit(a : TUInt24Rec) : Cardinal;{$ifdef USE_INLINE}inline;{$ENDIF}
  102. class operator Implicit(a : TUInt24Rec) : LongInt;{$ifdef USE_INLINE}inline;{$ENDIF}
  103. class operator Implicit(a : TUInt24Rec) : Word;{$ifdef USE_INLINE}inline;{$ENDIF}
  104. class operator Implicit(a : TUInt24Rec) : Byte;{$ifdef USE_INLINE}inline;{$ENDIF}
  105. class operator Implicit(a : Cardinal) : TUInt24Rec;{$ifdef USE_INLINE}inline;{$ENDIF}
  106. class operator Explicit(a : TUInt24Rec) : Cardinal;{$ifdef USE_INLINE}inline;{$ENDIF}
  107. class operator Equal(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  108. class operator Equal(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  109. class operator Equal(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  110. class operator Equal(a : TUInt24Rec; b : LongInt): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  111. class operator Equal(a : LongInt; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  112. class operator Equal(a : TUInt24Rec; b : Word): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  113. class operator Equal(a : Word; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  114. class operator Equal(a : TUInt24Rec; b : Byte): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  115. class operator Equal(a : Byte; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  116. class operator NotEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  117. class operator NotEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  118. class operator NotEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  119. class operator GreaterThan(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  120. class operator GreaterThan(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  121. class operator GreaterThan(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  122. class operator GreaterThanOrEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  123. class operator GreaterThanOrEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  124. class operator GreaterThanOrEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  125. class operator LessThan(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  126. class operator LessThan(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  127. class operator LessThan(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  128. class operator LessThanOrEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  129. class operator LessThanOrEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  130. class operator LessThanOrEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  131. end;
  132. UInt24 = TUInt24Rec;
  133. PUInt24 = ^UInt24;
  134. TUnicodeCodePoint = Cardinal;
  135. TUnicodeCodePointArray = array of TUnicodeCodePoint;
  136. TDecompositionArray = array of TUnicodeCodePointArray;
  137. TNumericValue = Double;
  138. TNumericValueArray = array of TNumericValue;
  139. TBlockItemRec = packed record
  140. RangeStart : TUnicodeCodePoint;
  141. RangeEnd : TUnicodeCodePoint;
  142. Name : string[120];
  143. CanonicalName : string[120];
  144. end;
  145. TBlocks = array of TBlockItemRec;
  146. PPropRec = ^TPropRec;
  147. { TPropRec }
  148. TPropRec = packed record
  149. private
  150. function GetCategory : TUnicodeCategory;inline;
  151. procedure SetCategory(AValue : TUnicodeCategory);
  152. function GetWhiteSpace : Boolean;inline;
  153. procedure SetWhiteSpace(AValue : Boolean);
  154. function GetHangulSyllable : Boolean;inline;
  155. procedure SetHangulSyllable(AValue : Boolean);
  156. public
  157. CategoryData : Byte;
  158. PropID : Word;
  159. CCC : Byte; // Canonical Combining Class
  160. NumericIndex : Byte;
  161. SimpleUpperCase : UInt24;
  162. SimpleLowerCase : UInt24;
  163. DecompositionID : SmallInt;
  164. public
  165. property Category : TUnicodeCategory read GetCategory write SetCategory;
  166. property WhiteSpace : Boolean read GetWhiteSpace write SetWhiteSpace;
  167. property HangulSyllable : Boolean read GetHangulSyllable write SetHangulSyllable;
  168. end;
  169. TPropRecArray = array of TPropRec;
  170. TDecompositionIndexRec = packed record
  171. StartPosition : Word;
  172. Length : Byte;
  173. end;
  174. TDecompositionBook = X_PACKED record
  175. Index : array of TDecompositionIndexRec;
  176. CodePoints : array of TUnicodeCodePoint;
  177. end;
  178. PDataLineRec = ^TDataLineRec;
  179. TDataLineRec = record
  180. PropID : Integer;
  181. case LineType : Byte of
  182. 0 : (CodePoint : TUnicodeCodePoint);
  183. 1 : (StartCodePoint, EndCodePoint : TUnicodeCodePoint);
  184. end;
  185. TDataLineRecArray = array of TDataLineRec;
  186. TCodePointRec = record
  187. case LineType : Byte of
  188. 0 : (CodePoint : TUnicodeCodePoint);
  189. 1 : (StartCodePoint, EndCodePoint : TUnicodeCodePoint);
  190. end;
  191. TCodePointRecArray = array of TCodePointRec;
  192. TPropListLineRec = packed record
  193. CodePoint : TCodePointRec;
  194. PropName : string[123];
  195. end;
  196. TPropListLineRecArray = array of TPropListLineRec;
  197. { TUCA_WeightRec }
  198. TUCA_WeightRec = packed record
  199. public
  200. Weights : array[0..3] of Cardinal;
  201. Variable : Boolean;
  202. public
  203. class operator Equal(a, b: TUCA_WeightRec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  204. end;
  205. TUCA_WeightRecArray = array of TUCA_WeightRec;
  206. PUCA_LineContextItemRec = ^TUCA_LineContextItemRec;
  207. TUCA_LineContextItemRec = X_PACKED record
  208. public
  209. CodePoints : TUnicodeCodePointArray;
  210. Weights : TUCA_WeightRecArray;
  211. public
  212. procedure Clear();
  213. procedure Assign(ASource : PUCA_LineContextItemRec);
  214. function Clone() : TUCA_LineContextItemRec;
  215. end;
  216. PUCA_LineContextRec = ^TUCA_LineContextRec;
  217. TUCA_LineContextRec = X_PACKED record
  218. public
  219. Data : array of TUCA_LineContextItemRec;
  220. public
  221. procedure Clear();
  222. procedure Assign(ASource : PUCA_LineContextRec);
  223. function Clone() : TUCA_LineContextRec;
  224. end;
  225. PUCA_LineRec = ^TUCA_LineRec;
  226. TUCA_LineRec = X_PACKED record
  227. public
  228. CodePoints : TUnicodeCodePointArray;
  229. Weights : TUCA_WeightRecArray;
  230. Context : TUCA_LineContextRec;
  231. //Variable : Boolean;
  232. Deleted : Boolean;
  233. Stored : Boolean;
  234. public
  235. procedure Clear();
  236. procedure Assign(ASource : PUCA_LineRec);
  237. function Clone() : TUCA_LineRec;
  238. function HasContext() : Boolean;
  239. end;
  240. TUCA_VariableKind = (
  241. ucaShifted, ucaNonIgnorable, ucaBlanked, ucaShiftedTrimmed,
  242. ucaIgnoreSP
  243. );
  244. TUCA_DataBook = X_PACKED record
  245. Version : string;
  246. VariableWeight : TUCA_VariableKind;
  247. Backwards : array[0..3] of Boolean;
  248. Lines : array of TUCA_LineRec;
  249. end;
  250. PUCA_DataBook = ^TUCA_DataBook;
  251. TUCA_DataBookIndex = array of Integer;
  252. type
  253. TUCA_PropWeights = packed record
  254. Weights : array[0..2] of Word;
  255. //Variable : Byte;
  256. end;
  257. PUCA_PropWeights = ^TUCA_PropWeights;
  258. TUCA_PropItemContextRec = packed record
  259. CodePointCount : Byte;
  260. WeightCount : Byte;
  261. //CodePoints : UInt24;
  262. //Weights : TUCA_PropWeights;
  263. end;
  264. PUCA_PropItemContextRec = ^TUCA_PropItemContextRec;
  265. TUCA_PropItemContextTreeNodeRec = packed record
  266. Left : Word;
  267. Right : Word;
  268. Data : TUCA_PropItemContextRec;
  269. end;
  270. PUCA_PropItemContextTreeNodeRec = ^TUCA_PropItemContextTreeNodeRec;
  271. TUCA_PropItemContextTreeRec = packed record
  272. public
  273. Size : UInt24;
  274. public
  275. function GetData:PUCA_PropItemContextTreeNodeRec;inline;
  276. property Data : PUCA_PropItemContextTreeNodeRec read GetData;
  277. end;
  278. PUCA_PropItemContextTreeRec = ^TUCA_PropItemContextTreeRec;
  279. { TUCA_PropItemRec }
  280. TUCA_PropItemRec = packed record
  281. private
  282. const FLAG_VALID = 0;
  283. const FLAG_CODEPOINT = 1;
  284. const FLAG_CONTEXTUAL = 2;
  285. const FLAG_DELETION = 3;
  286. const FLAG_COMPRESS_WEIGHT_1 = 6;
  287. const FLAG_COMPRESS_WEIGHT_2 = 7;
  288. private
  289. function GetWeightSize : Word;inline;
  290. public
  291. WeightLength : Byte;
  292. ChildCount : Byte;
  293. Size : Word;
  294. Flags : Byte;
  295. public
  296. function HasCodePoint() : Boolean;inline;
  297. function GetCodePoint() : UInt24;//inline;
  298. property CodePoint : UInt24 read GetCodePoint;
  299. //Weights : array[0..WeightLength] of TUCA_PropWeights;
  300. procedure GetWeightArray(ADest : PUCA_PropWeights);
  301. function GetSelfOnlySize() : Cardinal;inline;
  302. procedure SetContextual(AValue : Boolean);inline;
  303. function GetContextual() : Boolean;inline;
  304. property Contextual : Boolean read GetContextual write setContextual;
  305. function GetContext() : PUCA_PropItemContextTreeRec;
  306. procedure SetDeleted(AValue : Boolean);inline;
  307. function IsDeleted() : Boolean;inline;
  308. function IsValid() : Boolean;inline;
  309. function IsWeightCompress_1() : Boolean;inline;
  310. function IsWeightCompress_2() : Boolean;inline;
  311. end;
  312. PUCA_PropItemRec = ^TUCA_PropItemRec;
  313. TUCA_PropIndexItem = packed record
  314. CodePoint : Cardinal;
  315. Position : Integer;
  316. end;
  317. PUCA_PropIndexItem = ^TUCA_PropIndexItem;
  318. TUCA_PropBook = X_PACKED record
  319. ItemSize : Integer;
  320. Index : array of TUCA_PropIndexItem;
  321. Items : PUCA_PropItemRec; //Native Endian
  322. ItemsOtherEndian : PUCA_PropItemRec;//Non Native Endian
  323. VariableLowLimit : Word;
  324. VariableHighLimit : Word;
  325. end;
  326. PUCA_PropBook = ^TUCA_PropBook;
  327. TBmpFirstTable = array[0..255] of Byte;
  328. TBmpSecondTableItem = array[0..255] of Word;
  329. TBmpSecondTable = array of TBmpSecondTableItem;
  330. T3lvlBmp1Table = array[0..255] of Byte;
  331. T3lvlBmp2TableItem = array[0..15] of Word;
  332. T3lvlBmp2Table = array of T3lvlBmp2TableItem;
  333. T3lvlBmp3TableItem = array[0..15] of Word;
  334. T3lvlBmp3Table = array of T3lvlBmp3TableItem;
  335. TucaBmpFirstTable = array[0..255] of Byte;
  336. TucaBmpSecondTableItem = array[0..255] of Cardinal;
  337. TucaBmpSecondTable = array of TucaBmpSecondTableItem;
  338. PucaBmpFirstTable = ^TucaBmpFirstTable;
  339. PucaBmpSecondTable = ^TucaBmpSecondTable;
  340. const
  341. LOW_SURROGATE_BEGIN = Word($DC00);
  342. LOW_SURROGATE_END = Word($DFFF);
  343. LOW_SURROGATE_COUNT = LOW_SURROGATE_END - LOW_SURROGATE_BEGIN + 1;
  344. HIGH_SURROGATE_BEGIN = Word($D800);
  345. HIGH_SURROGATE_END = Word($DBFF);
  346. HIGH_SURROGATE_COUNT = HIGH_SURROGATE_END - HIGH_SURROGATE_BEGIN + 1;
  347. type
  348. TOBmpFirstTable = array[0..(HIGH_SURROGATE_COUNT-1)] of Word;
  349. TOBmpSecondTableItem = array[0..(LOW_SURROGATE_COUNT-1)] of Word;
  350. TOBmpSecondTable = array of TOBmpSecondTableItem;
  351. T3lvlOBmp1Table = array[0..1023] of Byte;
  352. T3lvlOBmp2TableItem = array[0..31] of Word;
  353. T3lvlOBmp2Table = array of T3lvlOBmp2TableItem;
  354. T3lvlOBmp3TableItem = array[0..31] of Word;
  355. T3lvlOBmp3Table = array of T3lvlOBmp3TableItem;
  356. TucaOBmpFirstTable = array[0..(HIGH_SURROGATE_COUNT-1)] of Word;
  357. TucaOBmpSecondTableItem = array[0..(LOW_SURROGATE_COUNT-1)] of Cardinal;
  358. TucaOBmpSecondTable = array of TucaOBmpSecondTableItem;
  359. PucaOBmpFirstTable = ^TucaOBmpFirstTable;
  360. PucaOBmpSecondTable = ^TucaOBmpSecondTable;
  361. type
  362. TEndianKind = (ekLittle, ekBig);
  363. const
  364. ENDIAN_SUFFIX : array[TEndianKind] of string[2] = ('le','be');
  365. {$IFDEF ENDIAN_LITTLE}
  366. ENDIAN_NATIVE = ekLittle;
  367. ENDIAN_NON_NATIVE = ekBig;
  368. {$ENDIF ENDIAN_LITTLE}
  369. {$IFDEF ENDIAN_BIG}
  370. ENDIAN_NATIVE = ekBig;
  371. ENDIAN_NON_NATIVE = ekLittle;
  372. {$ENDIF ENDIAN_BIG}
  373. procedure GenerateLicenceText(ADest : TStream);
  374. function BoolToByte(AValue : Boolean): Byte;inline;
  375. function IsHangulSyllable(
  376. const ACodePoint : TUnicodeCodePoint;
  377. const AHangulList : TCodePointRecArray
  378. ) : Boolean;
  379. procedure ParseHangulSyllableTypes(
  380. ADataAStream : TMemoryStream;
  381. var ACodePointList : TCodePointRecArray
  382. );
  383. procedure ParseProps(
  384. ADataAStream : TMemoryStream;
  385. var APropList : TPropListLineRecArray
  386. );
  387. function FindCodePointsByProperty(
  388. const APropName : string;
  389. const APropList : TPropListLineRecArray
  390. ) : TCodePointRecArray;
  391. procedure ParseBlokcs(
  392. ADataAStream : TMemoryStream;
  393. var ABlocks : TBlocks
  394. );
  395. procedure ParseUCAFile(
  396. ADataAStream : TMemoryStream;
  397. var ABook : TUCA_DataBook
  398. );
  399. procedure MakeUCA_Props(
  400. ABook : PUCA_DataBook;
  401. out AProps : PUCA_PropBook
  402. );
  403. procedure FreeUcaBook(var ABook : PUCA_PropBook);
  404. procedure MakeUCA_BmpTables(
  405. var AFirstTable : TucaBmpFirstTable;
  406. var ASecondTable : TucaBmpSecondTable;
  407. const APropBook : PUCA_PropBook
  408. );
  409. procedure MakeUCA_OBmpTables(
  410. var AFirstTable : TucaOBmpFirstTable;
  411. var ASecondTable : TucaOBmpSecondTable;
  412. const APropBook : PUCA_PropBook
  413. );
  414. function GetPropPosition(
  415. const AHighS,
  416. ALowS : Word;
  417. const AFirstTable : PucaOBmpFirstTable;
  418. const ASecondTable : PucaOBmpSecondTable
  419. ): Integer;inline;overload;
  420. procedure GenerateUCA_Head(
  421. ADest : TStream;
  422. ABook : PUCA_DataBook;
  423. AProps : PUCA_PropBook
  424. );
  425. procedure GenerateUCA_BmpTables(
  426. AStream,
  427. ANativeEndianStream,
  428. ANonNativeEndianStream : TStream;
  429. var AFirstTable : TucaBmpFirstTable;
  430. var ASecondTable : TucaBmpSecondTable
  431. );
  432. procedure GenerateBinaryUCA_BmpTables(
  433. ANativeEndianStream,
  434. ANonNativeEndianStream : TStream;
  435. var AFirstTable : TucaBmpFirstTable;
  436. var ASecondTable : TucaBmpSecondTable
  437. );
  438. procedure GenerateUCA_PropTable(
  439. ADest : TStream;
  440. const APropBook : PUCA_PropBook;
  441. const AEndian : TEndianKind
  442. );
  443. procedure GenerateBinaryUCA_PropTable(
  444. // WARNING : files must be generated for each endianess (Little / Big)
  445. ANativeEndianStream,
  446. ANonNativeEndianStream : TStream;
  447. const APropBook : PUCA_PropBook
  448. );
  449. procedure GenerateUCA_OBmpTables(
  450. AStream,
  451. ANativeEndianStream,
  452. ANonNativeEndianStream : TStream;
  453. var AFirstTable : TucaOBmpFirstTable;
  454. var ASecondTable : TucaOBmpSecondTable
  455. );
  456. procedure GenerateBinaryUCA_OBmpTables(
  457. ANativeEndianStream,
  458. ANonNativeEndianStream : TStream;
  459. var AFirstTable : TucaOBmpFirstTable;
  460. var ASecondTable : TucaOBmpSecondTable
  461. );
  462. procedure Parse_UnicodeData(
  463. ADataAStream : TMemoryStream;
  464. var APropList : TPropRecArray;
  465. var ANumericTable : TNumericValueArray;
  466. var ADataLineList : TDataLineRecArray;
  467. var ADecomposition : TDecompositionArray;
  468. const AHangulList : TCodePointRecArray;
  469. const AWhiteSpaces : TCodePointRecArray
  470. );
  471. procedure MakeDecomposition(
  472. const ARawData : TDecompositionArray;
  473. var ABook : TDecompositionBook
  474. );
  475. procedure MakeBmpTables(
  476. var AFirstTable : TBmpFirstTable;
  477. var ASecondTable : TBmpSecondTable;
  478. const ADataLineList : TDataLineRecArray
  479. );
  480. procedure MakeBmpTables3Levels(
  481. var AFirstTable : T3lvlBmp1Table;
  482. var ASecondTable : T3lvlBmp2Table;
  483. var AThirdTable : T3lvlBmp3Table;
  484. const ADataLineList : TDataLineRecArray
  485. );
  486. procedure GenerateBmpTables(
  487. ADest : TStream;
  488. var AFirstTable : TBmpFirstTable;
  489. var ASecondTable : TBmpSecondTable
  490. );
  491. procedure Generate3lvlBmpTables(
  492. ADest : TStream;
  493. var AFirstTable : T3lvlBmp1Table;
  494. var ASecondTable : T3lvlBmp2Table;
  495. var AThirdTable : T3lvlBmp3Table
  496. );
  497. procedure GeneratePropTable(
  498. ADest : TStream;
  499. const APropList : TPropRecArray;
  500. const AEndian : TEndianKind
  501. );
  502. procedure GenerateNumericTable(
  503. ADest : TStream;
  504. const ANumList : TNumericValueArray;
  505. const ACompleteUnit : Boolean
  506. );
  507. procedure GenerateDecompositionBookTable(
  508. ADest : TStream;
  509. const ABook : TDecompositionBook;
  510. const AEndian : TEndianKind
  511. );
  512. procedure GenerateOutBmpTable(
  513. ADest : TStream;
  514. const AList : TDataLineRecArray
  515. );
  516. function Compress(const AData : TDataLineRecArray) : TDataLineRecArray;
  517. function EvaluateFloat(const AStr : string) : Double;
  518. function StrToCategory(const AStr : string) : TUnicodeCategory;
  519. function StringToCodePoint(ACP : string) : TUnicodeCodePoint;
  520. function IsWhiteSpace(
  521. const ACodePoint : TUnicodeCodePoint;
  522. const AWhiteSpaces : TCodePointRecArray
  523. ) : Boolean;
  524. function GetPropID(
  525. ACodePoint : TUnicodeCodePoint;
  526. const ADataLineList : TDataLineRecArray
  527. ) : Cardinal;
  528. //--------------------
  529. procedure MakeOBmpTables(
  530. var AFirstTable : TOBmpFirstTable;
  531. var ASecondTable : TOBmpSecondTable;
  532. const ADataLineList : TDataLineRecArray
  533. );
  534. procedure MakeOBmpTables3Levels(
  535. var AFirstTable : T3lvlOBmp1Table;
  536. var ASecondTable : T3lvlOBmp2Table;
  537. var AThirdTable : T3lvlOBmp3Table;
  538. const ADataLineList : TDataLineRecArray
  539. );
  540. procedure GenerateOBmpTables(
  541. ADest : TStream;
  542. var AFirstTable : TOBmpFirstTable;
  543. var ASecondTable : TOBmpSecondTable
  544. );
  545. procedure Generate3lvlOBmpTables(
  546. ADest : TStream;
  547. var AFirstTable : T3lvlOBmp1Table;
  548. var ASecondTable : T3lvlOBmp2Table;
  549. var AThirdTable : T3lvlOBmp3Table
  550. );
  551. function GetProp(
  552. const AHighS,
  553. ALowS : Word;
  554. const AProps : TPropRecArray;
  555. var AFirstTable : TOBmpFirstTable;
  556. var ASecondTable : TOBmpSecondTable
  557. ): PPropRec; inline;overload;
  558. function GetProp(
  559. const AHighS,
  560. ALowS : Word;
  561. const AProps : TPropRecArray;
  562. var AFirstTable : T3lvlOBmp1Table;
  563. var ASecondTable : T3lvlOBmp2Table;
  564. var AThirdTable : T3lvlOBmp3Table
  565. ): PPropRec; inline;overload;
  566. procedure FromUCS4(const AValue : TUnicodeCodePoint; var AHighS, ALowS : Word);inline;
  567. function ToUCS4(const AHighS, ALowS : Word) : TUnicodeCodePoint; inline;
  568. type
  569. TBitOrder = 0..7;
  570. function IsBitON(const AData : Byte; const ABit : TBitOrder) : Boolean ;{$IFDEF USE_INLINE}inline;{$ENDIF}
  571. procedure SetBit(var AData : Byte; const ABit : TBitOrder; const AValue : Boolean);{$IFDEF USE_INLINE}inline;{$ENDIF}
  572. function GenerateEndianIncludeFileName(
  573. const AStoreName : string;
  574. const AEndian : TEndianKind
  575. ): string;inline;
  576. procedure ReverseFromNativeEndian(
  577. const AData : PUCA_PropItemRec;
  578. const ADataLen : Cardinal;
  579. const ADest : PUCA_PropItemRec
  580. );
  581. procedure ReverseToNativeEndian(
  582. const AData : PUCA_PropItemRec;
  583. const ADataLen : Cardinal;
  584. const ADest : PUCA_PropItemRec
  585. );
  586. procedure CompareProps(
  587. const AProp1,
  588. AProp2 : PUCA_PropItemRec;
  589. const ADataLen : Integer
  590. );
  591. type
  592. TCollationName = array[0..(128-1)] of Byte;
  593. TCollationVersion = TCollationName;
  594. TSerializedCollationHeader = packed record
  595. Base : TCollationName;
  596. Version : TCollationVersion;
  597. CollationName : TCollationName;
  598. CollationAliases : TCollationName; // ";" separated
  599. VariableWeight : Byte;
  600. Backwards : Byte;
  601. BMP_Table1Length : DWord;
  602. BMP_Table2Length : DWord;
  603. OBMP_Table1Length : DWord;
  604. OBMP_Table2Length : DWord;
  605. PropCount : DWord;
  606. VariableLowLimit : Word;
  607. VariableHighLimit : Word;
  608. NoNormalization : Byte;
  609. Strength : Byte;
  610. ChangedFields : Byte;
  611. end;
  612. PSerializedCollationHeader = ^TSerializedCollationHeader;
  613. procedure StringToByteArray(AStr : UnicodeString; var ABuffer : array of Byte);overload;
  614. procedure StringToByteArray(AStr : UnicodeString; ABuffer : PByte; const ABufferLength : Integer);overload;
  615. procedure ReverseRecordBytes(var AItem : TSerializedCollationHeader);
  616. procedure ReverseBytes(var AData; const ALength : Integer);
  617. procedure ReverseArray(var AValue; const AArrayLength, AItemSize : PtrInt);
  618. function CalcMaxLevel2Value(ALines : array of TUCA_LineRec) : Cardinal;
  619. procedure RewriteLevel2Values(ALines : PUCA_LineRec; ALength : Integer);
  620. function RewriteLevel2(
  621. const ALevel1Value : Cardinal;
  622. ALines : PUCA_LineRec;
  623. const ALinesLength : Integer
  624. ) : Integer;
  625. resourcestring
  626. SInsufficientMemoryBuffer = 'Insufficient Memory Buffer';
  627. implementation
  628. uses
  629. typinfo, Math, AVL_Tree,
  630. trie;
  631. type
  632. TCardinalRec = packed record
  633. {$ifdef FPC_LITTLE_ENDIAN}
  634. byte0, byte1, byte2, byte3 : Byte;
  635. {$else FPC_LITTLE_ENDIAN}
  636. byte3, byte2, byte1, byte0 : Byte;
  637. {$endif FPC_LITTLE_ENDIAN}
  638. end;
  639. TWordRec = packed record
  640. {$ifdef FPC_LITTLE_ENDIAN}
  641. byte0, byte1 : Byte;
  642. {$else FPC_LITTLE_ENDIAN}
  643. byte1, byte0 : Byte;
  644. {$endif FPC_LITTLE_ENDIAN}
  645. end;
  646. { TUInt24Rec }
  647. class operator TUInt24Rec.Explicit(a : TUInt24Rec) : Cardinal;
  648. begin
  649. TCardinalRec(Result).byte0 := a.byte0;
  650. TCardinalRec(Result).byte1 := a.byte1;
  651. TCardinalRec(Result).byte2 := a.byte2;
  652. TCardinalRec(Result).byte3 := 0;
  653. end;
  654. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Cardinal;
  655. begin
  656. TCardinalRec(Result).byte0 := a.byte0;
  657. TCardinalRec(Result).byte1 := a.byte1;
  658. TCardinalRec(Result).byte2 := a.byte2;
  659. TCardinalRec(Result).byte3 := 0;
  660. end;
  661. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : LongInt;
  662. begin
  663. Result := Cardinal(a);
  664. end;
  665. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Word;
  666. begin
  667. {$IFOPT R+}
  668. if (a.byte2 > 0) then
  669. Error(reIntOverflow);
  670. {$ENDIF R+}
  671. TWordRec(Result).byte0 := a.byte0;
  672. TWordRec(Result).byte1 := a.byte1;
  673. end;
  674. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Byte;
  675. begin
  676. {$IFOPT R+}
  677. if (a.byte1 > 0) or (a.byte2 > 0) then
  678. Error(reIntOverflow);
  679. {$ENDIF R+}
  680. Result := a.byte0;
  681. end;
  682. class operator TUInt24Rec.Implicit(a : Cardinal) : TUInt24Rec;
  683. begin
  684. {$IFOPT R+}
  685. if (a > $FFFFFF) then
  686. Error(reIntOverflow);
  687. {$ENDIF R+}
  688. Result.byte0 := TCardinalRec(a).byte0;
  689. Result.byte1 := TCardinalRec(a).byte1;
  690. Result.byte2 := TCardinalRec(a).byte2;
  691. end;
  692. class operator TUInt24Rec.Equal(a, b : TUInt24Rec) : Boolean;
  693. begin
  694. Result := (a.byte0 = b.byte0) and (a.byte1 = b.byte1) and (a.byte2 = b.byte2);
  695. end;
  696. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Cardinal) : Boolean;
  697. begin
  698. Result := (TCardinalRec(b).byte3 = 0) and
  699. (a.byte0 = TCardinalRec(b).byte0) and
  700. (a.byte1 = TCardinalRec(b).byte1) and
  701. (a.byte2 = TCardinalRec(b).byte2);
  702. end;
  703. class operator TUInt24Rec.Equal(a : Cardinal; b : TUInt24Rec) : Boolean;
  704. begin
  705. Result := (b = a);
  706. end;
  707. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : LongInt) : Boolean;
  708. begin
  709. Result := (LongInt(a) = b);
  710. end;
  711. class operator TUInt24Rec.Equal(a : LongInt; b : TUInt24Rec) : Boolean;
  712. begin
  713. Result := (b = a);
  714. end;
  715. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Word) : Boolean;
  716. begin
  717. Result := (a.byte2 = 0) and
  718. (a.byte0 = TWordRec(b).byte0) and
  719. (a.byte1 = TWordRec(b).byte1);
  720. end;
  721. class operator TUInt24Rec.Equal(a : Word; b : TUInt24Rec) : Boolean;
  722. begin
  723. Result := (b = a);
  724. end;
  725. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Byte) : Boolean;
  726. begin
  727. Result := (a.byte2 = 0) and
  728. (a.byte1 = 0) and
  729. (a.byte0 = b);
  730. end;
  731. class operator TUInt24Rec.Equal(a : Byte; b : TUInt24Rec) : Boolean;
  732. begin
  733. Result := (b = a);
  734. end;
  735. class operator TUInt24Rec.NotEqual(a, b : TUInt24Rec) : Boolean;
  736. begin
  737. Result := (a.byte0 <> b.byte0) or (a.byte1 <> b.byte1) or (a.byte2 <> b.byte2);
  738. end;
  739. class operator TUInt24Rec.NotEqual(a : TUInt24Rec; b : Cardinal) : Boolean;
  740. begin
  741. Result := (TCardinalRec(b).byte3 <> 0) or
  742. (a.byte0 <> TCardinalRec(b).byte0) or
  743. (a.byte1 <> TCardinalRec(b).byte1) or
  744. (a.byte2 <> TCardinalRec(b).byte2);
  745. end;
  746. class operator TUInt24Rec.NotEqual(a : Cardinal; b : TUInt24Rec) : Boolean;
  747. begin
  748. Result := (b <> a);
  749. end;
  750. class operator TUInt24Rec.GreaterThan(a, b: TUInt24Rec): Boolean;
  751. begin
  752. Result := (a.byte2 > b.byte2) or
  753. ((a.byte2 = b.byte2) and (a.byte1 > b.byte1)) or
  754. ((a.byte2 = b.byte2) and (a.byte1 = b.byte1) and (a.byte0 > b.byte0));
  755. end;
  756. class operator TUInt24Rec.GreaterThan(a: TUInt24Rec; b: Cardinal): Boolean;
  757. begin
  758. Result := Cardinal(a) > b;
  759. end;
  760. class operator TUInt24Rec.GreaterThan(a: Cardinal; b: TUInt24Rec): Boolean;
  761. begin
  762. Result := a > Cardinal(b);
  763. end;
  764. class operator TUInt24Rec.GreaterThanOrEqual(a, b: TUInt24Rec): Boolean;
  765. begin
  766. Result := (a.byte2 > b.byte2) or
  767. ((a.byte2 = b.byte2) and (a.byte1 > b.byte1)) or
  768. ((a.byte2 = b.byte2) and (a.byte1 = b.byte1) and (a.byte0 >= b.byte0));
  769. end;
  770. class operator TUInt24Rec.GreaterThanOrEqual(a: TUInt24Rec; b: Cardinal): Boolean;
  771. begin
  772. Result := Cardinal(a) >= b;
  773. end;
  774. class operator TUInt24Rec.GreaterThanOrEqual(a: Cardinal; b: TUInt24Rec): Boolean;
  775. begin
  776. Result := a >= Cardinal(b);
  777. end;
  778. class operator TUInt24Rec.LessThan(a, b: TUInt24Rec): Boolean;
  779. begin
  780. Result := (b > a);
  781. end;
  782. class operator TUInt24Rec.LessThan(a: TUInt24Rec; b: Cardinal): Boolean;
  783. begin
  784. Result := Cardinal(a) < b;
  785. end;
  786. class operator TUInt24Rec.LessThan(a: Cardinal; b: TUInt24Rec): Boolean;
  787. begin
  788. Result := a < Cardinal(b);
  789. end;
  790. class operator TUInt24Rec.LessThanOrEqual(a, b: TUInt24Rec): Boolean;
  791. begin
  792. Result := (b >= a);
  793. end;
  794. class operator TUInt24Rec.LessThanOrEqual(a: TUInt24Rec; b: Cardinal): Boolean;
  795. begin
  796. Result := Cardinal(a) <= b;
  797. end;
  798. class operator TUInt24Rec.LessThanOrEqual(a: Cardinal; b: TUInt24Rec): Boolean;
  799. begin
  800. Result := a <= Cardinal(b);
  801. end;
  802. { TUCA_WeightRec }
  803. class operator TUCA_WeightRec.Equal(a, b : TUCA_WeightRec) : Boolean;
  804. begin
  805. Result := (a.Weights[0] = b.Weights[0]) and (a.Weights[1] = b.Weights[1]) and
  806. (a.Weights[2] = b.Weights[2]) and (a.Weights[3] = b.Weights[3]) and
  807. (a.Variable = b.Variable);
  808. end;
  809. procedure StringToByteArray(AStr : UnicodeString; var ABuffer : array of Byte);
  810. begin
  811. StringToByteArray(AStr,@(ABuffer[Low(ABuffer)]),Length(ABuffer));
  812. end;
  813. procedure StringToByteArray(AStr : UnicodeString; ABuffer : PByte; const ABufferLength : Integer);
  814. var
  815. c, i, bl : Integer;
  816. ps : PWord;
  817. pb : PByte;
  818. begin
  819. if (ABufferLength < 1) then
  820. exit;
  821. c := Length(AStr);
  822. if (c > ABufferLength) then
  823. c := ABufferLength;
  824. bl := 0;
  825. pb := ABuffer;
  826. if (c > 0) then begin
  827. ps := PWord(@AStr[1]);
  828. for i := 1 to c do begin
  829. if (ps^ <= High(Byte)) then begin
  830. pb^ := ps^;
  831. bl := bl+1;
  832. Inc(pb);
  833. end;
  834. Inc(ps);
  835. end;
  836. end;
  837. if (bl < ABufferLength) then begin
  838. for i := bl+1 to ABufferLength do begin
  839. pb^:= 0;
  840. Inc(pb);
  841. end;
  842. end;
  843. end;
  844. function GenerateEndianIncludeFileName(
  845. const AStoreName : string;
  846. const AEndian : TEndianKind
  847. ): string;inline;
  848. begin
  849. Result := ExtractFilePath(AStoreName) +
  850. ChangeFileExt(ExtractFileName(AStoreName),Format('_%s.inc',[ENDIAN_SUFFIX[AEndian]]));
  851. end;
  852. function IsBitON(const AData : Byte; const ABit : TBitOrder) : Boolean ;
  853. begin
  854. Result := ( ( AData and ( 1 shl ABit ) ) <> 0 );
  855. end;
  856. procedure SetBit(var AData : Byte; const ABit : TBitOrder; const AValue : Boolean);
  857. begin
  858. if AValue then
  859. AData := AData or (1 shl (ABit mod 8))
  860. else
  861. AData := AData and ( not ( 1 shl ( ABit mod 8 ) ) );
  862. end;
  863. var
  864. FS : TFormatSettings;
  865. function EvaluateFloat(const AStr : string) : Double;
  866. var
  867. s, n, d : string;
  868. i : Integer;
  869. begin
  870. Result := 0;
  871. s := Trim(AStr);
  872. if (Length(s) > 0) then begin
  873. i := Pos('/',s);
  874. if (i < 1) then
  875. Result := StrToFloat(s,FS)
  876. else begin
  877. n := Copy(s,1,i-1);
  878. d := Copy(s,i+1,MaxInt);
  879. Result := StrToInt(n) / StrToInt(d);
  880. end;
  881. end;
  882. end;
  883. function StrToCategory(const AStr : string) : TUnicodeCategory;
  884. var
  885. s : string;
  886. begin
  887. s := UpperCase(Trim(AStr));
  888. if (s = 'LU') then
  889. Result := ucUppercaseLetter
  890. else if (s = 'LL') then
  891. Result := ucLowercaseLetter
  892. else if (s = 'LT') then
  893. Result := ucTitlecaseLetter
  894. else if (s = 'LM') then
  895. Result := ucModifierLetter
  896. else if (s = 'LO') then
  897. Result := ucOtherLetter
  898. else
  899. if (s = 'MN') then
  900. Result := ucNonSpacingMark
  901. else if (s = 'MC') then
  902. Result := ucCombiningMark
  903. else if (s = 'ME') then
  904. Result := ucEnclosingMark
  905. else
  906. if (s = 'ND') then
  907. Result := ucDecimalNumber
  908. else if (s = 'NL') then
  909. Result := ucLetterNumber
  910. else if (s = 'NO') then
  911. Result := ucOtherNumber
  912. else
  913. if (s = 'PC') then
  914. Result := ucConnectPunctuation
  915. else if (s = 'PD') then
  916. Result := ucDashPunctuation
  917. else if (s = 'PS') then
  918. Result := ucOpenPunctuation
  919. else if (s = 'PE') then
  920. Result := ucClosePunctuation
  921. else if (s = 'PI') then
  922. Result := ucInitialPunctuation
  923. else if (s = 'PF') then
  924. Result := ucFinalPunctuation
  925. else if (s = 'PO') then
  926. Result := ucOtherPunctuation
  927. else
  928. if (s = 'SM') then
  929. Result := ucMathSymbol
  930. else if (s = 'SC') then
  931. Result := ucCurrencySymbol
  932. else if (s = 'SK') then
  933. Result := ucModifierSymbol
  934. else if (s = 'SO') then
  935. Result := ucOtherSymbol
  936. else
  937. if (s = 'ZS') then
  938. Result := ucSpaceSeparator
  939. else if (s = 'ZL') then
  940. Result := ucLineSeparator
  941. else if (s = 'ZP') then
  942. Result := ucParagraphSeparator
  943. else
  944. if (s = 'CC') then
  945. Result := ucControl
  946. else if (s = 'CF') then
  947. Result := ucFormat
  948. else if (s = 'CS') then
  949. Result := ucSurrogate
  950. else if (s = 'CO') then
  951. Result := ucPrivateUse
  952. else
  953. Result := ucUnassigned;
  954. end;
  955. function StringToCodePoint(ACP : string) : TUnicodeCodePoint;
  956. var
  957. s : string;
  958. begin
  959. s := Trim(ACP);
  960. Result := 0;
  961. if (Length(s) > 0) and (s <> '#') then
  962. Result := StrToInt('$' + s);
  963. end;
  964. {function IsWhiteSpace(const ACodePoint : TUnicodeCodePoint) : Boolean;
  965. begin
  966. case ACodePoint of
  967. $0009..$000D : Result := True;// White_Space # Cc [5] <control-0009>..<control-000D>
  968. $0020 : Result := True;// White_Space # Zs SPACE
  969. $0085 : Result := True;// White_Space # Cc <control-0085>
  970. $00A0 : Result := True;// White_Space # Zs NO-BREAK SPACE
  971. $1680 : Result := True;// White_Space # Zs OGHAM SPACE MARK
  972. $180E : Result := True;// White_Space # Zs MONGOLIAN VOWEL SEPARATOR
  973. $2000..$200A : Result := True;// White_Space # Zs [11] EN QUAD..HAIR SPACE
  974. $2028 : Result := True;// White_Space # Zl LINE SEPARATOR
  975. $2029 : Result := True;// White_Space # Zp PARAGRAPH SEPARATOR
  976. $202F : Result := True;// White_Space # Zs NARROW NO-BREAK SPACE
  977. $205F : Result := True;// White_Space # Zs MEDIUM MATHEMATICAL SPACE
  978. $3000 : Result := True;// White_Space # Zs IDEOGRAPHIC SPACE
  979. else
  980. Result := False;
  981. end;
  982. end;}
  983. function IsWhiteSpace(
  984. const ACodePoint : TUnicodeCodePoint;
  985. const AWhiteSpaces : TCodePointRecArray
  986. ) : Boolean;
  987. var
  988. i : Integer;
  989. p : ^TCodePointRec;
  990. begin
  991. p := @AWhiteSpaces[Low(AWhiteSpaces)];
  992. for i := Low(AWhiteSpaces) to High(AWhiteSpaces) do begin
  993. if (p^.LineType = 0) then begin
  994. if (p^.CodePoint = ACodePoint) then
  995. exit(True);
  996. end else begin
  997. if (ACodePoint >= p^.StartCodePoint) and (ACodePoint <= p^.EndCodePoint) then
  998. exit(True);
  999. end;
  1000. Inc(p);
  1001. end;
  1002. Result := False;
  1003. end;
  1004. function NormalizeBlockName(const AName : string) : string;
  1005. var
  1006. i, c, k : Integer;
  1007. s : string;
  1008. begin
  1009. c := Length(AName);
  1010. SetLength(Result,c);
  1011. s := LowerCase(AName);
  1012. k := 0;
  1013. for i := 1 to c do begin
  1014. if (s[1] in ['a'..'z','0'..'9','-']) then begin
  1015. k := k + 1;
  1016. Result[k] := s[i];
  1017. end;
  1018. end;
  1019. SetLength(Result,k);
  1020. end;
  1021. procedure ParseBlokcs(
  1022. ADataAStream : TMemoryStream;
  1023. var ABlocks : TBlocks
  1024. );
  1025. const
  1026. LINE_LENGTH = 1024;
  1027. DATA_LENGTH = 25000;
  1028. var
  1029. p : PAnsiChar;
  1030. actualDataLen : Integer;
  1031. bufferLength, bufferPos, lineLength, linePos : Integer;
  1032. line : ansistring;
  1033. function NextLine() : Boolean;
  1034. var
  1035. locOldPos : Integer;
  1036. locOldPointer : PAnsiChar;
  1037. begin
  1038. Result := False;
  1039. locOldPointer := p;
  1040. locOldPos := bufferPos;
  1041. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1042. Inc(p);
  1043. Inc(bufferPos);
  1044. end;
  1045. if (locOldPos = bufferPos) and (p^ = #10) then begin
  1046. lineLength := 0;
  1047. Inc(p);
  1048. Inc(bufferPos);
  1049. linePos := 1;
  1050. Result := True;
  1051. end else if (locOldPos < bufferPos) then begin
  1052. lineLength := (bufferPos - locOldPos);
  1053. Move(locOldPointer^,line[1],lineLength);
  1054. if (p^ = #10) then begin
  1055. Dec(lineLength);
  1056. Inc(p);
  1057. Inc(bufferPos);
  1058. end;
  1059. linePos := 1;
  1060. Result := True;
  1061. end;
  1062. end;
  1063. function NextToken() : ansistring;
  1064. var
  1065. k : Integer;
  1066. begin
  1067. k := linePos;
  1068. if (linePos < lineLength) and (line[linePos] in [';','#','.']) then begin
  1069. Inc(linePos);
  1070. Result := Copy(line,k,(linePos-k));
  1071. exit;
  1072. end;
  1073. while (linePos < lineLength) and not(line[linePos] in [';','#','.']) do
  1074. Inc(linePos);
  1075. if (linePos > k) then begin
  1076. if (line[linePos] in [';','#','.']) then
  1077. Result := Copy(line,k,(linePos-k))
  1078. else
  1079. Result := Copy(line,k,(linePos-k+1));
  1080. Result := Trim(Result);
  1081. end else begin
  1082. Result := '';
  1083. end;
  1084. end;
  1085. procedure ParseLine();
  1086. var
  1087. locData : TBlockItemRec;
  1088. s : ansistring;
  1089. begin
  1090. s := NextToken();
  1091. if (s = '') or (s[1] = '#') then
  1092. exit;
  1093. locData.RangeStart := StrToInt('$'+s);
  1094. s := NextToken();
  1095. if (s <> '.') then
  1096. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  1097. s := NextToken();
  1098. if (s <> '.') then
  1099. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  1100. s := NextToken();
  1101. locData.RangeEnd := StrToInt('$'+s);
  1102. s := NextToken();
  1103. if (s <> ';') then
  1104. raise Exception.CreateFmt('";" expected but "%s" found.',[s]);
  1105. locData.Name := Trim(NextToken());
  1106. locData.CanonicalName := NormalizeBlockName(locData.Name);
  1107. if (Length(ABlocks) <= actualDataLen) then
  1108. SetLength(ABlocks,Length(ABlocks)*2);
  1109. ABlocks[actualDataLen] := locData;
  1110. Inc(actualDataLen);
  1111. end;
  1112. procedure Prepare();
  1113. begin
  1114. SetLength(ABlocks,DATA_LENGTH);
  1115. actualDataLen := 0;
  1116. bufferLength := ADataAStream.Size;
  1117. bufferPos := 0;
  1118. p := ADataAStream.Memory;
  1119. lineLength := 0;
  1120. SetLength(line,LINE_LENGTH);
  1121. end;
  1122. begin
  1123. Prepare();
  1124. while NextLine() do
  1125. ParseLine();
  1126. SetLength(ABlocks,actualDataLen);
  1127. end;
  1128. procedure ParseProps(
  1129. ADataAStream : TMemoryStream;
  1130. var APropList : TPropListLineRecArray
  1131. );
  1132. const
  1133. LINE_LENGTH = 1024;
  1134. DATA_LENGTH = 25000;
  1135. var
  1136. p : PAnsiChar;
  1137. actualDataLen : Integer;
  1138. bufferLength, bufferPos, lineLength, linePos : Integer;
  1139. line : ansistring;
  1140. function NextLine() : Boolean;
  1141. var
  1142. locOldPos : Integer;
  1143. locOldPointer : PAnsiChar;
  1144. begin
  1145. Result := False;
  1146. locOldPointer := p;
  1147. locOldPos := bufferPos;
  1148. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1149. Inc(p);
  1150. Inc(bufferPos);
  1151. end;
  1152. if (locOldPos = bufferPos) and (p^ = #10) then begin
  1153. lineLength := 0;
  1154. Inc(p);
  1155. Inc(bufferPos);
  1156. linePos := 1;
  1157. Result := True;
  1158. end else if (locOldPos < bufferPos) then begin
  1159. lineLength := (bufferPos - locOldPos);
  1160. Move(locOldPointer^,line[1],lineLength);
  1161. if (p^ = #10) then begin
  1162. Dec(lineLength);
  1163. Inc(p);
  1164. Inc(bufferPos);
  1165. end;
  1166. linePos := 1;
  1167. Result := True;
  1168. end;
  1169. end;
  1170. function NextToken() : ansistring;
  1171. var
  1172. k : Integer;
  1173. begin
  1174. k := linePos;
  1175. if (linePos < lineLength) and (line[linePos] in [';','#','.']) then begin
  1176. Inc(linePos);
  1177. Result := Copy(line,k,(linePos-k));
  1178. exit;
  1179. end;
  1180. while (linePos < lineLength) and not(line[linePos] in [';','#','.']) do
  1181. Inc(linePos);
  1182. if (linePos > k) then begin
  1183. if (line[linePos] in [';','#','.']) then
  1184. Result := Copy(line,k,(linePos-k))
  1185. else
  1186. Result := Copy(line,k,(linePos-k+1));
  1187. Result := Trim(Result);
  1188. end else begin
  1189. Result := '';
  1190. end;
  1191. end;
  1192. procedure ParseLine();
  1193. var
  1194. locCP : Cardinal;
  1195. locData : TPropListLineRec;
  1196. s : ansistring;
  1197. begin
  1198. s := NextToken();
  1199. if (s = '') or (s[1] = '#') then
  1200. exit;
  1201. locCP := StrToInt('$'+s);
  1202. s := NextToken();
  1203. if (s = ';') then begin
  1204. locData.CodePoint.LineType := 0;
  1205. locData.CodePoint.CodePoint := locCP;
  1206. end else begin
  1207. if (s = '') or (s <> '.') or (NextToken() <> '.') then
  1208. raise Exception.CreateFmt('Invalid line : "%s".',[Copy(line,1,lineLength)]);
  1209. locData.CodePoint.LineType := 1;
  1210. locData.CodePoint.StartCodePoint := locCP;
  1211. locData.CodePoint.EndCodePoint := StrToInt('$'+NextToken());
  1212. s := NextToken();
  1213. if (s <> ';') then
  1214. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  1215. end;
  1216. locData.PropName := Trim(NextToken());
  1217. if (Length(APropList) <= actualDataLen) then
  1218. SetLength(APropList,Length(APropList)*2);
  1219. APropList[actualDataLen] := locData;
  1220. Inc(actualDataLen);
  1221. end;
  1222. procedure Prepare();
  1223. begin
  1224. SetLength(APropList,DATA_LENGTH);
  1225. actualDataLen := 0;
  1226. bufferLength := ADataAStream.Size;
  1227. bufferPos := 0;
  1228. p := ADataAStream.Memory;
  1229. lineLength := 0;
  1230. SetLength(line,LINE_LENGTH);
  1231. end;
  1232. begin
  1233. Prepare();
  1234. while NextLine() do
  1235. ParseLine();
  1236. SetLength(APropList,actualDataLen);
  1237. end;
  1238. function FindCodePointsByProperty(
  1239. const APropName : string;
  1240. const APropList : TPropListLineRecArray
  1241. ) : TCodePointRecArray;
  1242. var
  1243. r : TCodePointRecArray;
  1244. i, k : Integer;
  1245. s : string;
  1246. begin
  1247. k := 0;
  1248. r := nil;
  1249. s := LowerCase(Trim(APropName));
  1250. for i := Low(APropList) to High(APropList) do begin
  1251. if (LowerCase(APropList[i].PropName) = s) then begin
  1252. if (k >= Length(r)) then begin
  1253. if (k = 0) then
  1254. SetLength(r,24)
  1255. else
  1256. SetLength(r,(2*Length(r)));
  1257. end;
  1258. r[k] := APropList[i].CodePoint;
  1259. Inc(k);
  1260. end;
  1261. end;
  1262. SetLength(r,k);
  1263. Result := r;
  1264. end;
  1265. procedure ParseHangulSyllableTypes(
  1266. ADataAStream : TMemoryStream;
  1267. var ACodePointList : TCodePointRecArray
  1268. );
  1269. const
  1270. LINE_LENGTH = 1024;
  1271. DATA_LENGTH = 25000;
  1272. var
  1273. p : PAnsiChar;
  1274. actualDataLen : Integer;
  1275. bufferLength, bufferPos, lineLength, linePos : Integer;
  1276. line : ansistring;
  1277. function NextLine() : Boolean;
  1278. var
  1279. locOldPos : Integer;
  1280. locOldPointer : PAnsiChar;
  1281. begin
  1282. Result := False;
  1283. locOldPointer := p;
  1284. locOldPos := bufferPos;
  1285. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1286. Inc(p);
  1287. Inc(bufferPos);
  1288. end;
  1289. if (locOldPos = bufferPos) and (p^ = #10) then begin
  1290. lineLength := 0;
  1291. Inc(p);
  1292. Inc(bufferPos);
  1293. linePos := 1;
  1294. Result := True;
  1295. end else if (locOldPos < bufferPos) then begin
  1296. lineLength := (bufferPos - locOldPos);
  1297. Move(locOldPointer^,line[1],lineLength);
  1298. if (p^ = #10) then begin
  1299. Dec(lineLength);
  1300. Inc(p);
  1301. Inc(bufferPos);
  1302. end;
  1303. linePos := 1;
  1304. Result := True;
  1305. end;
  1306. end;
  1307. function NextToken() : ansistring;
  1308. var
  1309. k : Integer;
  1310. begin
  1311. k := linePos;
  1312. if (linePos < lineLength) and (line[linePos] = '.') then begin
  1313. Inc(linePos);
  1314. while (linePos < lineLength) and (line[linePos] = '.') do begin
  1315. Inc(linePos);
  1316. end;
  1317. Result := Copy(line,k,(linePos-k));
  1318. exit;
  1319. end;
  1320. while (linePos < lineLength) and not(line[linePos] in [';','#','.']) do
  1321. Inc(linePos);
  1322. if (linePos > k) then begin
  1323. if (line[linePos] in [';','#','.']) then
  1324. Result := Copy(line,k,(linePos-k))
  1325. else
  1326. Result := Copy(line,k,(linePos-k+1));
  1327. Result := Trim(Result);
  1328. end else begin
  1329. Result := '';
  1330. end;
  1331. //Inc(linePos);
  1332. end;
  1333. procedure ParseLine();
  1334. var
  1335. locData : TCodePointRec;
  1336. s : ansistring;
  1337. begin
  1338. s := NextToken();
  1339. if (s = '') or (s[1] = '#') then
  1340. exit;
  1341. locData.CodePoint := StrToInt('$'+s);
  1342. s := NextToken();
  1343. if (s = '') or (s[1] in [';','#']) then begin
  1344. locData.LineType := 0;
  1345. end else begin
  1346. if (s <> '..') then
  1347. raise Exception.CreateFmt('Unknown line type : "%s"',[Copy(line,1,lineLength)]);
  1348. locData.StartCodePoint := locData.CodePoint;
  1349. locData.EndCodePoint := StrToInt('$'+NextToken());
  1350. locData.LineType := 1;
  1351. end;
  1352. if (Length(ACodePointList) <= actualDataLen) then
  1353. SetLength(ACodePointList,Length(ACodePointList)*2);
  1354. ACodePointList[actualDataLen] := locData;
  1355. Inc(actualDataLen);
  1356. end;
  1357. procedure Prepare();
  1358. begin
  1359. SetLength(ACodePointList,DATA_LENGTH);
  1360. actualDataLen := 0;
  1361. bufferLength := ADataAStream.Size;
  1362. bufferPos := 0;
  1363. p := ADataAStream.Memory;
  1364. lineLength := 0;
  1365. SetLength(line,LINE_LENGTH);
  1366. end;
  1367. begin
  1368. Prepare();
  1369. while NextLine() do
  1370. ParseLine();
  1371. SetLength(ACodePointList,actualDataLen);
  1372. end;
  1373. function IsHangulSyllable(
  1374. const ACodePoint : TUnicodeCodePoint;
  1375. const AHangulList : TCodePointRecArray
  1376. ) : Boolean;
  1377. var
  1378. i : Integer;
  1379. p : ^TCodePointRec;
  1380. begin
  1381. Result := False;
  1382. p := @AHangulList[Low(AHangulList)];
  1383. for i := Low(AHangulList) to High(AHangulList) do begin
  1384. if ( (p^.LineType = 0) and (ACodePoint = p^.CodePoint) ) or
  1385. ( (p^.LineType = 1) and (ACodePoint >= p^.StartCodePoint) and (ACodePoint <= p^.EndCodePoint) )
  1386. then begin
  1387. Result := True;
  1388. Break;
  1389. end;
  1390. Inc(p);
  1391. end;
  1392. end;
  1393. function IndexOf(
  1394. const AProp : TPropRec;
  1395. const APropList : TPropRecArray;
  1396. const AActualLen : Integer
  1397. ) : Integer;overload;
  1398. var
  1399. i : Integer;
  1400. p : PPropRec;
  1401. begin
  1402. Result := -1;
  1403. if (AActualLen > 0) then begin
  1404. p := @APropList[0];
  1405. for i := 0 to AActualLen - 1 do begin
  1406. if (AProp.Category = p^.Category) and
  1407. (AProp.CCC = p^.CCC) and
  1408. (AProp.NumericIndex = p^.NumericIndex) and
  1409. (AProp.SimpleUpperCase = p^.SimpleUpperCase) and
  1410. (AProp.SimpleLowerCase = p^.SimpleLowerCase) and
  1411. (AProp.WhiteSpace = p^.WhiteSpace) and
  1412. //
  1413. (AProp.DecompositionID = p^.DecompositionID) and
  1414. (* ( (AProp.DecompositionID = -1 ) and (p^.DecompositionID = -1) ) or
  1415. ( (AProp.DecompositionID <> -1 ) and (p^.DecompositionID <> -1) )
  1416. *)
  1417. (AProp.HangulSyllable = p^.HangulSyllable)
  1418. then begin
  1419. Result := i;
  1420. Break;
  1421. end;
  1422. Inc(p);
  1423. end;
  1424. end;
  1425. end;
  1426. function IndexOf(
  1427. const AItem : TUnicodeCodePointArray;
  1428. const AList : TDecompositionArray
  1429. ) : Integer;overload;
  1430. var
  1431. p : TUnicodeCodePointArray;
  1432. i : Integer;
  1433. begin
  1434. Result := -1;
  1435. if (Length(AList) = 0) then
  1436. exit;
  1437. for i := Low(AList) to High(AList) do begin
  1438. p := AList[i];
  1439. if (Length(p) = Length(AItem)) then begin
  1440. if CompareMem(@p[0],@AItem[0],Length(AItem)*SizeOf(TUnicodeCodePoint)) then
  1441. exit(i);
  1442. end;
  1443. end;
  1444. Result := -1;
  1445. end;
  1446. function IndexOf(
  1447. const AItem : TNumericValue;
  1448. const AList : TNumericValueArray;
  1449. const AActualLen : Integer
  1450. ) : Integer;overload;
  1451. var
  1452. p : ^TNumericValue;
  1453. i : Integer;
  1454. begin
  1455. Result := -1;
  1456. if (AActualLen = 0) then
  1457. exit;
  1458. p := @AList[Low(AList)];
  1459. for i := Low(AList) to AActualLen - 1 do begin
  1460. if (AItem = p^) then
  1461. exit(i);
  1462. Inc(p);
  1463. end;
  1464. Result := -1;
  1465. end;
  1466. procedure Parse_UnicodeData(
  1467. ADataAStream : TMemoryStream;
  1468. var APropList : TPropRecArray;
  1469. var ANumericTable : TNumericValueArray;
  1470. var ADataLineList : TDataLineRecArray;
  1471. var ADecomposition : TDecompositionArray;
  1472. const AHangulList : TCodePointRecArray;
  1473. const AWhiteSpaces : TCodePointRecArray
  1474. );
  1475. const
  1476. LINE_LENGTH = 1024;
  1477. PROP_LENGTH = 5000;
  1478. DATA_LENGTH = 25000;
  1479. var
  1480. p : PAnsiChar;
  1481. bufferLength, bufferPos : Integer;
  1482. actualPropLen, actualDataLen, actualNumLen : Integer;
  1483. line : ansistring;
  1484. lineLength, linePos : Integer;
  1485. function NextLine() : Boolean;
  1486. var
  1487. locOldPos : Integer;
  1488. locOldPointer : PAnsiChar;
  1489. begin
  1490. Result := False;
  1491. locOldPointer := p;
  1492. locOldPos := bufferPos;
  1493. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1494. Inc(p);
  1495. Inc(bufferPos);
  1496. end;
  1497. if (locOldPos < bufferPos) then begin
  1498. lineLength := (bufferPos - locOldPos);
  1499. Move(locOldPointer^,line[1],lineLength);
  1500. if (p^ = #10) then begin
  1501. Dec(lineLength);
  1502. Inc(p);
  1503. Inc(bufferPos);
  1504. end;
  1505. if (lineLength > 7) then begin
  1506. linePos := 1;
  1507. Result := True;
  1508. end;
  1509. end;
  1510. end;
  1511. function NextToken() : ansistring;
  1512. var
  1513. k : Integer;
  1514. begin
  1515. k := linePos;
  1516. while (linePos < lineLength) and not(line[linePos] in [';','#']) do
  1517. Inc(linePos);
  1518. if (linePos > k) then begin
  1519. if (line[linePos] in [';','#']) then
  1520. Result := Copy(line,k,(linePos-k))
  1521. else
  1522. Result := Copy(line,k,(linePos-k+1));
  1523. Result := Trim(Result);
  1524. end else begin
  1525. Result := '';
  1526. end;
  1527. Inc(linePos);
  1528. end;
  1529. function ParseCanonicalDecomposition(AStr : ansistring) : TUnicodeCodePointArray;
  1530. var
  1531. locStr, ks : ansistring;
  1532. k0,k : Integer;
  1533. begin
  1534. SetLength(Result,0);
  1535. locStr := UpperCase(Trim(AStr));
  1536. if (locStr = '') or (locStr[1] = '<') then
  1537. exit;
  1538. k0 := 1;
  1539. k := 1;
  1540. while (k <= Length(locStr)) do begin
  1541. while (k <= Length(locStr)) and (locStr[k] in ['0'..'9','A'..'F']) do
  1542. inc(k);
  1543. ks := Trim(Copy(locStr,k0,k-k0));
  1544. SetLength(Result,Length(Result)+1);
  1545. Result[Length(Result)-1] := StringToCodePoint(ks);
  1546. Inc(k);
  1547. k0 := k;
  1548. end;
  1549. end;
  1550. procedure ParseLine();
  1551. var
  1552. locCP : TUnicodeCodePoint;
  1553. locProp : TPropRec;
  1554. locData : TDataLineRec;
  1555. s : ansistring;
  1556. locRangeStart, locRangeEnd : Boolean;
  1557. k : Integer;
  1558. locDecompItem : TUnicodeCodePointArray;
  1559. numVal : TNumericValue;
  1560. begin
  1561. FillChar(locData,SizeOf(locData),#0);
  1562. FillChar(locProp,SizeOf(locProp),#0);
  1563. locCP := StrToInt('$'+NextToken());
  1564. s := NextToken();
  1565. locRangeStart := AnsiEndsText(', First>',s);
  1566. if locRangeStart then
  1567. locRangeEnd := False
  1568. else
  1569. locRangeEnd := AnsiEndsText(', Last>',s);
  1570. if locRangeStart then begin
  1571. locData.LineType := 1;
  1572. locData.StartCodePoint := locCP;
  1573. end else if locRangeEnd then begin
  1574. ADataLineList[actualDataLen - 1].EndCodePoint := locCP;
  1575. exit;
  1576. //locData.EndCodePoint := locCP;
  1577. end else begin
  1578. locData.LineType := 0;
  1579. locData.CodePoint := locCP;
  1580. end;
  1581. locProp.Category := StrToCategory(NextToken());
  1582. locProp.CCC := StrToInt(NextToken());//Canonical_Combining_Class
  1583. NextToken();//Bidi_Class
  1584. s := NextToken();//Decomposition_Type
  1585. locDecompItem := ParseCanonicalDecomposition(s);
  1586. if (Length(locDecompItem) = 0) then
  1587. locProp.DecompositionID := -1
  1588. else begin
  1589. locProp.DecompositionID := IndexOf(locDecompItem,ADecomposition);
  1590. if (locProp.DecompositionID = -1) then begin
  1591. k := Length(ADecomposition);
  1592. locProp.DecompositionID := k;
  1593. SetLength(ADecomposition,k+1);
  1594. ADecomposition[k] := locDecompItem;
  1595. end;
  1596. end;
  1597. numVal := EvaluateFloat(NextToken());
  1598. if (numVal <> Double(0.0)) then begin
  1599. NextToken();
  1600. NextToken();
  1601. end else begin
  1602. s := NextToken();
  1603. if (s <> '') then
  1604. numVal := EvaluateFloat(s);
  1605. s := NextToken();
  1606. if (numVal = Double(0.0)) then
  1607. numVal := EvaluateFloat(s);
  1608. end;
  1609. k := IndexOf(numVal,ANumericTable,actualNumLen);
  1610. if (k = -1) then begin
  1611. if (actualNumLen >= Length(ANumericTable)) then
  1612. SetLength(ANumericTable,(actualNumLen*2));
  1613. ANumericTable[actualNumLen] := numVal;
  1614. k := actualNumLen;
  1615. Inc(actualNumLen);
  1616. end;
  1617. locProp.NumericIndex := k;
  1618. NextToken();//Bidi_Mirroed
  1619. NextToken();//Unicode_l_Name
  1620. NextToken();//ISO_Comment
  1621. locProp.SimpleUpperCase := StringToCodePoint(NextToken());
  1622. locProp.SimpleLowerCase := StringToCodePoint(NextToken());
  1623. NextToken();//Simple_Title_Case_Mapping
  1624. locProp.WhiteSpace := IsWhiteSpace(locCP,AWhiteSpaces);
  1625. locProp.HangulSyllable := IsHangulSyllable(locCP,AHangulList);
  1626. k := IndexOf(locProp,APropList,actualPropLen);
  1627. if (k = -1) then begin
  1628. k := actualPropLen;
  1629. locProp.PropID := k{ + 1};
  1630. APropList[k] := locProp;
  1631. Inc(actualPropLen);
  1632. end;
  1633. locData.PropID := k;
  1634. if (actualDataLen >= Length(ADataLineList)) then
  1635. SetLength(ADataLineList,(2*Length(ADataLineList)));
  1636. ADataLineList[actualDataLen] := locData;
  1637. Inc(actualDataLen);
  1638. end;
  1639. procedure Prepare();
  1640. var
  1641. r : TPropRec;
  1642. begin
  1643. SetLength(APropList,PROP_LENGTH);
  1644. actualPropLen := 0;
  1645. SetLength(ADataLineList,DATA_LENGTH);
  1646. actualDataLen := 0;
  1647. bufferLength := ADataAStream.Size;
  1648. bufferPos := 0;
  1649. p := ADataAStream.Memory;
  1650. lineLength := 0;
  1651. SetLength(line,LINE_LENGTH);
  1652. SetLength(ANumericTable,500);
  1653. actualNumLen := 0;
  1654. FillChar(r,SizeOf(r),#0);
  1655. r.PropID := 0;
  1656. r.Category := ucUnassigned;
  1657. r.DecompositionID := -1;
  1658. r.NumericIndex := 0;
  1659. APropList[0] := r;
  1660. Inc(actualPropLen);
  1661. ANumericTable[0] := 0;
  1662. Inc(actualNumLen);
  1663. end;
  1664. begin
  1665. Prepare();
  1666. while NextLine() do
  1667. ParseLine();
  1668. SetLength(APropList,actualPropLen);
  1669. SetLength(ADataLineList,actualDataLen);
  1670. SetLength(ANumericTable,actualNumLen);
  1671. end;
  1672. function GetPropID(
  1673. ACodePoint : TUnicodeCodePoint;
  1674. const ADataLineList : TDataLineRecArray
  1675. ) : Cardinal;
  1676. var
  1677. i : Integer;
  1678. p : PDataLineRec;
  1679. begin
  1680. Result := 0;
  1681. p := @ADataLineList[Low(ADataLineList)];
  1682. for i := Low(ADataLineList) to High(ADataLineList) do begin
  1683. if (p^.LineType = 0) then begin
  1684. if (p^.CodePoint = ACodePoint) then begin
  1685. Result := p^.PropID;
  1686. Break;
  1687. end;
  1688. end else begin
  1689. if (p^.StartCodePoint <= ACodePoint) and (p^.EndCodePoint >= ACodePoint) then begin
  1690. Result := p^.PropID;
  1691. Break;
  1692. end;
  1693. end;
  1694. Inc(p);
  1695. end;
  1696. end;
  1697. procedure MakeDecomposition(
  1698. const ARawData : TDecompositionArray;
  1699. var ABook : TDecompositionBook
  1700. );
  1701. var
  1702. i, c, locPos : Integer;
  1703. locItem : TUnicodeCodePointArray;
  1704. begin
  1705. c := 0;
  1706. for i := Low(ARawData) to High(ARawData) do
  1707. c := c + Length(ARawData[i]);
  1708. SetLength(ABook.CodePoints,c);
  1709. SetLength(ABook.Index,Length(ARawData));
  1710. locPos := 0;
  1711. for i := Low(ARawData) to High(ARawData) do begin
  1712. locItem := ARawData[i];
  1713. ABook.Index[i].StartPosition := locPos;
  1714. ABook.Index[i].Length := Length(locItem);
  1715. Move(locItem[0],ABook.CodePoints[locPos],(Length(locItem) * SizeOf(TUnicodeCodePoint)));
  1716. locPos := locPos + Length(locItem);
  1717. end;
  1718. end;
  1719. type
  1720. PBmpSecondTableItem = ^TBmpSecondTableItem;
  1721. function IndexOf(
  1722. const AItem : PBmpSecondTableItem;
  1723. const ATable : TBmpSecondTable;
  1724. const ATableActualLength : Integer
  1725. ) : Integer;overload;
  1726. var
  1727. i : Integer;
  1728. p : PBmpSecondTableItem;
  1729. begin
  1730. Result := -1;
  1731. if (ATableActualLength > 0) then begin
  1732. p := @ATable[0];
  1733. for i := 0 to ATableActualLength - 1 do begin
  1734. if CompareMem(p,AItem,SizeOf(TBmpSecondTableItem)) then begin
  1735. Result := i;
  1736. Break;
  1737. end;
  1738. Inc(p);
  1739. end;
  1740. end;
  1741. end;
  1742. procedure MakeBmpTables(
  1743. var AFirstTable : TBmpFirstTable;
  1744. var ASecondTable : TBmpSecondTable;
  1745. const ADataLineList : TDataLineRecArray
  1746. );
  1747. var
  1748. locLowByte, locHighByte : Byte;
  1749. locTableItem : TBmpSecondTableItem;
  1750. locCP : TUnicodeCodePoint;
  1751. i, locSecondActualLen : Integer;
  1752. begin
  1753. SetLength(ASecondTable,120);
  1754. locSecondActualLen := 0;
  1755. for locHighByte := 0 to 255 do begin
  1756. FillChar(locTableItem,SizeOf(locTableItem),#0);
  1757. for locLowByte := 0 to 255 do begin
  1758. locCP := (locHighByte * 256) + locLowByte;
  1759. locTableItem[locLowByte] := GetPropID(locCP,ADataLineList)// - 1;
  1760. end;
  1761. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  1762. if (i = -1) then begin
  1763. if (locSecondActualLen = Length(ASecondTable)) then
  1764. SetLength(ASecondTable,locSecondActualLen + 50);
  1765. i := locSecondActualLen;
  1766. ASecondTable[i] := locTableItem;
  1767. Inc(locSecondActualLen);
  1768. end;
  1769. AFirstTable[locHighByte] := i;
  1770. end;
  1771. SetLength(ASecondTable,locSecondActualLen);
  1772. end;
  1773. type
  1774. P3lvlBmp3TableItem = ^T3lvlBmp3TableItem;
  1775. function IndexOf(
  1776. const AItem : P3lvlBmp3TableItem;
  1777. const ATable : T3lvlBmp3Table;
  1778. const ATableActualLength : Integer
  1779. ) : Integer;overload;
  1780. var
  1781. i : Integer;
  1782. p : P3lvlBmp3TableItem;
  1783. begin
  1784. Result := -1;
  1785. if (ATableActualLength > 0) then begin
  1786. p := @ATable[0];
  1787. for i := 0 to ATableActualLength - 1 do begin
  1788. if CompareMem(p,AItem,SizeOf(T3lvlBmp3TableItem)) then begin
  1789. Result := i;
  1790. Break;
  1791. end;
  1792. Inc(p);
  1793. end;
  1794. end;
  1795. end;
  1796. type
  1797. P3lvlBmp2TableItem = ^T3lvlBmp2TableItem;
  1798. function IndexOf(
  1799. const AItem : P3lvlBmp2TableItem;
  1800. const ATable : T3lvlBmp2Table
  1801. ) : Integer;overload;
  1802. var
  1803. i : Integer;
  1804. p : P3lvlBmp2TableItem;
  1805. begin
  1806. Result := -1;
  1807. if (Length(ATable) > 0) then begin
  1808. p := @ATable[0];
  1809. for i := 0 to Length(ATable) - 1 do begin
  1810. if CompareMem(p,AItem,SizeOf(T3lvlBmp2TableItem)) then begin
  1811. Result := i;
  1812. Break;
  1813. end;
  1814. Inc(p);
  1815. end;
  1816. end;
  1817. end;
  1818. procedure MakeBmpTables3Levels(
  1819. var AFirstTable : T3lvlBmp1Table;
  1820. var ASecondTable : T3lvlBmp2Table;
  1821. var AThirdTable : T3lvlBmp3Table;
  1822. const ADataLineList : TDataLineRecArray
  1823. );
  1824. var
  1825. locLowByte0, locLowByte1, locHighByte : Byte;
  1826. locTableItem2 : T3lvlBmp2TableItem;
  1827. locTableItem3 : T3lvlBmp3TableItem;
  1828. locCP : TUnicodeCodePoint;
  1829. i, locThirdActualLen : Integer;
  1830. begin
  1831. SetLength(AThirdTable,120);
  1832. locThirdActualLen := 0;
  1833. for locHighByte := 0 to 255 do begin
  1834. FillChar(locTableItem2,SizeOf(locTableItem2),#0);
  1835. for locLowByte0 := 0 to 15 do begin
  1836. FillChar(locTableItem3,SizeOf(locTableItem3),#0);
  1837. for locLowByte1 := 0 to 15 do begin
  1838. locCP := (locHighByte * 256) + (locLowByte0*16) + locLowByte1;
  1839. locTableItem3[locLowByte1] := GetPropID(locCP,ADataLineList);
  1840. end;
  1841. i := IndexOf(@locTableItem3,AThirdTable,locThirdActualLen);
  1842. if (i = -1) then begin
  1843. if (locThirdActualLen = Length(AThirdTable)) then
  1844. SetLength(AThirdTable,locThirdActualLen + 50);
  1845. i := locThirdActualLen;
  1846. AThirdTable[i] := locTableItem3;
  1847. Inc(locThirdActualLen);
  1848. end;
  1849. locTableItem2[locLowByte0] := i;
  1850. end;
  1851. i := IndexOf(@locTableItem2,ASecondTable);
  1852. if (i = -1) then begin
  1853. i := Length(ASecondTable);
  1854. SetLength(ASecondTable,(i + 1));
  1855. ASecondTable[i] := locTableItem2;
  1856. end;
  1857. AFirstTable[locHighByte] := i;
  1858. end;
  1859. SetLength(AThirdTable,locThirdActualLen);
  1860. end;
  1861. procedure GenerateLicenceText(ADest : TStream);
  1862. var
  1863. s : ansistring;
  1864. begin
  1865. s := SLicenseText + sLineBreak + sLineBreak;
  1866. ADest.Write(s[1],Length(s));
  1867. end;
  1868. procedure GenerateBmpTables(
  1869. ADest : TStream;
  1870. var AFirstTable : TBmpFirstTable;
  1871. var ASecondTable : TBmpSecondTable
  1872. );
  1873. procedure AddLine(const ALine : ansistring);
  1874. var
  1875. buffer : ansistring;
  1876. begin
  1877. buffer := ALine + sLineBreak;
  1878. ADest.Write(buffer[1],Length(buffer));
  1879. end;
  1880. var
  1881. i, j, c : Integer;
  1882. locLine : string;
  1883. begin
  1884. AddLine('const');
  1885. AddLine(' UC_TABLE_1 : array[0..255] of Byte = (');
  1886. locLine := '';
  1887. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  1888. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  1889. if (((i+1) mod 16) = 0) then begin
  1890. locLine := ' ' + locLine;
  1891. AddLine(locLine);
  1892. locLine := '';
  1893. end;
  1894. end;
  1895. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  1896. locLine := ' ' + locLine;
  1897. AddLine(locLine);
  1898. AddLine(' );' + sLineBreak);
  1899. AddLine(' UC_TABLE_2 : array[0..(256*' + IntToStr(Length(ASecondTable)) +'-1)] of Word =(');
  1900. c := High(ASecondTable);
  1901. for i := Low(ASecondTable) to c do begin
  1902. locLine := '';
  1903. for j := Low(TBmpSecondTableItem) to High(TBmpSecondTableItem) do begin
  1904. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  1905. if (((j+1) mod 16) = 0) then begin
  1906. if (i = c) and (j = 255) then
  1907. Delete(locLine,Length(locLine),1);
  1908. locLine := ' ' + locLine;
  1909. AddLine(locLine);
  1910. locLine := '';
  1911. end;
  1912. end;
  1913. end;
  1914. AddLine(' );' + sLineBreak);
  1915. end;
  1916. //----------------------------------
  1917. procedure Generate3lvlBmpTables(
  1918. ADest : TStream;
  1919. var AFirstTable : T3lvlBmp1Table;
  1920. var ASecondTable : T3lvlBmp2Table;
  1921. var AThirdTable : T3lvlBmp3Table
  1922. );
  1923. procedure AddLine(const ALine : ansistring);
  1924. var
  1925. buffer : ansistring;
  1926. begin
  1927. buffer := ALine + sLineBreak;
  1928. ADest.Write(buffer[1],Length(buffer));
  1929. end;
  1930. var
  1931. i, j, c : Integer;
  1932. locLine : string;
  1933. begin
  1934. AddLine('const');
  1935. AddLine(' UC_TABLE_1 : array[0..255] of Byte = (');
  1936. locLine := '';
  1937. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  1938. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  1939. if (((i+1) mod 16) = 0) then begin
  1940. locLine := ' ' + locLine;
  1941. AddLine(locLine);
  1942. locLine := '';
  1943. end;
  1944. end;
  1945. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  1946. locLine := ' ' + locLine;
  1947. AddLine(locLine);
  1948. AddLine(' );' + sLineBreak);
  1949. AddLine(' UC_TABLE_2 : array[0..' + IntToStr(Length(ASecondTable)-1) +'] of array[0..15] of Word = (');
  1950. c := High(ASecondTable);
  1951. for i := Low(ASecondTable) to c do begin
  1952. locLine := '(';
  1953. for j := Low(T3lvlBmp2TableItem) to High(T3lvlBmp2TableItem) do
  1954. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  1955. Delete(locLine,Length(locLine),1);
  1956. locLine := ' ' + locLine + ')';
  1957. if (i < c) then
  1958. locLine := locLine + ',';
  1959. AddLine(locLine);
  1960. end;
  1961. AddLine(' );' + sLineBreak);
  1962. AddLine(' UC_TABLE_3 : array[0..' + IntToStr(Length(AThirdTable)-1) +'] of array[0..15] of Word = (');
  1963. c := High(AThirdTable);
  1964. for i := Low(AThirdTable) to c do begin
  1965. locLine := '(';
  1966. for j := Low(T3lvlBmp3TableItem) to High(T3lvlBmp3TableItem) do
  1967. locLine := locLine + IntToStr(AThirdTable[i][j]) + ',';
  1968. Delete(locLine,Length(locLine),1);
  1969. locLine := ' ' + locLine + ')';
  1970. if (i < c) then
  1971. locLine := locLine + ',';
  1972. AddLine(locLine);
  1973. end;
  1974. AddLine(' );' + sLineBreak);
  1975. end;
  1976. function UInt24ToStr(const AValue : UInt24; const AEndian : TEndianKind): string;inline;
  1977. begin
  1978. if (AEndian = ekBig) then
  1979. Result := Format(
  1980. '(byte2 : $%s; byte1 : $%s; byte0 : $%s;)',
  1981. [ IntToHex(AValue.byte2,2), IntToHex(AValue.byte1,2),
  1982. IntToHex(AValue.byte0,2)
  1983. ]
  1984. )
  1985. else
  1986. Result := Format(
  1987. '(byte0 : $%s; byte1 : $%s; byte2 : $%s;)',
  1988. [ IntToHex(AValue.byte0,2), IntToHex(AValue.byte1,2),
  1989. IntToHex(AValue.byte2,2)
  1990. ]
  1991. );
  1992. end;
  1993. procedure GeneratePropTable(
  1994. ADest : TStream;
  1995. const APropList : TPropRecArray;
  1996. const AEndian : TEndianKind
  1997. );
  1998. procedure AddLine(const ALine : ansistring);
  1999. var
  2000. buffer : ansistring;
  2001. begin
  2002. buffer := ALine + sLineBreak;
  2003. ADest.Write(buffer[1],Length(buffer));
  2004. end;
  2005. var
  2006. i : Integer;
  2007. locLine : string;
  2008. p : PPropRec;
  2009. begin
  2010. AddLine('');
  2011. AddLine('const');
  2012. AddLine(' UC_PROP_REC_COUNT = ' + IntToStr(Length(APropList)) + ';');
  2013. AddLine(' UC_PROP_ARRAY : array[0..(UC_PROP_REC_COUNT-1)] of TUC_Prop = (');
  2014. p := @APropList[0];
  2015. for i := Low(APropList) to High(APropList) - 1 do begin
  2016. locLine := ' (CategoryData : ' + IntToStr(p^.CategoryData) + ';' +
  2017. ' CCC : ' + IntToStr(p^.CCC) + ';' +
  2018. ' NumericIndex : ' + IntToStr(p^.NumericIndex) + ';' +
  2019. ' SimpleUpperCase : ' + UInt24ToStr(p^.SimpleUpperCase,AEndian) + ';' +
  2020. ' SimpleLowerCase : ' + UInt24ToStr(p^.SimpleLowerCase,AEndian) + ';' +
  2021. ' DecompositionID : ' + IntToStr(p^.DecompositionID) + '),';
  2022. AddLine(locLine);
  2023. Inc(p);
  2024. end;
  2025. locLine := //' (Category : TUnicodeCategory.' + GetEnumName(pti,Ord(p^.Category)) + ';' +
  2026. ' (CategoryData : ' + IntToStr(p^.CategoryData) + ';' +
  2027. ' CCC : ' + IntToStr(p^.CCC) + ';' +
  2028. ' NumericIndex : ' + IntToStr(p^.NumericIndex) + ';' +
  2029. ' SimpleUpperCase : ' + UInt24ToStr(p^.SimpleUpperCase,AEndian) + ';' +
  2030. ' SimpleLowerCase : ' + UInt24ToStr(p^.SimpleLowerCase,AEndian) + ';' +
  2031. ' DecompositionID : ' + IntToStr(p^.DecompositionID) + ')';
  2032. AddLine(locLine);
  2033. AddLine(' );' + sLineBreak);
  2034. end;
  2035. procedure GenerateNumericTable(
  2036. ADest : TStream;
  2037. const ANumList : TNumericValueArray;
  2038. const ACompleteUnit : Boolean
  2039. );
  2040. procedure AddLine(const ALine : ansistring);
  2041. var
  2042. buffer : ansistring;
  2043. begin
  2044. buffer := ALine + sLineBreak;
  2045. ADest.Write(buffer[1],Length(buffer));
  2046. end;
  2047. var
  2048. i : Integer;
  2049. locLine : string;
  2050. p : ^TNumericValue;
  2051. begin
  2052. if ACompleteUnit then begin
  2053. GenerateLicenceText(ADest);
  2054. AddLine('unit unicodenumtable;');
  2055. AddLine('interface');
  2056. AddLine('');
  2057. end;
  2058. AddLine('');
  2059. AddLine('const');
  2060. AddLine(' UC_NUMERIC_COUNT = ' + IntToStr(Length(ANumList)) + ';');
  2061. AddLine(' UC_NUMERIC_ARRAY : array[0..(UC_NUMERIC_COUNT-1)] of Double = (');
  2062. locLine := '';
  2063. p := @ANumList[0];
  2064. for i := Low(ANumList) to High(ANumList) - 1 do begin
  2065. locLine := locLine + FloatToStr(p^,FS) + ' ,';
  2066. if (i > 0) and ((i mod 8) = 0) then begin
  2067. AddLine(' ' + locLine);
  2068. locLine := '';
  2069. end;
  2070. Inc(p);
  2071. end;
  2072. locLine := locLine + FloatToStr(p^,FS);
  2073. AddLine(' ' + locLine);
  2074. AddLine(' );' + sLineBreak);
  2075. if ACompleteUnit then begin
  2076. AddLine('');
  2077. AddLine('implementation');
  2078. AddLine('');
  2079. AddLine('end.');
  2080. end;
  2081. end;
  2082. procedure GenerateDecompositionBookTable(
  2083. ADest : TStream;
  2084. const ABook : TDecompositionBook;
  2085. const AEndian : TEndianKind
  2086. );
  2087. procedure AddLine(const ALine : ansistring);
  2088. var
  2089. buffer : ansistring;
  2090. begin
  2091. buffer := ALine + sLineBreak;
  2092. ADest.Write(buffer[1],Length(buffer));
  2093. end;
  2094. var
  2095. i, k : Integer;
  2096. p : ^TDecompositionIndexRec;
  2097. cp : ^TUnicodeCodePoint;
  2098. cp24 : UInt24;
  2099. locLine : string;
  2100. begin
  2101. AddLine('const');
  2102. AddLine(' UC_DEC_BOOK_INDEX_LENGTH = ' + IntToStr(Length(ABook.Index)) + ';');
  2103. AddLine(' UC_DEC_BOOK_DATA_LENGTH = ' + IntToStr(Length(ABook.CodePoints)) + ';');
  2104. AddLine('type');
  2105. AddLine(' TDecompositionIndexRec = packed record');
  2106. AddLine(' StartPosition : Word;');
  2107. AddLine(' Length : Byte;');
  2108. AddLine(' end;');
  2109. AddLine(' TDecompositionBookRec = packed record');
  2110. AddLine(' Index : array[0..(UC_DEC_BOOK_INDEX_LENGTH-1)] of TDecompositionIndexRec;');
  2111. AddLine(' CodePoints : array[0..(UC_DEC_BOOK_DATA_LENGTH-1)] of UInt24;');
  2112. AddLine(' end;');
  2113. AddLine('const');
  2114. AddLine(' UC_DEC_BOOK_DATA : TDecompositionBookRec = (');
  2115. p := @ABook.Index[0];
  2116. AddLine(' Index : (// Index BEGIN');
  2117. k := 0;
  2118. locLine := ' ';
  2119. for i := Low(ABook.Index) to High(ABook.Index) - 1 do begin
  2120. locLine := locLine + '(StartPosition : ' + IntToStr(p^.StartPosition) + ';' +
  2121. ' Length : ' + IntToStr(p^.Length) + '), ';
  2122. k := k + 1;
  2123. if (k >= 2) then begin
  2124. AddLine(locLine);
  2125. locLine := ' ';
  2126. k := 0;
  2127. end;
  2128. Inc(p);
  2129. end;
  2130. locLine := locLine + '(StartPosition : ' + IntToStr(p^.StartPosition) + ';' +
  2131. ' Length : ' + IntToStr(p^.Length) + ')';
  2132. AddLine(locLine);
  2133. AddLine(' ); // Index END');
  2134. cp := @ABook.CodePoints[0];
  2135. AddLine(' CodePoints : (// CodePoints BEGIN');
  2136. k := 0;
  2137. locLine := ' ';
  2138. for i := Low(ABook.CodePoints) to High(ABook.CodePoints) - 1 do begin
  2139. cp24 := cp^;
  2140. locLine := locLine + Format('%s,',[UInt24ToStr(cp24,AEndian)]);
  2141. Inc(k);
  2142. if (k >= 16) then begin
  2143. AddLine(locLine);
  2144. k := 0;
  2145. locLine := ' ';
  2146. end;
  2147. Inc(cp);
  2148. end;
  2149. cp24 := cp^;
  2150. locLine := locLine + Format('%s',[UInt24ToStr(cp24,AEndian)]);
  2151. AddLine(locLine);
  2152. AddLine(' ); // CodePoints END');
  2153. AddLine(' );' + sLineBreak);
  2154. end;
  2155. procedure GenerateOutBmpTable(
  2156. ADest : TStream;
  2157. const AList : TDataLineRecArray
  2158. );
  2159. procedure AddLine(const ALine : ansistring);
  2160. var
  2161. buffer : ansistring;
  2162. begin
  2163. buffer := ALine + sLineBreak;
  2164. ADest.Write(buffer[1],Length(buffer));
  2165. end;
  2166. var
  2167. i, j : Integer;
  2168. locLine : string;
  2169. p : PDataLineRec;
  2170. begin
  2171. AddLine('');
  2172. //AddLine(' UC_PROP_REC_COUNT = ' + IntToStr(Length(APropList)) + ';');
  2173. //AddLine(' UC_PROP_ARRAY : array[0..(UC_PROP_REC_COUNT-1)] of TUC_Prop = (');
  2174. j := -1;
  2175. p := @AList[0];
  2176. for i := 0 to Length(AList) - 1 do begin
  2177. if ((p^.LineType = 0) and (p^.CodePoint >$FFFF)) or
  2178. (p^.StartCodePoint > $FFFF)
  2179. then begin
  2180. j := i;
  2181. Break;
  2182. end;
  2183. Inc(p);
  2184. end;
  2185. if (j < 0) then
  2186. exit;
  2187. for i := j to Length(AList) - 2 do begin
  2188. locLine := ' (PropID : ' + IntToStr(p^.PropID) + ';' +
  2189. ' CodePoint : ' + IntToStr(p^.CodePoint) + ';' +
  2190. ' RangeEnd : ' + IntToStr(p^.EndCodePoint) + '),' ;
  2191. AddLine(locLine);
  2192. Inc(p);
  2193. end;
  2194. locLine := ' (PropID : ' + IntToStr(p^.PropID) + ';' +
  2195. ' CodePoint : ' + IntToStr(p^.CodePoint) + ';' +
  2196. ' RangeEnd : ' + IntToStr(p^.EndCodePoint) + ')' ;
  2197. AddLine(locLine);
  2198. AddLine(' );' + sLineBreak);
  2199. end;
  2200. function Compress(const AData : TDataLineRecArray) : TDataLineRecArray;
  2201. var
  2202. k, i, locResLen : Integer;
  2203. q, p, pr : PDataLineRec;
  2204. k_end : TUnicodeCodePoint;
  2205. begin
  2206. locResLen := 1;
  2207. SetLength(Result,Length(AData));
  2208. FillChar(Result[0],Length(Result),#0);
  2209. Result[0] := AData[0];
  2210. q := @AData[0];
  2211. k := 0;
  2212. while (k < Length(AData)) do begin
  2213. if (q^.LineType = 0) then
  2214. k_end := q^.CodePoint
  2215. else
  2216. k_end := q^.EndCodePoint;
  2217. if ((k+1) = Length(AData)) then begin
  2218. i := k;
  2219. end else begin
  2220. p := @AData[k+1];
  2221. i := k +1;
  2222. while (i < (Length(AData) {- 1})) do begin
  2223. if (p^.PropID <> q^.PropID) then begin
  2224. i := i - 1;
  2225. Break;
  2226. end;
  2227. if (p^.LineType = 0) then begin
  2228. if (p^.CodePoint <> (k_end + 1)) then begin
  2229. i := i - 1;
  2230. Break;
  2231. end;
  2232. Inc(k_end);
  2233. end else begin
  2234. if (p^.StartCodePoint <> (k_end + 1)) then begin
  2235. i := i - 1;
  2236. Break;
  2237. end;
  2238. k_end := p^.EndCodePoint;
  2239. end;
  2240. Inc(i);
  2241. Inc(p);
  2242. end;
  2243. end;
  2244. {if (i = k) then begin
  2245. Result[locResLen] := q^;
  2246. Inc(locResLen);
  2247. end else begin }
  2248. p := @AData[i];
  2249. pr := @Result[locResLen];
  2250. pr^.PropID := q^.PropID;
  2251. if (q^.LineType = 0) then
  2252. pr^.StartCodePoint := q^.CodePoint
  2253. else
  2254. pr^.StartCodePoint := q^.StartCodePoint;
  2255. pr^.LineType := 1;
  2256. if (p^.LineType = 0) then
  2257. pr^.EndCodePoint := p^.CodePoint
  2258. else
  2259. pr^.EndCodePoint := p^.EndCodePoint;
  2260. Inc(locResLen);
  2261. //end;
  2262. k := i + 1;
  2263. if (k = Length(AData)) then
  2264. Break;
  2265. q := @AData[k];
  2266. end;
  2267. SetLength(Result,locResLen);
  2268. end;
  2269. procedure ParseUCAFile(
  2270. ADataAStream : TMemoryStream;
  2271. var ABook : TUCA_DataBook
  2272. );
  2273. const
  2274. LINE_LENGTH = 1024;
  2275. DATA_LENGTH = 25000;
  2276. var
  2277. p : PAnsiChar;
  2278. actualDataLen : Integer;
  2279. bufferLength, bufferPos, lineLength, linePos : Integer;
  2280. line : ansistring;
  2281. function NextLine() : Boolean;
  2282. var
  2283. locOldPos : Integer;
  2284. locOldPointer : PAnsiChar;
  2285. begin
  2286. Result := False;
  2287. locOldPointer := p;
  2288. locOldPos := bufferPos;
  2289. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  2290. Inc(p);
  2291. Inc(bufferPos);
  2292. end;
  2293. if (locOldPos = bufferPos) and (p^ = #10) then begin
  2294. lineLength := 0;
  2295. Inc(p);
  2296. Inc(bufferPos);
  2297. linePos := 1;
  2298. Result := True;
  2299. end else if (locOldPos < bufferPos) then begin
  2300. lineLength := (bufferPos - locOldPos) + 1;
  2301. Move(locOldPointer^,line[1],lineLength);
  2302. if (p^ = #10) then begin
  2303. Dec(lineLength);
  2304. Inc(p);
  2305. Inc(bufferPos);
  2306. end;
  2307. linePos := 1;
  2308. Result := True;
  2309. end;
  2310. end;
  2311. procedure SkipSpace();
  2312. begin
  2313. while (linePos < lineLength) and (line[linePos] in [' ',#9]) do
  2314. Inc(linePos);
  2315. end;
  2316. function NextToken() : ansistring;
  2317. const C_SEPARATORS = [';','#','.','[',']','*','@'];
  2318. var
  2319. k : Integer;
  2320. begin
  2321. SkipSpace();
  2322. k := linePos;
  2323. if (linePos <= lineLength) and (line[linePos] in C_SEPARATORS) then begin
  2324. Result := line[linePos];
  2325. Inc(linePos);
  2326. exit;
  2327. end;
  2328. while (linePos <= lineLength) and not(line[linePos] in (C_SEPARATORS+[' '])) do
  2329. Inc(linePos);
  2330. if (linePos > k) then begin
  2331. if (line[Min(linePos,lineLength)] in C_SEPARATORS) then
  2332. Result := Copy(line,k,(linePos-k))
  2333. else
  2334. Result := Copy(line,k,(linePos-k+1));
  2335. Result := Trim(Result);
  2336. end else begin
  2337. Result := '';
  2338. end;
  2339. end;
  2340. procedure CheckToken(const AToken : string);
  2341. var
  2342. a, b : string;
  2343. begin
  2344. a := LowerCase(Trim(AToken));
  2345. b := LowerCase(Trim(NextToken()));
  2346. if (a <> b) then
  2347. raise Exception.CreateFmt('Expected token "%s" but found "%s", Line = "%s".',[a,b,line]);
  2348. end;
  2349. function ReadWeightBlock(var ADest : TUCA_WeightRec) : Boolean;
  2350. var
  2351. s :AnsiString;
  2352. k : Integer;
  2353. begin
  2354. Result := False;
  2355. s := NextToken();
  2356. if (s <> '[') then
  2357. exit;
  2358. s := NextToken();
  2359. if (s = '.') then
  2360. ADest.Variable := False
  2361. else begin
  2362. if (s <> '*') then
  2363. raise Exception.CreateFmt('Expected "%s" but found "%s".',['*',s]);
  2364. ADest.Variable := True;
  2365. end;
  2366. ADest.Weights[0] := StrToInt('$'+NextToken());
  2367. for k := 1 to WEIGHT_LEVEL_COUNT-1 do begin
  2368. CheckToken('.');
  2369. ADest.Weights[k] := StrToInt('$'+NextToken());
  2370. end;
  2371. CheckToken(']');
  2372. Result := True;
  2373. end;
  2374. procedure ParseHeaderVar();
  2375. var
  2376. s,ss : string;
  2377. k : Integer;
  2378. begin
  2379. s := NextToken();
  2380. if (s = 'version') then begin
  2381. ss := '';
  2382. while True do begin
  2383. s := NextToken();
  2384. if (s = '') then
  2385. Break;
  2386. ss := ss + s;
  2387. end;
  2388. ABook.Version := ss;
  2389. end else if (s = 'variable') then begin
  2390. if (s = 'blanked') then
  2391. ABook.VariableWeight := ucaBlanked
  2392. else if (s = 'non-ignorable') then
  2393. ABook.VariableWeight := ucaNonIgnorable
  2394. else if (s = 'shifted') then
  2395. ABook.VariableWeight := ucaShifted
  2396. else if (s = 'shift-trimmed') then
  2397. ABook.VariableWeight := ucaShiftedTrimmed
  2398. else if (s = 'ignoresp') then
  2399. ABook.VariableWeight := ucaIgnoreSP
  2400. else
  2401. raise Exception.CreateFmt('Unknown "@variable" type : "%s".',[s]);
  2402. end else if (s = 'backwards') or (s = 'forwards') then begin
  2403. ss := s;
  2404. s := NextToken();
  2405. k := StrToInt(s);
  2406. if (k < 1) or (k > 4) then
  2407. raise Exception.CreateFmt('Invalid "%s" position : %d.',[ss,s]);
  2408. ABook.Backwards[k] := (s = 'backwards');
  2409. end;
  2410. end;
  2411. procedure ParseLine();
  2412. var
  2413. locData : ^TUCA_LineRec;
  2414. s : ansistring;
  2415. kc : Integer;
  2416. begin
  2417. if (Length(ABook.Lines) <= actualDataLen) then
  2418. SetLength(ABook.Lines,Length(ABook.Lines)*2);
  2419. locData := @ABook.Lines[actualDataLen];
  2420. s := NextToken();
  2421. if (s = '') or (s[1] = '#') then
  2422. exit;
  2423. if (s[1] = '@') then begin
  2424. ParseHeaderVar();
  2425. exit;
  2426. end;
  2427. SetLength(locData^.CodePoints,10);
  2428. locData^.CodePoints[0] := StrToInt('$'+s);
  2429. kc := 1;
  2430. while True do begin
  2431. s := Trim(NextToken());
  2432. if (s = '') then
  2433. exit;
  2434. if (s = ';') then
  2435. Break;
  2436. locData^.CodePoints[kc] := StrToInt('$'+s);
  2437. Inc(kc);
  2438. end;
  2439. if (kc = 0) then
  2440. exit;
  2441. SetLength(locData^.CodePoints,kc);
  2442. SetLength(locData^.Weights,24);
  2443. kc := 0;
  2444. while ReadWeightBlock(locData^.Weights[kc]) do begin
  2445. Inc(kc);
  2446. end;
  2447. SetLength(locData^.Weights,kc);
  2448. Inc(actualDataLen);
  2449. end;
  2450. procedure Prepare();
  2451. var
  2452. k : Integer;
  2453. begin
  2454. ABook.VariableWeight := ucaShifted;
  2455. for k := Low(ABook.Backwards) to High(ABook.Backwards) do
  2456. ABook.Backwards[k] := False;
  2457. SetLength(ABook.Lines,DATA_LENGTH);
  2458. actualDataLen := 0;
  2459. bufferLength := ADataAStream.Size;
  2460. bufferPos := 0;
  2461. p := ADataAStream.Memory;
  2462. lineLength := 0;
  2463. SetLength(line,LINE_LENGTH);
  2464. end;
  2465. begin
  2466. Prepare();
  2467. while NextLine() do
  2468. ParseLine();
  2469. SetLength(ABook.Lines,actualDataLen);
  2470. end;
  2471. procedure Dump(X : array of TUnicodeCodePoint; const ATitle : string = '');
  2472. var
  2473. i : Integer;
  2474. begin
  2475. Write(ATitle, ' ');
  2476. for i := 0 to Length(X) - 1 do
  2477. Write(X[i],' ');
  2478. WriteLn();
  2479. end;
  2480. function IsGreaterThan(A, B : PUCA_LineRec) : Integer;
  2481. var
  2482. i, hb : Integer;
  2483. begin
  2484. if (A=B) then
  2485. exit(0);
  2486. Result := 1;
  2487. hb := Length(B^.CodePoints) - 1;
  2488. for i := 0 to Length(A^.CodePoints) - 1 do begin
  2489. if (i > hb) then
  2490. exit;
  2491. if (A^.CodePoints[i] < B^.CodePoints[i]) then
  2492. exit(-1);
  2493. if (A^.CodePoints[i] > B^.CodePoints[i]) then
  2494. exit(1);
  2495. end;
  2496. if (Length(A^.CodePoints) = Length(B^.CodePoints)) then
  2497. exit(0);
  2498. exit(-1);
  2499. end;
  2500. procedure QuickSort(
  2501. var AList : TUCA_DataBookIndex;
  2502. L, R : Longint;
  2503. ABook : PUCA_DataBook
  2504. );overload;
  2505. var
  2506. I, J : Longint;
  2507. P, Q : Integer;
  2508. begin
  2509. repeat
  2510. I := L;
  2511. J := R;
  2512. P := AList[ (L + R) div 2 ];
  2513. repeat
  2514. while IsGreaterThan(@ABook^.Lines[P], @ABook^.Lines[AList[i]]) > 0 do
  2515. I := I + 1;
  2516. while IsGreaterThan(@ABook^.Lines[P], @ABook^.Lines[AList[J]]) < 0 do
  2517. J := J - 1;
  2518. If I <= J then
  2519. begin
  2520. Q := AList[I];
  2521. AList[I] := AList[J];
  2522. AList[J] := Q;
  2523. I := I + 1;
  2524. J := J - 1;
  2525. end;
  2526. until I > J;
  2527. // sort the smaller range recursively
  2528. // sort the bigger range via the loop
  2529. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  2530. if J - L < R - I then
  2531. begin
  2532. if L < J then
  2533. QuickSort(AList, L, J, ABook);
  2534. L := I;
  2535. end
  2536. else
  2537. begin
  2538. if I < R then
  2539. QuickSort(AList, I, R, ABook);
  2540. R := J;
  2541. end;
  2542. until L >= R;
  2543. end;
  2544. function CreateIndex(ABook : PUCA_DataBook) : TUCA_DataBookIndex;
  2545. var
  2546. r : TUCA_DataBookIndex;
  2547. i, c : Integer;
  2548. begin
  2549. c := Length(ABook^.Lines);
  2550. SetLength(r,c);
  2551. for i := 0 to c - 1 do
  2552. r[i] := i;
  2553. QuickSort(r,0,c-1,ABook);
  2554. Result := r;
  2555. end;
  2556. function ConstructContextTree(
  2557. const AContext : PUCA_LineContextRec;
  2558. var ADestBuffer;
  2559. const ADestBufferLength : Cardinal
  2560. ) : PUCA_PropItemContextTreeRec;forward;
  2561. function ConstructItem(
  2562. AItem : PUCA_PropItemRec;
  2563. ACodePoint : Cardinal;
  2564. AValid : Byte;
  2565. AChildCount : Byte;
  2566. const AWeights : array of TUCA_WeightRec;
  2567. const AStoreCP : Boolean;
  2568. const AContext : PUCA_LineContextRec;
  2569. const ADeleted : Boolean
  2570. ) : Cardinal;
  2571. var
  2572. i : Integer;
  2573. p : PUCA_PropItemRec;
  2574. pw : PUCA_PropWeights;
  2575. pb : PByte;
  2576. hasContext : Boolean;
  2577. contextTree : PUCA_PropItemContextTreeRec;
  2578. wl : Integer;
  2579. begin
  2580. p := AItem;
  2581. p^.Size := 0;
  2582. p^.Flags := 0;
  2583. p^.WeightLength := 0;
  2584. SetBit(p^.Flags,AItem^.FLAG_VALID,(AValid <> 0));
  2585. p^.ChildCount := AChildCount;
  2586. hasContext := (AContext <> nil) and (Length(AContext^.Data) > 0);
  2587. if hasContext then
  2588. wl := 0
  2589. else
  2590. wl := Length(AWeights);
  2591. p^.WeightLength := wl;
  2592. if (wl = 0) then begin
  2593. Result := SizeOf(TUCA_PropItemRec);
  2594. if ADeleted then
  2595. SetBit(AItem^.Flags,AItem^.FLAG_DELETION,True);
  2596. end else begin
  2597. Result := SizeOf(TUCA_PropItemRec) + (wl*SizeOf(TUCA_PropWeights));
  2598. pb := PByte(PtrUInt(p) + SizeOf(TUCA_PropItemRec));
  2599. Unaligned(PWord(pb)^) := AWeights[0].Weights[0];
  2600. pb := pb + 2;
  2601. if (AWeights[0].Weights[1] > High(Byte)) then begin
  2602. Unaligned(PWord(pb)^) := AWeights[0].Weights[1];
  2603. pb := pb + 2;
  2604. end else begin
  2605. SetBit(p^.Flags,p^.FLAG_COMPRESS_WEIGHT_1,True);
  2606. pb^ := AWeights[0].Weights[1];
  2607. pb := pb + 1;
  2608. Result := Result - 1;
  2609. end;
  2610. if (AWeights[0].Weights[2] > High(Byte)) then begin
  2611. Unaligned(PWord(pb)^) := AWeights[0].Weights[2];
  2612. pb := pb + 2;
  2613. end else begin
  2614. SetBit(p^.Flags,p^.FLAG_COMPRESS_WEIGHT_2,True);
  2615. pb^ := AWeights[0].Weights[2];
  2616. pb := pb + 1;
  2617. Result := Result - 1;
  2618. end;
  2619. pw := PUCA_PropWeights(pb);
  2620. for i := 1 to wl - 1 do begin
  2621. pw^.Weights[0] := AWeights[i].Weights[0];
  2622. pw^.Weights[1] := AWeights[i].Weights[1];
  2623. pw^.Weights[2] := AWeights[i].Weights[2];
  2624. //pw^.Variable := BoolToByte(AWeights[i].Variable);
  2625. Inc(pw);
  2626. end;
  2627. end;
  2628. hasContext := (AContext <> nil) and (Length(AContext^.Data) > 0);
  2629. if AStoreCP or hasContext then begin
  2630. Unaligned(PUInt24(PtrUInt(AItem)+Result)^) := ACodePoint;
  2631. Result := Result + SizeOf(UInt24);
  2632. SetBit(AItem^.Flags,AItem^.FLAG_CODEPOINT,True);
  2633. end;
  2634. if hasContext then begin
  2635. contextTree := ConstructContextTree(AContext,Unaligned(Pointer(PtrUInt(AItem)+Result)^),MaxInt);
  2636. Result := Result + Cardinal(contextTree^.Size);
  2637. SetBit(AItem^.Flags,AItem^.FLAG_CONTEXTUAL,True);
  2638. end;
  2639. p^.Size := Result;
  2640. end;
  2641. function CalcCharChildCount(
  2642. const ASearchStartPos : Integer;
  2643. const ALinePos : Integer;
  2644. const ABookLines : PUCA_LineRec;
  2645. const AMaxLength : Integer;
  2646. const ABookIndex : TUCA_DataBookIndex;
  2647. out ALineCount : Word
  2648. ) : Byte;
  2649. var
  2650. locLinePos : Integer;
  2651. p : PUCA_LineRec;
  2652. procedure IncP();
  2653. begin
  2654. Inc(locLinePos);
  2655. p := @ABookLines[ABookIndex[locLinePos]];
  2656. end;
  2657. var
  2658. i, locTargetLen, locTargetBufferSize, r : Integer;
  2659. locTarget : array[0..127] of Cardinal;
  2660. locLastChar : Cardinal;
  2661. begin
  2662. locLinePos := ALinePos;
  2663. p := @ABookLines[ABookIndex[locLinePos]];
  2664. locTargetLen := ASearchStartPos;
  2665. locTargetBufferSize := (locTargetLen*SizeOf(Cardinal));
  2666. Move(p^.CodePoints[0],locTarget[0],locTargetBufferSize);
  2667. if (Length(p^.CodePoints) = ASearchStartPos) then begin
  2668. r := 0;
  2669. locLastChar := High(Cardinal);
  2670. end else begin
  2671. r := 1;
  2672. locLastChar := p^.CodePoints[ASearchStartPos];
  2673. end;
  2674. i := 1;
  2675. while (i < AMaxLength) do begin
  2676. IncP();
  2677. if (Length(p^.CodePoints) < locTargetLen) then
  2678. Break;
  2679. if not CompareMem(@locTarget[0],@p^.CodePoints[0],locTargetBufferSize) then
  2680. Break;
  2681. if (p^.CodePoints[ASearchStartPos] <> locLastChar) then begin
  2682. Inc(r);
  2683. locLastChar := p^.CodePoints[ASearchStartPos];
  2684. end;
  2685. Inc(i);
  2686. end;
  2687. ALineCount := i;
  2688. Result := r;
  2689. end;
  2690. function BuildTrie(
  2691. const ALinePos : Integer;
  2692. const ABookLines : PUCA_LineRec;
  2693. const AMaxLength : Integer;
  2694. const ABookIndex : TUCA_DataBookIndex
  2695. ) : PTrieNode;
  2696. var
  2697. p : PUCA_LineRec;
  2698. root : PTrieNode;
  2699. ki, k, i : Integer;
  2700. key : array of TKeyType;
  2701. begin
  2702. k := ABookIndex[ALinePos];
  2703. p := @ABookLines[k];
  2704. if (Length(p^.CodePoints) = 1) then
  2705. root := CreateNode(p^.CodePoints[0],k)
  2706. else
  2707. root := CreateNode(p^.CodePoints[0]);
  2708. for i := ALinePos to ALinePos + AMaxLength - 1 do begin
  2709. k := ABookIndex[i];
  2710. p := @ABookLines[k];
  2711. if (Length(p^.CodePoints) = 1) then begin
  2712. InsertWord(root,p^.CodePoints[0],k);
  2713. end else begin
  2714. SetLength(key,Length(p^.CodePoints));
  2715. for ki := 0 to Length(p^.CodePoints) - 1 do
  2716. key[ki] := p^.CodePoints[ki];
  2717. InsertWord(root,key,k);
  2718. end;
  2719. end;
  2720. Result := root;
  2721. end;
  2722. function BoolToByte(AValue : Boolean): Byte;inline;
  2723. begin
  2724. if AValue then
  2725. Result := 1
  2726. else
  2727. Result := 0;
  2728. end;
  2729. function InternalConstructFromTrie(
  2730. const ATrie : PTrieNode;
  2731. const AItem : PUCA_PropItemRec;
  2732. const ALines : PUCA_LineRec;
  2733. const AStoreCp : Boolean
  2734. ) : Cardinal;
  2735. var
  2736. i : Integer;
  2737. size : Cardinal;
  2738. p : PUCA_PropItemRec;
  2739. n : PTrieNode;
  2740. begin
  2741. if (ATrie = nil) then
  2742. exit(0);
  2743. p := AItem;
  2744. n := ATrie;
  2745. if n^.DataNode then
  2746. size := ConstructItem(p,n^.Key,1,n^.ChildCount,ALines[n^.Data].Weights,AStoreCp,@(ALines[n^.Data].Context),ALines[n^.Data].Deleted)
  2747. else
  2748. size := ConstructItem(p,n^.Key,0,n^.ChildCount,[],AStoreCp,nil,False);
  2749. Result := size;
  2750. if (n^.ChildCount > 0) then begin
  2751. for i := 0 to n^.ChildCount - 1 do begin
  2752. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2753. size := InternalConstructFromTrie(n^.Children[i],p,ALines,True);
  2754. Result := Result + size;
  2755. end;
  2756. end;
  2757. AItem^.Size := Result;
  2758. end;
  2759. function ConstructFromTrie(
  2760. const ATrie : PTrieNode;
  2761. const AItem : PUCA_PropItemRec;
  2762. const ALines : PUCA_LineRec
  2763. ) : Integer;
  2764. begin
  2765. Result := InternalConstructFromTrie(ATrie,AItem,ALines,False);
  2766. end;
  2767. procedure MakeUCA_Props(
  2768. ABook : PUCA_DataBook;
  2769. out AProps : PUCA_PropBook
  2770. );
  2771. var
  2772. propIndexCount : Integer;
  2773. procedure CapturePropIndex(AItem : PUCA_PropItemRec; ACodePoint : Cardinal);
  2774. begin
  2775. AProps^.Index[propIndexCount].CodePoint := ACodePoint;
  2776. AProps^.Index[propIndexCount].Position := PtrUInt(AItem) - PtrUInt(AProps^.Items);
  2777. propIndexCount := propIndexCount + 1;
  2778. end;
  2779. var
  2780. locIndex : TUCA_DataBookIndex;
  2781. i, c, k, kc : Integer;
  2782. p, p1, p2 : PUCA_PropItemRec;
  2783. lines, pl1, pl2 : PUCA_LineRec;
  2784. childCount, lineCount : Word;
  2785. size : Cardinal;
  2786. trieRoot : PTrieNode;
  2787. MaxChildCount, MaxSize : Cardinal;
  2788. childList : array of PUCA_PropItemRec;
  2789. begin
  2790. locIndex := CreateIndex(ABook);
  2791. i := Length(ABook^.Lines);
  2792. i := 30 * i * (SizeOf(TUCA_PropItemRec) + SizeOf(TUCA_PropWeights));
  2793. AProps := AllocMem(SizeOf(TUCA_PropBook));
  2794. AProps^.ItemSize := i;
  2795. AProps^.Items := AllocMem(i);
  2796. propIndexCount := 0;
  2797. SetLength(AProps^.Index,Length(ABook^.Lines));
  2798. p := AProps^.Items;
  2799. lines := @ABook^.Lines[0];
  2800. c := Length(locIndex);
  2801. i := 0;
  2802. MaxChildCount := 0; MaxSize := 0;
  2803. while (i < (c-1)) do begin
  2804. pl1 := @lines[locIndex[i]];
  2805. if not pl1^.Stored then begin
  2806. i := i + 1;
  2807. Continue;
  2808. end;
  2809. pl2 := @lines[locIndex[i+1]];
  2810. if (pl1^.CodePoints[0] <> pl2^.CodePoints[0]) then begin
  2811. if (Length(pl1^.CodePoints) = 1) then begin
  2812. size := ConstructItem(p,pl1^.CodePoints[0],1,0,pl1^.Weights,False,@pl1^.Context,pl1^.Deleted);
  2813. CapturePropIndex(p,pl1^.CodePoints[0]);
  2814. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2815. if (size > MaxSize) then
  2816. MaxSize := size;
  2817. end else begin
  2818. kc := Length(pl1^.CodePoints);
  2819. SetLength(childList,kc);
  2820. for k := 0 to kc - 2 do begin
  2821. size := ConstructItem(p,pl1^.CodePoints[k],0,1,[],(k>0),nil,False);
  2822. if (k = 0) then
  2823. CapturePropIndex(p,pl1^.CodePoints[k]);
  2824. childList[k] := p;
  2825. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2826. end;
  2827. size := ConstructItem(p,pl1^.CodePoints[kc-1],1,0,pl1^.Weights,True,@pl1^.Context,pl1^.Deleted);
  2828. childList[kc-1] := p;
  2829. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2830. for k := kc - 2 downto 0 do begin
  2831. p1 := childList[k];
  2832. p2 := childList[k+1];
  2833. p1^.Size := p1^.Size + p2^.Size;
  2834. end;
  2835. if (p1^.Size > MaxSize) then
  2836. MaxSize := p1^.Size;
  2837. end;
  2838. lineCount := 1;
  2839. end else begin
  2840. childCount := CalcCharChildCount(1,i,lines,c,locIndex,lineCount);
  2841. if (childCount < 1) then
  2842. raise Exception.CreateFmt('Expected "child count > 1" but found %d.',[childCount]);
  2843. if (lineCount < 2) then
  2844. raise Exception.CreateFmt('Expected "line count > 2" but found %d.',[lineCount]);
  2845. if (childCount > MaxChildCount) then
  2846. MaxChildCount := childCount;
  2847. trieRoot := BuildTrie(i,lines,lineCount,locIndex);
  2848. size := ConstructFromTrie(trieRoot,p,lines);
  2849. CapturePropIndex(p,pl1^.CodePoints[0]);
  2850. FreeNode(trieRoot);
  2851. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2852. if (size > MaxSize) then
  2853. MaxSize := size;
  2854. end;
  2855. i := i + lineCount;
  2856. end;
  2857. if (i = (c-1)) then begin
  2858. pl1 := @lines[locIndex[i]];
  2859. if (Length(pl1^.CodePoints) = 1) then begin
  2860. size := ConstructItem(p,pl1^.CodePoints[0],1,0,pl1^.Weights,False,@pl1^.Context,pl1^.Deleted);
  2861. CapturePropIndex(p,pl1^.CodePoints[0]);
  2862. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2863. if (size > MaxSize) then
  2864. MaxSize := size;
  2865. end else begin
  2866. kc := Length(pl1^.CodePoints);
  2867. SetLength(childList,kc);
  2868. for k := 0 to kc - 2 do begin
  2869. size := ConstructItem(p,pl1^.CodePoints[k],0,1,[],(k>0),@pl1^.Context,pl1^.Deleted);
  2870. if (k = 0) then
  2871. CapturePropIndex(p,pl1^.CodePoints[0]);
  2872. childList[k] := p;
  2873. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2874. end;
  2875. size := ConstructItem(p,pl1^.CodePoints[kc-1],1,0,pl1^.Weights,True,@pl1^.Context,pl1^.Deleted);
  2876. childList[kc-1] := p;
  2877. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2878. for i := kc - 2 downto 0 do begin
  2879. p1 := childList[i];
  2880. p2 := childList[i+1];
  2881. p1^.Size := p1^.Size + p2^.Size;
  2882. end;
  2883. if (size > MaxSize) then
  2884. MaxSize := size;
  2885. end;
  2886. end;
  2887. //c := Int64(PtrUInt(p)) - Int64(PtrUInt(AProps^.Items));
  2888. c := UInt64(PtrUInt(p)) - UInt64(PtrUInt(AProps^.Items));
  2889. ReAllocMem(AProps^.Items,c);
  2890. AProps^.ItemSize := c;
  2891. SetLength(AProps^.Index,propIndexCount);
  2892. AProps^.ItemsOtherEndian := AllocMem(AProps^.ItemSize);
  2893. ReverseFromNativeEndian(AProps^.Items,AProps^.ItemSize,AProps^.ItemsOtherEndian);
  2894. k := 0;
  2895. c := High(Word);
  2896. for i := 0 to Length(ABook^.Lines) - 1 do begin
  2897. if (Length(ABook^.Lines[i].Weights) > 0) then begin
  2898. if (ABook^.Lines[i].Weights[0].Variable) then begin
  2899. if (ABook^.Lines[i].Weights[0].Weights[0] > k) then
  2900. k := ABook^.Lines[i].Weights[0].Weights[0];
  2901. if (ABook^.Lines[i].Weights[0].Weights[0] < c) then
  2902. c := ABook^.Lines[i].Weights[0].Weights[0];
  2903. end;
  2904. end;
  2905. end;
  2906. AProps^.VariableHighLimit := k;
  2907. AProps^.VariableLowLimit := c;
  2908. end;
  2909. procedure FreeUcaBook(var ABook : PUCA_PropBook);
  2910. var
  2911. p : PUCA_PropBook;
  2912. begin
  2913. if (ABook = nil) then
  2914. exit;
  2915. p := ABook;
  2916. ABook := nil;
  2917. p^.Index := nil;
  2918. FreeMem(p^.Items,p^.ItemSize);
  2919. FreeMem(p^.ItemsOtherEndian,p^.ItemSize);
  2920. FreeMem(p,SizeOf(p^));
  2921. end;
  2922. function IndexOf(const ACodePoint : Cardinal; APropBook : PUCA_PropBook): Integer;overload;
  2923. var
  2924. i : Integer;
  2925. begin
  2926. for i := 0 to Length(APropBook^.Index) - 1 do begin
  2927. if (ACodePoint = APropBook^.Index[i].CodePoint) then
  2928. exit(i);
  2929. end;
  2930. Result := -1;
  2931. end;
  2932. type
  2933. PucaBmpSecondTableItem = ^TucaBmpSecondTableItem;
  2934. function IndexOf(
  2935. const AItem : PucaBmpSecondTableItem;
  2936. const ATable : TucaBmpSecondTable;
  2937. const ATableActualLength : Integer
  2938. ) : Integer;overload;
  2939. var
  2940. i : Integer;
  2941. p : PucaBmpSecondTableItem;
  2942. begin
  2943. Result := -1;
  2944. if (ATableActualLength > 0) then begin
  2945. p := @ATable[0];
  2946. for i := 0 to ATableActualLength - 1 do begin
  2947. if CompareMem(p,AItem,SizeOf(TucaBmpSecondTableItem)) then begin
  2948. Result := i;
  2949. Break;
  2950. end;
  2951. Inc(p);
  2952. end;
  2953. end;
  2954. end;
  2955. procedure MakeUCA_BmpTables(
  2956. var AFirstTable : TucaBmpFirstTable;
  2957. var ASecondTable : TucaBmpSecondTable;
  2958. const APropBook : PUCA_PropBook
  2959. );
  2960. var
  2961. locLowByte, locHighByte : Byte;
  2962. locTableItem : TucaBmpSecondTableItem;
  2963. locCP : TUnicodeCodePoint;
  2964. i, locSecondActualLen : Integer;
  2965. k : Integer;
  2966. begin
  2967. SetLength(ASecondTable,120);
  2968. locSecondActualLen := 0;
  2969. for locHighByte := 0 to 255 do begin
  2970. FillChar(locTableItem,SizeOf(locTableItem),#0);
  2971. for locLowByte := 0 to 255 do begin
  2972. locCP := (locHighByte * 256) + locLowByte;
  2973. k := IndexOf(locCP,APropBook);
  2974. if (k = -1) then
  2975. k := 0
  2976. else
  2977. k := APropBook^.Index[k].Position + 1;
  2978. locTableItem[locLowByte] := k;
  2979. end;
  2980. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  2981. if (i = -1) then begin
  2982. if (locSecondActualLen = Length(ASecondTable)) then
  2983. SetLength(ASecondTable,locSecondActualLen + 50);
  2984. i := locSecondActualLen;
  2985. ASecondTable[i] := locTableItem;
  2986. Inc(locSecondActualLen);
  2987. end;
  2988. AFirstTable[locHighByte] := i;
  2989. end;
  2990. SetLength(ASecondTable,locSecondActualLen);
  2991. end;
  2992. function ToUCS4(const AHighS, ALowS : Word) : TUnicodeCodePoint; inline;
  2993. begin
  2994. //copied from utf16toutf32
  2995. Result := (UCS4Char(AHighS)-$d800) shl 10 + (UCS4Char(ALowS)-$dc00) + $10000;
  2996. end;
  2997. procedure FromUCS4(const AValue : TUnicodeCodePoint; var AHighS, ALowS : Word);
  2998. begin
  2999. AHighS := Word((AValue - $10000) shr 10 + $d800);
  3000. ALowS := Word((AValue - $10000) and $3ff + $dc00);
  3001. end;
  3002. type
  3003. PucaOBmpSecondTableItem = ^TucaOBmpSecondTableItem;
  3004. function IndexOf(
  3005. const AItem : PucaOBmpSecondTableItem;
  3006. const ATable : TucaOBmpSecondTable;
  3007. const ATableActualLength : Integer
  3008. ) : Integer;overload;
  3009. var
  3010. i : Integer;
  3011. p : PucaOBmpSecondTableItem;
  3012. begin
  3013. Result := -1;
  3014. if (ATableActualLength > 0) then begin
  3015. p := @ATable[0];
  3016. for i := 0 to ATableActualLength - 1 do begin
  3017. if CompareMem(p,AItem,SizeOf(TucaOBmpSecondTableItem)) then begin
  3018. Result := i;
  3019. Break;
  3020. end;
  3021. Inc(p);
  3022. end;
  3023. end;
  3024. end;
  3025. procedure MakeUCA_OBmpTables(
  3026. var AFirstTable : TucaOBmpFirstTable;
  3027. var ASecondTable : TucaOBmpSecondTable;
  3028. const APropBook : PUCA_PropBook
  3029. );
  3030. var
  3031. locLowByte, locHighByte : Word;
  3032. locTableItem : TucaOBmpSecondTableItem;
  3033. locCP : TUnicodeCodePoint;
  3034. i, locSecondActualLen : Integer;
  3035. k : Integer;
  3036. begin
  3037. if (Length(ASecondTable) = 0) then
  3038. SetLength(ASecondTable,2000);
  3039. locSecondActualLen := 0;
  3040. for locHighByte := 0 to HIGH_SURROGATE_COUNT - 1 do begin
  3041. FillChar(locTableItem,SizeOf(locTableItem),#0);
  3042. for locLowByte := 0 to LOW_SURROGATE_COUNT - 1 do begin
  3043. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + locLowByte);
  3044. k := IndexOf(locCP,APropBook);
  3045. if (k = -1) then
  3046. k := 0
  3047. else
  3048. k := APropBook^.Index[k].Position + 1;
  3049. locTableItem[locLowByte] := k;
  3050. end;
  3051. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  3052. if (i = -1) then begin
  3053. if (locSecondActualLen = Length(ASecondTable)) then
  3054. SetLength(ASecondTable,locSecondActualLen + 50);
  3055. i := locSecondActualLen;
  3056. ASecondTable[i] := locTableItem;
  3057. Inc(locSecondActualLen);
  3058. end;
  3059. AFirstTable[locHighByte] := i;
  3060. end;
  3061. SetLength(ASecondTable,locSecondActualLen);
  3062. end;
  3063. function GetPropPosition(
  3064. const AHighS,
  3065. ALowS : Word;
  3066. const AFirstTable : PucaOBmpFirstTable;
  3067. const ASecondTable : PucaOBmpSecondTable
  3068. ): Integer;inline;overload;
  3069. begin
  3070. Result := ASecondTable^[AFirstTable^[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN] - 1;
  3071. end;
  3072. procedure GenerateUCA_Head(
  3073. ADest : TStream;
  3074. ABook : PUCA_DataBook;
  3075. AProps : PUCA_PropBook
  3076. );
  3077. procedure AddLine(const ALine : ansistring);
  3078. var
  3079. buffer : ansistring;
  3080. begin
  3081. buffer := ALine + sLineBreak;
  3082. ADest.Write(buffer[1],Length(buffer));
  3083. end;
  3084. begin
  3085. AddLine('const');
  3086. //AddLine(' VERSION_STRING = ' + QuotedStr(ABook^.Version) + ';');
  3087. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(AProps^.VariableLowLimit) + ';');
  3088. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(AProps^.VariableHighLimit) + ';');
  3089. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(Ord(ABook^.VariableWeight)) + ';');
  3090. AddLine(' BACKWARDS_0 = ' + BoolToStr(ABook^.Backwards[0],'True','False') + ';');
  3091. AddLine(' BACKWARDS_1 = ' + BoolToStr(ABook^.Backwards[1],'True','False') + ';');
  3092. AddLine(' BACKWARDS_2 = ' + BoolToStr(ABook^.Backwards[2],'True','False') + ';');
  3093. AddLine(' BACKWARDS_3 = ' + BoolToStr(ABook^.Backwards[3],'True','False') + ';');
  3094. AddLine(' PROP_COUNT = ' + IntToStr(Ord(AProps^.ItemSize)) + ';');
  3095. AddLine('');
  3096. end;
  3097. procedure GenerateUCA_BmpTables(
  3098. AStream,
  3099. ANativeEndianStream,
  3100. ANonNativeEndianStream : TStream;
  3101. var AFirstTable : TucaBmpFirstTable;
  3102. var ASecondTable : TucaBmpSecondTable
  3103. );
  3104. procedure AddLine(AOut : TStream; const ALine : ansistring);
  3105. var
  3106. buffer : ansistring;
  3107. begin
  3108. buffer := ALine + sLineBreak;
  3109. AOut.Write(buffer[1],Length(buffer));
  3110. end;
  3111. var
  3112. i, j, c : Integer;
  3113. locLine : string;
  3114. value : UInt24;
  3115. begin
  3116. AddLine(AStream,'const');
  3117. AddLine(AStream,' UCA_TABLE_1 : array[0..255] of Byte = (');
  3118. locLine := '';
  3119. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3120. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3121. if (((i+1) mod 16) = 0) then begin
  3122. locLine := ' ' + locLine;
  3123. AddLine(AStream,locLine);
  3124. locLine := '';
  3125. end;
  3126. end;
  3127. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3128. locLine := ' ' + locLine;
  3129. AddLine(AStream,locLine);
  3130. AddLine(AStream,' );' + sLineBreak);
  3131. AddLine(ANativeEndianStream,'const');
  3132. AddLine(ANativeEndianStream,' UCA_TABLE_2 : array[0..(256*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3133. c := High(ASecondTable);
  3134. for i := Low(ASecondTable) to c do begin
  3135. locLine := '';
  3136. for j := Low(TucaBmpSecondTableItem) to High(TucaBmpSecondTableItem) do begin
  3137. value := ASecondTable[i][j];
  3138. locLine := locLine + UInt24ToStr(value,ENDIAN_NATIVE) + ',';
  3139. if (((j+1) mod 2) = 0) then begin
  3140. if (i = c) and (j = 255) then
  3141. Delete(locLine,Length(locLine),1);
  3142. locLine := ' ' + locLine;
  3143. AddLine(ANativeEndianStream,locLine);
  3144. locLine := '';
  3145. end;
  3146. end;
  3147. end;
  3148. AddLine(ANativeEndianStream,' );' + sLineBreak);
  3149. AddLine(ANonNativeEndianStream,'const');
  3150. AddLine(ANonNativeEndianStream,' UCA_TABLE_2 : array[0..(256*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3151. c := High(ASecondTable);
  3152. for i := Low(ASecondTable) to c do begin
  3153. locLine := '';
  3154. for j := Low(TucaBmpSecondTableItem) to High(TucaBmpSecondTableItem) do begin
  3155. value := ASecondTable[i][j];
  3156. locLine := locLine + UInt24ToStr(value,ENDIAN_NON_NATIVE) + ',';
  3157. if (((j+1) mod 2) = 0) then begin
  3158. if (i = c) and (j = 255) then
  3159. Delete(locLine,Length(locLine),1);
  3160. locLine := ' ' + locLine;
  3161. AddLine(ANonNativeEndianStream,locLine);
  3162. locLine := '';
  3163. end;
  3164. end;
  3165. end;
  3166. AddLine(ANonNativeEndianStream,' );' + sLineBreak);
  3167. end;
  3168. procedure GenerateBinaryUCA_BmpTables(
  3169. ANativeEndianStream,
  3170. ANonNativeEndianStream : TStream;
  3171. var AFirstTable : TucaBmpFirstTable;
  3172. var ASecondTable : TucaBmpSecondTable
  3173. );
  3174. var
  3175. i, j : Integer;
  3176. value : UInt24;
  3177. begin
  3178. ANativeEndianStream.Write(AFirstTable[0],Length(AFirstTable));
  3179. ANonNativeEndianStream.Write(AFirstTable[0],Length(AFirstTable));
  3180. for i := Low(ASecondTable) to High(ASecondTable) do begin
  3181. for j := Low(TucaBmpSecondTableItem) to High(TucaBmpSecondTableItem) do begin
  3182. value := ASecondTable[i][j];
  3183. ANativeEndianStream.Write(value,SizeOf(value));
  3184. ReverseBytes(value,SizeOf(value));
  3185. ANonNativeEndianStream.Write(value,SizeOf(value));
  3186. end;
  3187. end;
  3188. end;
  3189. procedure GenerateUCA_PropTable(
  3190. // WARNING : files must be generated for each endianess (Little / Big)
  3191. ADest : TStream;
  3192. const APropBook : PUCA_PropBook;
  3193. const AEndian : TEndianKind
  3194. );
  3195. procedure AddLine(const ALine : ansistring);
  3196. var
  3197. buffer : ansistring;
  3198. begin
  3199. buffer := ALine + sLineBreak;
  3200. ADest.Write(buffer[1],Length(buffer));
  3201. end;
  3202. var
  3203. i, c : Integer;
  3204. locLine : string;
  3205. p : PByte;
  3206. begin
  3207. c := APropBook^.ItemSize;
  3208. AddLine('const');
  3209. AddLine(' UCA_PROPS : array[0..' + IntToStr(c-1) + '] of Byte = (');
  3210. locLine := '';
  3211. if (AEndian = ENDIAN_NATIVE) then
  3212. p := PByte(APropBook^.Items)
  3213. else
  3214. p := PByte(APropBook^.ItemsOtherEndian);
  3215. for i := 0 to c - 2 do begin
  3216. locLine := locLine + IntToStr(p[i]) + ',';
  3217. if (((i+1) mod 60) = 0) then begin
  3218. locLine := ' ' + locLine;
  3219. AddLine(locLine);
  3220. locLine := '';
  3221. end;
  3222. end;
  3223. locLine := locLine + IntToStr(p[c-1]);
  3224. locLine := ' ' + locLine;
  3225. AddLine(locLine);
  3226. AddLine(' );' + sLineBreak);
  3227. end;
  3228. procedure GenerateBinaryUCA_PropTable(
  3229. // WARNING : files must be generated for each endianess (Little / Big)
  3230. ANativeEndianStream,
  3231. ANonNativeEndianStream : TStream;
  3232. const APropBook : PUCA_PropBook
  3233. );
  3234. begin
  3235. ANativeEndianStream.Write(APropBook^.Items^,APropBook^.ItemSize);
  3236. ANonNativeEndianStream.Write(APropBook^.ItemsOtherEndian^,APropBook^.ItemSize);
  3237. end;
  3238. procedure GenerateUCA_OBmpTables(
  3239. AStream,
  3240. ANativeEndianStream,
  3241. ANonNativeEndianStream : TStream;
  3242. var AFirstTable : TucaOBmpFirstTable;
  3243. var ASecondTable : TucaOBmpSecondTable
  3244. );
  3245. procedure AddLine(AOut : TStream; const ALine : ansistring);
  3246. var
  3247. buffer : ansistring;
  3248. begin
  3249. buffer := ALine + sLineBreak;
  3250. AOut.Write(buffer[1],Length(buffer));
  3251. end;
  3252. var
  3253. i, j, c : Integer;
  3254. locLine : string;
  3255. value : UInt24;
  3256. begin
  3257. AddLine(AStream,'const');
  3258. AddLine(AStream,' UCAO_TABLE_1 : array[0..' + IntToStr(HIGH_SURROGATE_COUNT-1) + '] of Word = (');
  3259. locLine := '';
  3260. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3261. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3262. if (((i+1) mod 16) = 0) then begin
  3263. locLine := ' ' + locLine;
  3264. AddLine(AStream,locLine);
  3265. locLine := '';
  3266. end;
  3267. end;
  3268. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3269. locLine := ' ' + locLine;
  3270. AddLine(AStream,locLine);
  3271. AddLine(AStream,' );' + sLineBreak);
  3272. AddLine(ANativeEndianStream,' UCAO_TABLE_2 : array[0..('+IntToStr(LOW_SURROGATE_COUNT)+'*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3273. c := High(ASecondTable);
  3274. for i := Low(ASecondTable) to c do begin
  3275. locLine := '';
  3276. for j := Low(TucaOBmpSecondTableItem) to High(TucaOBmpSecondTableItem) do begin
  3277. value := ASecondTable[i][j];
  3278. locLine := locLine + UInt24ToStr(value,ENDIAN_NATIVE) + ',';
  3279. if (((j+1) mod 2) = 0) then begin
  3280. if (i = c) and (j = High(TucaOBmpSecondTableItem)) then
  3281. Delete(locLine,Length(locLine),1);
  3282. locLine := ' ' + locLine;
  3283. AddLine(ANativeEndianStream,locLine);
  3284. locLine := '';
  3285. end;
  3286. end;
  3287. end;
  3288. AddLine(ANativeEndianStream,' );' + sLineBreak);
  3289. AddLine(ANonNativeEndianStream,' UCAO_TABLE_2 : array[0..('+IntToStr(LOW_SURROGATE_COUNT)+'*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3290. c := High(ASecondTable);
  3291. for i := Low(ASecondTable) to c do begin
  3292. locLine := '';
  3293. for j := Low(TucaOBmpSecondTableItem) to High(TucaOBmpSecondTableItem) do begin
  3294. value := ASecondTable[i][j];
  3295. locLine := locLine + UInt24ToStr(value,ENDIAN_NON_NATIVE) + ',';
  3296. if (((j+1) mod 2) = 0) then begin
  3297. if (i = c) and (j = High(TucaOBmpSecondTableItem)) then
  3298. Delete(locLine,Length(locLine),1);
  3299. locLine := ' ' + locLine;
  3300. AddLine(ANonNativeEndianStream,locLine);
  3301. locLine := '';
  3302. end;
  3303. end;
  3304. end;
  3305. AddLine(ANonNativeEndianStream,' );' + sLineBreak);
  3306. end;
  3307. procedure GenerateBinaryUCA_OBmpTables(
  3308. ANativeEndianStream,
  3309. ANonNativeEndianStream : TStream;
  3310. var AFirstTable : TucaOBmpFirstTable;
  3311. var ASecondTable : TucaOBmpSecondTable
  3312. );
  3313. var
  3314. i, j : Integer;
  3315. locLine : string;
  3316. wordValue : Word;
  3317. value : UInt24;
  3318. begin
  3319. for i := Low(AFirstTable) to High(AFirstTable) do begin
  3320. wordValue := AFirstTable[i];
  3321. ANativeEndianStream.Write(wordValue,SizeOf(wordValue));
  3322. ReverseBytes(wordValue,SizeOf(wordValue));
  3323. ANonNativeEndianStream.Write(wordValue,SizeOf(wordValue));
  3324. end;
  3325. for i := Low(ASecondTable) to High(ASecondTable) do begin
  3326. for j := Low(TucaOBmpSecondTableItem) to High(TucaOBmpSecondTableItem) do begin
  3327. value := ASecondTable[i][j];
  3328. ANativeEndianStream.Write(value,SizeOf(value));
  3329. ReverseBytes(value,SizeOf(value));
  3330. ANonNativeEndianStream.Write(value,SizeOf(value));
  3331. end;
  3332. end;
  3333. end;
  3334. type
  3335. POBmpSecondTableItem = ^TOBmpSecondTableItem;
  3336. function IndexOf(
  3337. const AItem : POBmpSecondTableItem;
  3338. const ATable : TOBmpSecondTable;
  3339. const ATableActualLength : Integer
  3340. ) : Integer;overload;
  3341. var
  3342. i : Integer;
  3343. p : POBmpSecondTableItem;
  3344. begin
  3345. Result := -1;
  3346. if (ATableActualLength > 0) then begin
  3347. p := @ATable[0];
  3348. for i := 0 to ATableActualLength - 1 do begin
  3349. if CompareMem(p,AItem,SizeOf(TOBmpSecondTableItem)) then begin
  3350. Result := i;
  3351. Break;
  3352. end;
  3353. Inc(p);
  3354. end;
  3355. end;
  3356. end;
  3357. procedure MakeOBmpTables(
  3358. var AFirstTable : TOBmpFirstTable;
  3359. var ASecondTable : TOBmpSecondTable;
  3360. const ADataLineList : TDataLineRecArray
  3361. );
  3362. var
  3363. locLowByte, locHighByte : Word;
  3364. locTableItem : TOBmpSecondTableItem;
  3365. locCP : TUnicodeCodePoint;
  3366. i, locSecondActualLen : Integer;
  3367. begin
  3368. SetLength(ASecondTable,2000);
  3369. locSecondActualLen := 0;
  3370. for locHighByte := 0 to HIGH_SURROGATE_COUNT - 1 do begin
  3371. FillChar(locTableItem,SizeOf(locTableItem),#0);
  3372. for locLowByte := 0 to LOW_SURROGATE_COUNT - 1 do begin
  3373. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + locLowByte);
  3374. locTableItem[locLowByte] := GetPropID(locCP,ADataLineList)// - 1;
  3375. end;
  3376. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  3377. if (i = -1) then begin
  3378. if (locSecondActualLen = Length(ASecondTable)) then
  3379. SetLength(ASecondTable,locSecondActualLen + 50);
  3380. i := locSecondActualLen;
  3381. ASecondTable[i] := locTableItem;
  3382. Inc(locSecondActualLen);
  3383. end;
  3384. AFirstTable[locHighByte] := i;
  3385. end;
  3386. SetLength(ASecondTable,locSecondActualLen);
  3387. end;
  3388. type
  3389. P3lvlOBmp3TableItem = ^T3lvlOBmp3TableItem;
  3390. function IndexOf(
  3391. const AItem : P3lvlOBmp3TableItem;
  3392. const ATable : T3lvlOBmp3Table;
  3393. const ATableActualLength : Integer
  3394. ) : Integer;overload;
  3395. var
  3396. i : Integer;
  3397. p : P3lvlOBmp3TableItem;
  3398. begin
  3399. Result := -1;
  3400. if (ATableActualLength > 0) then begin
  3401. p := @ATable[0];
  3402. for i := 0 to ATableActualLength - 1 do begin
  3403. if CompareMem(p,AItem,SizeOf(T3lvlOBmp3TableItem)) then begin
  3404. Result := i;
  3405. Break;
  3406. end;
  3407. Inc(p);
  3408. end;
  3409. end;
  3410. end;
  3411. type
  3412. P3lvlOBmp2TableItem = ^T3lvlOBmp2TableItem;
  3413. function IndexOf(
  3414. const AItem : P3lvlOBmp2TableItem;
  3415. const ATable : T3lvlOBmp2Table
  3416. ) : Integer;overload;
  3417. var
  3418. i : Integer;
  3419. p : P3lvlOBmp2TableItem;
  3420. begin
  3421. Result := -1;
  3422. if (Length(ATable) > 0) then begin
  3423. p := @ATable[0];
  3424. for i := 0 to Length(ATable) - 1 do begin
  3425. if CompareMem(p,AItem,SizeOf(T3lvlOBmp2TableItem)) then begin
  3426. Result := i;
  3427. Break;
  3428. end;
  3429. Inc(p);
  3430. end;
  3431. end;
  3432. end;
  3433. procedure MakeOBmpTables3Levels(
  3434. var AFirstTable : T3lvlOBmp1Table;
  3435. var ASecondTable : T3lvlOBmp2Table;
  3436. var AThirdTable : T3lvlOBmp3Table;
  3437. const ADataLineList : TDataLineRecArray
  3438. );
  3439. var
  3440. locLowByte0, locLowByte1, locHighByte : Word;
  3441. locTableItem2 : T3lvlOBmp2TableItem;
  3442. locTableItem3 : T3lvlOBmp3TableItem;
  3443. locCP : TUnicodeCodePoint;
  3444. i, locThirdActualLen : Integer;
  3445. begin
  3446. SetLength(AThirdTable,120);
  3447. locThirdActualLen := 0;
  3448. for locHighByte := 0 to 1023 do begin
  3449. FillChar(locTableItem2,SizeOf(locTableItem2),#0);
  3450. for locLowByte0 := 0 to 31 do begin
  3451. FillChar(locTableItem3,SizeOf(locTableItem3),#0);
  3452. for locLowByte1 := 0 to 31 do begin
  3453. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + (locLowByte0*32) + locLowByte1);
  3454. locTableItem3[locLowByte1] := GetPropID(locCP,ADataLineList);
  3455. end;
  3456. i := IndexOf(@locTableItem3,AThirdTable,locThirdActualLen);
  3457. if (i = -1) then begin
  3458. if (locThirdActualLen = Length(AThirdTable)) then
  3459. SetLength(AThirdTable,locThirdActualLen + 50);
  3460. i := locThirdActualLen;
  3461. AThirdTable[i] := locTableItem3;
  3462. Inc(locThirdActualLen);
  3463. end;
  3464. locTableItem2[locLowByte0] := i;
  3465. end;
  3466. i := IndexOf(@locTableItem2,ASecondTable);
  3467. if (i = -1) then begin
  3468. i := Length(ASecondTable);
  3469. SetLength(ASecondTable,(i + 1));
  3470. ASecondTable[i] := locTableItem2;
  3471. end;
  3472. AFirstTable[locHighByte] := i;
  3473. end;
  3474. SetLength(AThirdTable,locThirdActualLen);
  3475. end;
  3476. procedure GenerateOBmpTables(
  3477. ADest : TStream;
  3478. var AFirstTable : TOBmpFirstTable;
  3479. var ASecondTable : TOBmpSecondTable
  3480. );
  3481. procedure AddLine(const ALine : ansistring);
  3482. var
  3483. buffer : ansistring;
  3484. begin
  3485. buffer := ALine + sLineBreak;
  3486. ADest.Write(buffer[1],Length(buffer));
  3487. end;
  3488. var
  3489. i, j, c : Integer;
  3490. locLine : string;
  3491. begin
  3492. AddLine('const');
  3493. AddLine(' UCO_TABLE_1 : array[0..' + IntToStr(HIGH_SURROGATE_COUNT-1) + '] of Word = (');
  3494. locLine := '';
  3495. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3496. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3497. if (((i+1) mod 16) = 0) then begin
  3498. locLine := ' ' + locLine;
  3499. AddLine(locLine);
  3500. locLine := '';
  3501. end;
  3502. end;
  3503. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3504. locLine := ' ' + locLine;
  3505. AddLine(locLine);
  3506. AddLine(' );' + sLineBreak);
  3507. AddLine(' UCO_TABLE_2 : array[0..('+IntToStr(LOW_SURROGATE_COUNT)+'*' + IntToStr(Length(ASecondTable)) +'-1)] of Word =(');
  3508. c := High(ASecondTable);
  3509. for i := Low(ASecondTable) to c do begin
  3510. locLine := '';
  3511. for j := Low(TOBmpSecondTableItem) to High(TOBmpSecondTableItem) do begin
  3512. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  3513. if (((j+1) mod 16) = 0) then begin
  3514. if (i = c) and (j = High(TOBmpSecondTableItem)) then
  3515. Delete(locLine,Length(locLine),1);
  3516. locLine := ' ' + locLine;
  3517. AddLine(locLine);
  3518. locLine := '';
  3519. end;
  3520. end;
  3521. end;
  3522. AddLine(' );' + sLineBreak);
  3523. end;
  3524. //----------------------------------
  3525. procedure Generate3lvlOBmpTables(
  3526. ADest : TStream;
  3527. var AFirstTable : T3lvlOBmp1Table;
  3528. var ASecondTable : T3lvlOBmp2Table;
  3529. var AThirdTable : T3lvlOBmp3Table
  3530. );
  3531. procedure AddLine(const ALine : ansistring);
  3532. var
  3533. buffer : ansistring;
  3534. begin
  3535. buffer := ALine + sLineBreak;
  3536. ADest.Write(buffer[1],Length(buffer));
  3537. end;
  3538. var
  3539. i, j, c : Integer;
  3540. locLine : string;
  3541. begin
  3542. AddLine('const');
  3543. AddLine(' UCO_TABLE_1 : array[0..1023] of Word = (');
  3544. locLine := '';
  3545. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3546. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3547. if (((i+1) mod 16) = 0) then begin
  3548. locLine := ' ' + locLine;
  3549. AddLine(locLine);
  3550. locLine := '';
  3551. end;
  3552. end;
  3553. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3554. locLine := ' ' + locLine;
  3555. AddLine(locLine);
  3556. AddLine(' );' + sLineBreak);
  3557. AddLine(' UCO_TABLE_2 : array[0..' + IntToStr(Length(ASecondTable)-1) +'] of array[0..31] of Word = (');
  3558. c := High(ASecondTable);
  3559. for i := Low(ASecondTable) to c do begin
  3560. locLine := '(';
  3561. for j := Low(T3lvlOBmp2TableItem) to High(T3lvlOBmp2TableItem) do
  3562. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  3563. Delete(locLine,Length(locLine),1);
  3564. locLine := ' ' + locLine + ')';
  3565. if (i < c) then
  3566. locLine := locLine + ',';
  3567. AddLine(locLine);
  3568. end;
  3569. AddLine(' );' + sLineBreak);
  3570. AddLine(' UCO_TABLE_3 : array[0..' + IntToStr(Length(AThirdTable)-1) +'] of array[0..31] of Word = (');
  3571. c := High(AThirdTable);
  3572. for i := Low(AThirdTable) to c do begin
  3573. locLine := '(';
  3574. for j := Low(T3lvlOBmp3TableItem) to High(T3lvlOBmp3TableItem) do
  3575. locLine := locLine + IntToStr(AThirdTable[i][j]) + ',';
  3576. Delete(locLine,Length(locLine),1);
  3577. locLine := ' ' + locLine + ')';
  3578. if (i < c) then
  3579. locLine := locLine + ',';
  3580. AddLine(locLine);
  3581. end;
  3582. AddLine(' );' + sLineBreak);
  3583. end;
  3584. function GetProp(
  3585. const AHighS,
  3586. ALowS : Word;
  3587. const AProps : TPropRecArray;
  3588. var AFirstTable : TOBmpFirstTable;
  3589. var ASecondTable : TOBmpSecondTable
  3590. ): PPropRec;
  3591. begin
  3592. Result := @AProps[ASecondTable[AFirstTable[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN]];
  3593. end;
  3594. function GetProp(
  3595. const AHighS,
  3596. ALowS : Word;
  3597. const AProps : TPropRecArray;
  3598. var AFirstTable : T3lvlOBmp1Table;
  3599. var ASecondTable : T3lvlOBmp2Table;
  3600. var AThirdTable : T3lvlOBmp3Table
  3601. ): PPropRec;
  3602. begin
  3603. Result := @AProps[AThirdTable[ASecondTable[AFirstTable[AHighS]][ALowS div 32]][ALowS mod 32]];
  3604. //Result := @AProps[ASecondTable[AFirstTable[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN]];
  3605. end;
  3606. { TUCA_PropItemContextTreeRec }
  3607. function TUCA_PropItemContextTreeRec.GetData : PUCA_PropItemContextTreeNodeRec;
  3608. begin
  3609. if (Size = 0) then
  3610. Result := nil
  3611. else
  3612. Result := PUCA_PropItemContextTreeNodeRec(
  3613. PtrUInt(
  3614. PtrUInt(@Self) + SizeOf(UInt24){Size}
  3615. )
  3616. );
  3617. end;
  3618. { TUCA_LineContextRec }
  3619. procedure TUCA_LineContextRec.Clear;
  3620. begin
  3621. Data := nil
  3622. end;
  3623. procedure TUCA_LineContextRec.Assign(ASource : PUCA_LineContextRec);
  3624. var
  3625. c, i : Integer;
  3626. begin
  3627. if (ASource = nil) then begin
  3628. Clear();
  3629. exit;
  3630. end;
  3631. c := Length(ASource^.Data);
  3632. SetLength(Self.Data,c);
  3633. for i := 0 to c-1 do
  3634. Self.Data[i].Assign(@ASource^.Data[i]);
  3635. end;
  3636. function TUCA_LineContextRec.Clone : TUCA_LineContextRec;
  3637. begin
  3638. Result.Clear();
  3639. Result.Assign(@Self);
  3640. end;
  3641. { TUCA_LineContextItemRec }
  3642. procedure TUCA_LineContextItemRec.Clear();
  3643. begin
  3644. CodePoints := nil;
  3645. Weights := nil;
  3646. end;
  3647. procedure TUCA_LineContextItemRec.Assign(ASource : PUCA_LineContextItemRec);
  3648. begin
  3649. if (ASource = nil) then begin
  3650. Clear();
  3651. exit;
  3652. end;
  3653. Self.CodePoints := Copy(ASource^.CodePoints);
  3654. Self.Weights := Copy(ASource^.Weights);
  3655. end;
  3656. function TUCA_LineContextItemRec.Clone() : TUCA_LineContextItemRec;
  3657. begin
  3658. Result.Clear();
  3659. Result.Assign(@Self);
  3660. end;
  3661. { TUCA_LineRec }
  3662. procedure TUCA_LineRec.Clear;
  3663. begin
  3664. CodePoints := nil;
  3665. Weights := nil;
  3666. Deleted := False;
  3667. Stored := False;
  3668. Context.Clear();
  3669. end;
  3670. procedure TUCA_LineRec.Assign(ASource : PUCA_LineRec);
  3671. begin
  3672. if (ASource = nil) then begin
  3673. Clear();
  3674. exit;
  3675. end;
  3676. Self.CodePoints := Copy(ASource^.CodePoints);
  3677. Self.Weights := Copy(ASource^.Weights);
  3678. Self.Deleted := ASource^.Deleted;
  3679. Self.Stored := ASource^.Stored;
  3680. Self.Context.Assign(@ASource^.Context);
  3681. end;
  3682. function TUCA_LineRec.Clone : TUCA_LineRec;
  3683. begin
  3684. Result.Clear();
  3685. Result.Assign(@Self);
  3686. end;
  3687. function TUCA_LineRec.HasContext() : Boolean;
  3688. begin
  3689. Result := (Length(Context.Data) > 0);
  3690. end;
  3691. { TPropRec }
  3692. function TPropRec.GetCategory: TUnicodeCategory;
  3693. begin
  3694. Result := TUnicodeCategory((CategoryData and Byte($F8)) shr 3);
  3695. end;
  3696. procedure TPropRec.SetCategory(AValue: TUnicodeCategory);
  3697. var
  3698. b : Byte;
  3699. begin
  3700. b := Ord(AValue);
  3701. b := b shl 3;
  3702. CategoryData := CategoryData or b;
  3703. //CategoryData := CategoryData or Byte(Byte(Ord(AValue)) shl 3);
  3704. end;
  3705. function TPropRec.GetWhiteSpace: Boolean;
  3706. begin
  3707. Result := IsBitON(CategoryData,0);
  3708. end;
  3709. procedure TPropRec.SetWhiteSpace(AValue: Boolean);
  3710. begin
  3711. SetBit(CategoryData,0,AValue);
  3712. end;
  3713. function TPropRec.GetHangulSyllable: Boolean;
  3714. begin
  3715. Result := IsBitON(CategoryData,1);
  3716. end;
  3717. procedure TPropRec.SetHangulSyllable(AValue: Boolean);
  3718. begin
  3719. SetBit(CategoryData,1,AValue);
  3720. end;
  3721. { TUCA_PropItemRec }
  3722. function TUCA_PropItemRec.GetWeightSize : Word;
  3723. var
  3724. c : Integer;
  3725. begin
  3726. c := WeightLength;
  3727. if (c = 0) then
  3728. exit(0);
  3729. Result := c*SizeOf(TUCA_PropWeights);
  3730. if IsWeightCompress_1() then
  3731. Result := Result - 1;
  3732. if IsWeightCompress_2() then
  3733. Result := Result - 1;
  3734. end;
  3735. function TUCA_PropItemRec.HasCodePoint(): Boolean;
  3736. begin
  3737. Result := IsBitON(Flags,FLAG_CODEPOINT);
  3738. end;
  3739. procedure TUCA_PropItemRec.GetWeightArray(ADest: PUCA_PropWeights);
  3740. var
  3741. c : Integer;
  3742. p : PByte;
  3743. pd : PUCA_PropWeights;
  3744. begin
  3745. c := WeightLength;
  3746. p := PByte(PtrUInt(@Self) + SizeOf(TUCA_PropItemRec));
  3747. pd := ADest;
  3748. pd^.Weights[0] := PWord(p)^;
  3749. p := p + 2;
  3750. if not IsWeightCompress_1() then begin
  3751. pd^.Weights[1] := PWord(p)^;
  3752. p := p + 2;
  3753. end else begin
  3754. pd^.Weights[1] := p^;
  3755. p := p + 1;
  3756. end;
  3757. if not IsWeightCompress_2() then begin
  3758. pd^.Weights[2] := PWord(p)^;
  3759. p := p + 2;
  3760. end else begin
  3761. pd^.Weights[2] := p^;
  3762. p := p + 1;
  3763. end;
  3764. if (c > 1) then
  3765. Move(p^, (pd+1)^, ((c-1)*SizeOf(TUCA_PropWeights)));
  3766. end;
  3767. function TUCA_PropItemRec.GetSelfOnlySize() : Cardinal;
  3768. begin
  3769. Result := SizeOf(TUCA_PropItemRec);
  3770. if (WeightLength > 0) then begin
  3771. Result := Result + (WeightLength * Sizeof(TUCA_PropWeights));
  3772. if IsWeightCompress_1() then
  3773. Result := Result - 1;
  3774. if IsWeightCompress_2() then
  3775. Result := Result - 1;
  3776. end;
  3777. if HasCodePoint() then
  3778. Result := Result + SizeOf(UInt24);
  3779. if Contextual then
  3780. Result := Result + Cardinal(GetContext()^.Size);
  3781. end;
  3782. procedure TUCA_PropItemRec.SetContextual(AValue : Boolean);
  3783. begin
  3784. SetBit(Flags,FLAG_CONTEXTUAL,AValue);
  3785. end;
  3786. function TUCA_PropItemRec.GetContextual : Boolean;
  3787. begin
  3788. Result := IsBitON(Flags,FLAG_CONTEXTUAL);
  3789. end;
  3790. function TUCA_PropItemRec.GetContext() : PUCA_PropItemContextTreeRec;
  3791. var
  3792. p : PtrUInt;
  3793. begin
  3794. if not Contextual then
  3795. exit(nil);
  3796. p := PtrUInt(@Self) + SizeOf(TUCA_PropItemRec);
  3797. if IsBitON(Flags,FLAG_CODEPOINT) then
  3798. p := p + SizeOf(UInt24);
  3799. Result := PUCA_PropItemContextTreeRec(p);
  3800. end;
  3801. procedure TUCA_PropItemRec.SetDeleted(AValue: Boolean);
  3802. begin
  3803. SetBit(Flags,FLAG_DELETION,AValue);
  3804. end;
  3805. function TUCA_PropItemRec.IsDeleted: Boolean;
  3806. begin
  3807. Result := IsBitON(Flags,FLAG_DELETION);
  3808. end;
  3809. function TUCA_PropItemRec.IsValid() : Boolean;
  3810. begin
  3811. Result := IsBitON(Flags,FLAG_VALID);
  3812. end;
  3813. function TUCA_PropItemRec.IsWeightCompress_1 : Boolean;
  3814. begin
  3815. Result := IsBitON(Flags,FLAG_COMPRESS_WEIGHT_1);
  3816. end;
  3817. function TUCA_PropItemRec.IsWeightCompress_2 : Boolean;
  3818. begin
  3819. Result := IsBitON(Flags,FLAG_COMPRESS_WEIGHT_2);
  3820. end;
  3821. function TUCA_PropItemRec.GetCodePoint: UInt24;
  3822. begin
  3823. if HasCodePoint() then begin
  3824. if Contextual then
  3825. Result := PUInt24(
  3826. PtrUInt(@Self) + Self.GetSelfOnlySize()- SizeOf(UInt24) -
  3827. Cardinal(GetContext()^.Size)
  3828. )^
  3829. else
  3830. Result := PUInt24(PtrUInt(@Self) + Self.GetSelfOnlySize() - SizeOf(UInt24))^
  3831. end else begin
  3832. raise Exception.Create('TUCA_PropItemRec.GetCodePoint : "No code point available."');
  3833. end
  3834. end;
  3835. function avl_CompareCodePoints(Item1, Item2: Pointer): Integer;
  3836. var
  3837. a, b : PUCA_LineContextItemRec;
  3838. i, hb : Integer;
  3839. begin
  3840. if (Item1 = Item2) then
  3841. exit(0);
  3842. if (Item1 = nil) then
  3843. exit(-1);
  3844. if (Item2 = nil) then
  3845. exit(1);
  3846. a := Item1;
  3847. b := Item2;
  3848. if (a^.CodePoints = b^.CodePoints) then
  3849. exit(0);
  3850. Result := 1;
  3851. hb := Length(b^.CodePoints) - 1;
  3852. for i := 0 to Length(a^.CodePoints) - 1 do begin
  3853. if (i > hb) then
  3854. exit;
  3855. if (a^.CodePoints[i] < b^.CodePoints[i]) then
  3856. exit(-1);
  3857. if (a^.CodePoints[i] > b^.CodePoints[i]) then
  3858. exit(1);
  3859. end;
  3860. if (Length(a^.CodePoints) = Length(b^.CodePoints)) then
  3861. exit(0);
  3862. exit(-1);
  3863. end;
  3864. function ConstructAvlContextTree(AContext : PUCA_LineContextRec) : TAVLTree;
  3865. var
  3866. r : TAVLTree;
  3867. i : Integer;
  3868. begin
  3869. r := TAVLTree.Create(@avl_CompareCodePoints);
  3870. try
  3871. for i := 0 to Length(AContext^.Data) - 1 do
  3872. r.Add(@AContext^.Data[i]);
  3873. Result := r;
  3874. except
  3875. FreeAndNil(r);
  3876. raise;
  3877. end;
  3878. end;
  3879. function ConstructContextTree(
  3880. const AContext : PUCA_LineContextRec;
  3881. var ADestBuffer;
  3882. const ADestBufferLength : Cardinal
  3883. ) : PUCA_PropItemContextTreeRec;
  3884. function CalcItemOnlySize(AItem : TAVLTreeNode) : Cardinal;
  3885. var
  3886. kitem : PUCA_LineContextItemRec;
  3887. begin
  3888. if (AItem = nil) then
  3889. exit(0);
  3890. kitem := AItem.Data;
  3891. Result := SizeOf(PUCA_PropItemContextTreeNodeRec^.Left) +
  3892. SizeOf(PUCA_PropItemContextTreeNodeRec^.Right) +
  3893. SizeOf(PUCA_PropItemContextRec^.CodePointCount) +
  3894. (Length(kitem^.CodePoints)*SizeOf(UInt24)) +
  3895. SizeOf(PUCA_PropItemContextRec^.WeightCount) +
  3896. (Length(kitem^.Weights)*SizeOf(TUCA_PropWeights));
  3897. end;
  3898. function CalcItemSize(AItem : TAVLTreeNode) : Cardinal;
  3899. begin
  3900. if (AItem = nil) then
  3901. exit(0);
  3902. Result := CalcItemOnlySize(AItem);
  3903. if (AItem.Left <> nil) then
  3904. Result := Result + CalcItemSize(AItem.Left);
  3905. if (AItem.Right <> nil) then
  3906. Result := Result + CalcItemSize(AItem.Right);
  3907. end;
  3908. function CalcSize(AData : TAVLTree) : Cardinal;
  3909. begin
  3910. Result := SizeOf(PUCA_PropItemContextTreeRec^.Size) + CalcItemSize(AData.Root);
  3911. end;
  3912. function ConstructItem(ASource : TAVLTreeNode; ADest : PUCA_PropItemContextTreeNodeRec) : Cardinal;
  3913. var
  3914. k : Integer;
  3915. kitem : PUCA_LineContextItemRec;
  3916. kpcp : PUInt24;
  3917. kpw : PUCA_PropWeights;
  3918. pextra : PtrUInt;
  3919. pnext : PUCA_PropItemContextTreeNodeRec;
  3920. begin
  3921. kitem := ASource.Data;
  3922. ADest^.Data.CodePointCount := Length(kitem^.CodePoints);
  3923. ADest^.Data.WeightCount := Length(kitem^.Weights);
  3924. pextra := PtrUInt(ADest)+SizeOf(ADest^.Left)+SizeOf(ADest^.Right)+
  3925. SizeOf(ADest^.Data.CodePointCount)+SizeOf(ADest^.Data.WeightCount);
  3926. if (ADest^.Data.CodePointCount > 0) then begin
  3927. kpcp := PUInt24(pextra);
  3928. for k := 0 to ADest^.Data.CodePointCount - 1 do begin
  3929. kpcp^ := kitem^.CodePoints[k];
  3930. Inc(kpcp);
  3931. end;
  3932. end;
  3933. if (ADest^.Data.WeightCount > 0) then begin
  3934. kpw := PUCA_PropWeights(pextra + (ADest^.Data.CodePointCount*SizeOf(UInt24)));
  3935. for k := 0 to ADest^.Data.WeightCount - 1 do begin
  3936. kpw^.Weights[0] := kitem^.Weights[k].Weights[0];
  3937. kpw^.Weights[1] := kitem^.Weights[k].Weights[1];
  3938. kpw^.Weights[2] := kitem^.Weights[k].Weights[2];
  3939. Inc(kpw);
  3940. end;
  3941. end;
  3942. Result := CalcItemOnlySize(ASource);
  3943. if (ASource.Left <> nil) then begin
  3944. pnext := PUCA_PropItemContextTreeNodeRec(PtrUInt(ADest) + Result);
  3945. ADest^.Left := Result;
  3946. Result := Result + ConstructItem(ASource.Left,pnext);
  3947. end else begin
  3948. ADest^.Left := 0;
  3949. end;
  3950. if (ASource.Right <> nil) then begin
  3951. pnext := PUCA_PropItemContextTreeNodeRec(PtrUInt(ADest) + Result);
  3952. ADest^.Right := Result;
  3953. Result := Result + ConstructItem(ASource.Right,pnext);
  3954. end else begin
  3955. ADest^.Right := 0;
  3956. end;
  3957. end;
  3958. var
  3959. c : PtrUInt;
  3960. r : PUCA_PropItemContextTreeRec;
  3961. p : PUCA_PropItemContextTreeNodeRec;
  3962. tempTree : TAVLTree;
  3963. begin
  3964. tempTree := ConstructAvlContextTree(AContext);
  3965. try
  3966. c := CalcSize(tempTree);
  3967. if (ADestBufferLength > 0) and (c > ADestBufferLength) then
  3968. raise Exception.Create(SInsufficientMemoryBuffer);
  3969. r := @ADestBuffer;
  3970. r^.Size := c;
  3971. p := PUCA_PropItemContextTreeNodeRec(PtrUInt(r) + SizeOf(r^.Size));
  3972. ConstructItem(tempTree.Root,p);
  3973. finally
  3974. tempTree.Free();
  3975. end;
  3976. Result := r;
  3977. end;
  3978. procedure ReverseRecordBytes(var AItem : TSerializedCollationHeader);
  3979. begin
  3980. ReverseBytes(AItem.BMP_Table1Length,SizeOf(AItem.BMP_Table1Length));
  3981. ReverseBytes(AItem.BMP_Table2Length,SizeOf(AItem.BMP_Table2Length));
  3982. ReverseBytes(AItem.OBMP_Table1Length,SizeOf(AItem.OBMP_Table1Length));
  3983. ReverseBytes(AItem.OBMP_Table2Length,SizeOf(AItem.OBMP_Table2Length));
  3984. ReverseBytes(AItem.PropCount,SizeOf(AItem.PropCount));
  3985. ReverseBytes(AItem.VariableLowLimit,SizeOf(AItem.VariableLowLimit));
  3986. ReverseBytes(AItem.VariableHighLimit,SizeOf(AItem.VariableHighLimit));
  3987. end;
  3988. procedure ReverseBytes(var AData; const ALength : Integer);
  3989. var
  3990. i,j : PtrInt;
  3991. c : Byte;
  3992. p : PByte;
  3993. begin
  3994. if (ALength = 1) then
  3995. exit;
  3996. p := @AData;
  3997. j := ALength div 2;
  3998. for i := 0 to Pred(j) do begin
  3999. c := p[i];
  4000. p[i] := p[(ALength - 1 ) - i];
  4001. p[(ALength - 1 ) - i] := c;
  4002. end;
  4003. end;
  4004. procedure ReverseArray(var AValue; const AArrayLength, AItemSize : PtrInt);
  4005. var
  4006. p : PByte;
  4007. i : PtrInt;
  4008. begin
  4009. if ( AArrayLength > 0 ) and ( AItemSize > 1 ) then begin
  4010. p := @AValue;
  4011. for i := 0 to Pred(AArrayLength) do begin
  4012. ReverseBytes(p^,AItemSize);
  4013. Inc(p,AItemSize);
  4014. end;
  4015. end;
  4016. end;
  4017. procedure ReverseContextNodeFromNativeEndian(s, d : PUCA_PropItemContextTreeNodeRec);
  4018. var
  4019. k : PtrUInt;
  4020. p_s, p_d : PByte;
  4021. begin
  4022. d^.Left := s^.Left;
  4023. ReverseBytes(d^.Left,SizeOf(d^.Left));
  4024. d^.Right := s^.Right;
  4025. ReverseBytes(d^.Right,SizeOf(d^.Right));
  4026. d^.Data.CodePointCount := s^.Data.CodePointCount;
  4027. ReverseBytes(d^.Data.CodePointCount,SizeOf(d^.Data.CodePointCount));
  4028. d^.Data.WeightCount := s^.Data.WeightCount;
  4029. ReverseBytes(d^.Data.WeightCount,SizeOf(d^.Data.WeightCount));
  4030. k := SizeOf(TUCA_PropItemContextTreeNodeRec);
  4031. p_s := PByte(PtrUInt(s) + k);
  4032. p_d := PByte(PtrUInt(d) + k);
  4033. k := (s^.Data.CodePointCount*SizeOf(UInt24));
  4034. Move(p_s^,p_d^, k);
  4035. ReverseArray(p_d^,s^.Data.CodePointCount,SizeOf(UInt24));
  4036. p_s := PByte(PtrUInt(p_s) + k);
  4037. p_d := PByte(PtrUInt(p_d) + k);
  4038. k := (s^.Data.WeightCount*SizeOf(TUCA_PropWeights));
  4039. Move(p_s^,p_d^,k);
  4040. ReverseArray(p_d^,(s^.Data.WeightCount*Length(TUCA_PropWeights.Weights)),SizeOf(TUCA_PropWeights.Weights[0]));
  4041. if (s^.Left > 0) then
  4042. ReverseContextNodeFromNativeEndian(
  4043. PUCA_PropItemContextTreeNodeRec(PtrUInt(s) + s^.Left),
  4044. PUCA_PropItemContextTreeNodeRec(PtrUInt(d) + s^.Left)
  4045. );
  4046. if (s^.Right > 0) then
  4047. ReverseContextNodeFromNativeEndian(
  4048. PUCA_PropItemContextTreeNodeRec(PtrUInt(s) + s^.Right),
  4049. PUCA_PropItemContextTreeNodeRec(PtrUInt(d) + s^.Right)
  4050. );
  4051. end;
  4052. procedure ReverseContextFromNativeEndian(s, d : PUCA_PropItemContextTreeRec);
  4053. var
  4054. k : PtrUInt;
  4055. begin
  4056. d^.Size := s^.Size;
  4057. ReverseBytes(d^.Size,SizeOf(d^.Size));
  4058. if (s^.Size = 0) then
  4059. exit;
  4060. k := SizeOf(s^.Size);
  4061. ReverseContextNodeFromNativeEndian(
  4062. PUCA_PropItemContextTreeNodeRec(PtrUInt(s)+k),
  4063. PUCA_PropItemContextTreeNodeRec(PtrUInt(d)+k)
  4064. );
  4065. end;
  4066. procedure ReverseFromNativeEndian(
  4067. const AData : PUCA_PropItemRec;
  4068. const ADataLen : Cardinal;
  4069. const ADest : PUCA_PropItemRec
  4070. );
  4071. var
  4072. s, d : PUCA_PropItemRec;
  4073. sCtx, dCtx : PUCA_PropItemContextTreeRec;
  4074. dataEnd : PtrUInt;
  4075. k, i : PtrUInt;
  4076. p_s, p_d : PByte;
  4077. pw_s, pw_d : PUCA_PropWeights;
  4078. begin
  4079. dataEnd := PtrUInt(AData) + ADataLen;
  4080. s := AData;
  4081. d := ADest;
  4082. while True do begin
  4083. d^.WeightLength := s^.WeightLength;
  4084. ReverseBytes(d^.WeightLength,SizeOf(d^.WeightLength));
  4085. d^.ChildCount := s^.ChildCount;
  4086. ReverseBytes(d^.ChildCount,SizeOf(d^.ChildCount));
  4087. d^.Size := s^.Size;
  4088. ReverseBytes(d^.Size,SizeOf(d^.Size));
  4089. d^.Flags := s^.Flags;
  4090. ReverseBytes(d^.Flags,SizeOf(d^.Flags));
  4091. if s^.Contextual then begin
  4092. k := SizeOf(TUCA_PropItemRec);
  4093. if s^.HasCodePoint() then
  4094. k := k + SizeOf(UInt24);
  4095. sCtx := PUCA_PropItemContextTreeRec(PtrUInt(s) + k);
  4096. dCtx := PUCA_PropItemContextTreeRec(PtrUInt(d) + k);
  4097. ReverseContextFromNativeEndian(sCtx,dCtx);
  4098. end;
  4099. if s^.HasCodePoint() then begin
  4100. if s^.Contextual then
  4101. k := s^.GetSelfOnlySize()- SizeOf(UInt24) - Cardinal(s^.GetContext()^.Size)
  4102. else
  4103. k := s^.GetSelfOnlySize() - SizeOf(UInt24);
  4104. p_s := PByte(PtrUInt(s) + k);
  4105. p_d := PByte(PtrUInt(d) + k);
  4106. Unaligned(PUInt24(p_d)^) := Unaligned(PUInt24(p_s)^);
  4107. ReverseBytes(p_d^,SizeOf(UInt24));
  4108. end;
  4109. if (s^.WeightLength > 0) then begin
  4110. k := SizeOf(TUCA_PropItemRec);
  4111. p_s := PByte(PtrUInt(s) + k);
  4112. p_d := PByte(PtrUInt(d) + k);
  4113. k := SizeOf(Word);
  4114. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4115. ReverseBytes(Unaligned(p_d^),k);
  4116. p_s := PByte(PtrUInt(p_s) + k);
  4117. p_d := PByte(PtrUInt(p_d) + k);
  4118. if s^.IsWeightCompress_1() then begin
  4119. k := SizeOf(Byte);
  4120. PByte(p_d)^ := PByte(p_s)^;
  4121. end else begin
  4122. k := SizeOf(Word);
  4123. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4124. end;
  4125. ReverseBytes(p_d^,k);
  4126. p_s := PByte(PtrUInt(p_s) + k);
  4127. p_d := PByte(PtrUInt(p_d) + k);
  4128. if s^.IsWeightCompress_2() then begin
  4129. k := SizeOf(Byte);
  4130. PByte(p_d)^ := PByte(p_s)^;
  4131. end else begin
  4132. k := SizeOf(Word);
  4133. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4134. end;
  4135. ReverseBytes(p_d^,k);
  4136. if (s^.WeightLength > 1) then begin
  4137. pw_s := PUCA_PropWeights(PtrUInt(p_s) + k);
  4138. pw_d := PUCA_PropWeights(PtrUInt(p_d) + k);
  4139. for i := 1 to s^.WeightLength - 1 do begin
  4140. pw_d^.Weights[0] := pw_s^.Weights[0];
  4141. pw_d^.Weights[1] := pw_s^.Weights[1];
  4142. pw_d^.Weights[2] := pw_s^.Weights[2];
  4143. ReverseArray(pw_d^,3,SizeOf(pw_s^.Weights[0]));
  4144. Inc(pw_s);
  4145. Inc(pw_d);
  4146. end;
  4147. end;
  4148. end;
  4149. k := s^.GetSelfOnlySize();
  4150. s := PUCA_PropItemRec(PtrUInt(s)+k);
  4151. d := PUCA_PropItemRec(PtrUInt(d)+k);
  4152. if (PtrUInt(s) >= dataEnd) then
  4153. Break;
  4154. end;
  4155. if ( (PtrUInt(s)-PtrUInt(AData)) <> (PtrUInt(d)-PtrUInt(ADest)) ) then
  4156. raise Exception.CreateFmt('Read data length(%d) differs from written data length(%d).',[(PtrUInt(s)-PtrUInt(AData)), (PtrUInt(d)-PtrUInt(ADest))]);
  4157. end;
  4158. //------------------------------------------------------------------------------
  4159. procedure ReverseContextNodeToNativeEndian(s, d : PUCA_PropItemContextTreeNodeRec);
  4160. var
  4161. k : PtrUInt;
  4162. p_s, p_d : PByte;
  4163. begin
  4164. d^.Left := s^.Left;
  4165. ReverseBytes(d^.Left,SizeOf(d^.Left));
  4166. d^.Right := s^.Right;
  4167. ReverseBytes(d^.Right,SizeOf(d^.Right));
  4168. d^.Data.CodePointCount := s^.Data.CodePointCount;
  4169. ReverseBytes(d^.Data.CodePointCount,SizeOf(d^.Data.CodePointCount));
  4170. d^.Data.WeightCount := s^.Data.WeightCount;
  4171. ReverseBytes(d^.Data.WeightCount,SizeOf(d^.Data.WeightCount));
  4172. k := SizeOf(TUCA_PropItemContextTreeNodeRec);
  4173. p_s := PByte(PtrUInt(s) + k);
  4174. p_d := PByte(PtrUInt(d) + k);
  4175. k := (d^.Data.CodePointCount*SizeOf(UInt24));
  4176. Move(p_s^,p_d^, k);
  4177. ReverseArray(p_d^,d^.Data.CodePointCount,SizeOf(UInt24));
  4178. p_s := PByte(PtrUInt(p_s) + k);
  4179. p_d := PByte(PtrUInt(p_d) + k);
  4180. k := (d^.Data.WeightCount*SizeOf(TUCA_PropWeights));
  4181. Move(p_s^,p_d^,k);
  4182. ReverseArray(p_d^,(d^.Data.WeightCount*Length(TUCA_PropWeights.Weights)),SizeOf(TUCA_PropWeights.Weights[0]));
  4183. if (d^.Left > 0) then
  4184. ReverseContextNodeToNativeEndian(
  4185. PUCA_PropItemContextTreeNodeRec(PtrUInt(s) + d^.Left),
  4186. PUCA_PropItemContextTreeNodeRec(PtrUInt(d) + d^.Left)
  4187. );
  4188. if (d^.Right > 0) then
  4189. ReverseContextNodeToNativeEndian(
  4190. PUCA_PropItemContextTreeNodeRec(PtrUInt(s) + d^.Right),
  4191. PUCA_PropItemContextTreeNodeRec(PtrUInt(d) + d^.Right)
  4192. );
  4193. end;
  4194. procedure ReverseContextToNativeEndian(s, d : PUCA_PropItemContextTreeRec);
  4195. var
  4196. k : PtrUInt;
  4197. begin
  4198. d^.Size := s^.Size;
  4199. ReverseBytes(d^.Size,SizeOf(d^.Size));
  4200. if (s^.Size = 0) then
  4201. exit;
  4202. k := SizeOf(s^.Size);
  4203. ReverseContextNodeToNativeEndian(
  4204. PUCA_PropItemContextTreeNodeRec(PtrUInt(s)+k),
  4205. PUCA_PropItemContextTreeNodeRec(PtrUInt(d)+k)
  4206. );
  4207. end;
  4208. procedure ReverseToNativeEndian(
  4209. const AData : PUCA_PropItemRec;
  4210. const ADataLen : Cardinal;
  4211. const ADest : PUCA_PropItemRec
  4212. );
  4213. var
  4214. s, d : PUCA_PropItemRec;
  4215. sCtx, dCtx : PUCA_PropItemContextTreeRec;
  4216. dataEnd : PtrUInt;
  4217. k, i : PtrUInt;
  4218. p_s, p_d : PByte;
  4219. pw_s, pw_d : PUCA_PropWeights;
  4220. begin
  4221. dataEnd := PtrUInt(AData) + ADataLen;
  4222. s := AData;
  4223. d := ADest;
  4224. while True do begin
  4225. d^.WeightLength := s^.WeightLength;
  4226. ReverseBytes(d^.WeightLength,SizeOf(d^.WeightLength));
  4227. d^.ChildCount := s^.ChildCount;
  4228. ReverseBytes(d^.ChildCount,SizeOf(d^.ChildCount));
  4229. d^.Size := s^.Size;
  4230. ReverseBytes(d^.Size,SizeOf(d^.Size));
  4231. d^.Flags := s^.Flags;
  4232. ReverseBytes(d^.Flags,SizeOf(d^.Flags));
  4233. if d^.Contextual then begin
  4234. k := SizeOf(TUCA_PropItemRec);
  4235. if d^.HasCodePoint() then
  4236. k := k + SizeOf(UInt24);
  4237. sCtx := PUCA_PropItemContextTreeRec(PtrUInt(s) + k);
  4238. dCtx := PUCA_PropItemContextTreeRec(PtrUInt(d) + k);
  4239. ReverseContextToNativeEndian(sCtx,dCtx);
  4240. end;
  4241. if d^.HasCodePoint() then begin
  4242. if d^.Contextual then
  4243. k := d^.GetSelfOnlySize()- SizeOf(UInt24) - Cardinal(d^.GetContext()^.Size)
  4244. else
  4245. k := d^.GetSelfOnlySize() - SizeOf(UInt24);
  4246. p_s := PByte(PtrUInt(s) + k);
  4247. p_d := PByte(PtrUInt(d) + k);
  4248. Unaligned(PUInt24(p_d)^) := Unaligned(PUInt24(p_s)^);
  4249. ReverseBytes(p_d^,SizeOf(UInt24));
  4250. end;
  4251. if (d^.WeightLength > 0) then begin
  4252. k := SizeOf(TUCA_PropItemRec);
  4253. p_s := PByte(PtrUInt(s) + k);
  4254. p_d := PByte(PtrUInt(d) + k);
  4255. k := SizeOf(Word);
  4256. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4257. ReverseBytes(p_d^,k);
  4258. p_s := PByte(PtrUInt(p_s) + k);
  4259. p_d := PByte(PtrUInt(p_d) + k);
  4260. if d^.IsWeightCompress_1() then begin
  4261. k := SizeOf(Byte);
  4262. PByte(p_d)^ := PByte(p_s)^;
  4263. end else begin
  4264. k := SizeOf(Word);
  4265. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4266. end;
  4267. ReverseBytes(p_d^,k);
  4268. p_s := PByte(PtrUInt(p_s) + k);
  4269. p_d := PByte(PtrUInt(p_d) + k);
  4270. if d^.IsWeightCompress_2() then begin
  4271. k := SizeOf(Byte);
  4272. PByte(p_d)^ := PByte(p_s)^;
  4273. end else begin
  4274. k := SizeOf(Word);
  4275. Unaligned(PWord(p_d)^) := Unaligned(PWord(p_s)^);
  4276. end;
  4277. ReverseBytes(p_d^,k);
  4278. if (d^.WeightLength > 1) then begin
  4279. pw_s := PUCA_PropWeights(PtrUInt(p_s) + k);
  4280. pw_d := PUCA_PropWeights(PtrUInt(p_d) + k);
  4281. for i := 1 to d^.WeightLength - 1 do begin
  4282. pw_d^.Weights[0] := pw_s^.Weights[0];
  4283. pw_d^.Weights[1] := pw_s^.Weights[1];
  4284. pw_d^.Weights[2] := pw_s^.Weights[2];
  4285. ReverseArray(pw_d^,3,SizeOf(pw_s^.Weights[0]));
  4286. Inc(pw_s);
  4287. Inc(pw_d);
  4288. end;
  4289. end;
  4290. end;
  4291. k := d^.GetSelfOnlySize();
  4292. s := PUCA_PropItemRec(PtrUInt(s)+k);
  4293. d := PUCA_PropItemRec(PtrUInt(d)+k);
  4294. if (PtrUInt(s) >= dataEnd) then
  4295. Break;
  4296. end;
  4297. if ( (PtrUInt(s)-PtrUInt(AData)) <> (PtrUInt(d)-PtrUInt(ADest)) ) then
  4298. raise Exception.CreateFmt('Read data length(%d) differs from written data length(%d).',[(PtrUInt(s)-PtrUInt(AData)), (PtrUInt(d)-PtrUInt(ADest))]);
  4299. end;
  4300. procedure Check(const ACondition : Boolean; const AMsg : string);overload;
  4301. begin
  4302. if not ACondition then
  4303. raise Exception.Create(AMsg);
  4304. end;
  4305. procedure Check(
  4306. const ACondition : Boolean;
  4307. const AFormatMsg : string;
  4308. const AArgs : array of const
  4309. );overload;
  4310. begin
  4311. Check(ACondition,Format(AFormatMsg,AArgs));
  4312. end;
  4313. procedure Check(const ACondition : Boolean);overload;
  4314. begin
  4315. Check(ACondition,'Check failed.')
  4316. end;
  4317. procedure CompareWeights(a, b : PUCA_PropWeights; const ALength : Integer);
  4318. var
  4319. i : Integer;
  4320. begin
  4321. if (ALength > 0) then begin
  4322. for i := 0 to ALength - 1 do begin
  4323. Check(a[i].Weights[0]=b[i].Weights[0]);
  4324. Check(a[i].Weights[1]=b[i].Weights[1]);
  4325. Check(a[i].Weights[2]=b[i].Weights[2]);
  4326. end;
  4327. end;
  4328. end;
  4329. procedure CompareCodePoints(a, b : PUInt24; const ALength : Integer);
  4330. var
  4331. i : Integer;
  4332. begin
  4333. if (ALength > 0) then begin
  4334. for i := 0 to ALength - 1 do
  4335. Check(a[i]=b[i]);
  4336. end;
  4337. end;
  4338. procedure CompareContextNode(AProp1, AProp2 : PUCA_PropItemContextTreeNodeRec);
  4339. var
  4340. a, b : PUCA_PropItemContextTreeNodeRec;
  4341. k : Cardinal;
  4342. begin
  4343. if (AProp1=nil) then begin
  4344. Check(AProp2=nil);
  4345. exit;
  4346. end;
  4347. a := AProp1;
  4348. b := AProp2;
  4349. Check(a^.Left=b^.Left);
  4350. Check(a^.Right=b^.Right);
  4351. Check(a^.Data.CodePointCount=b^.Data.CodePointCount);
  4352. Check(a^.Data.WeightCount=b^.Data.WeightCount);
  4353. k := SizeOf(a^.Data);
  4354. CompareCodePoints(
  4355. PUInt24(PtrUInt(a)+k),
  4356. PUInt24(PtrUInt(b)+k),
  4357. a^.Data.CodePointCount
  4358. );
  4359. k := SizeOf(a^.Data)+ (a^.Data.CodePointCount*SizeOf(UInt24));
  4360. CompareWeights(
  4361. PUCA_PropWeights(PtrUInt(a)+k),
  4362. PUCA_PropWeights(PtrUInt(b)+k),
  4363. a^.Data.WeightCount
  4364. );
  4365. if (a^.Left > 0) then begin
  4366. k := a^.Left;
  4367. CompareContextNode(
  4368. PUCA_PropItemContextTreeNodeRec(PtrUInt(a)+k),
  4369. PUCA_PropItemContextTreeNodeRec(PtrUInt(b)+k)
  4370. );
  4371. end;
  4372. if (a^.Right > 0) then begin
  4373. k := a^.Right;
  4374. CompareContextNode(
  4375. PUCA_PropItemContextTreeNodeRec(PtrUInt(a)+k),
  4376. PUCA_PropItemContextTreeNodeRec(PtrUInt(b)+k)
  4377. );
  4378. end;
  4379. end;
  4380. procedure CompareContext(AProp1, AProp2 : PUCA_PropItemContextTreeRec);
  4381. var
  4382. a, b : PUCA_PropItemContextTreeNodeRec;
  4383. k : Integer;
  4384. begin
  4385. if (AProp1=nil) then begin
  4386. Check(AProp2=nil);
  4387. exit;
  4388. end;
  4389. Check(AProp1^.Size=AProp2^.Size);
  4390. k := Cardinal(AProp1^.Size);
  4391. a := PUCA_PropItemContextTreeNodeRec(PtrUInt(AProp1)+k);
  4392. b := PUCA_PropItemContextTreeNodeRec(PtrUInt(AProp2)+k);
  4393. CompareContextNode(a,b);
  4394. end;
  4395. procedure CompareProps(const AProp1, AProp2 : PUCA_PropItemRec; const ADataLen : Integer);
  4396. var
  4397. a, b, pend : PUCA_PropItemRec;
  4398. wa, wb : array of TUCA_PropWeights;
  4399. k : Integer;
  4400. begin
  4401. if (ADataLen <= 0) then
  4402. exit;
  4403. a := PUCA_PropItemRec(AProp1);
  4404. b := PUCA_PropItemRec(AProp2);
  4405. pend := PUCA_PropItemRec(PtrUInt(AProp1)+ADataLen);
  4406. while (a<pend) do begin
  4407. Check(a^.WeightLength=b^.WeightLength);
  4408. Check(a^.ChildCount=b^.ChildCount);
  4409. Check(a^.Size=b^.Size);
  4410. Check(a^.Flags=b^.Flags);
  4411. if a^.HasCodePoint() then
  4412. Check(a^.CodePoint = b^.CodePoint);
  4413. if (a^.WeightLength > 0) then begin
  4414. k := a^.WeightLength;
  4415. SetLength(wa,k);
  4416. SetLength(wb,k);
  4417. a^.GetWeightArray(@wa[0]);
  4418. b^.GetWeightArray(@wb[0]);
  4419. CompareWeights(@wa[0],@wb[0],k);
  4420. end;
  4421. if a^.Contextual then
  4422. CompareContext(a^.GetContext(),b^.GetContext());
  4423. Check(a^.GetSelfOnlySize()=b^.GetSelfOnlySize());
  4424. k := a^.GetSelfOnlySize();
  4425. a := PUCA_PropItemRec(PtrUInt(a)+k);
  4426. b := PUCA_PropItemRec(PtrUInt(b)+k);
  4427. end;
  4428. end;
  4429. Procedure QuickSort(AList : PCardinal; L, R : Longint);overload;
  4430. var
  4431. I, J : Longint;
  4432. P, Q : Cardinal;
  4433. begin
  4434. repeat
  4435. I := L;
  4436. J := R;
  4437. P := AList[ (L + R) div 2 ];
  4438. repeat
  4439. while (P > AList[i]) do
  4440. I := I + 1;
  4441. while (P < AList[J]) do
  4442. J := J - 1;
  4443. If I <= J then
  4444. begin
  4445. Q := AList[I];
  4446. AList[I] := AList[J];
  4447. AList[J] := Q;
  4448. I := I + 1;
  4449. J := J - 1;
  4450. end;
  4451. until I > J;
  4452. if J - L < R - I then
  4453. begin
  4454. if L < J then
  4455. QuickSort(AList, L, J);
  4456. L := I;
  4457. end
  4458. else
  4459. begin
  4460. if I < R then
  4461. QuickSort(AList, I, R);
  4462. R := J;
  4463. end;
  4464. until L >= R;
  4465. end;
  4466. function CalcMaxLevel2Count(
  4467. const ALevel1Value : Cardinal;
  4468. ALines : array of TUCA_LineRec
  4469. ) : Integer;
  4470. var
  4471. i, c, k : Integer;
  4472. ac : Integer;
  4473. items : array of Cardinal;
  4474. p : PUCA_LineRec;
  4475. pw : ^TUCA_WeightRec;
  4476. begin
  4477. c := Length(ALines);
  4478. if (c < 1) then
  4479. exit(0);
  4480. SetLength(items,0);
  4481. ac := 0;
  4482. p := @ALines[Low(ALines)];
  4483. for i := 0 to c-1 do begin
  4484. if (Length(p^.Weights) > 0) then begin
  4485. pw := @p^.Weights[Low(p^.Weights)];
  4486. for k := 0 to Length(p^.Weights)-1 do begin
  4487. if (pw^.Weights[0] = ALevel1Value) then begin
  4488. if (ac = 0) or (IndexDWord(items[0],ac,pw^.Weights[1]) < 0) then begin
  4489. if (ac >= Length(items)) then
  4490. SetLength(items,Length(items)+256);
  4491. items[ac] := pw^.Weights[1];
  4492. ac := ac+1;
  4493. end;
  4494. end;
  4495. Inc(pw);
  4496. end;
  4497. end;
  4498. Inc(p);
  4499. end;
  4500. Result := ac;
  4501. end;
  4502. function RewriteLevel2(
  4503. const ALevel1Value : Cardinal;
  4504. ALines : PUCA_LineRec;
  4505. const ALinesLength : Integer
  4506. ) : Integer;
  4507. var
  4508. i, c, k : Integer;
  4509. ac : Integer;
  4510. items : array of Cardinal;
  4511. p : PUCA_LineRec;
  4512. pw : ^TUCA_WeightRec;
  4513. newValue : Int64;
  4514. begin
  4515. c := ALinesLength;
  4516. if (c < 1) then
  4517. exit(0);
  4518. SetLength(items,256);
  4519. ac := 0;
  4520. p := ALines;
  4521. for i := 0 to c-1 do begin
  4522. if (Length(p^.Weights) > 0) then begin
  4523. for k := 0 to Length(p^.Weights)-1 do begin
  4524. pw := @p^.Weights[k];
  4525. if (pw^.Weights[0] = ALevel1Value) then begin
  4526. if (ac = 0) or (IndexDWord(items[0],ac,pw^.Weights[1]) < 0) then begin
  4527. if (ac >= Length(items)) then
  4528. SetLength(items,Length(items)+256);
  4529. items[ac] := pw^.Weights[1];
  4530. ac := ac+1;
  4531. end;
  4532. end;
  4533. end;
  4534. end;
  4535. Inc(p);
  4536. end;
  4537. SetLength(items,ac);
  4538. if (ac > 1) then
  4539. QuickSort(@items[0],0,(ac-1));
  4540. p := ALines;
  4541. for i := 0 to c-1 do begin
  4542. if (Length(p^.Weights) > 0) then begin
  4543. for k := 0 to Length(p^.Weights)-1 do begin
  4544. pw := @p^.Weights[k];
  4545. if (pw^.Weights[0] = ALevel1Value) then begin
  4546. newValue := IndexDWord(items[0],ac,pw^.Weights[1]);
  4547. if (newValue < 0) then
  4548. raise Exception.CreateFmt('level 2 value %d missed in rewrite of level 1 value of %d.',[pw^.Weights[1],ALevel1Value]);
  4549. pw^.Weights[1] := newValue;//+1;
  4550. end;
  4551. end;
  4552. end;
  4553. Inc(p);
  4554. end;
  4555. if (Length(items) > 0) then
  4556. Result := items[Length(items)-1]
  4557. else
  4558. Result := 0;
  4559. end;
  4560. procedure RewriteLevel2Values(ALines : PUCA_LineRec; ALength : Integer);
  4561. var
  4562. c, i, ac, k : Integer;
  4563. p : PUCA_LineRec;
  4564. level1List : array of Cardinal;
  4565. pw : ^TUCA_WeightRec;
  4566. begin
  4567. c := ALength;
  4568. if (c < 1) then
  4569. exit;
  4570. ac := 0;
  4571. SetLength(level1List,c);
  4572. p := ALines;
  4573. for i := 0 to c-1 do begin
  4574. if (Length(p^.Weights) > 0) then begin
  4575. for k := 0 to Length(p^.Weights)-1 do begin
  4576. pw := @p^.Weights[k];
  4577. if (ac = 0) or (IndexDWord(level1List[0],ac,pw^.Weights[0]) < 0) then begin
  4578. if (ac >= Length(level1List)) then
  4579. SetLength(level1List,ac+1000);
  4580. level1List[ac] := pw^.Weights[0];
  4581. RewriteLevel2(level1List[ac],ALines,ALength);
  4582. ac := ac+1;
  4583. end;
  4584. end;
  4585. end;
  4586. Inc(p);
  4587. end;
  4588. end;
  4589. function CalcMaxLevel2Value(ALines : array of TUCA_LineRec) : Cardinal;
  4590. var
  4591. i, c, k, tempValue : Integer;
  4592. p : PUCA_LineRec;
  4593. maxLevel : Cardinal;
  4594. maxValue : Integer;
  4595. begin
  4596. c := Length(ALines);
  4597. if (c < 2) then
  4598. exit(0);
  4599. maxLevel := 0;
  4600. maxValue := CalcMaxLevel2Count(maxLevel,ALines);
  4601. p := @ALines[Low(ALines)+1];
  4602. for i := 1 to c-1 do begin
  4603. if (Length(p^.Weights) > 0) then begin
  4604. for k := 0 to Length(p^.Weights)-1 do begin
  4605. if (p^.Weights[k].Weights[0] <> maxLevel) then begin
  4606. tempValue := CalcMaxLevel2Count(p^.Weights[k].Weights[0],ALines);
  4607. if (tempValue > maxValue) then begin
  4608. maxLevel := p^.Weights[k].Weights[0];
  4609. maxValue := tempValue;
  4610. end;
  4611. end;
  4612. end;
  4613. end;
  4614. Inc(p);
  4615. end;
  4616. Result := maxValue;
  4617. end;
  4618. initialization
  4619. FS := DefaultFormatSettings;
  4620. FS.DecimalSeparator := '.';
  4621. end.