helper.pas 139 KB

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