helper.pas 113 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021
  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
  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. 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. locData : TBlockItemRec;
  963. s : ansistring;
  964. begin
  965. s := NextToken();
  966. if (s = '') or (s[1] = '#') then
  967. exit;
  968. locData.RangeStart := StrToInt('$'+s);
  969. s := NextToken();
  970. if (s <> '.') then
  971. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  972. s := NextToken();
  973. if (s <> '.') then
  974. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  975. s := NextToken();
  976. locData.RangeEnd := StrToInt('$'+s);
  977. s := NextToken();
  978. if (s <> ';') then
  979. raise Exception.CreateFmt('";" expected but "%s" found.',[s]);
  980. locData.Name := Trim(NextToken());
  981. locData.CanonicalName := NormalizeBlockName(locData.Name);
  982. if (Length(ABlocks) <= actualDataLen) then
  983. SetLength(ABlocks,Length(ABlocks)*2);
  984. ABlocks[actualDataLen] := locData;
  985. Inc(actualDataLen);
  986. end;
  987. procedure Prepare();
  988. begin
  989. SetLength(ABlocks,DATA_LENGTH);
  990. actualDataLen := 0;
  991. bufferLength := ADataAStream.Size;
  992. bufferPos := 0;
  993. p := ADataAStream.Memory;
  994. lineLength := 0;
  995. SetLength(line,LINE_LENGTH);
  996. end;
  997. begin
  998. Prepare();
  999. while NextLine() do
  1000. ParseLine();
  1001. SetLength(ABlocks,actualDataLen);
  1002. end;
  1003. procedure ParseProps(
  1004. ADataAStream : TMemoryStream;
  1005. var APropList : TPropListLineRecArray
  1006. );
  1007. const
  1008. LINE_LENGTH = 1024;
  1009. DATA_LENGTH = 25000;
  1010. var
  1011. p : PAnsiChar;
  1012. actualDataLen : Integer;
  1013. bufferLength, bufferPos, lineLength, linePos : Integer;
  1014. line : ansistring;
  1015. function NextLine() : Boolean;
  1016. var
  1017. locOldPos : Integer;
  1018. locOldPointer : PAnsiChar;
  1019. begin
  1020. Result := False;
  1021. locOldPointer := p;
  1022. locOldPos := bufferPos;
  1023. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1024. Inc(p);
  1025. Inc(bufferPos);
  1026. end;
  1027. if (locOldPos = bufferPos) and (p^ = #10) then begin
  1028. lineLength := 0;
  1029. Inc(p);
  1030. Inc(bufferPos);
  1031. linePos := 1;
  1032. Result := True;
  1033. end else if (locOldPos < bufferPos) then begin
  1034. lineLength := (bufferPos - locOldPos);
  1035. Move(locOldPointer^,line[1],lineLength);
  1036. if (p^ = #10) then begin
  1037. Dec(lineLength);
  1038. Inc(p);
  1039. Inc(bufferPos);
  1040. end;
  1041. linePos := 1;
  1042. Result := True;
  1043. end;
  1044. end;
  1045. function NextToken() : ansistring;
  1046. var
  1047. k : Integer;
  1048. begin
  1049. k := linePos;
  1050. if (linePos < lineLength) and (line[linePos] in [';','#','.']) then begin
  1051. Inc(linePos);
  1052. Result := Copy(line,k,(linePos-k));
  1053. exit;
  1054. end;
  1055. while (linePos < lineLength) and not(line[linePos] in [';','#','.']) do
  1056. Inc(linePos);
  1057. if (linePos > k) then begin
  1058. if (line[linePos] in [';','#','.']) then
  1059. Result := Copy(line,k,(linePos-k))
  1060. else
  1061. Result := Copy(line,k,(linePos-k+1));
  1062. Result := Trim(Result);
  1063. end else begin
  1064. Result := '';
  1065. end;
  1066. end;
  1067. procedure ParseLine();
  1068. var
  1069. locCP : Cardinal;
  1070. locData : TPropListLineRec;
  1071. s : ansistring;
  1072. begin
  1073. s := NextToken();
  1074. if (s = '') or (s[1] = '#') then
  1075. exit;
  1076. locCP := StrToInt('$'+s);
  1077. s := NextToken();
  1078. if (s = ';') then begin
  1079. locData.CodePoint.LineType := 0;
  1080. locData.CodePoint.CodePoint := locCP;
  1081. end else begin
  1082. if (s = '') or (s <> '.') or (NextToken() <> '.') then
  1083. raise Exception.CreateFmt('Invalid line : "%s".',[Copy(line,1,lineLength)]);
  1084. locData.CodePoint.LineType := 1;
  1085. locData.CodePoint.StartCodePoint := locCP;
  1086. locData.CodePoint.EndCodePoint := StrToInt('$'+NextToken());
  1087. s := NextToken();
  1088. if (s <> ';') then
  1089. raise Exception.CreateFmt('"." expected but "%s" found.',[s]);
  1090. end;
  1091. locData.PropName := Trim(NextToken());
  1092. if (Length(APropList) <= actualDataLen) then
  1093. SetLength(APropList,Length(APropList)*2);
  1094. APropList[actualDataLen] := locData;
  1095. Inc(actualDataLen);
  1096. end;
  1097. procedure Prepare();
  1098. begin
  1099. SetLength(APropList,DATA_LENGTH);
  1100. actualDataLen := 0;
  1101. bufferLength := ADataAStream.Size;
  1102. bufferPos := 0;
  1103. p := ADataAStream.Memory;
  1104. lineLength := 0;
  1105. SetLength(line,LINE_LENGTH);
  1106. end;
  1107. begin
  1108. Prepare();
  1109. while NextLine() do
  1110. ParseLine();
  1111. SetLength(APropList,actualDataLen);
  1112. end;
  1113. function FindCodePointsByProperty(
  1114. const APropName : string;
  1115. const APropList : TPropListLineRecArray
  1116. ) : TCodePointRecArray;
  1117. var
  1118. r : TCodePointRecArray;
  1119. i, k : Integer;
  1120. s : string;
  1121. begin
  1122. k := 0;
  1123. r := nil;
  1124. s := LowerCase(Trim(APropName));
  1125. for i := Low(APropList) to High(APropList) do begin
  1126. if (LowerCase(APropList[i].PropName) = s) then begin
  1127. if (k >= Length(r)) then begin
  1128. if (k = 0) then
  1129. SetLength(r,24)
  1130. else
  1131. SetLength(r,(2*Length(r)));
  1132. end;
  1133. r[k] := APropList[i].CodePoint;
  1134. Inc(k);
  1135. end;
  1136. end;
  1137. SetLength(r,k);
  1138. Result := r;
  1139. end;
  1140. procedure ParseHangulSyllableTypes(
  1141. ADataAStream : TMemoryStream;
  1142. var ACodePointList : TCodePointRecArray
  1143. );
  1144. const
  1145. LINE_LENGTH = 1024;
  1146. DATA_LENGTH = 25000;
  1147. var
  1148. p : PAnsiChar;
  1149. actualDataLen : Integer;
  1150. bufferLength, bufferPos, lineLength, linePos : Integer;
  1151. line : ansistring;
  1152. function NextLine() : Boolean;
  1153. var
  1154. locOldPos : Integer;
  1155. locOldPointer : PAnsiChar;
  1156. begin
  1157. Result := False;
  1158. locOldPointer := p;
  1159. locOldPos := bufferPos;
  1160. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1161. Inc(p);
  1162. Inc(bufferPos);
  1163. end;
  1164. if (locOldPos = bufferPos) and (p^ = #10) then begin
  1165. lineLength := 0;
  1166. Inc(p);
  1167. Inc(bufferPos);
  1168. linePos := 1;
  1169. Result := True;
  1170. end else if (locOldPos < bufferPos) then begin
  1171. lineLength := (bufferPos - locOldPos);
  1172. Move(locOldPointer^,line[1],lineLength);
  1173. if (p^ = #10) then begin
  1174. Dec(lineLength);
  1175. Inc(p);
  1176. Inc(bufferPos);
  1177. end;
  1178. linePos := 1;
  1179. Result := True;
  1180. end;
  1181. end;
  1182. function NextToken() : ansistring;
  1183. var
  1184. k : Integer;
  1185. begin
  1186. k := linePos;
  1187. if (linePos < lineLength) and (line[linePos] = '.') then begin
  1188. Inc(linePos);
  1189. while (linePos < lineLength) and (line[linePos] = '.') do begin
  1190. Inc(linePos);
  1191. end;
  1192. Result := Copy(line,k,(linePos-k));
  1193. exit;
  1194. end;
  1195. while (linePos < lineLength) and not(line[linePos] in [';','#','.']) do
  1196. Inc(linePos);
  1197. if (linePos > k) then begin
  1198. if (line[linePos] in [';','#','.']) then
  1199. Result := Copy(line,k,(linePos-k))
  1200. else
  1201. Result := Copy(line,k,(linePos-k+1));
  1202. Result := Trim(Result);
  1203. end else begin
  1204. Result := '';
  1205. end;
  1206. //Inc(linePos);
  1207. end;
  1208. procedure ParseLine();
  1209. var
  1210. locData : TCodePointRec;
  1211. s : ansistring;
  1212. begin
  1213. s := NextToken();
  1214. if (s = '') or (s[1] = '#') then
  1215. exit;
  1216. locData.CodePoint := StrToInt('$'+s);
  1217. s := NextToken();
  1218. if (s = '') or (s[1] in [';','#']) then begin
  1219. locData.LineType := 0;
  1220. end else begin
  1221. if (s <> '..') then
  1222. raise Exception.CreateFmt('Unknown line type : "%s"',[Copy(line,1,lineLength)]);
  1223. locData.StartCodePoint := locData.CodePoint;
  1224. locData.EndCodePoint := StrToInt('$'+NextToken());
  1225. locData.LineType := 1;
  1226. end;
  1227. if (Length(ACodePointList) <= actualDataLen) then
  1228. SetLength(ACodePointList,Length(ACodePointList)*2);
  1229. ACodePointList[actualDataLen] := locData;
  1230. Inc(actualDataLen);
  1231. end;
  1232. procedure Prepare();
  1233. begin
  1234. SetLength(ACodePointList,DATA_LENGTH);
  1235. actualDataLen := 0;
  1236. bufferLength := ADataAStream.Size;
  1237. bufferPos := 0;
  1238. p := ADataAStream.Memory;
  1239. lineLength := 0;
  1240. SetLength(line,LINE_LENGTH);
  1241. end;
  1242. begin
  1243. Prepare();
  1244. while NextLine() do
  1245. ParseLine();
  1246. SetLength(ACodePointList,actualDataLen);
  1247. end;
  1248. function IsHangulSyllable(
  1249. const ACodePoint : TUnicodeCodePoint;
  1250. const AHangulList : TCodePointRecArray
  1251. ) : Boolean;
  1252. var
  1253. i : Integer;
  1254. p : ^TCodePointRec;
  1255. begin
  1256. Result := False;
  1257. p := @AHangulList[Low(AHangulList)];
  1258. for i := Low(AHangulList) to High(AHangulList) do begin
  1259. if ( (p^.LineType = 0) and (ACodePoint = p^.CodePoint) ) or
  1260. ( (p^.LineType = 1) and (ACodePoint >= p^.StartCodePoint) and (ACodePoint <= p^.EndCodePoint) )
  1261. then begin
  1262. Result := True;
  1263. Break;
  1264. end;
  1265. Inc(p);
  1266. end;
  1267. end;
  1268. function IndexOf(
  1269. const AProp : TPropRec;
  1270. const APropList : TPropRecArray;
  1271. const AActualLen : Integer
  1272. ) : Integer;overload;
  1273. var
  1274. i : Integer;
  1275. p : PPropRec;
  1276. begin
  1277. Result := -1;
  1278. if (AActualLen > 0) then begin
  1279. p := @APropList[0];
  1280. for i := 0 to AActualLen - 1 do begin
  1281. if (AProp.Category = p^.Category) and
  1282. (AProp.CCC = p^.CCC) and
  1283. (AProp.NumericIndex = p^.NumericIndex) and
  1284. (AProp.SimpleUpperCase = p^.SimpleUpperCase) and
  1285. (AProp.SimpleLowerCase = p^.SimpleLowerCase) and
  1286. (AProp.WhiteSpace = p^.WhiteSpace) and
  1287. //
  1288. (AProp.DecompositionID = p^.DecompositionID) and
  1289. (* ( (AProp.DecompositionID = -1 ) and (p^.DecompositionID = -1) ) or
  1290. ( (AProp.DecompositionID <> -1 ) and (p^.DecompositionID <> -1) )
  1291. *)
  1292. (AProp.HangulSyllable = p^.HangulSyllable)
  1293. then begin
  1294. Result := i;
  1295. Break;
  1296. end;
  1297. Inc(p);
  1298. end;
  1299. end;
  1300. end;
  1301. function IndexOf(
  1302. const AItem : TUnicodeCodePointArray;
  1303. const AList : TDecompositionArray
  1304. ) : Integer;overload;
  1305. var
  1306. p : TUnicodeCodePointArray;
  1307. i : Integer;
  1308. begin
  1309. Result := -1;
  1310. if (Length(AList) = 0) then
  1311. exit;
  1312. for i := Low(AList) to High(AList) do begin
  1313. p := AList[i];
  1314. if (Length(p) = Length(AItem)) then begin
  1315. if CompareMem(@p[0],@AItem[0],Length(AItem)*SizeOf(TUnicodeCodePoint)) then
  1316. exit(i);
  1317. end;
  1318. end;
  1319. Result := -1;
  1320. end;
  1321. function IndexOf(
  1322. const AItem : TNumericValue;
  1323. const AList : TNumericValueArray;
  1324. const AActualLen : Integer
  1325. ) : Integer;overload;
  1326. var
  1327. p : ^TNumericValue;
  1328. i : Integer;
  1329. begin
  1330. Result := -1;
  1331. if (AActualLen = 0) then
  1332. exit;
  1333. p := @AList[Low(AList)];
  1334. for i := Low(AList) to AActualLen - 1 do begin
  1335. if (AItem = p^) then
  1336. exit(i);
  1337. Inc(p);
  1338. end;
  1339. Result := -1;
  1340. end;
  1341. procedure Parse_UnicodeData(
  1342. ADataAStream : TMemoryStream;
  1343. var APropList : TPropRecArray;
  1344. var ANumericTable : TNumericValueArray;
  1345. var ADataLineList : TDataLineRecArray;
  1346. var ADecomposition : TDecompositionArray;
  1347. const AHangulList : TCodePointRecArray;
  1348. const AWhiteSpaces : TCodePointRecArray
  1349. );
  1350. const
  1351. LINE_LENGTH = 1024;
  1352. PROP_LENGTH = 5000;
  1353. DATA_LENGTH = 25000;
  1354. var
  1355. p : PAnsiChar;
  1356. bufferLength, bufferPos : Integer;
  1357. actualPropLen, actualDataLen, actualNumLen : Integer;
  1358. line : ansistring;
  1359. lineLength, linePos : Integer;
  1360. function NextLine() : Boolean;
  1361. var
  1362. locOldPos : Integer;
  1363. locOldPointer : PAnsiChar;
  1364. begin
  1365. Result := False;
  1366. locOldPointer := p;
  1367. locOldPos := bufferPos;
  1368. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  1369. Inc(p);
  1370. Inc(bufferPos);
  1371. end;
  1372. if (locOldPos < bufferPos) then begin
  1373. lineLength := (bufferPos - locOldPos);
  1374. Move(locOldPointer^,line[1],lineLength);
  1375. if (p^ = #10) then begin
  1376. Dec(lineLength);
  1377. Inc(p);
  1378. Inc(bufferPos);
  1379. end;
  1380. if (lineLength > 7) then begin
  1381. linePos := 1;
  1382. Result := True;
  1383. end;
  1384. end;
  1385. end;
  1386. function NextToken() : ansistring;
  1387. var
  1388. k : Integer;
  1389. begin
  1390. k := linePos;
  1391. while (linePos < lineLength) and not(line[linePos] in [';','#']) do
  1392. Inc(linePos);
  1393. if (linePos > k) then begin
  1394. if (line[linePos] in [';','#']) then
  1395. Result := Copy(line,k,(linePos-k))
  1396. else
  1397. Result := Copy(line,k,(linePos-k+1));
  1398. Result := Trim(Result);
  1399. end else begin
  1400. Result := '';
  1401. end;
  1402. Inc(linePos);
  1403. end;
  1404. function ParseCanonicalDecomposition(AStr : ansistring) : TUnicodeCodePointArray;
  1405. var
  1406. locStr, ks : ansistring;
  1407. k0,k : Integer;
  1408. begin
  1409. SetLength(Result,0);
  1410. locStr := UpperCase(Trim(AStr));
  1411. if (locStr = '') or (locStr[1] = '<') then
  1412. exit;
  1413. k0 := 1;
  1414. k := 1;
  1415. while (k <= Length(locStr)) do begin
  1416. while (k <= Length(locStr)) and (locStr[k] in ['0'..'9','A'..'F']) do
  1417. inc(k);
  1418. ks := Trim(Copy(locStr,k0,k-k0));
  1419. SetLength(Result,Length(Result)+1);
  1420. Result[Length(Result)-1] := StringToCodePoint(ks);
  1421. Inc(k);
  1422. k0 := k;
  1423. end;
  1424. end;
  1425. procedure ParseLine();
  1426. var
  1427. locCP : TUnicodeCodePoint;
  1428. locProp : TPropRec;
  1429. locData : TDataLineRec;
  1430. s : ansistring;
  1431. locRangeStart, locRangeEnd : Boolean;
  1432. k : Integer;
  1433. locDecompItem : TUnicodeCodePointArray;
  1434. numVal : TNumericValue;
  1435. begin
  1436. FillChar(locData,SizeOf(locData),#0);
  1437. FillChar(locProp,SizeOf(locProp),#0);
  1438. locCP := StrToInt('$'+NextToken());
  1439. s := NextToken();
  1440. locRangeStart := AnsiEndsText(', First>',s);
  1441. if locRangeStart then
  1442. locRangeEnd := False
  1443. else
  1444. locRangeEnd := AnsiEndsText(', Last>',s);
  1445. if locRangeStart then begin
  1446. locData.LineType := 1;
  1447. locData.StartCodePoint := locCP;
  1448. end else if locRangeEnd then begin
  1449. ADataLineList[actualDataLen - 1].EndCodePoint := locCP;
  1450. exit;
  1451. //locData.EndCodePoint := locCP;
  1452. end else begin
  1453. locData.LineType := 0;
  1454. locData.CodePoint := locCP;
  1455. end;
  1456. locProp.Category := StrToCategory(NextToken());
  1457. locProp.CCC := StrToInt(NextToken());//Canonical_Combining_Class
  1458. NextToken();//Bidi_Class
  1459. s := NextToken();//Decomposition_Type
  1460. locDecompItem := ParseCanonicalDecomposition(s);
  1461. if (Length(locDecompItem) = 0) then
  1462. locProp.DecompositionID := -1
  1463. else begin
  1464. locProp.DecompositionID := IndexOf(locDecompItem,ADecomposition);
  1465. if (locProp.DecompositionID = -1) then begin
  1466. k := Length(ADecomposition);
  1467. locProp.DecompositionID := k;
  1468. SetLength(ADecomposition,k+1);
  1469. ADecomposition[k] := locDecompItem;
  1470. end;
  1471. end;
  1472. numVal := EvaluateFloat(NextToken());
  1473. if (numVal <> Double(0.0)) then begin
  1474. NextToken();
  1475. NextToken();
  1476. end else begin
  1477. s := NextToken();
  1478. if (s <> '') then
  1479. numVal := EvaluateFloat(s);
  1480. s := NextToken();
  1481. if (numVal = Double(0.0)) then
  1482. numVal := EvaluateFloat(s);
  1483. end;
  1484. k := IndexOf(numVal,ANumericTable,actualNumLen);
  1485. if (k = -1) then begin
  1486. if (actualNumLen >= Length(ANumericTable)) then
  1487. SetLength(ANumericTable,(actualNumLen*2));
  1488. ANumericTable[actualNumLen] := numVal;
  1489. k := actualNumLen;
  1490. Inc(actualNumLen);
  1491. end;
  1492. locProp.NumericIndex := k;
  1493. NextToken();//Bidi_Mirroed
  1494. NextToken();//Unicode_l_Name
  1495. NextToken();//ISO_Comment
  1496. locProp.SimpleUpperCase := StringToCodePoint(NextToken());
  1497. locProp.SimpleLowerCase := StringToCodePoint(NextToken());
  1498. NextToken();//Simple_Title_Case_Mapping
  1499. locProp.WhiteSpace := IsWhiteSpace(locCP,AWhiteSpaces);
  1500. locProp.HangulSyllable := IsHangulSyllable(locCP,AHangulList);
  1501. k := IndexOf(locProp,APropList,actualPropLen);
  1502. if (k = -1) then begin
  1503. k := actualPropLen;
  1504. locProp.PropID := k{ + 1};
  1505. APropList[k] := locProp;
  1506. Inc(actualPropLen);
  1507. end;
  1508. locData.PropID := k;
  1509. ADataLineList[actualDataLen] := locData;
  1510. Inc(actualDataLen);
  1511. end;
  1512. procedure Prepare();
  1513. var
  1514. r : TPropRec;
  1515. begin
  1516. SetLength(APropList,PROP_LENGTH);
  1517. actualPropLen := 0;
  1518. SetLength(ADataLineList,DATA_LENGTH);
  1519. actualDataLen := 0;
  1520. bufferLength := ADataAStream.Size;
  1521. bufferPos := 0;
  1522. p := ADataAStream.Memory;
  1523. lineLength := 0;
  1524. SetLength(line,LINE_LENGTH);
  1525. SetLength(ANumericTable,500);
  1526. actualNumLen := 0;
  1527. FillChar(r,SizeOf(r),#0);
  1528. r.PropID := 0;
  1529. r.Category := ucUnassigned;
  1530. r.DecompositionID := -1;
  1531. r.NumericIndex := 0;
  1532. APropList[0] := r;
  1533. Inc(actualPropLen);
  1534. ANumericTable[0] := 0;
  1535. Inc(actualNumLen);
  1536. end;
  1537. begin
  1538. Prepare();
  1539. while NextLine() do
  1540. ParseLine();
  1541. SetLength(APropList,actualPropLen);
  1542. SetLength(ADataLineList,actualDataLen);
  1543. SetLength(ANumericTable,actualNumLen);
  1544. end;
  1545. function GetPropID(
  1546. ACodePoint : TUnicodeCodePoint;
  1547. const ADataLineList : TDataLineRecArray
  1548. ) : Cardinal;
  1549. var
  1550. i : Integer;
  1551. p : PDataLineRec;
  1552. begin
  1553. Result := 0;
  1554. p := @ADataLineList[Low(ADataLineList)];
  1555. for i := Low(ADataLineList) to High(ADataLineList) do begin
  1556. if (p^.LineType = 0) then begin
  1557. if (p^.CodePoint = ACodePoint) then begin
  1558. Result := p^.PropID;
  1559. Break;
  1560. end;
  1561. end else begin
  1562. if (p^.StartCodePoint <= ACodePoint) and (p^.EndCodePoint >= ACodePoint) then begin
  1563. Result := p^.PropID;
  1564. Break;
  1565. end;
  1566. end;
  1567. Inc(p);
  1568. end;
  1569. end;
  1570. procedure MakeDecomposition(
  1571. const ARawData : TDecompositionArray;
  1572. var ABook : TDecompositionBook
  1573. );
  1574. var
  1575. i, c, locPos : Integer;
  1576. locItem : TUnicodeCodePointArray;
  1577. begin
  1578. c := 0;
  1579. for i := Low(ARawData) to High(ARawData) do
  1580. c := c + Length(ARawData[i]);
  1581. SetLength(ABook.CodePoints,c);
  1582. SetLength(ABook.Index,Length(ARawData));
  1583. locPos := 0;
  1584. for i := Low(ARawData) to High(ARawData) do begin
  1585. locItem := ARawData[i];
  1586. ABook.Index[i].StartPosition := locPos;
  1587. ABook.Index[i].Length := Length(locItem);
  1588. Move(locItem[0],ABook.CodePoints[locPos],(Length(locItem) * SizeOf(TUnicodeCodePoint)));
  1589. locPos := locPos + Length(locItem);
  1590. end;
  1591. end;
  1592. type
  1593. PBmpSecondTableItem = ^TBmpSecondTableItem;
  1594. function IndexOf(
  1595. const AItem : PBmpSecondTableItem;
  1596. const ATable : TBmpSecondTable;
  1597. const ATableActualLength : Integer
  1598. ) : Integer;overload;
  1599. var
  1600. i : Integer;
  1601. p : PBmpSecondTableItem;
  1602. begin
  1603. Result := -1;
  1604. if (ATableActualLength > 0) then begin
  1605. p := @ATable[0];
  1606. for i := 0 to ATableActualLength - 1 do begin
  1607. if CompareMem(p,AItem,SizeOf(TBmpSecondTableItem)) then begin
  1608. Result := i;
  1609. Break;
  1610. end;
  1611. Inc(p);
  1612. end;
  1613. end;
  1614. end;
  1615. procedure MakeBmpTables(
  1616. var AFirstTable : TBmpFirstTable;
  1617. var ASecondTable : TBmpSecondTable;
  1618. const APropList : TPropRecArray;
  1619. const ADataLineList : TDataLineRecArray
  1620. );
  1621. var
  1622. locLowByte, locHighByte : Byte;
  1623. locTableItem : TBmpSecondTableItem;
  1624. locCP : TUnicodeCodePoint;
  1625. i, locSecondActualLen : Integer;
  1626. begin
  1627. SetLength(ASecondTable,120);
  1628. locSecondActualLen := 0;
  1629. for locHighByte := 0 to 255 do begin
  1630. FillChar(locTableItem,SizeOf(locTableItem),#0);
  1631. for locLowByte := 0 to 255 do begin
  1632. locCP := (locHighByte * 256) + locLowByte;
  1633. locTableItem[locLowByte] := GetPropID(locCP,ADataLineList)// - 1;
  1634. end;
  1635. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  1636. if (i = -1) then begin
  1637. if (locSecondActualLen = Length(ASecondTable)) then
  1638. SetLength(ASecondTable,locSecondActualLen + 50);
  1639. i := locSecondActualLen;
  1640. ASecondTable[i] := locTableItem;
  1641. Inc(locSecondActualLen);
  1642. end;
  1643. AFirstTable[locHighByte] := i;
  1644. end;
  1645. SetLength(ASecondTable,locSecondActualLen);
  1646. end;
  1647. type
  1648. P3lvlBmp3TableItem = ^T3lvlBmp3TableItem;
  1649. function IndexOf(
  1650. const AItem : P3lvlBmp3TableItem;
  1651. const ATable : T3lvlBmp3Table;
  1652. const ATableActualLength : Integer
  1653. ) : Integer;overload;
  1654. var
  1655. i : Integer;
  1656. p : P3lvlBmp3TableItem;
  1657. begin
  1658. Result := -1;
  1659. if (ATableActualLength > 0) then begin
  1660. p := @ATable[0];
  1661. for i := 0 to ATableActualLength - 1 do begin
  1662. if CompareMem(p,AItem,SizeOf(T3lvlBmp3TableItem)) then begin
  1663. Result := i;
  1664. Break;
  1665. end;
  1666. Inc(p);
  1667. end;
  1668. end;
  1669. end;
  1670. type
  1671. P3lvlBmp2TableItem = ^T3lvlBmp2TableItem;
  1672. function IndexOf(
  1673. const AItem : P3lvlBmp2TableItem;
  1674. const ATable : T3lvlBmp2Table
  1675. ) : Integer;overload;
  1676. var
  1677. i : Integer;
  1678. p : P3lvlBmp2TableItem;
  1679. begin
  1680. Result := -1;
  1681. if (Length(ATable) > 0) then begin
  1682. p := @ATable[0];
  1683. for i := 0 to Length(ATable) - 1 do begin
  1684. if CompareMem(p,AItem,SizeOf(T3lvlBmp2TableItem)) then begin
  1685. Result := i;
  1686. Break;
  1687. end;
  1688. Inc(p);
  1689. end;
  1690. end;
  1691. end;
  1692. procedure MakeBmpTables3Levels(
  1693. var AFirstTable : T3lvlBmp1Table;
  1694. var ASecondTable : T3lvlBmp2Table;
  1695. var AThirdTable : T3lvlBmp3Table;
  1696. const ADataLineList : TDataLineRecArray
  1697. );
  1698. var
  1699. locLowByte0, locLowByte1, locHighByte : Byte;
  1700. locTableItem2 : T3lvlBmp2TableItem;
  1701. locTableItem3 : T3lvlBmp3TableItem;
  1702. locCP : TUnicodeCodePoint;
  1703. i, locThirdActualLen : Integer;
  1704. begin
  1705. SetLength(AThirdTable,120);
  1706. locThirdActualLen := 0;
  1707. for locHighByte := 0 to 255 do begin
  1708. FillChar(locTableItem2,SizeOf(locTableItem2),#0);
  1709. for locLowByte0 := 0 to 15 do begin
  1710. FillChar(locTableItem3,SizeOf(locTableItem3),#0);
  1711. for locLowByte1 := 0 to 15 do begin
  1712. locCP := (locHighByte * 256) + (locLowByte0*16) + locLowByte1;
  1713. locTableItem3[locLowByte1] := GetPropID(locCP,ADataLineList);
  1714. end;
  1715. i := IndexOf(@locTableItem3,AThirdTable,locThirdActualLen);
  1716. if (i = -1) then begin
  1717. if (locThirdActualLen = Length(AThirdTable)) then
  1718. SetLength(AThirdTable,locThirdActualLen + 50);
  1719. i := locThirdActualLen;
  1720. AThirdTable[i] := locTableItem3;
  1721. Inc(locThirdActualLen);
  1722. end;
  1723. locTableItem2[locLowByte0] := i;
  1724. end;
  1725. i := IndexOf(@locTableItem2,ASecondTable);
  1726. if (i = -1) then begin
  1727. i := Length(ASecondTable);
  1728. SetLength(ASecondTable,(i + 1));
  1729. ASecondTable[i] := locTableItem2;
  1730. end;
  1731. AFirstTable[locHighByte] := i;
  1732. end;
  1733. SetLength(AThirdTable,locThirdActualLen);
  1734. end;
  1735. procedure GenerateLicenceText(ADest : TStream);
  1736. var
  1737. s : ansistring;
  1738. begin
  1739. s := SLicenseText + sLineBreak + sLineBreak;
  1740. ADest.Write(s[1],Length(s));
  1741. end;
  1742. procedure GenerateBmpTables(
  1743. ADest : TStream;
  1744. var AFirstTable : TBmpFirstTable;
  1745. var ASecondTable : TBmpSecondTable
  1746. );
  1747. procedure AddLine(const ALine : ansistring);
  1748. var
  1749. buffer : ansistring;
  1750. begin
  1751. buffer := ALine + sLineBreak;
  1752. ADest.Write(buffer[1],Length(buffer));
  1753. end;
  1754. var
  1755. i, j, c : Integer;
  1756. locLine : string;
  1757. begin
  1758. AddLine('const');
  1759. AddLine(' UC_TABLE_1 : array[0..255] of Byte = (');
  1760. locLine := '';
  1761. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  1762. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  1763. if (((i+1) mod 16) = 0) then begin
  1764. locLine := ' ' + locLine;
  1765. AddLine(locLine);
  1766. locLine := '';
  1767. end;
  1768. end;
  1769. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  1770. locLine := ' ' + locLine;
  1771. AddLine(locLine);
  1772. AddLine(' );' + sLineBreak);
  1773. AddLine(' UC_TABLE_2 : array[0..(256*' + IntToStr(Length(ASecondTable)) +'-1)] of Word =(');
  1774. c := High(ASecondTable);
  1775. for i := Low(ASecondTable) to c do begin
  1776. locLine := '';
  1777. for j := Low(TBmpSecondTableItem) to High(TBmpSecondTableItem) do begin
  1778. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  1779. if (((j+1) mod 16) = 0) then begin
  1780. if (i = c) and (j = 255) then
  1781. Delete(locLine,Length(locLine),1);
  1782. locLine := ' ' + locLine;
  1783. AddLine(locLine);
  1784. locLine := '';
  1785. end;
  1786. end;
  1787. end;
  1788. AddLine(' );' + sLineBreak);
  1789. end;
  1790. //----------------------------------
  1791. procedure Generate3lvlBmpTables(
  1792. ADest : TStream;
  1793. var AFirstTable : T3lvlBmp1Table;
  1794. var ASecondTable : T3lvlBmp2Table;
  1795. var AThirdTable : T3lvlBmp3Table
  1796. );
  1797. procedure AddLine(const ALine : ansistring);
  1798. var
  1799. buffer : ansistring;
  1800. begin
  1801. buffer := ALine + sLineBreak;
  1802. ADest.Write(buffer[1],Length(buffer));
  1803. end;
  1804. var
  1805. i, j, c : Integer;
  1806. locLine : string;
  1807. begin
  1808. AddLine('const');
  1809. AddLine(' UC_TABLE_1 : array[0..255] of Byte = (');
  1810. locLine := '';
  1811. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  1812. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  1813. if (((i+1) mod 16) = 0) then begin
  1814. locLine := ' ' + locLine;
  1815. AddLine(locLine);
  1816. locLine := '';
  1817. end;
  1818. end;
  1819. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  1820. locLine := ' ' + locLine;
  1821. AddLine(locLine);
  1822. AddLine(' );' + sLineBreak);
  1823. AddLine(' UC_TABLE_2 : array[0..' + IntToStr(Length(ASecondTable)-1) +'] of array[0..15] of Word = (');
  1824. c := High(ASecondTable);
  1825. for i := Low(ASecondTable) to c do begin
  1826. locLine := '(';
  1827. for j := Low(T3lvlBmp2TableItem) to High(T3lvlBmp2TableItem) do
  1828. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  1829. Delete(locLine,Length(locLine),1);
  1830. locLine := ' ' + locLine + ')';
  1831. if (i < c) then
  1832. locLine := locLine + ',';
  1833. AddLine(locLine);
  1834. end;
  1835. AddLine(' );' + sLineBreak);
  1836. AddLine(' UC_TABLE_3 : array[0..' + IntToStr(Length(AThirdTable)-1) +'] of array[0..15] of Word = (');
  1837. c := High(AThirdTable);
  1838. for i := Low(AThirdTable) to c do begin
  1839. locLine := '(';
  1840. for j := Low(T3lvlBmp3TableItem) to High(T3lvlBmp3TableItem) do
  1841. locLine := locLine + IntToStr(AThirdTable[i][j]) + ',';
  1842. Delete(locLine,Length(locLine),1);
  1843. locLine := ' ' + locLine + ')';
  1844. if (i < c) then
  1845. locLine := locLine + ',';
  1846. AddLine(locLine);
  1847. end;
  1848. AddLine(' );' + sLineBreak);
  1849. end;
  1850. function UInt24ToStr(const AValue : UInt24; const AEndian : TEndianKind): string;inline;
  1851. begin
  1852. if (AEndian = ekBig) then
  1853. Result := Format(
  1854. '(byte2 : $%s; byte1 : $%s; byte0 : $%s;)',
  1855. [ IntToHex(AValue.byte2,2), IntToHex(AValue.byte1,2),
  1856. IntToHex(AValue.byte0,2)
  1857. ]
  1858. )
  1859. else
  1860. Result := Format(
  1861. '(byte0 : $%s; byte1 : $%s; byte2 : $%s;)',
  1862. [ IntToHex(AValue.byte0,2), IntToHex(AValue.byte1,2),
  1863. IntToHex(AValue.byte2,2)
  1864. ]
  1865. );
  1866. end;
  1867. procedure GeneratePropTable(
  1868. ADest : TStream;
  1869. const APropList : TPropRecArray;
  1870. const AEndian : TEndianKind
  1871. );
  1872. procedure AddLine(const ALine : ansistring);
  1873. var
  1874. buffer : ansistring;
  1875. begin
  1876. buffer := ALine + sLineBreak;
  1877. ADest.Write(buffer[1],Length(buffer));
  1878. end;
  1879. var
  1880. i : Integer;
  1881. locLine : string;
  1882. p : PPropRec;
  1883. begin
  1884. AddLine('');
  1885. AddLine('const');
  1886. AddLine(' UC_PROP_REC_COUNT = ' + IntToStr(Length(APropList)) + ';');
  1887. AddLine(' UC_PROP_ARRAY : array[0..(UC_PROP_REC_COUNT-1)] of TUC_Prop = (');
  1888. p := @APropList[0];
  1889. for i := Low(APropList) to High(APropList) - 1 do begin
  1890. locLine := //' (Category : TUnicodeCategory.' + GetEnumName(pti,Ord(p^.Category)) + ';' +
  1891. ' (CategoryData : ' + IntToStr(p^.CategoryData) + ';' +
  1892. ' CCC : ' + IntToStr(p^.CCC) + ';' +
  1893. ' NumericIndex : ' + IntToStr(p^.NumericIndex) + ';' +
  1894. ' SimpleUpperCase : ' + UInt24ToStr(p^.SimpleUpperCase,AEndian) + ';' +
  1895. ' SimpleLowerCase : ' + UInt24ToStr(p^.SimpleLowerCase,AEndian) + ';' +
  1896. ' DecompositionID : ' + IntToStr(p^.DecompositionID) + '),';
  1897. AddLine(locLine);
  1898. Inc(p);
  1899. end;
  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. AddLine(' );' + sLineBreak);
  1909. end;
  1910. procedure GenerateNumericTable(
  1911. ADest : TStream;
  1912. const ANumList : TNumericValueArray;
  1913. const ACompleteUnit : Boolean
  1914. );
  1915. procedure AddLine(const ALine : ansistring);
  1916. var
  1917. buffer : ansistring;
  1918. begin
  1919. buffer := ALine + sLineBreak;
  1920. ADest.Write(buffer[1],Length(buffer));
  1921. end;
  1922. var
  1923. i : Integer;
  1924. locLine : string;
  1925. p : ^TNumericValue;
  1926. begin
  1927. if ACompleteUnit then begin
  1928. GenerateLicenceText(ADest);
  1929. AddLine('unit unicodenumtable;');
  1930. AddLine('interface');
  1931. AddLine('');
  1932. end;
  1933. AddLine('');
  1934. AddLine('const');
  1935. AddLine(' UC_NUMERIC_COUNT = ' + IntToStr(Length(ANumList)) + ';');
  1936. AddLine(' UC_NUMERIC_ARRAY : array[0..(UC_NUMERIC_COUNT-1)] of Double = (');
  1937. locLine := '';
  1938. p := @ANumList[0];
  1939. for i := Low(ANumList) to High(ANumList) - 1 do begin
  1940. locLine := locLine + FloatToStr(p^,FS) + ' ,';
  1941. if (i > 0) and ((i mod 8) = 0) then begin
  1942. AddLine(' ' + locLine);
  1943. locLine := '';
  1944. end;
  1945. Inc(p);
  1946. end;
  1947. locLine := locLine + FloatToStr(p^,FS);
  1948. AddLine(' ' + locLine);
  1949. AddLine(' );' + sLineBreak);
  1950. if ACompleteUnit then begin
  1951. AddLine('');
  1952. AddLine('implementation');
  1953. AddLine('');
  1954. AddLine('end.');
  1955. end;
  1956. end;
  1957. procedure GenerateDecompositionBookTable(
  1958. ADest : TStream;
  1959. const ABook : TDecompositionBook;
  1960. const AEndian : TEndianKind
  1961. );
  1962. procedure AddLine(const ALine : ansistring);
  1963. var
  1964. buffer : ansistring;
  1965. begin
  1966. buffer := ALine + sLineBreak;
  1967. ADest.Write(buffer[1],Length(buffer));
  1968. end;
  1969. var
  1970. i, k : Integer;
  1971. p : ^TDecompositionIndexRec;
  1972. cp : ^TUnicodeCodePoint;
  1973. cp24 : UInt24;
  1974. locLine : string;
  1975. begin
  1976. AddLine('const');
  1977. AddLine(' UC_DEC_BOOK_INDEX_LENGTH = ' + IntToStr(Length(ABook.Index)) + ';');
  1978. AddLine(' UC_DEC_BOOK_DATA_LENGTH = ' + IntToStr(Length(ABook.CodePoints)) + ';');
  1979. AddLine('type');
  1980. AddLine(' TDecompositionIndexRec = packed record');
  1981. AddLine(' StartPosition : Word;');
  1982. AddLine(' Length : Byte;');
  1983. AddLine(' end;');
  1984. AddLine(' TDecompositionBookRec = packed record');
  1985. AddLine(' Index : array[0..(UC_DEC_BOOK_INDEX_LENGTH-1)] of TDecompositionIndexRec;');
  1986. AddLine(' CodePoints : array[0..(UC_DEC_BOOK_DATA_LENGTH-1)] of UInt24;');
  1987. AddLine(' end;');
  1988. AddLine('const');
  1989. AddLine(' UC_DEC_BOOK_DATA : TDecompositionBookRec = (');
  1990. p := @ABook.Index[0];
  1991. AddLine(' Index : (// Index BEGIN');
  1992. k := 0;
  1993. locLine := ' ';
  1994. for i := Low(ABook.Index) to High(ABook.Index) - 1 do begin
  1995. locLine := locLine + '(StartPosition : ' + IntToStr(p^.StartPosition) + ';' +
  1996. ' Length : ' + IntToStr(p^.Length) + '), ';
  1997. k := k + 1;
  1998. if (k >= 2) then begin
  1999. AddLine(locLine);
  2000. locLine := ' ';
  2001. k := 0;
  2002. end;
  2003. Inc(p);
  2004. end;
  2005. locLine := locLine + '(StartPosition : ' + IntToStr(p^.StartPosition) + ';' +
  2006. ' Length : ' + IntToStr(p^.Length) + ')';
  2007. AddLine(locLine);
  2008. AddLine(' ); // Index END');
  2009. cp := @ABook.CodePoints[0];
  2010. AddLine(' CodePoints : (// CodePoints BEGIN');
  2011. k := 0;
  2012. locLine := ' ';
  2013. for i := Low(ABook.CodePoints) to High(ABook.CodePoints) - 1 do begin
  2014. cp24 := cp^;
  2015. locLine := locLine + Format('%s,',[UInt24ToStr(cp24,AEndian)]);
  2016. Inc(k);
  2017. if (k >= 16) then begin
  2018. AddLine(locLine);
  2019. k := 0;
  2020. locLine := ' ';
  2021. end;
  2022. Inc(cp);
  2023. end;
  2024. cp24 := cp^;
  2025. locLine := locLine + Format('%s',[UInt24ToStr(cp24,AEndian)]);
  2026. AddLine(locLine);
  2027. AddLine(' ); // CodePoints END');
  2028. AddLine(' );' + sLineBreak);
  2029. end;
  2030. procedure GenerateOutBmpTable(
  2031. ADest : TStream;
  2032. const AList : TDataLineRecArray
  2033. );
  2034. procedure AddLine(const ALine : ansistring);
  2035. var
  2036. buffer : ansistring;
  2037. begin
  2038. buffer := ALine + sLineBreak;
  2039. ADest.Write(buffer[1],Length(buffer));
  2040. end;
  2041. var
  2042. i, j : Integer;
  2043. locLine : string;
  2044. p : PDataLineRec;
  2045. begin
  2046. AddLine('');
  2047. //AddLine(' UC_PROP_REC_COUNT = ' + IntToStr(Length(APropList)) + ';');
  2048. //AddLine(' UC_PROP_ARRAY : array[0..(UC_PROP_REC_COUNT-1)] of TUC_Prop = (');
  2049. j := -1;
  2050. p := @AList[0];
  2051. for i := 0 to Length(AList) - 1 do begin
  2052. if ((p^.LineType = 0) and (p^.CodePoint >$FFFF)) or
  2053. (p^.StartCodePoint > $FFFF)
  2054. then begin
  2055. j := i;
  2056. Break;
  2057. end;
  2058. Inc(p);
  2059. end;
  2060. if (j < 0) then
  2061. exit;
  2062. for i := j to Length(AList) - 2 do begin
  2063. locLine := ' (PropID : ' + IntToStr(p^.PropID) + ';' +
  2064. ' CodePoint : ' + IntToStr(p^.CodePoint) + ';' +
  2065. ' RangeEnd : ' + IntToStr(p^.EndCodePoint) + '),' ;
  2066. AddLine(locLine);
  2067. Inc(p);
  2068. end;
  2069. locLine := ' (PropID : ' + IntToStr(p^.PropID) + ';' +
  2070. ' CodePoint : ' + IntToStr(p^.CodePoint) + ';' +
  2071. ' RangeEnd : ' + IntToStr(p^.EndCodePoint) + ')' ;
  2072. AddLine(locLine);
  2073. AddLine(' );' + sLineBreak);
  2074. end;
  2075. function Compress(const AData : TDataLineRecArray) : TDataLineRecArray;
  2076. var
  2077. k, i, locResLen : Integer;
  2078. q, p, pr : PDataLineRec;
  2079. k_end : TUnicodeCodePoint;
  2080. begin
  2081. locResLen := 1;
  2082. SetLength(Result,Length(AData));
  2083. FillChar(Result[0],Length(Result),#0);
  2084. Result[0] := AData[0];
  2085. q := @AData[0];
  2086. k := 0;
  2087. while (k < Length(AData)) do begin
  2088. if (q^.LineType = 0) then
  2089. k_end := q^.CodePoint
  2090. else
  2091. k_end := q^.EndCodePoint;
  2092. if ((k+1) = Length(AData)) then begin
  2093. i := k;
  2094. end else begin
  2095. p := @AData[k+1];
  2096. i := k +1;
  2097. while (i < (Length(AData) {- 1})) do begin
  2098. if (p^.PropID <> q^.PropID) then begin
  2099. i := i - 1;
  2100. Break;
  2101. end;
  2102. if (p^.LineType = 0) then begin
  2103. if (p^.CodePoint <> (k_end + 1)) then begin
  2104. i := i - 1;
  2105. Break;
  2106. end;
  2107. Inc(k_end);
  2108. end else begin
  2109. if (p^.StartCodePoint <> (k_end + 1)) then begin
  2110. i := i - 1;
  2111. Break;
  2112. end;
  2113. k_end := p^.EndCodePoint;
  2114. end;
  2115. Inc(i);
  2116. Inc(p);
  2117. end;
  2118. end;
  2119. {if (i = k) then begin
  2120. Result[locResLen] := q^;
  2121. Inc(locResLen);
  2122. end else begin }
  2123. p := @AData[i];
  2124. pr := @Result[locResLen];
  2125. pr^.PropID := q^.PropID;
  2126. if (q^.LineType = 0) then
  2127. pr^.StartCodePoint := q^.CodePoint
  2128. else
  2129. pr^.StartCodePoint := q^.StartCodePoint;
  2130. pr^.LineType := 1;
  2131. if (p^.LineType = 0) then
  2132. pr^.EndCodePoint := p^.CodePoint
  2133. else
  2134. pr^.EndCodePoint := p^.EndCodePoint;
  2135. Inc(locResLen);
  2136. //end;
  2137. k := i + 1;
  2138. if (k = Length(AData)) then
  2139. Break;
  2140. q := @AData[k];
  2141. end;
  2142. SetLength(Result,locResLen);
  2143. end;
  2144. procedure ParseUCAFile(
  2145. ADataAStream : TMemoryStream;
  2146. var ABook : TUCA_DataBook
  2147. );
  2148. const
  2149. LINE_LENGTH = 1024;
  2150. DATA_LENGTH = 25000;
  2151. var
  2152. p : PAnsiChar;
  2153. actualDataLen : Integer;
  2154. bufferLength, bufferPos, lineLength, linePos : Integer;
  2155. line : ansistring;
  2156. function NextLine() : Boolean;
  2157. var
  2158. locOldPos : Integer;
  2159. locOldPointer : PAnsiChar;
  2160. begin
  2161. Result := False;
  2162. locOldPointer := p;
  2163. locOldPos := bufferPos;
  2164. while (bufferPos < bufferLength) and (p^ <> #10) do begin
  2165. Inc(p);
  2166. Inc(bufferPos);
  2167. end;
  2168. if (locOldPos = bufferPos) and (p^ = #10) then begin
  2169. lineLength := 0;
  2170. Inc(p);
  2171. Inc(bufferPos);
  2172. linePos := 1;
  2173. Result := True;
  2174. end else if (locOldPos < bufferPos) then begin
  2175. lineLength := (bufferPos - locOldPos) + 1;
  2176. Move(locOldPointer^,line[1],lineLength);
  2177. if (p^ = #10) then begin
  2178. Dec(lineLength);
  2179. Inc(p);
  2180. Inc(bufferPos);
  2181. end;
  2182. linePos := 1;
  2183. Result := True;
  2184. end;
  2185. end;
  2186. procedure SkipSpace();
  2187. begin
  2188. while (linePos < lineLength) and (line[linePos] in [' ',#9]) do
  2189. Inc(linePos);
  2190. end;
  2191. function NextToken() : ansistring;
  2192. const C_SEPARATORS = [';','#','.','[',']','*','@'];
  2193. var
  2194. k : Integer;
  2195. begin
  2196. SkipSpace();
  2197. k := linePos;
  2198. if (linePos <= lineLength) and (line[linePos] in C_SEPARATORS) then begin
  2199. Result := line[linePos];
  2200. Inc(linePos);
  2201. exit;
  2202. end;
  2203. while (linePos <= lineLength) and not(line[linePos] in (C_SEPARATORS+[' '])) do
  2204. Inc(linePos);
  2205. if (linePos > k) then begin
  2206. if (line[Min(linePos,lineLength)] in C_SEPARATORS) then
  2207. Result := Copy(line,k,(linePos-k))
  2208. else
  2209. Result := Copy(line,k,(linePos-k+1));
  2210. Result := Trim(Result);
  2211. end else begin
  2212. Result := '';
  2213. end;
  2214. end;
  2215. procedure CheckToken(const AToken : string);
  2216. var
  2217. a, b : string;
  2218. begin
  2219. a := LowerCase(Trim(AToken));
  2220. b := LowerCase(Trim(NextToken()));
  2221. if (a <> b) then
  2222. raise Exception.CreateFmt('Expected token "%s" but found "%s".',[a,b]);
  2223. end;
  2224. function ReadWeightBlock(var ADest : TUCA_WeightRec) : Boolean;
  2225. var
  2226. s :AnsiString;
  2227. k : Integer;
  2228. begin
  2229. Result := False;
  2230. s := NextToken();
  2231. if (s <> '[') then
  2232. exit;
  2233. s := NextToken();
  2234. if (s = '.') then
  2235. ADest.Variable := False
  2236. else begin
  2237. if (s <> '*') then
  2238. raise Exception.CreateFmt('Expected "%s" but found "%s".',['*',s]);
  2239. ADest.Variable := True;
  2240. end;
  2241. ADest.Weights[0] := StrToInt('$'+NextToken());
  2242. for k := 1 to 3 do begin
  2243. CheckToken('.');
  2244. ADest.Weights[k] := StrToInt('$'+NextToken());
  2245. end;
  2246. CheckToken(']');
  2247. Result := True;
  2248. end;
  2249. procedure ParseHeaderVar();
  2250. var
  2251. s,ss : string;
  2252. k : Integer;
  2253. begin
  2254. s := NextToken();
  2255. if (s = 'version') then begin
  2256. ss := '';
  2257. while True do begin
  2258. s := NextToken();
  2259. if (s = '') then
  2260. Break;
  2261. ss := ss + s;
  2262. end;
  2263. ABook.Version := ss;
  2264. end else if (s = 'variable') then begin
  2265. if (s = 'blanked') then
  2266. ABook.VariableWeight := ucaBlanked
  2267. else if (s = 'non-ignorable') then
  2268. ABook.VariableWeight := ucaNonIgnorable
  2269. else if (s = 'shifted') then
  2270. ABook.VariableWeight := ucaShifted
  2271. else if (s = 'shift-trimmed') then
  2272. ABook.VariableWeight := ucaShiftedTrimmed
  2273. else if (s = 'ignoresp') then
  2274. ABook.VariableWeight := ucaIgnoreSP
  2275. else
  2276. raise Exception.CreateFmt('Unknown "@variable" type : "%s".',[s]);
  2277. end else if (s = 'backwards') or (s = 'forwards') then begin
  2278. ss := s;
  2279. s := NextToken();
  2280. k := StrToInt(s);
  2281. if (k < 1) or (k > 4) then
  2282. raise Exception.CreateFmt('Invalid "%s" position : %d.',[ss,s]);
  2283. ABook.Backwards[k] := (s = 'backwards');
  2284. end;
  2285. end;
  2286. procedure ParseLine();
  2287. var
  2288. locData : ^TUCA_LineRec;
  2289. s : ansistring;
  2290. kc : Integer;
  2291. begin
  2292. if (Length(ABook.Lines) <= actualDataLen) then
  2293. SetLength(ABook.Lines,Length(ABook.Lines)*2);
  2294. locData := @ABook.Lines[actualDataLen];
  2295. s := NextToken();
  2296. if (s = '') or (s[1] = '#') then
  2297. exit;
  2298. if (s[1] = '@') then begin
  2299. ParseHeaderVar();
  2300. exit;
  2301. end;
  2302. SetLength(locData^.CodePoints,10);
  2303. locData^.CodePoints[0] := StrToInt('$'+s);
  2304. kc := 1;
  2305. while True do begin
  2306. s := Trim(NextToken());
  2307. if (s = '') then
  2308. exit;
  2309. if (s = ';') then
  2310. Break;
  2311. locData^.CodePoints[kc] := StrToInt('$'+s);
  2312. Inc(kc);
  2313. end;
  2314. if (kc = 0) then
  2315. exit;
  2316. SetLength(locData^.CodePoints,kc);
  2317. SetLength(locData^.Weights,24);
  2318. kc := 0;
  2319. while ReadWeightBlock(locData^.Weights[kc]) do begin
  2320. Inc(kc);
  2321. end;
  2322. SetLength(locData^.Weights,kc);
  2323. Inc(actualDataLen);
  2324. end;
  2325. procedure Prepare();
  2326. var
  2327. k : Integer;
  2328. begin
  2329. ABook.VariableWeight := ucaShifted;
  2330. for k := Low(ABook.Backwards) to High(ABook.Backwards) do
  2331. ABook.Backwards[k] := False;
  2332. SetLength(ABook.Lines,DATA_LENGTH);
  2333. actualDataLen := 0;
  2334. bufferLength := ADataAStream.Size;
  2335. bufferPos := 0;
  2336. p := ADataAStream.Memory;
  2337. lineLength := 0;
  2338. SetLength(line,LINE_LENGTH);
  2339. end;
  2340. begin
  2341. Prepare();
  2342. while NextLine() do
  2343. ParseLine();
  2344. SetLength(ABook.Lines,actualDataLen);
  2345. end;
  2346. procedure Dump(X : array of TUnicodeCodePoint; const ATitle : string = '');
  2347. var
  2348. i : Integer;
  2349. begin
  2350. Write(ATitle, ' ');
  2351. for i := 0 to Length(X) - 1 do
  2352. Write(X[i],' ');
  2353. WriteLn();
  2354. end;
  2355. function IsGreaterThan(A, B : PUCA_LineRec) : Integer;
  2356. var
  2357. i, hb : Integer;
  2358. begin
  2359. if (A=B) then
  2360. exit(0);
  2361. Result := 1;
  2362. hb := Length(B^.CodePoints) - 1;
  2363. for i := 0 to Length(A^.CodePoints) - 1 do begin
  2364. if (i > hb) then
  2365. exit;
  2366. if (A^.CodePoints[i] < B^.CodePoints[i]) then
  2367. exit(-1);
  2368. if (A^.CodePoints[i] > B^.CodePoints[i]) then
  2369. exit(1);
  2370. end;
  2371. if (Length(A^.CodePoints) = Length(B^.CodePoints)) then
  2372. exit(0);
  2373. exit(-1);
  2374. end;
  2375. Procedure QuickSort(var AList: TUCA_DataBookIndex; L, R : Longint;
  2376. ABook : PUCA_DataBook);
  2377. var
  2378. I, J : Longint;
  2379. P, Q : Integer;
  2380. begin
  2381. repeat
  2382. I := L;
  2383. J := R;
  2384. P := AList[ (L + R) div 2 ];
  2385. repeat
  2386. while IsGreaterThan(@ABook^.Lines[P], @ABook^.Lines[AList[i]]) > 0 do
  2387. I := I + 1;
  2388. while IsGreaterThan(@ABook^.Lines[P], @ABook^.Lines[AList[J]]) < 0 do
  2389. J := J - 1;
  2390. If I <= J then
  2391. begin
  2392. Q := AList[I];
  2393. AList[I] := AList[J];
  2394. AList[J] := Q;
  2395. I := I + 1;
  2396. J := J - 1;
  2397. end;
  2398. until I > J;
  2399. // sort the smaller range recursively
  2400. // sort the bigger range via the loop
  2401. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  2402. if J - L < R - I then
  2403. begin
  2404. if L < J then
  2405. QuickSort(AList, L, J, ABook);
  2406. L := I;
  2407. end
  2408. else
  2409. begin
  2410. if I < R then
  2411. QuickSort(AList, I, R, ABook);
  2412. R := J;
  2413. end;
  2414. until L >= R;
  2415. end;
  2416. function CreateIndex(ABook : PUCA_DataBook) : TUCA_DataBookIndex;
  2417. var
  2418. r : TUCA_DataBookIndex;
  2419. i, c : Integer;
  2420. begin
  2421. c := Length(ABook^.Lines);
  2422. SetLength(r,c);
  2423. for i := 0 to c - 1 do
  2424. r[i] := i;
  2425. QuickSort(r,0,c-1,ABook);
  2426. Result := r;
  2427. end;
  2428. function ConstructContextTree(
  2429. const AContext : PUCA_LineContextRec;
  2430. var ADestBuffer;
  2431. const ADestBufferLength : Integer
  2432. ) : PUCA_PropItemContextTreeRec;forward;
  2433. function ConstructItem(
  2434. AItem : PUCA_PropItemRec;
  2435. ACodePoint : Cardinal;
  2436. AValid : Byte;
  2437. AChildCount : Byte;
  2438. const AWeights : array of TUCA_WeightRec;
  2439. const AStoreCP : Boolean;
  2440. const AContext : PUCA_LineContextRec;
  2441. const ADeleted : Boolean
  2442. ) : Integer;
  2443. var
  2444. i, c : Integer;
  2445. p : PUCA_PropItemRec;
  2446. pw : PUCA_PropWeights;
  2447. pb : PByte;
  2448. hasContext : Boolean;
  2449. contextTree : PUCA_PropItemContextTreeRec;
  2450. begin
  2451. p := AItem;
  2452. {if AStoreCP then begin
  2453. PUInt24(p)^ := ACodePoint;
  2454. p := PUCA_PropItemRec(PtrUInt(p) + SizeOf(UInt24));
  2455. end; }
  2456. p^.Flags := 0;
  2457. p^.Valid := 0;
  2458. SetBit(p^.Valid,BIT_POS_VALIDE,(AValid <> 0));
  2459. p^.ChildCount := AChildCount;
  2460. c := Length(AWeights);
  2461. p^.WeightLength := c;
  2462. if (c = 0) then begin
  2463. Result := SizeOf(TUCA_PropItemRec);
  2464. if ADeleted then
  2465. SetBit(AItem^.Flags,AItem^.FLAG_DELETION,True);
  2466. end else begin
  2467. Result := SizeOf(TUCA_PropItemRec) + (c*SizeOf(TUCA_PropWeights));//PtrUInt(pw) - PtrUInt(AItem);
  2468. //pw := PUCA_PropWeights(PtrUInt(p) + SizeOf(TUCA_PropItemRec));
  2469. pb := PByte(PtrUInt(p) + SizeOf(TUCA_PropItemRec));
  2470. PWord(pb)^ := AWeights[0].Weights[0];
  2471. pb := pb + 2;
  2472. if (AWeights[0].Weights[1] > High(Byte)) then begin
  2473. SetBit(p^.Valid,(BIT_POS_COMPRESS_WEIGHT_1),True);
  2474. PWord(pb)^ := AWeights[0].Weights[1];
  2475. pb := pb + 2;
  2476. end else begin
  2477. pb^ := AWeights[0].Weights[1];
  2478. pb := pb + 1;
  2479. Result := Result - 1;
  2480. end;
  2481. if (AWeights[0].Weights[2] > High(Byte)) then begin
  2482. SetBit(p^.Valid,(BIT_POS_COMPRESS_WEIGHT_2),True);
  2483. PWord(pb)^ := AWeights[0].Weights[2];
  2484. pb := pb + 2;
  2485. end else begin
  2486. pb^ := AWeights[0].Weights[2];
  2487. pb := pb + 1;
  2488. Result := Result - 1;
  2489. end;
  2490. pw := PUCA_PropWeights(pb);
  2491. for i := 1 to c - 1 do begin
  2492. pw^.Weights[0] := AWeights[i].Weights[0];
  2493. pw^.Weights[1] := AWeights[i].Weights[1];
  2494. pw^.Weights[2] := AWeights[i].Weights[2];
  2495. //pw^.Variable := BoolToByte(AWeights[i].Variable);
  2496. Inc(pw);
  2497. end;
  2498. end;
  2499. hasContext := (AContext <> nil) and (Length(AContext^.Data) > 0);
  2500. if AStoreCP or hasContext then begin
  2501. PUInt24(PtrUInt(AItem)+Result)^ := ACodePoint;
  2502. Result := Result + SizeOf(UInt24);
  2503. SetBit(AItem^.Flags,AItem^.FLAG_CODEPOINT,True);
  2504. end;
  2505. if hasContext then begin
  2506. contextTree := ConstructContextTree(AContext,Pointer(PtrUInt(AItem)+Result)^,-1);
  2507. Result := Result + Cardinal(contextTree^.Size);
  2508. SetBit(AItem^.Flags,AItem^.FLAG_CONTEXTUAL,True);
  2509. end;
  2510. p^.Size := Result;
  2511. end;
  2512. function CalcCharChildCount(
  2513. const AChar : Cardinal;
  2514. const ASearchStartPos : Integer;
  2515. const ALinePos : Integer;
  2516. const ABookLines : PUCA_LineRec;
  2517. const AMaxLength : Integer;
  2518. const ABookIndex : TUCA_DataBookIndex;
  2519. out ALineCount : Integer
  2520. ) : Byte;
  2521. var
  2522. locLinePos : Integer;
  2523. p : PUCA_LineRec;
  2524. procedure IncP();
  2525. begin
  2526. Inc(locLinePos);
  2527. p := @ABookLines[ABookIndex[locLinePos]];
  2528. end;
  2529. procedure DoDump();
  2530. var
  2531. px : PUCA_LineRec;
  2532. k, ki : Integer;
  2533. begin
  2534. WriteLn;
  2535. WriteLn('Dump');
  2536. for k := ALinePos to ALinePos + 15 do begin
  2537. px := @ABookLines[ABookIndex[k]];
  2538. for ki := 0 to Length(px^.CodePoints) -1 do
  2539. Write(px^.CodePoints[ki],' ');
  2540. WriteLn;
  2541. end;
  2542. end;
  2543. var
  2544. i, locTargetLen, locTargetBufferSize, r : Integer;
  2545. locTarget : array[0..127] of Cardinal;
  2546. locLastChar : Cardinal;
  2547. begin
  2548. locLinePos := ALinePos;
  2549. p := @ABookLines[ABookIndex[locLinePos]];
  2550. locTargetLen := ASearchStartPos;
  2551. locTargetBufferSize := (locTargetLen*SizeOf(Cardinal));
  2552. Move(p^.CodePoints[0],locTarget[0],locTargetBufferSize);
  2553. if (Length(p^.CodePoints) = ASearchStartPos) then begin
  2554. r := 0;
  2555. locLastChar := High(Cardinal);
  2556. end else begin
  2557. r := 1;
  2558. locLastChar := p^.CodePoints[ASearchStartPos];
  2559. end;
  2560. IncP();
  2561. i := 1;
  2562. while (i < AMaxLength) do begin
  2563. if (Length(p^.CodePoints) < locTargetLen) then
  2564. Break;
  2565. if not CompareMem(@locTarget[0],@p^.CodePoints[0],locTargetBufferSize) then
  2566. Break;
  2567. if (p^.CodePoints[ASearchStartPos] <> locLastChar) then begin
  2568. Inc(r);
  2569. locLastChar := p^.CodePoints[ASearchStartPos];
  2570. end;
  2571. IncP();
  2572. Inc(i);
  2573. end;
  2574. ALineCount := i;
  2575. Result := r;
  2576. end;
  2577. function BuildTrie(
  2578. const ALinePos : Integer;
  2579. const ABookLines : PUCA_LineRec;
  2580. const AMaxLength : Integer;
  2581. const ABookIndex : TUCA_DataBookIndex
  2582. ) : PTrieNode;
  2583. var
  2584. p : PUCA_LineRec;
  2585. root : PTrieNode;
  2586. ki, k, i : Integer;
  2587. key : array of TKeyType;
  2588. begin
  2589. k := ABookIndex[ALinePos];
  2590. p := @ABookLines[k];
  2591. if (Length(p^.CodePoints) = 1) then
  2592. root := CreateNode(p^.CodePoints[0],k)
  2593. else
  2594. root := CreateNode(p^.CodePoints[0]);
  2595. for i := ALinePos to ALinePos + AMaxLength - 1 do begin
  2596. k := ABookIndex[i];
  2597. p := @ABookLines[k];
  2598. if (Length(p^.CodePoints) = 1) then begin
  2599. InsertWord(root,p^.CodePoints[0],k);
  2600. end else begin
  2601. SetLength(key,Length(p^.CodePoints));
  2602. for ki := 0 to Length(p^.CodePoints) - 1 do
  2603. key[ki] := p^.CodePoints[ki];
  2604. InsertWord(root,key,k);
  2605. end;
  2606. end;
  2607. Result := root;
  2608. end;
  2609. function BoolToByte(AValue : Boolean): Byte;inline;
  2610. begin
  2611. if AValue then
  2612. Result := 1
  2613. else
  2614. Result := 0;
  2615. end;
  2616. function InternalConstructFromTrie(
  2617. const ATrie : PTrieNode;
  2618. const AItem : PUCA_PropItemRec;
  2619. const ALines : PUCA_LineRec;
  2620. const AStoreCp : Boolean
  2621. ) : Integer;
  2622. var
  2623. i, size : Integer;
  2624. p : PUCA_PropItemRec;
  2625. n : PTrieNode;
  2626. begin
  2627. if (ATrie = nil) then
  2628. exit(0);
  2629. p := AItem;
  2630. n := ATrie;
  2631. if n^.DataNode then
  2632. size := ConstructItem(p,n^.Key,1,n^.ChildCount,ALines[n^.Data].Weights,AStoreCp,@(ALines[n^.Data].Context),ALines[n^.Data].Deleted)
  2633. else
  2634. size := ConstructItem(p,n^.Key,0,n^.ChildCount,[],AStoreCp,nil,False);
  2635. Result := size;
  2636. if (n^.ChildCount > 0) then begin
  2637. for i := 0 to n^.ChildCount - 1 do begin
  2638. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2639. size := InternalConstructFromTrie(n^.Children[i],p,ALines,True);
  2640. Result := Result + size;
  2641. end;
  2642. end;
  2643. AItem^.Size := Result;
  2644. end;
  2645. function ConstructFromTrie(
  2646. const ATrie : PTrieNode;
  2647. const AItem : PUCA_PropItemRec;
  2648. const ALines : PUCA_LineRec
  2649. ) : Integer;
  2650. begin
  2651. Result := InternalConstructFromTrie(ATrie,AItem,ALines,False);
  2652. end;
  2653. procedure MakeUCA_Props(
  2654. ABook : PUCA_DataBook;
  2655. out AProps : PUCA_PropBook
  2656. );
  2657. var
  2658. propIndexCount : Integer;
  2659. procedure CapturePropIndex(AItem : PUCA_PropItemRec; ACodePoint : Cardinal);
  2660. begin
  2661. AProps^.Index[propIndexCount].CodePoint := ACodePoint;
  2662. AProps^.Index[propIndexCount].Position := PtrUInt(AItem) - PtrUInt(AProps^.Items);
  2663. propIndexCount := propIndexCount + 1;
  2664. end;
  2665. var
  2666. locIndex : TUCA_DataBookIndex;
  2667. i, c, k, kc : Integer;
  2668. p, p1, p2 : PUCA_PropItemRec;
  2669. lines, pl1, pl2 : PUCA_LineRec;
  2670. childCount, lineCount, size : Integer;
  2671. trieRoot : PTrieNode;
  2672. MaxChildCount, MaxSize : Integer;
  2673. begin
  2674. locIndex := CreateIndex(ABook);
  2675. i := Length(ABook^.Lines);
  2676. i := 30 * i * (SizeOf(TUCA_PropItemRec) + SizeOf(TUCA_PropWeights));
  2677. GetMem(AProps,SizeOf(TUCA_DataBook));
  2678. AProps^.ItemSize := i;
  2679. GetMem(AProps^.Items,i);
  2680. propIndexCount := 0;
  2681. SetLength(AProps^.Index,Length(ABook^.Lines));
  2682. p := AProps^.Items;
  2683. lines := @ABook^.Lines[0];
  2684. c := Length(locIndex);
  2685. i := 0;
  2686. MaxChildCount := 0; MaxSize := 0;
  2687. while (i < (c-1)) do begin
  2688. pl1 := @lines[locIndex[i]];
  2689. if not pl1^.Stored then begin
  2690. i := i + 1;
  2691. Continue;
  2692. end;
  2693. pl2 := @lines[locIndex[i+1]];
  2694. if (pl1^.CodePoints[0] <> pl2^.CodePoints[0]) then begin
  2695. if (Length(pl1^.CodePoints) = 1) then begin
  2696. size := ConstructItem(p,pl1^.CodePoints[0],1,0,pl1^.Weights,False,@pl1^.Context,pl1^.Deleted);
  2697. CapturePropIndex(p,pl1^.CodePoints[0]);
  2698. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2699. if (size > MaxSize) then
  2700. MaxSize := size;
  2701. end else begin
  2702. kc := Length(pl1^.CodePoints);
  2703. for k := 0 to kc - 2 do begin
  2704. size := ConstructItem(p,pl1^.CodePoints[k],0,1,[],(k>0),@pl1^.Context,pl1^.Deleted);
  2705. if (k = 0) then
  2706. CapturePropIndex(p,pl1^.CodePoints[k]);
  2707. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2708. end;
  2709. size := ConstructItem(p,pl1^.CodePoints[kc-1],1,0,pl1^.Weights,True,@pl1^.Context,pl1^.Deleted);
  2710. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2711. p2 := p;
  2712. for k := kc - 2 downto 0 do begin
  2713. p1 := PUCA_PropItemRec(PtrUInt(p2) - p2^.Size);
  2714. p1^.Size := p1^.Size + p2^.Size;
  2715. p2 := p1;
  2716. end;
  2717. if (p1^.Size > MaxSize) then
  2718. MaxSize := p1^.Size;
  2719. end;
  2720. lineCount := 1;
  2721. end else begin
  2722. childCount := CalcCharChildCount(pl1^.CodePoints[0],1,i,lines,c,locIndex,lineCount);
  2723. if (childCount < 1) then
  2724. raise Exception.CreateFmt('Expected "child count > 1" but found %d.',[childCount]);
  2725. if (lineCount < 2) then
  2726. raise Exception.CreateFmt('Expected "line count > 2" but found %d.',[lineCount]);
  2727. if (childCount > MaxChildCount) then
  2728. MaxChildCount := childCount;
  2729. trieRoot := BuildTrie(i,lines,lineCount,locIndex);
  2730. size := ConstructFromTrie(trieRoot,p,lines);
  2731. CapturePropIndex(p,pl1^.CodePoints[0]);
  2732. FreeNode(trieRoot);
  2733. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2734. if (size > MaxSize) then
  2735. MaxSize := size;
  2736. end;
  2737. i := i + lineCount;
  2738. end;
  2739. if (i = (c-1)) then begin
  2740. pl1 := @lines[locIndex[i]];
  2741. if (Length(pl1^.CodePoints) = 1) then begin
  2742. size := ConstructItem(p,pl1^.CodePoints[0],1,0,pl1^.Weights,False,@pl1^.Context,pl1^.Deleted);
  2743. CapturePropIndex(p,pl1^.CodePoints[0]);
  2744. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2745. if (size > MaxSize) then
  2746. MaxSize := size;
  2747. end else begin
  2748. kc := Length(pl1^.CodePoints);
  2749. for k := 0 to kc - 2 do begin
  2750. size := ConstructItem(p,pl1^.CodePoints[k],0,1,[],(k>0),@pl1^.Context,pl1^.Deleted);
  2751. if (k = 0) then
  2752. CapturePropIndex(p,pl1^.CodePoints[0]);
  2753. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2754. end;
  2755. size := ConstructItem(p,pl1^.CodePoints[kc-1],1,0,pl1^.Weights,True,@pl1^.Context,pl1^.Deleted);
  2756. p := PUCA_PropItemRec(PtrUInt(p) + size);
  2757. p2 := p;
  2758. for k := kc - 2 downto 0 do begin
  2759. p1 := PUCA_PropItemRec(PtrUInt(p2) - p2^.Size);
  2760. p1^.Size := p1^.Size + p2^.Size;
  2761. p2 := p1;
  2762. end;
  2763. if (size > MaxSize) then
  2764. MaxSize := size;
  2765. end;
  2766. end;
  2767. c := Int64(PtrUInt(p)) - Int64(PtrUInt(AProps^.Items));
  2768. ReAllocMem(AProps^.Items,c);
  2769. AProps^.ItemSize := c;
  2770. SetLength(AProps^.Index,propIndexCount);
  2771. k := 0;
  2772. c := High(Word);
  2773. for i := 0 to Length(ABook^.Lines) - 1 do begin
  2774. if (Length(ABook^.Lines[i].Weights) > 0) then begin
  2775. if (ABook^.Lines[i].Weights[0].Variable) then begin
  2776. if (ABook^.Lines[i].Weights[0].Weights[0] > k) then
  2777. k := ABook^.Lines[i].Weights[0].Weights[0];
  2778. if (ABook^.Lines[i].Weights[0].Weights[0] < c) then
  2779. c := ABook^.Lines[i].Weights[0].Weights[0];
  2780. end;
  2781. end;
  2782. end;
  2783. AProps^.VariableHighLimit := k;
  2784. AProps^.VariableLowLimit := c;
  2785. end;
  2786. procedure FreeUcaBook(var ABook : PUCA_PropBook);
  2787. var
  2788. p : PUCA_PropBook;
  2789. begin
  2790. if (ABook = nil) then
  2791. exit;
  2792. p := ABook;
  2793. ABook := nil;
  2794. p^.Index := nil;
  2795. FreeMem(p^.Items,p^.ItemSize);
  2796. FreeMem(p,SizeOf(p^));
  2797. end;
  2798. function IndexOf(const ACodePoint : Cardinal; APropBook : PUCA_PropBook): Integer;overload;
  2799. var
  2800. i : Integer;
  2801. begin
  2802. for i := 0 to Length(APropBook^.Index) - 1 do begin
  2803. if (ACodePoint = APropBook^.Index[i].CodePoint) then
  2804. exit(i);
  2805. end;
  2806. Result := -1;
  2807. end;
  2808. type
  2809. PucaBmpSecondTableItem = ^TucaBmpSecondTableItem;
  2810. function IndexOf(
  2811. const AItem : PucaBmpSecondTableItem;
  2812. const ATable : TucaBmpSecondTable;
  2813. const ATableActualLength : Integer
  2814. ) : Integer;overload;
  2815. var
  2816. i : Integer;
  2817. p : PucaBmpSecondTableItem;
  2818. begin
  2819. Result := -1;
  2820. if (ATableActualLength > 0) then begin
  2821. p := @ATable[0];
  2822. for i := 0 to ATableActualLength - 1 do begin
  2823. if CompareMem(p,AItem,SizeOf(TucaBmpSecondTableItem)) then begin
  2824. Result := i;
  2825. Break;
  2826. end;
  2827. Inc(p);
  2828. end;
  2829. end;
  2830. end;
  2831. procedure MakeUCA_BmpTables(
  2832. var AFirstTable : TucaBmpFirstTable;
  2833. var ASecondTable : TucaBmpSecondTable;
  2834. const APropBook : PUCA_PropBook
  2835. );
  2836. var
  2837. locLowByte, locHighByte : Byte;
  2838. locTableItem : TucaBmpSecondTableItem;
  2839. locCP : TUnicodeCodePoint;
  2840. i, locSecondActualLen : Integer;
  2841. k : Integer;
  2842. begin
  2843. SetLength(ASecondTable,120);
  2844. locSecondActualLen := 0;
  2845. for locHighByte := 0 to 255 do begin
  2846. FillChar(locTableItem,SizeOf(locTableItem),#0);
  2847. for locLowByte := 0 to 255 do begin
  2848. locCP := (locHighByte * 256) + locLowByte;
  2849. k := IndexOf(locCP,APropBook);
  2850. if (k = -1) then
  2851. k := 0
  2852. else
  2853. k := APropBook^.Index[k].Position + 1;
  2854. locTableItem[locLowByte] := k;
  2855. end;
  2856. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  2857. if (i = -1) then begin
  2858. if (locSecondActualLen = Length(ASecondTable)) then
  2859. SetLength(ASecondTable,locSecondActualLen + 50);
  2860. i := locSecondActualLen;
  2861. ASecondTable[i] := locTableItem;
  2862. Inc(locSecondActualLen);
  2863. end;
  2864. AFirstTable[locHighByte] := i;
  2865. end;
  2866. SetLength(ASecondTable,locSecondActualLen);
  2867. end;
  2868. function ToUCS4(const AHighS, ALowS : Word) : TUnicodeCodePoint; inline;
  2869. begin
  2870. //copied from utf16toutf32
  2871. Result := (UCS4Char(AHighS)-$d800) shl 10 + (UCS4Char(ALowS)-$dc00) + $10000;
  2872. end;
  2873. procedure FromUCS4(const AValue : TUnicodeCodePoint; var AHighS, ALowS : Word);
  2874. begin
  2875. AHighS := Word((AValue - $10000) shr 10 + $d800);
  2876. ALowS := Word((AValue - $10000) and $3ff + $dc00);
  2877. end;
  2878. type
  2879. PucaOBmpSecondTableItem = ^TucaOBmpSecondTableItem;
  2880. function IndexOf(
  2881. const AItem : PucaOBmpSecondTableItem;
  2882. const ATable : TucaOBmpSecondTable;
  2883. const ATableActualLength : Integer
  2884. ) : Integer;overload;
  2885. var
  2886. i : Integer;
  2887. p : PucaOBmpSecondTableItem;
  2888. begin
  2889. Result := -1;
  2890. if (ATableActualLength > 0) then begin
  2891. p := @ATable[0];
  2892. for i := 0 to ATableActualLength - 1 do begin
  2893. if CompareMem(p,AItem,SizeOf(TucaOBmpSecondTableItem)) then begin
  2894. Result := i;
  2895. Break;
  2896. end;
  2897. Inc(p);
  2898. end;
  2899. end;
  2900. end;
  2901. procedure MakeUCA_OBmpTables(
  2902. var AFirstTable : TucaOBmpFirstTable;
  2903. var ASecondTable : TucaOBmpSecondTable;
  2904. const APropBook : PUCA_PropBook
  2905. );
  2906. var
  2907. locLowByte, locHighByte : Word;
  2908. locTableItem : TucaOBmpSecondTableItem;
  2909. locCP : TUnicodeCodePoint;
  2910. i, locSecondActualLen : Integer;
  2911. k : Integer;
  2912. begin
  2913. if (Length(ASecondTable) = 0) then
  2914. SetLength(ASecondTable,2000);
  2915. locSecondActualLen := 0;
  2916. for locHighByte := 0 to HIGH_SURROGATE_COUNT - 1 do begin
  2917. FillChar(locTableItem,SizeOf(locTableItem),#0);
  2918. for locLowByte := 0 to LOW_SURROGATE_COUNT - 1 do begin
  2919. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + locLowByte);
  2920. k := IndexOf(locCP,APropBook);
  2921. if (k = -1) then
  2922. k := 0
  2923. else
  2924. k := APropBook^.Index[k].Position + 1;
  2925. locTableItem[locLowByte] := k;
  2926. end;
  2927. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  2928. if (i = -1) then begin
  2929. if (locSecondActualLen = Length(ASecondTable)) then
  2930. SetLength(ASecondTable,locSecondActualLen + 50);
  2931. i := locSecondActualLen;
  2932. ASecondTable[i] := locTableItem;
  2933. Inc(locSecondActualLen);
  2934. end;
  2935. AFirstTable[locHighByte] := i;
  2936. end;
  2937. SetLength(ASecondTable,locSecondActualLen);
  2938. end;
  2939. function GetPropPosition(
  2940. const AHighS,
  2941. ALowS : Word;
  2942. const AFirstTable : PucaOBmpFirstTable;
  2943. const ASecondTable : PucaOBmpSecondTable
  2944. ): Integer;inline;overload;
  2945. begin
  2946. Result := ASecondTable^[AFirstTable^[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN] - 1;
  2947. end;
  2948. procedure GenerateUCA_Head(
  2949. ADest : TStream;
  2950. ABook : PUCA_DataBook;
  2951. AProps : PUCA_PropBook
  2952. );
  2953. procedure AddLine(const ALine : ansistring);
  2954. var
  2955. buffer : ansistring;
  2956. begin
  2957. buffer := ALine + sLineBreak;
  2958. ADest.Write(buffer[1],Length(buffer));
  2959. end;
  2960. begin
  2961. AddLine('const');
  2962. AddLine(' VERSION_STRING = ' + QuotedStr(ABook^.Version) + ';');
  2963. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(AProps^.VariableLowLimit) + ';');
  2964. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(AProps^.VariableHighLimit) + ';');
  2965. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(Ord(ABook^.VariableWeight)) + ';');
  2966. AddLine(' BACKWARDS_0 = ' + BoolToStr(ABook^.Backwards[0],'True','False') + ';');
  2967. AddLine(' BACKWARDS_1 = ' + BoolToStr(ABook^.Backwards[1],'True','False') + ';');
  2968. AddLine(' BACKWARDS_2 = ' + BoolToStr(ABook^.Backwards[2],'True','False') + ';');
  2969. AddLine(' BACKWARDS_3 = ' + BoolToStr(ABook^.Backwards[3],'True','False') + ';');
  2970. AddLine(' PROP_COUNT = ' + IntToStr(Ord(AProps^.ItemSize)) + ';');
  2971. AddLine('');
  2972. end;
  2973. procedure GenerateUCA_BmpTables(
  2974. AStream,
  2975. ABinStream : TStream;
  2976. var AFirstTable : TucaBmpFirstTable;
  2977. var ASecondTable : TucaBmpSecondTable;
  2978. const AEndian : TEndianKind
  2979. );
  2980. procedure AddLine(AOut : TStream; const ALine : ansistring);
  2981. var
  2982. buffer : ansistring;
  2983. begin
  2984. buffer := ALine + sLineBreak;
  2985. AOut.Write(buffer[1],Length(buffer));
  2986. end;
  2987. var
  2988. i, j, c : Integer;
  2989. locLine : string;
  2990. value : UInt24;
  2991. begin
  2992. AddLine(AStream,'const');
  2993. AddLine(AStream,' UCA_TABLE_1 : array[0..255] of Byte = (');
  2994. locLine := '';
  2995. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  2996. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  2997. if (((i+1) mod 16) = 0) then begin
  2998. locLine := ' ' + locLine;
  2999. AddLine(AStream,locLine);
  3000. locLine := '';
  3001. end;
  3002. end;
  3003. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3004. locLine := ' ' + locLine;
  3005. AddLine(AStream,locLine);
  3006. AddLine(AStream,' );' + sLineBreak);
  3007. AddLine(ABinStream,'const');
  3008. AddLine(ABinStream,' UCA_TABLE_2 : array[0..(256*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3009. c := High(ASecondTable);
  3010. for i := Low(ASecondTable) to c do begin
  3011. locLine := '';
  3012. for j := Low(TucaBmpSecondTableItem) to High(TucaBmpSecondTableItem) do begin
  3013. value := ASecondTable[i][j];
  3014. locLine := locLine + UInt24ToStr(value,AEndian) + ',';
  3015. if (((j+1) mod 2) = 0) then begin
  3016. if (i = c) and (j = 255) then
  3017. Delete(locLine,Length(locLine),1);
  3018. locLine := ' ' + locLine;
  3019. AddLine(ABinStream,locLine);
  3020. locLine := '';
  3021. end;
  3022. end;
  3023. end;
  3024. AddLine(ABinStream,' );' + sLineBreak);
  3025. end;
  3026. procedure GenerateUCA_PropTable(
  3027. // WARNING : files must be generated for each endianess (Little / Big)
  3028. ADest : TStream;
  3029. const APropBook : PUCA_PropBook
  3030. );
  3031. procedure AddLine(const ALine : ansistring);
  3032. var
  3033. buffer : ansistring;
  3034. begin
  3035. buffer := ALine + sLineBreak;
  3036. ADest.Write(buffer[1],Length(buffer));
  3037. end;
  3038. var
  3039. i, c : Integer;
  3040. locLine : string;
  3041. p : PByte;
  3042. begin
  3043. c := APropBook^.ItemSize;
  3044. AddLine('const');
  3045. AddLine(' UCA_PROPS : array[0..' + IntToStr(c-1) + '] of Byte = (');
  3046. locLine := '';
  3047. p := PByte(APropBook^.Items);
  3048. for i := 0 to c - 2 do begin
  3049. locLine := locLine + IntToStr(p[i]) + ',';
  3050. if (((i+1) mod 60) = 0) then begin
  3051. locLine := ' ' + locLine;
  3052. AddLine(locLine);
  3053. locLine := '';
  3054. end;
  3055. end;
  3056. locLine := locLine + IntToStr(p[c-1]);
  3057. locLine := ' ' + locLine;
  3058. AddLine(locLine);
  3059. AddLine(' );' + sLineBreak);
  3060. end;
  3061. procedure GenerateUCA_OBmpTables(
  3062. AStream,
  3063. ABinStream : TStream;
  3064. var AFirstTable : TucaOBmpFirstTable;
  3065. var ASecondTable : TucaOBmpSecondTable;
  3066. const AEndian : TEndianKind
  3067. );
  3068. procedure AddLine(AOut : TStream; const ALine : ansistring);
  3069. var
  3070. buffer : ansistring;
  3071. begin
  3072. buffer := ALine + sLineBreak;
  3073. AOut.Write(buffer[1],Length(buffer));
  3074. end;
  3075. var
  3076. i, j, c : Integer;
  3077. locLine : string;
  3078. value : UInt24;
  3079. begin
  3080. AddLine(AStream,'const');
  3081. AddLine(AStream,' UCAO_TABLE_1 : array[0..' + IntToStr(HIGH_SURROGATE_COUNT-1) + '] of Word = (');
  3082. locLine := '';
  3083. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3084. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3085. if (((i+1) mod 16) = 0) then begin
  3086. locLine := ' ' + locLine;
  3087. AddLine(AStream,locLine);
  3088. locLine := '';
  3089. end;
  3090. end;
  3091. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3092. locLine := ' ' + locLine;
  3093. AddLine(AStream,locLine);
  3094. AddLine(AStream,' );' + sLineBreak);
  3095. AddLine(ABinStream,' UCAO_TABLE_2 : array[0..('+IntToStr(LOW_SURROGATE_COUNT)+'*' + IntToStr(Length(ASecondTable)) +'-1)] of UInt24 =(');
  3096. c := High(ASecondTable);
  3097. for i := Low(ASecondTable) to c do begin
  3098. locLine := '';
  3099. for j := Low(TucaOBmpSecondTableItem) to High(TucaOBmpSecondTableItem) do begin
  3100. value := ASecondTable[i][j];
  3101. locLine := locLine + UInt24ToStr(value,AEndian) + ',';
  3102. if (((j+1) mod 2) = 0) then begin
  3103. if (i = c) and (j = High(TucaOBmpSecondTableItem)) then
  3104. Delete(locLine,Length(locLine),1);
  3105. locLine := ' ' + locLine;
  3106. AddLine(ABinStream,locLine);
  3107. locLine := '';
  3108. end;
  3109. end;
  3110. end;
  3111. AddLine(ABinStream,' );' + sLineBreak);
  3112. end;
  3113. //-------------------------------------------
  3114. type
  3115. POBmpSecondTableItem = ^TOBmpSecondTableItem;
  3116. function IndexOf(
  3117. const AItem : POBmpSecondTableItem;
  3118. const ATable : TOBmpSecondTable;
  3119. const ATableActualLength : Integer
  3120. ) : Integer;overload;
  3121. var
  3122. i : Integer;
  3123. p : POBmpSecondTableItem;
  3124. begin
  3125. Result := -1;
  3126. if (ATableActualLength > 0) then begin
  3127. p := @ATable[0];
  3128. for i := 0 to ATableActualLength - 1 do begin
  3129. if CompareMem(p,AItem,SizeOf(TOBmpSecondTableItem)) then begin
  3130. Result := i;
  3131. Break;
  3132. end;
  3133. Inc(p);
  3134. end;
  3135. end;
  3136. end;
  3137. procedure MakeOBmpTables(
  3138. var AFirstTable : TOBmpFirstTable;
  3139. var ASecondTable : TOBmpSecondTable;
  3140. const ADataLineList : TDataLineRecArray
  3141. );
  3142. var
  3143. locLowByte, locHighByte : Word;
  3144. locTableItem : TOBmpSecondTableItem;
  3145. locCP : TUnicodeCodePoint;
  3146. i, locSecondActualLen : Integer;
  3147. begin
  3148. SetLength(ASecondTable,2000);
  3149. locSecondActualLen := 0;
  3150. for locHighByte := 0 to HIGH_SURROGATE_COUNT - 1 do begin
  3151. FillChar(locTableItem,SizeOf(locTableItem),#0);
  3152. for locLowByte := 0 to LOW_SURROGATE_COUNT - 1 do begin
  3153. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + locLowByte);
  3154. locTableItem[locLowByte] := GetPropID(locCP,ADataLineList)// - 1;
  3155. end;
  3156. i := IndexOf(@locTableItem,ASecondTable,locSecondActualLen);
  3157. if (i = -1) then begin
  3158. if (locSecondActualLen = Length(ASecondTable)) then
  3159. SetLength(ASecondTable,locSecondActualLen + 50);
  3160. i := locSecondActualLen;
  3161. ASecondTable[i] := locTableItem;
  3162. Inc(locSecondActualLen);
  3163. end;
  3164. AFirstTable[locHighByte] := i;
  3165. end;
  3166. SetLength(ASecondTable,locSecondActualLen);
  3167. end;
  3168. type
  3169. P3lvlOBmp3TableItem = ^T3lvlOBmp3TableItem;
  3170. function IndexOf(
  3171. const AItem : P3lvlOBmp3TableItem;
  3172. const ATable : T3lvlOBmp3Table;
  3173. const ATableActualLength : Integer
  3174. ) : Integer;overload;
  3175. var
  3176. i : Integer;
  3177. p : P3lvlOBmp3TableItem;
  3178. begin
  3179. Result := -1;
  3180. if (ATableActualLength > 0) then begin
  3181. p := @ATable[0];
  3182. for i := 0 to ATableActualLength - 1 do begin
  3183. if CompareMem(p,AItem,SizeOf(T3lvlOBmp3TableItem)) then begin
  3184. Result := i;
  3185. Break;
  3186. end;
  3187. Inc(p);
  3188. end;
  3189. end;
  3190. end;
  3191. type
  3192. P3lvlOBmp2TableItem = ^T3lvlOBmp2TableItem;
  3193. function IndexOf(
  3194. const AItem : P3lvlOBmp2TableItem;
  3195. const ATable : T3lvlOBmp2Table
  3196. ) : Integer;overload;
  3197. var
  3198. i : Integer;
  3199. p : P3lvlOBmp2TableItem;
  3200. begin
  3201. Result := -1;
  3202. if (Length(ATable) > 0) then begin
  3203. p := @ATable[0];
  3204. for i := 0 to Length(ATable) - 1 do begin
  3205. if CompareMem(p,AItem,SizeOf(T3lvlOBmp2TableItem)) then begin
  3206. Result := i;
  3207. Break;
  3208. end;
  3209. Inc(p);
  3210. end;
  3211. end;
  3212. end;
  3213. procedure MakeOBmpTables3Levels(
  3214. var AFirstTable : T3lvlOBmp1Table;
  3215. var ASecondTable : T3lvlOBmp2Table;
  3216. var AThirdTable : T3lvlOBmp3Table;
  3217. const ADataLineList : TDataLineRecArray
  3218. );
  3219. var
  3220. locLowByte0, locLowByte1, locHighByte : Word;
  3221. locTableItem2 : T3lvlOBmp2TableItem;
  3222. locTableItem3 : T3lvlOBmp3TableItem;
  3223. locCP : TUnicodeCodePoint;
  3224. i, locThirdActualLen : Integer;
  3225. begin
  3226. SetLength(AThirdTable,120);
  3227. locThirdActualLen := 0;
  3228. for locHighByte := 0 to 1023 do begin
  3229. FillChar(locTableItem2,SizeOf(locTableItem2),#0);
  3230. for locLowByte0 := 0 to 31 do begin
  3231. FillChar(locTableItem3,SizeOf(locTableItem3),#0);
  3232. for locLowByte1 := 0 to 31 do begin
  3233. locCP := ToUCS4(HIGH_SURROGATE_BEGIN + locHighByte,LOW_SURROGATE_BEGIN + (locLowByte0*32) + locLowByte1);
  3234. locTableItem3[locLowByte1] := GetPropID(locCP,ADataLineList);
  3235. end;
  3236. i := IndexOf(@locTableItem3,AThirdTable,locThirdActualLen);
  3237. if (i = -1) then begin
  3238. if (locThirdActualLen = Length(AThirdTable)) then
  3239. SetLength(AThirdTable,locThirdActualLen + 50);
  3240. i := locThirdActualLen;
  3241. AThirdTable[i] := locTableItem3;
  3242. Inc(locThirdActualLen);
  3243. end;
  3244. locTableItem2[locLowByte0] := i;
  3245. end;
  3246. i := IndexOf(@locTableItem2,ASecondTable);
  3247. if (i = -1) then begin
  3248. i := Length(ASecondTable);
  3249. SetLength(ASecondTable,(i + 1));
  3250. ASecondTable[i] := locTableItem2;
  3251. end;
  3252. AFirstTable[locHighByte] := i;
  3253. end;
  3254. SetLength(AThirdTable,locThirdActualLen);
  3255. end;
  3256. procedure GenerateOBmpTables(
  3257. ADest : TStream;
  3258. var AFirstTable : TOBmpFirstTable;
  3259. var ASecondTable : TOBmpSecondTable
  3260. );
  3261. procedure AddLine(const ALine : ansistring);
  3262. var
  3263. buffer : ansistring;
  3264. begin
  3265. buffer := ALine + sLineBreak;
  3266. ADest.Write(buffer[1],Length(buffer));
  3267. end;
  3268. var
  3269. i, j, c : Integer;
  3270. locLine : string;
  3271. begin
  3272. AddLine('const');
  3273. AddLine(' UCO_TABLE_1 : array[0..' + IntToStr(HIGH_SURROGATE_COUNT-1) + '] of Word = (');
  3274. locLine := '';
  3275. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3276. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3277. if (((i+1) mod 16) = 0) then begin
  3278. locLine := ' ' + locLine;
  3279. AddLine(locLine);
  3280. locLine := '';
  3281. end;
  3282. end;
  3283. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3284. locLine := ' ' + locLine;
  3285. AddLine(locLine);
  3286. AddLine(' );' + sLineBreak);
  3287. AddLine(' UCO_TABLE_2 : array[0..('+IntToStr(LOW_SURROGATE_COUNT)+'*' + IntToStr(Length(ASecondTable)) +'-1)] of Word =(');
  3288. c := High(ASecondTable);
  3289. for i := Low(ASecondTable) to c do begin
  3290. locLine := '';
  3291. for j := Low(TOBmpSecondTableItem) to High(TOBmpSecondTableItem) do begin
  3292. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  3293. if (((j+1) mod 16) = 0) then begin
  3294. if (i = c) and (j = High(TOBmpSecondTableItem)) then
  3295. Delete(locLine,Length(locLine),1);
  3296. locLine := ' ' + locLine;
  3297. AddLine(locLine);
  3298. locLine := '';
  3299. end;
  3300. end;
  3301. end;
  3302. AddLine(' );' + sLineBreak);
  3303. end;
  3304. //----------------------------------
  3305. procedure Generate3lvlOBmpTables(
  3306. ADest : TStream;
  3307. var AFirstTable : T3lvlOBmp1Table;
  3308. var ASecondTable : T3lvlOBmp2Table;
  3309. var AThirdTable : T3lvlOBmp3Table
  3310. );
  3311. procedure AddLine(const ALine : ansistring);
  3312. var
  3313. buffer : ansistring;
  3314. begin
  3315. buffer := ALine + sLineBreak;
  3316. ADest.Write(buffer[1],Length(buffer));
  3317. end;
  3318. var
  3319. i, j, c : Integer;
  3320. locLine : string;
  3321. begin
  3322. AddLine('const');
  3323. AddLine(' UCO_TABLE_1 : array[0..1023] of Word = (');
  3324. locLine := '';
  3325. for i := Low(AFirstTable) to High(AFirstTable) - 1 do begin
  3326. locLine := locLine + IntToStr(AFirstTable[i]) + ',';
  3327. if (((i+1) mod 16) = 0) then begin
  3328. locLine := ' ' + locLine;
  3329. AddLine(locLine);
  3330. locLine := '';
  3331. end;
  3332. end;
  3333. locLine := locLine + IntToStr(AFirstTable[High(AFirstTable)]);
  3334. locLine := ' ' + locLine;
  3335. AddLine(locLine);
  3336. AddLine(' );' + sLineBreak);
  3337. AddLine(' UCO_TABLE_2 : array[0..' + IntToStr(Length(ASecondTable)-1) +'] of array[0..31] of Word = (');
  3338. c := High(ASecondTable);
  3339. for i := Low(ASecondTable) to c do begin
  3340. locLine := '(';
  3341. for j := Low(T3lvlOBmp2TableItem) to High(T3lvlOBmp2TableItem) do
  3342. locLine := locLine + IntToStr(ASecondTable[i][j]) + ',';
  3343. Delete(locLine,Length(locLine),1);
  3344. locLine := ' ' + locLine + ')';
  3345. if (i < c) then
  3346. locLine := locLine + ',';
  3347. AddLine(locLine);
  3348. end;
  3349. AddLine(' );' + sLineBreak);
  3350. AddLine(' UCO_TABLE_3 : array[0..' + IntToStr(Length(AThirdTable)-1) +'] of array[0..31] of Word = (');
  3351. c := High(AThirdTable);
  3352. for i := Low(AThirdTable) to c do begin
  3353. locLine := '(';
  3354. for j := Low(T3lvlOBmp3TableItem) to High(T3lvlOBmp3TableItem) do
  3355. locLine := locLine + IntToStr(AThirdTable[i][j]) + ',';
  3356. Delete(locLine,Length(locLine),1);
  3357. locLine := ' ' + locLine + ')';
  3358. if (i < c) then
  3359. locLine := locLine + ',';
  3360. AddLine(locLine);
  3361. end;
  3362. AddLine(' );' + sLineBreak);
  3363. end;
  3364. function GetProp(
  3365. const AHighS,
  3366. ALowS : Word;
  3367. const AProps : TPropRecArray;
  3368. var AFirstTable : TOBmpFirstTable;
  3369. var ASecondTable : TOBmpSecondTable
  3370. ): PPropRec;
  3371. begin
  3372. Result := @AProps[ASecondTable[AFirstTable[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN]];
  3373. end;
  3374. function GetProp(
  3375. const AHighS,
  3376. ALowS : Word;
  3377. const AProps : TPropRecArray;
  3378. var AFirstTable : T3lvlOBmp1Table;
  3379. var ASecondTable : T3lvlOBmp2Table;
  3380. var AThirdTable : T3lvlOBmp3Table
  3381. ): PPropRec;
  3382. begin
  3383. Result := @AProps[AThirdTable[ASecondTable[AFirstTable[AHighS]][ALowS div 32]][ALowS mod 32]];
  3384. //Result := @AProps[ASecondTable[AFirstTable[AHighS-HIGH_SURROGATE_BEGIN]][ALowS-LOW_SURROGATE_BEGIN]];
  3385. end;
  3386. { TUCA_PropItemContextTreeRec }
  3387. function TUCA_PropItemContextTreeRec.GetData : PUCA_PropItemContextTreeNodeRec;
  3388. begin
  3389. if (Size = 0) then
  3390. Result := nil
  3391. else
  3392. Result := PUCA_PropItemContextTreeNodeRec(
  3393. PtrUInt(
  3394. PtrUInt(@Self) + SizeOf(UInt24){Size}
  3395. )
  3396. );
  3397. end;
  3398. { TUCA_LineContextRec }
  3399. procedure TUCA_LineContextRec.Clear;
  3400. begin
  3401. Data := nil
  3402. end;
  3403. procedure TUCA_LineContextRec.Assign(ASource : TUCA_LineContextRec);
  3404. var
  3405. c, i : Integer;
  3406. begin
  3407. c := Length(ASource.Data);
  3408. SetLength(Self.Data,c);
  3409. for i := 0 to c-1 do
  3410. Self.Data[i].Assign(ASource.Data[i]);
  3411. end;
  3412. function TUCA_LineContextRec.Clone : TUCA_LineContextRec;
  3413. begin
  3414. Result.Clear();
  3415. Result.Assign(Self);
  3416. end;
  3417. { TUCA_LineContextItemRec }
  3418. procedure TUCA_LineContextItemRec.Clear();
  3419. begin
  3420. CodePoints := nil;
  3421. Weights := nil;
  3422. end;
  3423. procedure TUCA_LineContextItemRec.Assign(ASource : TUCA_LineContextItemRec);
  3424. begin
  3425. Self.CodePoints := Copy(ASource.CodePoints);
  3426. Self.Weights := Copy(ASource.Weights);
  3427. end;
  3428. function TUCA_LineContextItemRec.Clone() : TUCA_LineContextItemRec;
  3429. begin
  3430. Result.Clear();
  3431. Result.Assign(Self);
  3432. end;
  3433. { TUCA_LineRec }
  3434. procedure TUCA_LineRec.Clear;
  3435. begin
  3436. CodePoints := nil;
  3437. Weights := nil;
  3438. Deleted := False;
  3439. Stored := False;
  3440. Context.Clear();
  3441. end;
  3442. procedure TUCA_LineRec.Assign(ASource : TUCA_LineRec);
  3443. begin
  3444. Self.CodePoints := Copy(ASource.CodePoints);
  3445. Self.Weights := Copy(ASource.Weights);
  3446. Self.Deleted := ASource.Deleted;
  3447. Self.Stored := ASource.Stored;
  3448. Self.Context.Assign(ASource.Context);
  3449. end;
  3450. function TUCA_LineRec.Clone : TUCA_LineRec;
  3451. begin
  3452. Result.Clear();
  3453. Result.Assign(Self);
  3454. end;
  3455. function TUCA_LineRec.HasContext() : Boolean;
  3456. begin
  3457. Result := (Length(Context.Data) > 0);
  3458. end;
  3459. { TPropRec }
  3460. function TPropRec.GetCategory: TUnicodeCategory;
  3461. begin
  3462. Result := TUnicodeCategory((CategoryData and Byte($F8)) shr 3);
  3463. end;
  3464. procedure TPropRec.SetCategory(AValue: TUnicodeCategory);
  3465. var
  3466. b : Byte;
  3467. begin
  3468. b := Ord(AValue);
  3469. b := b shl 3;
  3470. CategoryData := CategoryData or b;
  3471. //CategoryData := CategoryData or Byte(Byte(Ord(AValue)) shl 3);
  3472. end;
  3473. function TPropRec.GetWhiteSpace: Boolean;
  3474. begin
  3475. Result := IsBitON(CategoryData,0);
  3476. end;
  3477. procedure TPropRec.SetWhiteSpace(AValue: Boolean);
  3478. begin
  3479. SetBit(CategoryData,0,AValue);
  3480. end;
  3481. function TPropRec.GetHangulSyllable: Boolean;
  3482. begin
  3483. Result := IsBitON(CategoryData,1);
  3484. end;
  3485. procedure TPropRec.SetHangulSyllable(AValue: Boolean);
  3486. begin
  3487. SetBit(CategoryData,1,AValue);
  3488. end;
  3489. { TUCA_PropItemRec }
  3490. function TUCA_PropItemRec.GetWeightLength: TWeightLength;
  3491. begin
  3492. //Result := TWeightLength(Valid and Byte($FC) shr 3);
  3493. Result := TWeightLength((Valid and Byte($F8)) shr 3);
  3494. end;
  3495. procedure TUCA_PropItemRec.SetWeightLength(AValue: TWeightLength);
  3496. begin
  3497. Valid := Valid or Byte(Byte(AValue) shl 3);
  3498. end;
  3499. function TUCA_PropItemRec.GetWeightSize : Word;
  3500. var
  3501. c : Integer;
  3502. begin
  3503. c := WeightLength;
  3504. if (c = 0) then
  3505. exit(0);
  3506. Result := c*SizeOf(TUCA_PropWeights);
  3507. if IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_1) then
  3508. Result := Result - 1;
  3509. if IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_2) then
  3510. Result := Result - 1;
  3511. end;
  3512. procedure TUCA_PropItemRec.GetWeightArray(ADest: PUCA_PropWeights);
  3513. var
  3514. c : Integer;
  3515. p : PByte;
  3516. pd : PUCA_PropWeights;
  3517. begin
  3518. c := WeightLength;
  3519. p := PByte(PtrUInt(@Self) + SizeOf(TUCA_PropItemRec));
  3520. pd := ADest;
  3521. pd^.Weights[0] := PWord(p)^;
  3522. p := p + 2;
  3523. if IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_1) then begin
  3524. pd^.Weights[1] := PWord(p)^;
  3525. p := p + 2;
  3526. end else begin
  3527. pd^.Weights[1] := p^;
  3528. p := p + 1;
  3529. end;
  3530. if IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_2) then begin
  3531. pd^.Weights[2] := PWord(p)^;
  3532. p := p + 2;
  3533. end else begin
  3534. pd^.Weights[2] := p^;
  3535. p := p + 1;
  3536. end;
  3537. if (c > 1) then
  3538. Move(p^, (pd+1)^, ((c-1)*SizeOf(TUCA_PropWeights)));
  3539. end;
  3540. function TUCA_PropItemRec.GetSelfOnlySize: Word;
  3541. begin
  3542. Result := SizeOf(TUCA_PropItemRec);
  3543. if (WeightLength > 0) then begin
  3544. Result := Result + (WeightLength * Sizeof(TUCA_PropWeights));
  3545. if not IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_1) then
  3546. Result := Result - 1;
  3547. if not IsBitON(Self.Valid,BIT_POS_COMPRESS_WEIGHT_2) then
  3548. Result := Result - 1;
  3549. end;
  3550. end;
  3551. procedure TUCA_PropItemRec.SetContextual(AValue : Boolean);
  3552. begin
  3553. SetBit(Flags,FLAG_CONTEXTUAL,AValue);
  3554. end;
  3555. function TUCA_PropItemRec.GetContextual : Boolean;
  3556. begin
  3557. Result := IsBitON(Flags,FLAG_CONTEXTUAL);
  3558. end;
  3559. function TUCA_PropItemRec.GetContext() : PUCA_PropItemContextTreeRec;
  3560. var
  3561. p : PtrUInt;
  3562. begin
  3563. if not Contextual then
  3564. exit(nil);
  3565. p := PtrUInt(@Self) + SizeOf(TUCA_PropItemRec);
  3566. if IsBitON(Flags,FLAG_CODEPOINT) then
  3567. p := p + SizeOf(UInt24);
  3568. Result := PUCA_PropItemContextTreeRec(p);
  3569. end;
  3570. procedure TUCA_PropItemRec.SetDeleted(AValue: Boolean);
  3571. begin
  3572. SetBit(Flags,FLAG_DELETION,AValue);
  3573. end;
  3574. function TUCA_PropItemRec.IsDeleted: Boolean;
  3575. begin
  3576. Result := IsBitON(Flags,FLAG_DELETION);
  3577. end;
  3578. function TUCA_PropItemRec.GetCodePoint: UInt24;
  3579. begin
  3580. Result := PUInt24(PtrUInt(@Self) + Self.GetSelfOnlySize())^;
  3581. end;
  3582. function avl_CompareCodePoints(Item1, Item2: Pointer): Integer;
  3583. var
  3584. a, b : PUCA_LineContextItemRec;
  3585. i, hb : Integer;
  3586. begin
  3587. if (Item1 = Item2) then
  3588. exit(0);
  3589. if (Item1 = nil) then
  3590. exit(-1);
  3591. if (Item2 = nil) then
  3592. exit(1);
  3593. a := Item1;
  3594. b := Item2;
  3595. if (a^.CodePoints = b^.CodePoints) then
  3596. exit(0);
  3597. Result := 1;
  3598. hb := Length(b^.CodePoints) - 1;
  3599. for i := 0 to Length(a^.CodePoints) - 1 do begin
  3600. if (i > hb) then
  3601. exit;
  3602. if (a^.CodePoints[i] < b^.CodePoints[i]) then
  3603. exit(-1);
  3604. if (a^.CodePoints[i] > b^.CodePoints[i]) then
  3605. exit(1);
  3606. end;
  3607. if (Length(a^.CodePoints) = Length(b^.CodePoints)) then
  3608. exit(0);
  3609. exit(-1);
  3610. end;
  3611. function ConstructAvlContextTree(AContext : PUCA_LineContextRec) : TAVLTree;
  3612. var
  3613. r : TAVLTree;
  3614. i : Integer;
  3615. begin
  3616. r := TAVLTree.Create(@avl_CompareCodePoints);
  3617. try
  3618. for i := 0 to Length(AContext^.Data) - 1 do
  3619. r.Add(@AContext^.Data[i]);
  3620. Result := r;
  3621. except
  3622. FreeAndNil(r);
  3623. raise;
  3624. end;
  3625. end;
  3626. function ConstructContextTree(
  3627. const AContext : PUCA_LineContextRec;
  3628. var ADestBuffer;
  3629. const ADestBufferLength : Integer
  3630. ) : PUCA_PropItemContextTreeRec;
  3631. function CalcItemOnlySize(AItem : TAVLTreeNode) : Cardinal;
  3632. var
  3633. kitem : PUCA_LineContextItemRec;
  3634. begin
  3635. if (AItem = nil) then
  3636. exit(0);
  3637. kitem := AItem.Data;
  3638. Result := SizeOf(PUCA_PropItemContextTreeNodeRec^.Left) +
  3639. SizeOf(PUCA_PropItemContextTreeNodeRec^.Right) +
  3640. SizeOf(PUCA_PropItemContextRec^.CodePointCount) +
  3641. (Length(kitem^.CodePoints)*SizeOf(UInt24)) +
  3642. SizeOf(PUCA_PropItemContextRec^.WeightCount) +
  3643. (Length(kitem^.Weights)*SizeOf(TUCA_PropWeights));
  3644. end;
  3645. function CalcItemSize(AItem : TAVLTreeNode) : Cardinal;
  3646. begin
  3647. if (AItem = nil) then
  3648. exit(0);
  3649. Result := CalcItemOnlySize(AItem);
  3650. if (AItem.Left <> nil) then
  3651. Result := Result + CalcItemSize(AItem.Left);
  3652. if (AItem.Right <> nil) then
  3653. Result := Result + CalcItemSize(AItem.Right);
  3654. end;
  3655. function CalcSize(AData : TAVLTree) : Cardinal;
  3656. begin
  3657. Result := SizeOf(PUCA_PropItemContextTreeRec^.Size) + CalcItemSize(AData.Root);
  3658. end;
  3659. function ConstructItem(ASource : TAVLTreeNode; ADest : PUCA_PropItemContextTreeNodeRec) : Cardinal;
  3660. var
  3661. k : Integer;
  3662. kitem : PUCA_LineContextItemRec;
  3663. kpcp : PUInt24;
  3664. kpw : PUCA_PropWeights;
  3665. pextra : PtrUInt;
  3666. pnext : PUCA_PropItemContextTreeNodeRec;
  3667. begin
  3668. kitem := ASource.Data;
  3669. ADest^.Data.CodePointCount := Length(kitem^.CodePoints);
  3670. ADest^.Data.WeightCount := Length(kitem^.Weights);
  3671. pextra := PtrUInt(ADest)+SizeOf(ADest^.Left)+SizeOf(ADest^.Right)+
  3672. SizeOf(ADest^.Data.CodePointCount)+SizeOf(ADest^.Data.WeightCount);
  3673. if (ADest^.Data.CodePointCount > 0) then begin
  3674. kpcp := PUInt24(pextra);
  3675. for k := 0 to ADest^.Data.CodePointCount - 1 do begin
  3676. kpcp^ := kitem^.CodePoints[k];
  3677. Inc(kpcp);
  3678. end;
  3679. end;
  3680. if (ADest^.Data.WeightCount > 0) then begin
  3681. kpw := PUCA_PropWeights(pextra + (ADest^.Data.CodePointCount*SizeOf(UInt24)));
  3682. for k := 0 to ADest^.Data.WeightCount - 1 do begin
  3683. kpw^.Weights[0] := kitem^.Weights[k].Weights[0];
  3684. kpw^.Weights[1] := kitem^.Weights[k].Weights[1];
  3685. kpw^.Weights[2] := kitem^.Weights[k].Weights[2];
  3686. Inc(kpw);
  3687. end;
  3688. end;
  3689. Result := CalcItemOnlySize(ASource);
  3690. if (ASource.Left <> nil) then begin
  3691. pnext := PUCA_PropItemContextTreeNodeRec(PtrUInt(ADest) + Result);
  3692. ADest^.Left := Result;
  3693. Result := Result + ConstructItem(ASource.Left,pnext);
  3694. end else begin
  3695. ADest^.Left := 0;
  3696. end;
  3697. if (ASource.Right <> nil) then begin
  3698. pnext := PUCA_PropItemContextTreeNodeRec(PtrUInt(ADest) + Result);
  3699. ADest^.Right := Result;
  3700. Result := Result + ConstructItem(ASource.Right,pnext);
  3701. end else begin
  3702. ADest^.Right := 0;
  3703. end;
  3704. end;
  3705. var
  3706. c : PtrUInt;
  3707. r : PUCA_PropItemContextTreeRec;
  3708. p : PUCA_PropItemContextTreeNodeRec;
  3709. tempTree : TAVLTree;
  3710. begin
  3711. tempTree := ConstructAvlContextTree(AContext);
  3712. try
  3713. c := CalcSize(tempTree);
  3714. if (ADestBufferLength > 0) and (c > ADestBufferLength) then
  3715. raise Exception.Create(SInsufficientMemoryBuffer);
  3716. r := @ADestBuffer;
  3717. r^.Size := c;
  3718. p := PUCA_PropItemContextTreeNodeRec(PtrUInt(r) + SizeOf(r^.Size));
  3719. ConstructItem(tempTree.Root,p);
  3720. finally
  3721. tempTree.Free();
  3722. end;
  3723. Result := r;
  3724. end;
  3725. initialization
  3726. FS := DefaultFormatSettings;
  3727. FS.DecimalSeparator := '.';
  3728. end.