helper.pas 114 KB

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