helper.pas 142 KB

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