helper.pas 143 KB

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