2
0

unicodedata.pas 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201
  1. { Unicode tables unit.
  2. Copyright (c) 2013 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. -------------------------------------------------------------------------------
  16. Overview of the Unicode Collation Algorithm(UCA) data layout :
  17. ============================================================
  18. The UCA data(see “TUCA_DataBook”) are organized into index data
  19. (see the “TUCA_DataBook” fields “BMP_Table1”, “BMP_Table2”,
  20. “OBMP_Table1” and “OBMP_Table2”) and actual properties data(see
  21. the “Props” field of “TUCA_DataBook”). The index is a 3 level
  22. tables designed to minimize the overhaul data size. The
  23. properties’ data contain the actual (used) UCA’s properties
  24. for the customized code points(or sequence of code points)
  25. data (see TUCA_PropItemRec).
  26. To get the properties’ record of a code point, one goes
  27. through the index data to get its offset into the “Props”
  28. serialized data, see the “GetPropUCA” procedure.
  29. The “TUCA_PropItemRec” record, that represents the actual
  30. properties, contains a fixed part and a variable part. The
  31. fixed part is directly expressed as fields of the record :
  32. “WeightLength”, “ChildCount”, “Size”, “Flags”. The
  33. variable part depends on some values of the fixed part; For
  34. example “WeightLength” specify the number of weight[1] item,
  35. it can be zero or not null; The “Flags” fields does contains
  36. some bit states to indicate for example if the record’s owner,
  37. that is the target code point, is present(it is not always
  38. necessary to store the code point as you are required to have
  39. this information in the first place in order to get the
  40. “TUCA_PropItemRec” record).
  41. The data, as it is organized now, is as follow for each code point :
  42. * the fixed part is serialized,
  43. * if there are weight item array, they are serialized
  44. (see the "WeigthLength")
  45. * the code point is serialized (if needed)
  46. * the context[2] array is serialized
  47. * The children[3] record are serialized.
  48. The “Size” represent the size of the whole record, including its
  49. children records(see [3]). The “GetSelfOnlySize” returns the size
  50. of the queried record, excluding the size of its children.
  51. Notes :
  52. [1] : A weight item is an array of 3 words. A code point/sequence of code
  53. point may have zero or multiple items.
  54. [2] : There are characters(mostly japanese ones) that do not have their
  55. own weighs; There inherit the weights of the preceding character
  56. in the string that you will be evaluating.
  57. [3] : Some unicode characters are expressed using more than one code point.
  58. In that case the properties records are serialized as a trie. The
  59. trie data structure is useful when many characters’ expression have
  60. the same starting code point(s).
  61. [4] TUCA_PropItemRec serialization :
  62. TUCA_PropItemRec :
  63. WeightLength, ChildCount, Size, Flags [weight item array]
  64. [Code Point] [Context data]
  65. [Child 0] [Child 1] .. [Child n]
  66. each [Child k] is a TUCA_PropItemRec.
  67. }
  68. {$IFNDEF FPC_DOTTEDUNITS}
  69. unit unicodedata;
  70. {$ENDIF FPC_DOTTEDUNITS}
  71. {$IFDEF FPC}
  72. {$mode delphi}
  73. {$H+}
  74. {$PACKENUM 1}
  75. {$warn 4056 off} //Conversion between ordinals and pointers is not portable
  76. {$DEFINE HAS_PUSH}
  77. {$DEFINE HAS_COMPARE_BYTE}
  78. {$DEFINE INLINE_SUPPORT_PRIVATE_VARS}
  79. {$DEFINE HAS_UNALIGNED}
  80. {$ENDIF FPC}
  81. {$IFNDEF FPC}
  82. {$UNDEF HAS_COMPARE_BYTE}
  83. {$UNDEF HAS_PUSH}
  84. {$DEFINE ENDIAN_LITTLE}
  85. {$ENDIF !FPC}
  86. {$SCOPEDENUMS ON}
  87. {$pointermath on}
  88. {$define USE_INLINE}
  89. { $define uni_debug}
  90. interface
  91. {$IFNDEF FPC}
  92. type
  93. UnicodeChar = WideChar;
  94. PUnicodeChar = ^UnicodeChar;
  95. SizeInt = NativeInt;
  96. DWord = UInt32;
  97. PDWord = ^DWord;
  98. PtrInt = NativeInt;
  99. PtrUInt = NativeUInt;
  100. {$ENDIF !FPC}
  101. {$IF not Declared(reCodesetConversion)}
  102. const reCodesetConversion = reRangeError;
  103. {$IFEND reCodesetConversion}
  104. {$IF not Declared(DirectorySeparator)}
  105. {$IFDEF MSWINDOWS}
  106. const DirectorySeparator = '\';
  107. {$ELSE}
  108. const DirectorySeparator = '/';
  109. {$ENDIF MSWINDOWS}
  110. {$IFEND DirectorySeparator}
  111. const
  112. MAX_WORD = High(Word);
  113. LOW_SURROGATE_BEGIN = Word($DC00);
  114. LOW_SURROGATE_END = Word($DFFF);
  115. HIGH_SURROGATE_BEGIN = Word($D800);
  116. HIGH_SURROGATE_END = Word($DBFF);
  117. HIGH_SURROGATE_COUNT = HIGH_SURROGATE_END - HIGH_SURROGATE_BEGIN + 1;
  118. UCS4_HALF_BASE = LongWord($10000);
  119. UCS4_HALF_MASK = Word($3FF);
  120. MAX_LEGAL_UTF32 = $10FFFF;
  121. const
  122. // Unicode General Category
  123. UGC_UppercaseLetter = 0;
  124. UGC_LowercaseLetter = 1;
  125. UGC_TitlecaseLetter = 2;
  126. UGC_ModifierLetter = 3;
  127. UGC_OtherLetter = 4;
  128. UGC_NonSpacingMark = 5;
  129. UGC_CombiningMark = 6;
  130. UGC_EnclosingMark = 7;
  131. UGC_DecimalNumber = 8;
  132. UGC_LetterNumber = 9;
  133. UGC_OtherNumber = 10;
  134. UGC_ConnectPunctuation = 11;
  135. UGC_DashPunctuation = 12;
  136. UGC_OpenPunctuation = 13;
  137. UGC_ClosePunctuation = 14;
  138. UGC_InitialPunctuation = 15;
  139. UGC_FinalPunctuation = 16;
  140. UGC_OtherPunctuation = 17;
  141. UGC_MathSymbol = 18;
  142. UGC_CurrencySymbol = 19;
  143. UGC_ModifierSymbol = 20;
  144. UGC_OtherSymbol = 21;
  145. UGC_SpaceSeparator = 22;
  146. UGC_LineSeparator = 23;
  147. UGC_ParagraphSeparator = 24;
  148. UGC_Control = 25;
  149. UGC_Format = 26;
  150. UGC_Surrogate = 27;
  151. UGC_PrivateUse = 28;
  152. UGC_Unassigned = 29;
  153. // Names
  154. UnicodeCategoryNames: array[0..29] of string[2] = (
  155. 'Lu',
  156. 'Ll',
  157. 'Lt',
  158. 'Lm',
  159. 'Lo',
  160. 'Mn',
  161. 'Mc',
  162. 'Me',
  163. 'Nd',
  164. 'Nl',
  165. 'No',
  166. 'Pc',
  167. 'Pd',
  168. 'Ps',
  169. 'Pe',
  170. 'Pi',
  171. 'Pf',
  172. 'Po',
  173. 'Sm',
  174. 'Sc',
  175. 'Sk',
  176. 'So',
  177. 'Zs',
  178. 'Zl',
  179. 'Zp',
  180. 'Cc',
  181. 'Cf',
  182. 'Cs',
  183. 'Co',
  184. 'Cn'
  185. );
  186. type
  187. TUInt24Rec = packed record
  188. public
  189. {$ifdef ENDIAN_LITTLE}
  190. a, b, c : Byte;
  191. {$else ENDIAN_LITTLE}
  192. c, b, a : Byte;
  193. {$endif ENDIAN_LITTLE}
  194. public
  195. property byte0 : Byte read a write a;
  196. property byte1 : Byte read b write b;
  197. property byte2 : Byte read c write c;
  198. public
  199. class operator Implicit(a : TUInt24Rec) : Cardinal;{$ifdef USE_INLINE}inline;{$ENDIF}
  200. class operator Implicit(a : TUInt24Rec) : LongInt;{$ifdef USE_INLINE}inline;{$ENDIF}
  201. class operator Implicit(a : TUInt24Rec) : Word;{$ifdef USE_INLINE}inline;{$ENDIF}
  202. class operator Implicit(a : TUInt24Rec) : Byte;{$ifdef USE_INLINE}inline;{$ENDIF}
  203. class operator Implicit(a : Cardinal) : TUInt24Rec;{$ifdef USE_INLINE}inline;{$ENDIF}
  204. class operator Equal(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  205. class operator Equal(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  206. class operator Equal(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  207. class operator Equal(a : TUInt24Rec; b : LongInt): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  208. class operator Equal(a : LongInt; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  209. class operator Equal(a : TUInt24Rec; b : Word): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  210. class operator Equal(a : Word; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  211. class operator Equal(a : TUInt24Rec; b : Byte): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  212. class operator Equal(a : Byte; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  213. class operator NotEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  214. class operator NotEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  215. class operator NotEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  216. class operator GreaterThan(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  217. class operator GreaterThan(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  218. class operator GreaterThan(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  219. class operator GreaterThanOrEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  220. class operator GreaterThanOrEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  221. class operator GreaterThanOrEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  222. class operator LessThan(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  223. class operator LessThan(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  224. class operator LessThan(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  225. class operator LessThanOrEqual(a, b: TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  226. class operator LessThanOrEqual(a : TUInt24Rec; b : Cardinal): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  227. class operator LessThanOrEqual(a : Cardinal; b : TUInt24Rec): Boolean;{$ifdef USE_INLINE}inline;{$ENDIF}
  228. end;
  229. UInt24 = TUInt24Rec;
  230. PUInt24 = ^UInt24;
  231. const
  232. ZERO_UINT24 : UInt24 =
  233. {$ifdef ENDIAN_LITTLE}
  234. (a : 0; b : 0; c : 0;);
  235. {$else ENDIAN_LITTLE}
  236. (c : 0; b : 0; a : 0;);
  237. {$endif ENDIAN_LITTLE}
  238. type
  239. PUC_Prop = ^TUC_Prop;
  240. { TUC_Prop }
  241. { On alignment-sensitive targets, at least some of them, assembler uses to forcibly align data >1 byte.
  242. This breaks intended layout of initialized constants/variables.
  243. A proper solution is to patch compiler to emit always unaligned directives for words/dwords/etc,
  244. but for now just declare this record as "unpacked". This causes bloat, but it's better than having
  245. entire unit not working at all. }
  246. TUC_Prop = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record
  247. private
  248. function GetCategory : Byte;inline;
  249. procedure SetCategory(AValue : Byte);
  250. function GetWhiteSpace : Boolean;inline;
  251. procedure SetWhiteSpace(AValue : Boolean);
  252. function GetHangulSyllable : Boolean;inline;
  253. procedure SetHangulSyllable(AValue : Boolean);
  254. function GetNumericValue: Double;inline;
  255. function GetUnifiedIdeograph : Boolean;inline;
  256. public //Shortned names
  257. C : Byte; //CategoryData
  258. C3 : Byte; //Canonical Combining Class
  259. N : Byte; //NumericIndex
  260. UC : UInt24; //SimpleUpperCase
  261. LC : UInt24; //SimpleLowerCase
  262. D : SmallInt; //DecompositionID
  263. public
  264. property CategoryData : Byte read C write C;
  265. property NumericIndex : Byte read N write N;
  266. property SimpleUpperCase : UInt24 read UC write UC;
  267. property SimpleLowerCase : UInt24 read LC write LC;
  268. property DecompositionID : SmallInt read D write D;
  269. public
  270. property Category : Byte read GetCategory write SetCategory;
  271. property WhiteSpace : Boolean read GetWhiteSpace write SetWhiteSpace;
  272. property HangulSyllable : Boolean read GetHangulSyllable write SetHangulSyllable;
  273. property UnifiedIdeograph : Boolean read GetUnifiedIdeograph;
  274. property NumericValue : Double read GetNumericValue;
  275. end;
  276. type
  277. TUCA_PropWeights = packed record
  278. Weights : array[0..2] of Word;
  279. end;
  280. PUCA_PropWeights = ^TUCA_PropWeights;
  281. TUCA_PropItemContextRec = packed record
  282. public
  283. CodePointCount : Byte;
  284. WeightCount : Byte;
  285. public
  286. function GetCodePoints() : PUInt24;inline;
  287. function GetWeights() : PUCA_PropWeights;inline;
  288. end;
  289. PUCA_PropItemContextRec = ^TUCA_PropItemContextRec;
  290. PUCA_PropItemContextTreeNodeRec = ^TUCA_PropItemContextTreeNodeRec;
  291. TUCA_PropItemContextTreeNodeRec = packed record
  292. public
  293. Left : Word;
  294. Right : Word;
  295. Data : TUCA_PropItemContextRec;
  296. public
  297. function GetLeftNode() : PUCA_PropItemContextTreeNodeRec;inline;
  298. function GetRightNode() : PUCA_PropItemContextTreeNodeRec;inline;
  299. end;
  300. { TUCA_PropItemContextTreeRec }
  301. TUCA_PropItemContextTreeRec = packed record
  302. public
  303. Size : UInt24;
  304. public
  305. function GetData:PUCA_PropItemContextTreeNodeRec;inline;
  306. property Data : PUCA_PropItemContextTreeNodeRec read GetData;
  307. function Find(
  308. const AChars : PUInt24;
  309. const ACharCount : Integer;
  310. out ANode : PUCA_PropItemContextTreeNodeRec
  311. ) : Boolean;
  312. end;
  313. PUCA_PropItemContextTreeRec = ^TUCA_PropItemContextTreeRec;
  314. { TUCA_PropItemRec }
  315. TUCA_PropItemRec = packed record
  316. private
  317. const FLAG_VALID = 0;
  318. const FLAG_CODEPOINT = 1;
  319. const FLAG_CONTEXTUAL = 2;
  320. const FLAG_DELETION = 3;
  321. const FLAG_COMPRESS_WEIGHT_1 = 6;
  322. const FLAG_COMPRESS_WEIGHT_2 = 7;
  323. private
  324. function GetCodePoint() : UInt24;inline;
  325. public
  326. WeightLength : Byte;
  327. ChildCount : Byte;
  328. Size : Word;
  329. Flags : Byte;
  330. public
  331. function HasCodePoint() : Boolean;inline;
  332. property CodePoint : UInt24 read GetCodePoint;
  333. //Weights : array[0..WeightLength] of TUCA_PropWeights;
  334. function IsValid() : Boolean;inline;
  335. //function GetWeightArray() : PUCA_PropWeights;inline;
  336. procedure GetWeightArray(ADest : PUCA_PropWeights);
  337. function GetSelfOnlySize() : Cardinal;inline;
  338. function GetContextual() : Boolean;inline;
  339. property Contextual : Boolean read GetContextual;
  340. function GetContext() : PUCA_PropItemContextTreeRec;
  341. function IsDeleted() : Boolean;inline;
  342. function IsWeightCompress_1() : Boolean;inline;
  343. function IsWeightCompress_2() : Boolean;inline;
  344. end;
  345. PUCA_PropItemRec = ^TUCA_PropItemRec;
  346. TUCA_VariableKind = (
  347. ucaShifted, ucaNonIgnorable, ucaBlanked, ucaShiftedTrimmed,
  348. ucaIgnoreSP // This one is not implemented !
  349. );
  350. TCollationName = array[0..(128-1)] of Byte;
  351. TCollationVersion = TCollationName;
  352. PUCA_DataBook = ^TUCA_DataBook;
  353. TUCA_DataBook = record
  354. public
  355. Base : PUCA_DataBook;
  356. Version : TCollationVersion;
  357. CollationName : TCollationName;
  358. VariableWeight : TUCA_VariableKind;
  359. Backwards : array[0..3] of Boolean;
  360. BMP_Table1 : PByte;
  361. BMP_Table2 : PUInt24;
  362. OBMP_Table1 : PWord;
  363. OBMP_Table2 : PUInt24;
  364. PropCount : Integer;
  365. Props : PUCA_PropItemRec;
  366. VariableLowLimit : Word;
  367. VariableHighLimit : Word;
  368. NoNormalization : Boolean;
  369. ComparisonStrength : Byte;
  370. Dynamic : Boolean;
  371. public
  372. function IsVariable(const AWeight : PUCA_PropWeights) : Boolean; inline;
  373. end;
  374. TUnicodeStringArray = array of UnicodeString;
  375. TCollationTableItem = record
  376. Collation : PUCA_DataBook;
  377. Aliases : TUnicodeStringArray;
  378. end;
  379. PCollationTableItem = ^TCollationTableItem;
  380. TCollationTableItemArray = array of TCollationTableItem;
  381. { TCollationTable }
  382. TCollationTable = record
  383. private
  384. FItems : TCollationTableItemArray;
  385. FCount : Integer;
  386. private
  387. function GetCapacity : Integer;
  388. function GetCount : Integer;
  389. function GetItem(const AIndex : Integer) : PCollationTableItem;
  390. procedure Grow();
  391. procedure ClearItem(AItem : PCollationTableItem);
  392. procedure AddAlias(
  393. AItem : PCollationTableItem;
  394. AAlias : UnicodeString
  395. );overload;
  396. public
  397. class function NormalizeName(AName : UnicodeString) : UnicodeString;static;
  398. procedure Clear();
  399. function IndexOf(AName : UnicodeString) : Integer;overload;
  400. function IndexOf(ACollation : PUCA_DataBook) : Integer;overload;
  401. function Find(AName : UnicodeString) : PCollationTableItem;overload;
  402. function Find(ACollation : PUCA_DataBook) : PCollationTableItem;overload;
  403. function Add(ACollation : PUCA_DataBook) : Integer;
  404. function AddAlias(AName, AAlias : UnicodeString) : Boolean;overload;
  405. function Remove(AIndex : Integer) : PUCA_DataBook;
  406. property Item[const AIndex : Integer] : PCollationTableItem read GetItem;default;
  407. property Count : Integer read GetCount;
  408. property Capacity : Integer read GetCapacity;
  409. end;
  410. TCollationField = (
  411. BackWard, VariableLowLimit, VariableHighLimit, Alternate, Normalization,
  412. Strength
  413. );
  414. TCollationFields = set of TCollationField;
  415. const
  416. ROOT_COLLATION_NAME = 'DUCET';
  417. ERROR_INVALID_CODEPOINT_SEQUENCE = 1;
  418. procedure FromUCS4(const AValue : UCS4Char; out AHighS, ALowS : UnicodeChar);
  419. function ToUCS4(const AHighS, ALowS : UnicodeChar) : UCS4Char;inline;
  420. function UnicodeIsSurrogatePair(
  421. const AHighSurrogate,
  422. ALowSurrogate : UnicodeChar
  423. ) : Boolean;inline;
  424. function UnicodeIsHighSurrogate(const AValue : UnicodeChar) : Boolean;inline;
  425. function UnicodeIsLowSurrogate(const AValue : UnicodeChar) : Boolean;inline;
  426. function UnicodeToUpper(
  427. const AString : UnicodeString;
  428. const AIgnoreInvalidSequence : Boolean;
  429. out AResultString : UnicodeString
  430. ) : Integer;
  431. function UnicodeToLower(
  432. const AString : UnicodeString;
  433. const AIgnoreInvalidSequence : Boolean;
  434. out AResultString : UnicodeString
  435. ) : Integer;
  436. function GetProps(const ACodePoint : Word) : PUC_Prop;overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  437. function GetProps(const AHighS, ALowS : UnicodeChar): PUC_Prop;overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  438. function GetProps(const ACodePoint : Cardinal) : PUC_Prop;overload;inline;
  439. function GetPropUCA(const AHighS, ALowS : UnicodeChar; const ABook : PUCA_DataBook): PUCA_PropItemRec; overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  440. function GetPropUCA(const AChar : UnicodeChar; const ABook : PUCA_DataBook) : PUCA_PropItemRec; overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  441. function NormalizeNFD(const AString : UnicodeString) : UnicodeString;inline;overload;
  442. function NormalizeNFD(const AStr : PUnicodeChar; ALength : SizeInt) : UnicodeString;overload;
  443. procedure CanonicalOrder(var AString : UnicodeString);inline;overload;
  444. procedure CanonicalOrder(AStr : PUnicodeChar; const ALength : SizeInt);overload;
  445. type
  446. TUCASortKeyItem = Word;
  447. TUCASortKey = array of TUCASortKeyItem;
  448. TCategoryMask = set of 0..31;
  449. const
  450. DEFAULT_UCA_COMPARISON_STRENGTH = 3;
  451. function ComputeSortKey(
  452. const AString : UnicodeString;
  453. const ACollation : PUCA_DataBook
  454. ) : TUCASortKey;inline;overload;
  455. function ComputeSortKey(
  456. const AStr : PUnicodeChar;
  457. const ALength : SizeInt;
  458. const ACollation : PUCA_DataBook
  459. ) : TUCASortKey;overload;
  460. function CompareSortKey(const A, B : TUCASortKey) : Integer;overload;
  461. function CompareSortKey(const A : TUCASortKey; const B : array of Word) : Integer;overload;
  462. function IncrementalCompareString(
  463. const AStrA : PUnicodeChar;
  464. const ALengthA : SizeInt;
  465. const AStrB : PUnicodeChar;
  466. const ALengthB : SizeInt;
  467. const ACollation : PUCA_DataBook
  468. ) : Integer;overload;
  469. function IncrementalCompareString(
  470. const AStrA,
  471. AStrB : UnicodeString;
  472. const ACollation : PUCA_DataBook
  473. ) : Integer;inline;overload;
  474. function FilterString(
  475. const AStr : PUnicodeChar;
  476. const ALength : SizeInt;
  477. const AExcludedMask : TCategoryMask
  478. ) : UnicodeString;overload;
  479. function FilterString(
  480. const AStr : UnicodeString;
  481. const AExcludedMask : TCategoryMask
  482. ) : UnicodeString;overload;inline;
  483. function RegisterCollation(const ACollation : PUCA_DataBook) : Boolean;overload;
  484. function RegisterCollation(
  485. const ACollation : PUCA_DataBook;
  486. const AAliasList : array of UnicodeString
  487. ) : Boolean;overload;
  488. function RegisterCollation(
  489. ADirectory, ALanguage : UnicodeString
  490. ) : Boolean;overload;
  491. function AddAliasCollation(
  492. ACollation : PUCA_DataBook;
  493. AALias : UnicodeString
  494. ) : Boolean;
  495. function UnregisterCollation(AName : UnicodeString): Boolean;
  496. procedure UnregisterCollations(const AFreeDynamicCollations : Boolean);
  497. function FindCollation(AName : UnicodeString): PUCA_DataBook;overload;
  498. function FindCollation(const AIndex : Integer): PUCA_DataBook;overload;
  499. function GetCollationCount() : Integer;
  500. procedure PrepareCollation(
  501. ACollation : PUCA_DataBook;
  502. const ABaseName : UnicodeString;
  503. const AChangedFields : TCollationFields
  504. );
  505. function LoadCollation(
  506. const AData : Pointer;
  507. const ADataLength : Integer;
  508. var AAliases : TUnicodeStringArray
  509. ) : PUCA_DataBook;overload;
  510. function LoadCollation(
  511. const AData : Pointer;
  512. const ADataLength : Integer
  513. ) : PUCA_DataBook;overload;
  514. function LoadCollation(
  515. const AFileName : UnicodeString;
  516. var AAliases : TUnicodeStringArray
  517. ) : PUCA_DataBook;overload;
  518. function LoadCollation(
  519. const AFileName : UnicodeString
  520. ) : PUCA_DataBook;overload;
  521. function LoadCollation(
  522. const ADirectory,
  523. ALanguage : UnicodeString;
  524. var AAliases : TUnicodeStringArray
  525. ) : PUCA_DataBook;overload;
  526. function LoadCollation(
  527. const ADirectory,
  528. ALanguage : UnicodeString
  529. ) : PUCA_DataBook;overload;
  530. procedure FreeCollation(AItem : PUCA_DataBook);
  531. type
  532. TSetOfByte = set of Byte;
  533. function BytesToString(
  534. const ABytes : array of Byte;
  535. const AValideChars : TSetOfByte
  536. ) : UnicodeString;
  537. function BytesToName(
  538. const ABytes : array of Byte
  539. ) : UnicodeString;
  540. type
  541. TEndianKind = (Little, Big);
  542. const
  543. ENDIAN_SUFFIX : array[TEndianKind] of UnicodeString = ('le','be');
  544. {$IFDEF ENDIAN_LITTLE}
  545. ENDIAN_NATIVE = TEndianKind.Little;
  546. ENDIAN_NON_NATIVE = TEndianKind.Big;
  547. {$ENDIF ENDIAN_LITTLE}
  548. {$IFDEF ENDIAN_BIG}
  549. ENDIAN_NATIVE = TEndianKind.Big;
  550. ENDIAN_NON_NATIVE = TEndianKind.Little;
  551. {$ENDIF ENDIAN_BIG}
  552. resourcestring
  553. SCollationNotFound = 'Collation not found : "%s".';
  554. implementation
  555. type
  556. TCardinalRec = packed record
  557. {$ifdef ENDIAN_LITTLE}
  558. byte0, byte1, byte2, byte3 : Byte;
  559. {$else ENDIAN_LITTLE}
  560. byte3, byte2, byte1, byte0 : Byte;
  561. {$endif ENDIAN_LITTLE}
  562. end;
  563. TWordRec = packed record
  564. {$ifdef ENDIAN_LITTLE}
  565. byte0, byte1 : Byte;
  566. {$else ENDIAN_LITTLE}
  567. byte1, byte0 : Byte;
  568. {$endif ENDIAN_LITTLE}
  569. end;
  570. const
  571. BYTES_OF_VALID_NAME_CHARS : set of Byte = [
  572. Ord('a')..Ord('z'), Ord('A')..Ord('Z'), Ord('-'),Ord('_')
  573. ];
  574. function BytesToString(
  575. const ABytes : array of Byte;
  576. const AValideChars : TSetOfByte
  577. ) : UnicodeString;
  578. var
  579. c, i, rl : Integer;
  580. pr : PWord;
  581. begin
  582. rl := 0;
  583. c := Length(ABytes);
  584. if (c > 0) then begin
  585. for i := 0 to c-1 do begin
  586. if not(ABytes[i] in AValideChars) then
  587. break;
  588. rl := rl+1;
  589. end;
  590. end;
  591. SetLength(Result,rl);
  592. if (rl > 0) then begin
  593. pr := PWord(@Result[1]);
  594. for i := 0 to rl-1 do begin
  595. pr^ := ABytes[i];
  596. Inc(pr);
  597. end;
  598. end;
  599. end;
  600. function BytesToName(
  601. const ABytes : array of Byte
  602. ) : UnicodeString;
  603. begin
  604. Result := BytesToString(ABytes,BYTES_OF_VALID_NAME_CHARS);
  605. end;
  606. { TCollationTable }
  607. function TCollationTable.GetCapacity : Integer;
  608. begin
  609. Result := Length(FItems);
  610. end;
  611. function TCollationTable.GetCount : Integer;
  612. begin
  613. if (FCount < 0) or (Length(FItems) < 1) or (FCount > Length(FItems)) then
  614. FCount := 0;
  615. Result := FCount;
  616. end;
  617. function TCollationTable.GetItem(const AIndex : Integer) : PCollationTableItem;
  618. begin
  619. if (AIndex < 0) or (AIndex >= Count) then
  620. Error(reRangeError);
  621. Result := @FItems[AIndex];
  622. end;
  623. procedure TCollationTable.Grow();
  624. var
  625. c0, c1 : Integer;
  626. begin
  627. c0 := Length(FItems);
  628. if (c0 < 1) then begin
  629. c0 := 1;
  630. if (FCount < 0) then
  631. FCount := 0;
  632. end;
  633. c1 := 2*c0;
  634. c0 := Length(FItems);
  635. SetLength(FItems,c1);
  636. FillChar(FItems[c0],((c1-c0)*SizeOf(TCollationTableItem)),#0);
  637. end;
  638. procedure TCollationTable.ClearItem(AItem : PCollationTableItem);
  639. begin
  640. if (AItem = nil) then
  641. exit;
  642. AItem^.Collation := nil;
  643. SetLength(AItem^.Aliases,0);
  644. end;
  645. procedure TCollationTable.AddAlias(
  646. AItem : PCollationTableItem;
  647. AAlias : UnicodeString
  648. );
  649. var
  650. n : UnicodeString;
  651. c, i : Integer;
  652. begin
  653. n := NormalizeName(AAlias);
  654. if (n = '') then
  655. exit;
  656. c := Length(AItem^.Aliases);
  657. if (c > 0) then begin
  658. for i := 0 to c-1 do begin
  659. if (AItem^.Aliases[i] = n) then
  660. exit;
  661. end;
  662. end;
  663. SetLength(AItem^.Aliases,(c+1));
  664. AItem^.Aliases[c] := n;
  665. end;
  666. class function TCollationTable.NormalizeName(
  667. AName : UnicodeString
  668. ) : UnicodeString;
  669. var
  670. r : UnicodeString;
  671. c, i, rl : Integer;
  672. cx : Word;
  673. begin
  674. c := Length(AName);
  675. rl := 0;
  676. SetLength(r,c);
  677. for i := 1 to c do begin
  678. case Ord(AName[i]) of
  679. Ord('a')..Ord('z') : cx := Ord(AName[i]);
  680. Ord('A')..Ord('Z') : cx := Ord(AName[i])+(Ord('a')-Ord('A'));
  681. Ord('0')..Ord('9'),
  682. Ord('-'), Ord('_') : cx := Ord(AName[i]);
  683. else
  684. cx := 0;
  685. end;
  686. if (cx > 0) then begin
  687. rl := rl+1;
  688. r[rl] := UnicodeChar(cx);
  689. end;
  690. end;
  691. SetLength(r,rl);
  692. Result := r;
  693. end;
  694. procedure TCollationTable.Clear();
  695. var
  696. p : PCollationTableItem;
  697. i : Integer;
  698. begin
  699. if (Count < 1) then
  700. exit;
  701. p := @FItems[0];
  702. for i := 0 to Count-1 do begin;
  703. ClearItem(p);
  704. Inc(p);
  705. end;
  706. FCount := 0;
  707. end;
  708. function TCollationTable.IndexOf(AName : UnicodeString) : Integer;
  709. var
  710. c, i, k : Integer;
  711. p : PCollationTableItem;
  712. n : UnicodeString;
  713. begin
  714. c := Count;
  715. if (c > 0) then begin
  716. // Names
  717. n := NormalizeName(AName);
  718. p := @FItems[0];
  719. for i := 0 to c-1 do begin
  720. if (Length(p^.Aliases) > 0) and (p^.Aliases[0] = n) then
  721. exit(i);
  722. Inc(p);
  723. end;
  724. // Aliases
  725. p := @FItems[0];
  726. for i := 0 to c-1 do begin
  727. if (Length(p^.Aliases) > 1) then begin
  728. for k := 1 to Length(p^.Aliases)-1 do begin
  729. if (p^.Aliases[k] = n) then
  730. exit(i);
  731. end;
  732. end;
  733. Inc(p);
  734. end;
  735. end;
  736. Result := -1;
  737. end;
  738. function TCollationTable.IndexOf(ACollation : PUCA_DataBook) : Integer;
  739. var
  740. c, i : Integer;
  741. p : PCollationTableItem;
  742. begin
  743. c := Count;
  744. if (c > 0) then begin
  745. p := @FItems[0];
  746. for i := 0 to c-1 do begin
  747. if (p^.Collation = ACollation) then
  748. exit(i);
  749. Inc(p);
  750. end;
  751. end;
  752. Result := -1;
  753. end;
  754. function TCollationTable.Find(AName : UnicodeString) : PCollationTableItem;
  755. var
  756. i : Integer;
  757. begin
  758. i := IndexOf(AName);
  759. if (i >= 0) then
  760. Result := @FItems[i]
  761. else
  762. Result := nil;
  763. end;
  764. function TCollationTable.Find(ACollation : PUCA_DataBook) : PCollationTableItem;
  765. var
  766. i : Integer;
  767. begin
  768. i := IndexOf(ACollation);
  769. if (i >= 0) then
  770. Result := @FItems[i]
  771. else
  772. Result := nil;
  773. end;
  774. function TCollationTable.Add(ACollation : PUCA_DataBook) : Integer;
  775. var
  776. c : Integer;
  777. p : PCollationTableItem;
  778. begin
  779. Result := IndexOf(ACollation);
  780. if (Result < 0) then begin
  781. c := Count;
  782. if (c >= Capacity) then
  783. Grow();
  784. p := @FItems[c];
  785. p^.Collation := ACollation;
  786. SetLength(p^.Aliases,1);
  787. p^.Aliases[0] := NormalizeName(BytesToName(ACollation^.CollationName));
  788. FCount := FCount+1;
  789. Result := c;
  790. end;
  791. end;
  792. function TCollationTable.AddAlias(AName, AAlias : UnicodeString) : Boolean;
  793. var
  794. p : PCollationTableItem;
  795. begin
  796. p := Find(AName);
  797. Result := (p <> nil);
  798. if Result then
  799. AddAlias(p,AAlias);
  800. end;
  801. function TCollationTable.Remove(AIndex : Integer) : PUCA_DataBook;
  802. var
  803. p, q : PCollationTableItem;
  804. c, i : Integer;
  805. begin
  806. if (AIndex < 0) or (AIndex >= Count) then
  807. Error(reRangeError);
  808. p := @FItems[AIndex];
  809. Result := p^.Collation;
  810. ClearItem(p);
  811. c := Count;
  812. if (AIndex < (c-1)) then begin
  813. for i := AIndex+1 to c-1 do begin
  814. q := p;
  815. Inc(p);
  816. Move(p^,q^,SizeOf(TCollationTableItem));
  817. end;
  818. FillChar(p^,SizeOf(TCollationTableItem),#0);
  819. end;
  820. FCount := FCount-1;
  821. end;
  822. { TUInt24Rec }
  823. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Cardinal;
  824. begin
  825. TCardinalRec(Result).byte0 := a.byte0;
  826. TCardinalRec(Result).byte1 := a.byte1;
  827. TCardinalRec(Result).byte2 := a.byte2;
  828. TCardinalRec(Result).byte3 := 0;
  829. end;
  830. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : LongInt;
  831. begin
  832. Result := Cardinal(a);
  833. end;
  834. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Word;
  835. begin
  836. {$IFOPT R+}
  837. if (a > $FFFF) then
  838. Error(reIntOverflow);
  839. {$ENDIF R+}
  840. TWordRec(Result).byte0 := a.byte0;
  841. TWordRec(Result).byte1 := a.byte1;
  842. end;
  843. class operator TUInt24Rec.Implicit(a : TUInt24Rec) : Byte;
  844. begin
  845. {$IFOPT R+}
  846. if (a > $FF) then
  847. Error(reIntOverflow);
  848. {$ENDIF R+}
  849. Result := a.byte0;
  850. end;
  851. class operator TUInt24Rec.Implicit(a : Cardinal) : TUInt24Rec;
  852. begin
  853. {$IFOPT R+}
  854. if (a > $FFFFFF) then
  855. Error(reIntOverflow);
  856. {$ENDIF R+}
  857. Result.byte0 := TCardinalRec(a).byte0;
  858. Result.byte1 := TCardinalRec(a).byte1;
  859. Result.byte2 := TCardinalRec(a).byte2;
  860. end;
  861. class operator TUInt24Rec.Equal(a, b : TUInt24Rec) : Boolean;
  862. begin
  863. Result := (a.byte0 = b.byte0) and (a.byte1 = b.byte1) and (a.byte2 = b.byte2);
  864. end;
  865. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Cardinal) : Boolean;
  866. begin
  867. Result := (TCardinalRec(b).byte3 = 0) and
  868. (a.byte0 = TCardinalRec(b).byte0) and
  869. (a.byte1 = TCardinalRec(b).byte1) and
  870. (a.byte2 = TCardinalRec(b).byte2);
  871. end;
  872. class operator TUInt24Rec.Equal(a : Cardinal; b : TUInt24Rec) : Boolean;
  873. begin
  874. Result := (b = a);
  875. end;
  876. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : LongInt) : Boolean;
  877. begin
  878. Result := (LongInt(a) = b);
  879. end;
  880. class operator TUInt24Rec.Equal(a : LongInt; b : TUInt24Rec) : Boolean;
  881. begin
  882. Result := (b = a);
  883. end;
  884. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Word) : Boolean;
  885. begin
  886. Result := (a.byte2 = 0) and
  887. (a.byte0 = TWordRec(b).byte0) and
  888. (a.byte1 = TWordRec(b).byte1);
  889. end;
  890. class operator TUInt24Rec.Equal(a : Word; b : TUInt24Rec) : Boolean;
  891. begin
  892. Result := (b = a);
  893. end;
  894. class operator TUInt24Rec.Equal(a : TUInt24Rec; b : Byte) : Boolean;
  895. begin
  896. Result := (a.byte2 = 0) and
  897. (a.byte1 = 0) and
  898. (a.byte0 = b);
  899. end;
  900. class operator TUInt24Rec.Equal(a : Byte; b : TUInt24Rec) : Boolean;
  901. begin
  902. Result := (b = a);
  903. end;
  904. class operator TUInt24Rec.NotEqual(a, b : TUInt24Rec) : Boolean;
  905. begin
  906. Result := (a.byte0 <> b.byte0) or (a.byte1 <> b.byte1) or (a.byte2 <> b.byte2);
  907. end;
  908. class operator TUInt24Rec.NotEqual(a : TUInt24Rec; b : Cardinal) : Boolean;
  909. begin
  910. Result := (TCardinalRec(b).byte3 <> 0) or
  911. (a.byte0 <> TCardinalRec(b).byte0) or
  912. (a.byte1 <> TCardinalRec(b).byte1) or
  913. (a.byte2 <> TCardinalRec(b).byte2);
  914. end;
  915. class operator TUInt24Rec.NotEqual(a : Cardinal; b : TUInt24Rec) : Boolean;
  916. begin
  917. Result := (b <> a);
  918. end;
  919. class operator TUInt24Rec.GreaterThan(a, b: TUInt24Rec): Boolean;
  920. begin
  921. Result := (a.byte2 > b.byte2) or
  922. ((a.byte2 = b.byte2) and (a.byte1 > b.byte1)) or
  923. ((a.byte2 = b.byte2) and (a.byte1 = b.byte1) and (a.byte0 > b.byte0));
  924. end;
  925. class operator TUInt24Rec.GreaterThan(a: TUInt24Rec; b: Cardinal): Boolean;
  926. begin
  927. Result := Cardinal(a) > b;
  928. end;
  929. class operator TUInt24Rec.GreaterThan(a: Cardinal; b: TUInt24Rec): Boolean;
  930. begin
  931. Result := a > Cardinal(b);
  932. end;
  933. class operator TUInt24Rec.GreaterThanOrEqual(a, b: TUInt24Rec): Boolean;
  934. begin
  935. Result := (a.byte2 > b.byte2) or
  936. ((a.byte2 = b.byte2) and (a.byte1 > b.byte1)) or
  937. ((a.byte2 = b.byte2) and (a.byte1 = b.byte1) and (a.byte0 >= b.byte0));
  938. end;
  939. class operator TUInt24Rec.GreaterThanOrEqual(a: TUInt24Rec; b: Cardinal): Boolean;
  940. begin
  941. Result := Cardinal(a) >= b;
  942. end;
  943. class operator TUInt24Rec.GreaterThanOrEqual(a: Cardinal; b: TUInt24Rec): Boolean;
  944. begin
  945. Result := a >= Cardinal(b);
  946. end;
  947. class operator TUInt24Rec.LessThan(a, b: TUInt24Rec): Boolean;
  948. begin
  949. Result := (b > a);
  950. end;
  951. class operator TUInt24Rec.LessThan(a: TUInt24Rec; b: Cardinal): Boolean;
  952. begin
  953. Result := Cardinal(a) < b;
  954. end;
  955. class operator TUInt24Rec.LessThan(a: Cardinal; b: TUInt24Rec): Boolean;
  956. begin
  957. Result := a < Cardinal(b);
  958. end;
  959. class operator TUInt24Rec.LessThanOrEqual(a, b: TUInt24Rec): Boolean;
  960. begin
  961. Result := (b >= a);
  962. end;
  963. class operator TUInt24Rec.LessThanOrEqual(a: TUInt24Rec; b: Cardinal): Boolean;
  964. begin
  965. Result := Cardinal(a) <= b;
  966. end;
  967. class operator TUInt24Rec.LessThanOrEqual(a: Cardinal; b: TUInt24Rec): Boolean;
  968. begin
  969. Result := a <= Cardinal(b);
  970. end;
  971. type
  972. TBitOrder = 0..7;
  973. function IsBitON(const AData : Byte; const ABit : TBitOrder) : Boolean ;inline;
  974. begin
  975. Result := ( ( AData and ( 1 shl ABit ) ) <> 0 );
  976. end;
  977. procedure SetBit(var AData : Byte; const ABit : TBitOrder; const AValue : Boolean);inline;
  978. begin
  979. if AValue then
  980. AData := AData or (1 shl (ABit mod 8))
  981. else
  982. AData := AData and ( not ( 1 shl ( ABit mod 8 ) ) );
  983. end;
  984. {$IFNDEF HAS_COMPARE_BYTE}
  985. function CompareByte(const A, B; ALength : SizeInt):SizeInt;
  986. var
  987. pa, pb : PByte;
  988. i : Integer;
  989. begin
  990. if (ALength < 1) then
  991. exit(0);
  992. pa := PByte(@A);
  993. pb := PByte(@B);
  994. if (pa = pb) then
  995. exit(0);
  996. for i := 1 to ALength do begin
  997. if (pa^ <> pb^) then
  998. exit(i);
  999. pa := pa+1;
  1000. pb := pb+1;
  1001. end;
  1002. Result := 0;
  1003. end;
  1004. {$ENDIF HAS_COMPARE_BYTE}
  1005. function IndexInArrayDWord(const ABuffer : array of DWord; AItem : DWord) : SizeInt;
  1006. var
  1007. c, i : Integer;
  1008. p : PDWord;
  1009. begin
  1010. Result := -1;
  1011. c := Length(ABuffer);
  1012. if (c < 1) then
  1013. exit;
  1014. p := @ABuffer[Low(ABuffer)];
  1015. for i := 1 to c do begin
  1016. if (p^ = AItem) then begin
  1017. Result := i-1;
  1018. break;
  1019. end;
  1020. p := p+1;
  1021. end;
  1022. end;
  1023. var
  1024. CollationTable : TCollationTable;
  1025. function IndexOfCollation(AName : UnicodeString) : Integer;
  1026. begin
  1027. Result := CollationTable.IndexOf(AName);
  1028. end;
  1029. function RegisterCollation(const ACollation : PUCA_DataBook) : Boolean;
  1030. begin
  1031. Result := RegisterCollation(ACollation,[]);
  1032. end;
  1033. function RegisterCollation(
  1034. const ACollation : PUCA_DataBook;
  1035. const AAliasList : array of UnicodeString
  1036. ) : Boolean;
  1037. var
  1038. i : Integer;
  1039. p : PCollationTableItem;
  1040. begin
  1041. Result := (CollationTable.IndexOf(BytesToName(ACollation^.CollationName)) = -1);
  1042. if Result then begin
  1043. i := CollationTable.Add(ACollation);
  1044. if (Length(AAliasList) > 0) then begin
  1045. p := CollationTable[i];
  1046. for i := Low(AAliasList) to High(AAliasList) do
  1047. CollationTable.AddAlias(p,AAliasList[i]);
  1048. end;
  1049. end;
  1050. end;
  1051. function RegisterCollation(ADirectory, ALanguage : UnicodeString) : Boolean;
  1052. var
  1053. cl : PUCA_DataBook;
  1054. al : TUnicodeStringArray;
  1055. begin
  1056. al := nil;
  1057. cl := LoadCollation(ADirectory,ALanguage,al);
  1058. if (cl = nil) then
  1059. exit(False);
  1060. try
  1061. Result := RegisterCollation(cl,al);
  1062. except
  1063. FreeCollation(cl);
  1064. raise;
  1065. end;
  1066. if not Result then
  1067. FreeCollation(cl);
  1068. end;
  1069. function AddAliasCollation(
  1070. ACollation : PUCA_DataBook;
  1071. AALias : UnicodeString
  1072. ) : Boolean;
  1073. var
  1074. p : PCollationTableItem;
  1075. begin
  1076. Result := False;
  1077. if (ACollation <> nil) then begin
  1078. p := CollationTable.Find(ACollation);
  1079. if (p <> nil) then begin
  1080. CollationTable.AddAlias(p,AALias);
  1081. Result := True;
  1082. end;
  1083. end;
  1084. end;
  1085. function UnregisterCollation(AName : UnicodeString): Boolean;
  1086. var
  1087. i : Integer;
  1088. begin
  1089. i := CollationTable.IndexOf(AName);
  1090. Result := (i >= 0);
  1091. if Result then
  1092. CollationTable.Remove(i);
  1093. end;
  1094. procedure UnregisterCollations(const AFreeDynamicCollations : Boolean);
  1095. var
  1096. i : Integer;
  1097. p : PCollationTableItem;
  1098. begin
  1099. if AFreeDynamicCollations then begin
  1100. for i := 0 to CollationTable.Count-1 do begin
  1101. p := CollationTable[i];
  1102. if p^.Collation.Dynamic then begin
  1103. FreeCollation(p^.Collation);
  1104. p^.Collation := nil;
  1105. end;
  1106. end;
  1107. end;
  1108. CollationTable.Clear();
  1109. end;
  1110. function FindCollation(AName : UnicodeString): PUCA_DataBook;overload;
  1111. var
  1112. p : PCollationTableItem;
  1113. begin
  1114. p := CollationTable.Find(AName);
  1115. if (p <> nil) then
  1116. Result := p^.Collation
  1117. else
  1118. Result := nil;
  1119. end;
  1120. function GetCollationCount() : Integer;
  1121. begin
  1122. Result := CollationTable.Count;
  1123. end;
  1124. function FindCollation(const AIndex : Integer): PUCA_DataBook;overload;
  1125. var
  1126. p : PCollationTableItem;
  1127. begin
  1128. p := CollationTable[AIndex];
  1129. if (p <> nil) then
  1130. Result := p^.Collation
  1131. else
  1132. Result := nil;
  1133. end;
  1134. procedure PrepareCollation(
  1135. ACollation : PUCA_DataBook;
  1136. const ABaseName : UnicodeString;
  1137. const AChangedFields : TCollationFields
  1138. );
  1139. var
  1140. s : UnicodeString;
  1141. p, base : PUCA_DataBook;
  1142. begin
  1143. if (ABaseName <> '') then
  1144. s := ABaseName
  1145. else
  1146. s := ROOT_COLLATION_NAME;
  1147. p := ACollation;
  1148. base := FindCollation(s);
  1149. if (base = nil) then
  1150. Error(reCodesetConversion);
  1151. p^.Base := base;
  1152. if not(TCollationField.BackWard in AChangedFields) then
  1153. p^.Backwards := base^.Backwards;
  1154. if not(TCollationField.VariableLowLimit in AChangedFields) then
  1155. p^.VariableLowLimit := base^.VariableLowLimit;
  1156. if not(TCollationField.VariableHighLimit in AChangedFields) then
  1157. p^.VariableLowLimit := base^.VariableHighLimit;
  1158. if not(TCollationField.Alternate in AChangedFields) then
  1159. p^.VariableWeight := base^.VariableWeight;
  1160. if not(TCollationField.Normalization in AChangedFields) then
  1161. p^.NoNormalization := base^.NoNormalization;
  1162. if not(TCollationField.Strength in AChangedFields) then
  1163. p^.ComparisonStrength := base^.ComparisonStrength;
  1164. end;
  1165. type
  1166. TSerializedCollationHeader = packed record
  1167. Base : TCollationName;
  1168. Version : TCollationVersion;
  1169. CollationName : TCollationName;
  1170. CollationAliases : TCollationName; // ";" separated
  1171. VariableWeight : Byte;
  1172. Backwards : Byte;
  1173. BMP_Table1Length : DWord;
  1174. BMP_Table2Length : DWord;
  1175. OBMP_Table1Length : DWord;
  1176. OBMP_Table2Length : DWord;
  1177. PropCount : DWord;
  1178. VariableLowLimit : Word;
  1179. VariableHighLimit : Word;
  1180. NoNormalization : Byte;
  1181. Strength : Byte;
  1182. ChangedFields : Byte;
  1183. end;
  1184. PSerializedCollationHeader = ^TSerializedCollationHeader;
  1185. procedure FreeCollation(AItem : PUCA_DataBook);
  1186. var
  1187. h : PSerializedCollationHeader;
  1188. begin
  1189. if (AItem = nil) or not(AItem^.Dynamic) then
  1190. exit;
  1191. h := PSerializedCollationHeader(PtrUInt(AItem) + SizeOf(TUCA_DataBook));
  1192. if (AItem^.BMP_Table1 <> nil) then
  1193. FreeMem(AItem^.BMP_Table1,h^.BMP_Table1Length);
  1194. if (AItem^.BMP_Table2 <> nil) then
  1195. FreeMem(AItem^.BMP_Table2,h^.BMP_Table2Length);
  1196. if (AItem^.OBMP_Table1 <> nil) then
  1197. FreeMem(AItem^.OBMP_Table1,h^.OBMP_Table1Length);
  1198. if (AItem^.OBMP_Table2 <> nil) then
  1199. FreeMem(AItem^.OBMP_Table2,h^.OBMP_Table2Length);
  1200. if (AItem^.Props <> nil) then
  1201. FreeMem(AItem^.Props,h^.PropCount);
  1202. FreeMem(AItem,(SizeOf(TUCA_DataBook)+SizeOf(TSerializedCollationHeader)));
  1203. end;
  1204. function ParseAliases(AStr : UnicodeString) : TUnicodeStringArray;
  1205. var
  1206. r : TUnicodeStringArray;
  1207. c, k, i : Integer;
  1208. s : UnicodeString;
  1209. begin
  1210. SetLength(r,0);
  1211. c := Length(AStr);
  1212. k := 1;
  1213. for i := 1 to c do begin
  1214. if (AStr[i] <> ';') then begin
  1215. k := i;
  1216. break;
  1217. end;
  1218. end;
  1219. s := '';
  1220. for i := 1 to c do begin
  1221. if (AStr[i] = ';') then begin
  1222. s := Copy(AStr,k,(i-k));
  1223. end else if (i = c) then begin
  1224. s := Copy(AStr,k,(i+1-k));
  1225. end;
  1226. if (s <> '') then begin
  1227. SetLength(r,(Length(r)+1));
  1228. r[High(r)] := s;
  1229. s := '';
  1230. k := i+1;
  1231. end;
  1232. end;
  1233. Result := r;
  1234. end;
  1235. function LoadCollation(
  1236. const AData : Pointer;
  1237. const ADataLength : Integer;
  1238. var AAliases : TUnicodeStringArray
  1239. ) : PUCA_DataBook;
  1240. var
  1241. dataPointer : PByte;
  1242. readedLength : LongInt;
  1243. function ReadBuffer(ADest : Pointer; ALength : LongInt) : Boolean;
  1244. begin
  1245. Result := (readedLength + ALength) <= ADataLength;
  1246. if not result then
  1247. exit;
  1248. Move(dataPointer^,ADest^,ALength);
  1249. Inc(dataPointer,ALength);
  1250. readedLength := readedLength + ALength;
  1251. end;
  1252. var
  1253. r : PUCA_DataBook;
  1254. h : PSerializedCollationHeader;
  1255. cfs : TCollationFields;
  1256. i : Integer;
  1257. baseName, s : UnicodeString;
  1258. begin
  1259. Result := nil;
  1260. readedLength := 0;
  1261. AAliases := nil;
  1262. dataPointer := AData;
  1263. r := AllocMem((SizeOf(TUCA_DataBook)+SizeOf(TSerializedCollationHeader)));
  1264. try
  1265. h := PSerializedCollationHeader(PtrUInt(r) + SizeOf(TUCA_DataBook));
  1266. if not ReadBuffer(h,SizeOf(TSerializedCollationHeader)) then
  1267. exit;
  1268. r^.Version := h^.Version;
  1269. r^.CollationName := h^.CollationName;
  1270. r^.VariableWeight := TUCA_VariableKind(h^.VariableWeight);
  1271. r^.Backwards[0] := IsBitON(h^.Backwards,0);
  1272. r^.Backwards[1] := IsBitON(h^.Backwards,1);
  1273. r^.Backwards[2] := IsBitON(h^.Backwards,2);
  1274. r^.Backwards[3] := IsBitON(h^.Backwards,3);
  1275. if (h^.BMP_Table1Length > 0) then begin
  1276. r^.BMP_Table1 := GetMemory(h^.BMP_Table1Length);
  1277. if not ReadBuffer(r^.BMP_Table1,h^.BMP_Table1Length) then
  1278. exit;
  1279. end;
  1280. if (h^.BMP_Table2Length > 0) then begin
  1281. r^.BMP_Table2 := GetMemory(h^.BMP_Table2Length);
  1282. if not ReadBuffer(r^.BMP_Table2,h^.BMP_Table2Length) then
  1283. exit;
  1284. end;
  1285. if (h^.OBMP_Table1Length > 0) then begin
  1286. r^.OBMP_Table1 := GetMemory(h^.OBMP_Table1Length);
  1287. if not ReadBuffer(r^.OBMP_Table1,h^.OBMP_Table1Length) then
  1288. exit;
  1289. end;
  1290. if (h^.OBMP_Table2Length > 0) then begin
  1291. r^.OBMP_Table2 := GetMemory(h^.OBMP_Table2Length);
  1292. if not ReadBuffer(r^.OBMP_Table2,h^.OBMP_Table2Length) then
  1293. exit;
  1294. end;
  1295. r^.PropCount := h^.PropCount;
  1296. if (h^.PropCount > 0) then begin
  1297. r^.Props := GetMemory(h^.PropCount);
  1298. if not ReadBuffer(r^.Props,h^.PropCount) then
  1299. exit;
  1300. end;
  1301. r^.VariableLowLimit := h^.VariableLowLimit;
  1302. r^.VariableHighLimit := h^.VariableHighLimit;
  1303. r^.NoNormalization := (h^.NoNormalization <> 0);
  1304. r^.ComparisonStrength := h^.Strength;
  1305. cfs := [];
  1306. for i := Ord(Low(TCollationField)) to Ord(High(TCollationField)) do begin
  1307. if IsBitON(h^.ChangedFields,i) then
  1308. cfs := cfs + [TCollationField(i)];
  1309. end;
  1310. baseName := BytesToName(h^.Base);
  1311. if (baseName = '') then begin
  1312. if (BytesToName(h^.CollationName) <> ROOT_COLLATION_NAME) then
  1313. baseName := ROOT_COLLATION_NAME
  1314. else
  1315. baseName := '';
  1316. end;
  1317. if (baseName <> '') then
  1318. PrepareCollation(r,baseName,cfs);
  1319. s := BytesToString(h^.CollationAliases,(BYTES_OF_VALID_NAME_CHARS+[Ord(';')]));
  1320. if (s <> '') then
  1321. AAliases := ParseAliases(s);
  1322. r^.Dynamic := True;
  1323. Result := r;
  1324. except
  1325. FreeCollation(r);
  1326. raise;
  1327. end;
  1328. end;
  1329. function LoadCollation(
  1330. const AData : Pointer;
  1331. const ADataLength : Integer
  1332. ) : PUCA_DataBook;
  1333. var
  1334. al : TUnicodeStringArray;
  1335. begin
  1336. al := nil;
  1337. Result := LoadCollation(AData,ADataLength,al);
  1338. end;
  1339. {$IFDEF HAS_PUSH}
  1340. {$PUSH}
  1341. {$ENDIF HAS_PUSH}
  1342. {$IFNDEF HAS_PUSH}
  1343. {$IFOPT I+}
  1344. {$DEFINE I_PLUS}
  1345. {$ELSE}
  1346. {$UNDEF I_PLUS}
  1347. {$ENDIF}
  1348. {$ENDIF HAS_PUSH}
  1349. function LoadCollation(
  1350. const AFileName : UnicodeString;
  1351. var AAliases : TUnicodeStringArray
  1352. ) : PUCA_DataBook;
  1353. const
  1354. BLOCK_SIZE = 16*1024;
  1355. var
  1356. f : File of Byte;
  1357. locSize, locReaded, c : LongInt;
  1358. locBuffer : PByte;
  1359. locBlockSize : LongInt;
  1360. begin
  1361. Result := nil;
  1362. {$I-}
  1363. if (AFileName = '') then
  1364. exit;
  1365. Assign(f,AFileName);
  1366. Reset(f);
  1367. try
  1368. if (IOResult <> 0) then
  1369. exit;
  1370. locSize := FileSize(f);
  1371. if (locSize < SizeOf(TSerializedCollationHeader)) then
  1372. exit;
  1373. locBuffer := GetMemory(locSize);
  1374. try
  1375. locBlockSize := BLOCK_SIZE;
  1376. locReaded := 0;
  1377. while (locReaded < locSize) do begin
  1378. if (locBlockSize > (locSize-locReaded)) then
  1379. locBlockSize := locSize-locReaded;
  1380. BlockRead(f,locBuffer[locReaded],locBlockSize,c);
  1381. if (IOResult <> 0) or (c <= 0) then
  1382. exit;
  1383. locReaded := locReaded + c;
  1384. end;
  1385. Result := LoadCollation(locBuffer,locSize,AAliases);
  1386. finally
  1387. FreeMemory(locBuffer);
  1388. end;
  1389. finally
  1390. Close(f);
  1391. end;
  1392. end;
  1393. function LoadCollation(
  1394. const AFileName : UnicodeString
  1395. ) : PUCA_DataBook;
  1396. var
  1397. al : TUnicodeStringArray;
  1398. begin
  1399. al := nil;
  1400. Result := LoadCollation(AFileName,al);
  1401. end;
  1402. {$IFDEF HAS_PUSH}
  1403. {$POP}
  1404. {$ELSE}
  1405. {$IFDEF I_PLUS}
  1406. {$I+}
  1407. {$ELSE}
  1408. {$I-}
  1409. {$ENDIF}
  1410. {$ENDIF HAS_PUSH}
  1411. function LoadCollation(
  1412. const ADirectory,
  1413. ALanguage : UnicodeString;
  1414. var AAliases : TUnicodeStringArray
  1415. ) : PUCA_DataBook;
  1416. var
  1417. fileName : UnicodeString;
  1418. begin
  1419. fileName := ADirectory;
  1420. if (fileName <> '') then begin
  1421. if (fileName[Length(fileName)] <> DirectorySeparator) then
  1422. fileName := fileName + DirectorySeparator;
  1423. end;
  1424. fileName := fileName + 'collation_' + ALanguage + '_' + ENDIAN_SUFFIX[ENDIAN_NATIVE] + '.bco';
  1425. Result := LoadCollation(fileName,AAliases);
  1426. end;
  1427. function LoadCollation(
  1428. const ADirectory,
  1429. ALanguage : UnicodeString
  1430. ) : PUCA_DataBook;
  1431. var
  1432. al : TUnicodeStringArray;
  1433. begin
  1434. al := nil;
  1435. Result := LoadCollation(ADirectory,ALanguage,al);
  1436. end;
  1437. {$INCLUDE unicodedata.inc}
  1438. {$IFDEF ENDIAN_LITTLE}
  1439. {$INCLUDE unicodedata_le.inc}
  1440. {$ENDIF ENDIAN_LITTLE}
  1441. {$IFDEF ENDIAN_BIG}
  1442. {$INCLUDE unicodedata_be.inc}
  1443. {$ENDIF ENDIAN_BIG}
  1444. procedure FromUCS4(const AValue : UCS4Char; out AHighS, ALowS : UnicodeChar);
  1445. begin
  1446. AHighS := UnicodeChar((AValue - $10000) shr 10 + $d800);
  1447. ALowS := UnicodeChar((AValue - $10000) and $3ff + $dc00);
  1448. end;
  1449. function ToUCS4(const AHighS, ALowS : UnicodeChar) : UCS4Char;inline;
  1450. begin
  1451. Result := (UCS4Char(Word(AHighS)) - HIGH_SURROGATE_BEGIN) shl 10 +
  1452. (UCS4Char(Word(ALowS)) - LOW_SURROGATE_BEGIN) + UCS4_HALF_BASE;
  1453. end;
  1454. function UnicodeIsSurrogatePair(
  1455. const AHighSurrogate,
  1456. ALowSurrogate : UnicodeChar
  1457. ) : Boolean;
  1458. begin
  1459. Result :=
  1460. ( (Word(AHighSurrogate) >= HIGH_SURROGATE_BEGIN) and
  1461. (Word(AHighSurrogate) <= HIGH_SURROGATE_END)
  1462. ) and
  1463. ( (Word(ALowSurrogate) >= LOW_SURROGATE_BEGIN) and
  1464. (Word(ALowSurrogate) <= LOW_SURROGATE_END)
  1465. )
  1466. end;
  1467. function UnicodeIsHighSurrogate(const AValue : UnicodeChar) : Boolean;
  1468. begin
  1469. Result := (Word(AValue) >= HIGH_SURROGATE_BEGIN) and
  1470. (Word(AValue) <= HIGH_SURROGATE_END);
  1471. end;
  1472. function UnicodeIsLowSurrogate(const AValue : UnicodeChar) : Boolean;
  1473. begin
  1474. Result := (Word(AValue) >= LOW_SURROGATE_BEGIN) and
  1475. (Word(AValue) <= LOW_SURROGATE_END);
  1476. end;
  1477. function GetProps(const ACodePoint : Word) : PUC_Prop;overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  1478. begin
  1479. Result:=
  1480. @UC_PROP_ARRAY[
  1481. UC_TABLE_3[
  1482. UC_TABLE_2[UC_TABLE_1[hi(ACodePoint)]]
  1483. [lo(ACodePoint) shr 4]
  1484. ][lo(ACodePoint) and $F]
  1485. ]; {
  1486. @UC_PROP_ARRAY[
  1487. UC_TABLE_2[
  1488. (UC_TABLE_1[WordRec(ACodePoint).Hi] * 256) +
  1489. WordRec(ACodePoint).Lo
  1490. ]
  1491. ];}
  1492. end;
  1493. function GetProps(const AHighS, ALowS : UnicodeChar): PUC_Prop;overload;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  1494. begin
  1495. Result:=
  1496. @UC_PROP_ARRAY[
  1497. UCO_TABLE_3[
  1498. UCO_TABLE_2[UCO_TABLE_1[Word(AHighS)-HIGH_SURROGATE_BEGIN]]
  1499. [(Word(ALowS) - LOW_SURROGATE_BEGIN) div 32]
  1500. ][(Word(ALowS) - LOW_SURROGATE_BEGIN) mod 32]
  1501. ]; {
  1502. Result:=
  1503. @UC_PROP_ARRAY[
  1504. UCO_TABLE_2[
  1505. (UCO_TABLE_1[Word(AHighS)-HIGH_SURROGATE_BEGIN] * HIGH_SURROGATE_COUNT) +
  1506. Word(ALowS) - LOW_SURROGATE_BEGIN
  1507. ]
  1508. ]; }
  1509. end;
  1510. function GetProps(const ACodePoint : Cardinal) : PUC_Prop;inline;
  1511. var
  1512. l, h : UnicodeChar;
  1513. begin
  1514. if (ACodePoint <= High(Word)) then
  1515. exit(GetProps(Word(ACodePoint)));
  1516. FromUCS4(ACodePoint,h,l);
  1517. Result := GetProps(h,l);
  1518. end;
  1519. function UnicodeToUpper(
  1520. const AString : UnicodeString;
  1521. const AIgnoreInvalidSequence : Boolean;
  1522. out AResultString : UnicodeString
  1523. ) : Integer;
  1524. var
  1525. i, c : SizeInt;
  1526. pp, pr : PUnicodeChar;
  1527. pu : PUC_Prop;
  1528. locIsSurrogate : Boolean;
  1529. r : UnicodeString;
  1530. begin
  1531. c := Length(AString);
  1532. SetLength(r,2*c);
  1533. if (c > 0) then begin
  1534. pp := @AString[1];
  1535. pr := @r[1];
  1536. i := 1;
  1537. while (i <= c) do begin
  1538. pu := GetProps(Word(pp^));
  1539. locIsSurrogate := (pu^.Category = UGC_Surrogate);
  1540. if locIsSurrogate then begin
  1541. if (i = c) or not(UnicodeIsSurrogatePair(pp[0],pp[1])) then begin
  1542. if AIgnoreInvalidSequence then begin
  1543. pr^ := pp^;
  1544. Inc(pp);
  1545. Inc(pr);
  1546. Inc(i);
  1547. Continue;
  1548. end;
  1549. exit(ERROR_INVALID_CODEPOINT_SEQUENCE);
  1550. end;
  1551. pu := GetProps(pp^,AString[i+1]);
  1552. end;
  1553. if (pu^.SimpleUpperCase = 0) then begin
  1554. pr^ := pp^;
  1555. if locIsSurrogate then begin
  1556. Inc(pp);
  1557. Inc(pr);
  1558. Inc(i);
  1559. pr^ := pp^;
  1560. end;
  1561. end else begin
  1562. if (pu^.SimpleUpperCase <= $FFFF) then begin
  1563. pr^ := UnicodeChar(Word(pu^.SimpleUpperCase));
  1564. end else begin
  1565. FromUCS4(UCS4Char(Cardinal(pu^.SimpleUpperCase)),pr^,PUnicodeChar(PtrUInt(pr)+SizeOf(UnicodeChar))^);
  1566. Inc(pr);
  1567. end;
  1568. if locIsSurrogate then begin
  1569. Inc(pp);
  1570. Inc(i);
  1571. end;
  1572. end;
  1573. Inc(pp);
  1574. Inc(pr);
  1575. Inc(i);
  1576. end;
  1577. Dec(pp);
  1578. i := ((PtrUInt(pr) - PtrUInt(@r[1])) div SizeOf(UnicodeChar));
  1579. SetLength(r,i);
  1580. AResultString := r;
  1581. end;
  1582. Result := 0;
  1583. end;
  1584. function UnicodeToLower(
  1585. const AString : UnicodeString;
  1586. const AIgnoreInvalidSequence : Boolean;
  1587. out AResultString : UnicodeString
  1588. ) : Integer;
  1589. var
  1590. i, c : SizeInt;
  1591. pp, pr : PUnicodeChar;
  1592. pu : PUC_Prop;
  1593. locIsSurrogate : Boolean;
  1594. r : UnicodeString;
  1595. begin
  1596. c := Length(AString);
  1597. SetLength(r,2*c);
  1598. if (c > 0) then begin
  1599. pp := @AString[1];
  1600. pr := @r[1];
  1601. i := 1;
  1602. while (i <= c) do begin
  1603. pu := GetProps(Word(pp^));
  1604. locIsSurrogate := (pu^.Category = UGC_Surrogate);
  1605. if locIsSurrogate then begin
  1606. if (i = c) or not(UnicodeIsSurrogatePair(pp[0],pp[1])) then begin
  1607. if AIgnoreInvalidSequence then begin
  1608. pr^ := pp^;
  1609. Inc(pp);
  1610. Inc(pr);
  1611. Inc(i);
  1612. Continue;
  1613. end;
  1614. exit(ERROR_INVALID_CODEPOINT_SEQUENCE);
  1615. end;
  1616. pu := GetProps(pp^,AString[i+1]);
  1617. end;
  1618. if (pu^.SimpleLowerCase = 0) then begin
  1619. pr^ := pp^;
  1620. if locIsSurrogate then begin
  1621. Inc(pp);
  1622. Inc(pr);
  1623. Inc(i);
  1624. pr^ := pp^;
  1625. end;
  1626. end else begin
  1627. if (pu^.SimpleLowerCase <= $FFFF) then begin
  1628. pr^ := UnicodeChar(Word(pu^.SimpleLowerCase));
  1629. end else begin
  1630. FromUCS4(UCS4Char(Cardinal(pu^.SimpleLowerCase)),pr^,PUnicodeChar(PtrUInt(pr)+SizeOf(UnicodeChar))^);
  1631. Inc(pr);
  1632. end;
  1633. if locIsSurrogate then begin
  1634. Inc(pp);
  1635. Inc(i);
  1636. end;
  1637. end;
  1638. Inc(pp);
  1639. Inc(pr);
  1640. Inc(i);
  1641. end;
  1642. Dec(pp);
  1643. i := ((PtrUInt(pr) - PtrUInt(@r[1])) div SizeOf(UnicodeChar));
  1644. SetLength(r,i);
  1645. AResultString := r;
  1646. end;
  1647. Result := 0;
  1648. end;
  1649. //----------------------------------------------------------------------
  1650. function DecomposeHangul(const AChar : Cardinal; ABuffer : PCardinal) : Integer;
  1651. const
  1652. SBase = $AC00;
  1653. LBase = $1100;
  1654. VBase = $1161;
  1655. TBase = $11A7;
  1656. LCount = 19;
  1657. VCount = 21;
  1658. TCount = 28;
  1659. NCount = VCount * TCount; // 588
  1660. SCount = LCount * NCount; // 11172
  1661. var
  1662. SIndex, L, V, T : Integer;
  1663. begin
  1664. SIndex := AChar - SBase;
  1665. if (SIndex < 0) or (SIndex >= SCount) then begin
  1666. ABuffer^ := AChar;
  1667. exit(1);
  1668. end;
  1669. L := LBase + SIndex div NCount;
  1670. V := VBase + (SIndex mod NCount) div TCount;
  1671. T := TBase + SIndex mod TCount;
  1672. ABuffer[0] := L;
  1673. ABuffer[1] := V;
  1674. Result := 2;
  1675. if (T <> TBase) then begin
  1676. ABuffer[2] := T;
  1677. Inc(Result);
  1678. end;
  1679. end;
  1680. function Decompose(const ADecomposeIndex : Integer; ABuffer : PUnicodeChar) : Integer;
  1681. var
  1682. locStack : array[0..23] of Cardinal;
  1683. locStackIdx : Integer;
  1684. ResultBuffer : array[0..23] of Cardinal;
  1685. ResultIdx : Integer;
  1686. procedure AddCompositionToStack(const AIndex : Integer);
  1687. var
  1688. pdecIdx : ^TDecompositionIndexRec;
  1689. k, kc : Integer;
  1690. pu : ^UInt24;
  1691. begin
  1692. pdecIdx := @(UC_DEC_BOOK_DATA.Index[AIndex]);
  1693. pu := @(UC_DEC_BOOK_DATA.CodePoints[pdecIdx^.S]);
  1694. kc := pdecIdx^.L;
  1695. Inc(pu,kc);
  1696. for k := 1 to kc do begin
  1697. Dec(pu);
  1698. locStack[locStackIdx + k] := pu^;
  1699. end;
  1700. locStackIdx := locStackIdx + kc;
  1701. end;
  1702. procedure AddResult(const AChar : Cardinal);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  1703. begin
  1704. Inc(ResultIdx);
  1705. ResultBuffer[ResultIdx] := AChar;
  1706. end;
  1707. function PopStack() : Cardinal;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  1708. begin
  1709. Result := locStack[locStackIdx];
  1710. Dec(locStackIdx);
  1711. end;
  1712. var
  1713. cu : Cardinal;
  1714. decIdx : SmallInt;
  1715. locIsWord : Boolean;
  1716. i : Integer;
  1717. p : PUnicodeChar;
  1718. begin
  1719. ResultIdx := -1;
  1720. locStackIdx := -1;
  1721. AddCompositionToStack(ADecomposeIndex);
  1722. while (locStackIdx >= 0) do begin
  1723. cu := PopStack();
  1724. locIsWord := (cu <= MAX_WORD);
  1725. if locIsWord then
  1726. decIdx := GetProps(Word(cu))^.DecompositionID
  1727. else
  1728. decIdx := GetProps(cu)^.DecompositionID;
  1729. if (decIdx = -1) then
  1730. AddResult(cu)
  1731. else
  1732. AddCompositionToStack(decIdx);
  1733. end;
  1734. p := ABuffer;
  1735. Result := 0;
  1736. for i := 0 to ResultIdx do begin
  1737. cu := ResultBuffer[i];
  1738. if (cu <= MAX_WORD) then begin
  1739. p[0] := UnicodeChar(Word(cu));
  1740. Inc(p);
  1741. end else begin
  1742. FromUCS4(cu,p[0],p[1]);
  1743. Inc(p,2);
  1744. Inc(Result);
  1745. end;
  1746. end;
  1747. Result := Result + ResultIdx + 1;
  1748. end;
  1749. procedure CanonicalOrder(var AString : UnicodeString);
  1750. begin
  1751. CanonicalOrder(@AString[1],Length(AString));
  1752. end;
  1753. procedure CanonicalOrder(AStr : PUnicodeChar; const ALength : SizeInt);
  1754. var
  1755. i, c : SizeInt;
  1756. p, q : PUnicodeChar;
  1757. locIsSurrogateP, locIsSurrogateQ : Boolean;
  1758. procedure Swap();
  1759. var
  1760. t, t1 : UnicodeChar;
  1761. begin
  1762. if not locIsSurrogateP then begin
  1763. if not locIsSurrogateQ then begin
  1764. t := p^;
  1765. p^ := q^;
  1766. q^ := t;
  1767. exit;
  1768. end;
  1769. t := p^;
  1770. p[0] := q[0];
  1771. p[1] := q[1];
  1772. q[1] := t;
  1773. exit;
  1774. end;
  1775. if not locIsSurrogateQ then begin
  1776. t := q[0];
  1777. p[2] := p[1];
  1778. p[1] := p[0];
  1779. p[0] := t;
  1780. exit;
  1781. end;
  1782. t := p[0];
  1783. t1 := p[1];
  1784. p[0] := q[0];
  1785. p[1] := q[1];
  1786. q[0] := t;
  1787. q[1] := t1;
  1788. end;
  1789. var
  1790. pu : PUC_Prop;
  1791. cccp, cccq : Byte;
  1792. begin
  1793. c := ALength;
  1794. if (c < 2) then
  1795. exit;
  1796. p := AStr;
  1797. i := 1;
  1798. while (i < c) do begin
  1799. pu := GetProps(Word(p^));
  1800. locIsSurrogateP := (pu^.Category = UGC_Surrogate);
  1801. if locIsSurrogateP then begin
  1802. if (i = (c - 1)) then
  1803. Break;
  1804. if not UnicodeIsSurrogatePair(p[0],p[1]) then begin
  1805. Inc(p);
  1806. Inc(i);
  1807. Continue;
  1808. end;
  1809. pu := GetProps(p[0],p[1]);
  1810. end;
  1811. if (pu^.C3 > 0) then begin
  1812. cccp := pu^.C3;
  1813. if locIsSurrogateP then
  1814. q := p + 2
  1815. else
  1816. q := p + 1;
  1817. pu := GetProps(Word(q^));
  1818. locIsSurrogateQ := (pu^.Category = UGC_Surrogate);
  1819. if locIsSurrogateQ then begin
  1820. if (i = c) then
  1821. Break;
  1822. if not UnicodeIsSurrogatePair(q[0],q[1]) then begin
  1823. Inc(p);
  1824. Inc(i);
  1825. Continue;
  1826. end;
  1827. pu := GetProps(q[0],q[1]);
  1828. end;
  1829. cccq := pu^.C3;
  1830. if (cccq > 0) and (cccp > cccq) then begin
  1831. Swap();
  1832. if (i > 1) then begin
  1833. Dec(p);
  1834. Dec(i);
  1835. pu := GetProps(Word(p^));
  1836. if (pu^.Category = UGC_Surrogate) then begin
  1837. if (i > 1) then begin
  1838. Dec(p);
  1839. Dec(i);
  1840. end;
  1841. end;
  1842. Continue;
  1843. end;
  1844. end;
  1845. end;
  1846. if locIsSurrogateP then begin
  1847. Inc(p);
  1848. Inc(i);
  1849. end;
  1850. Inc(p);
  1851. Inc(i);
  1852. end;
  1853. end;
  1854. //Canonical Decomposition
  1855. function NormalizeNFD(const AString : UnicodeString) : UnicodeString;
  1856. begin
  1857. Result := NormalizeNFD(@AString[1],Length(AString));
  1858. end;
  1859. function NormalizeNFD(const AStr : PUnicodeChar; ALength : SizeInt) : UnicodeString;
  1860. const MAX_EXPAND = 3;
  1861. var
  1862. i, c, kc, k : SizeInt;
  1863. pp, pr : PUnicodeChar;
  1864. pu : PUC_Prop;
  1865. locIsSurrogate : Boolean;
  1866. cpArray : array[0..7] of Cardinal;
  1867. cp : Cardinal;
  1868. begin
  1869. c := ALength;
  1870. SetLength(Result,(MAX_EXPAND*c));
  1871. if (c > 0) then begin
  1872. pp := AStr;
  1873. pr := @Result[1];
  1874. i := 1;
  1875. while (i <= c) do begin
  1876. pu := GetProps(Word(pp^));
  1877. locIsSurrogate := (pu^.Category = UGC_Surrogate);
  1878. if locIsSurrogate then begin
  1879. if (i = c) then
  1880. Break;
  1881. if not UnicodeIsSurrogatePair(pp[0],pp[1]) then begin
  1882. pr^ := pp^;
  1883. Inc(pp);
  1884. Inc(pr);
  1885. Inc(i);
  1886. Continue;
  1887. end;
  1888. pu := GetProps(pp[0],pp[1]);
  1889. end;
  1890. if pu^.HangulSyllable then begin
  1891. if locIsSurrogate then begin
  1892. cp := ToUCS4(pp[0],pp[1]);
  1893. Inc(pp);
  1894. Inc(i);
  1895. end else begin
  1896. cp := Word(pp^);
  1897. end;
  1898. kc := DecomposeHangul(cp,@cpArray[0]);
  1899. for k := 0 to kc - 1 do begin
  1900. if (cpArray[k] <= MAX_WORD) then begin
  1901. pr^ := UnicodeChar(Word(cpArray[k]));
  1902. pr := pr + 1;
  1903. end else begin
  1904. FromUCS4(cpArray[k],pr[0],pr[1]);
  1905. pr := pr + 2;
  1906. end;
  1907. end;
  1908. if (kc > 0) then
  1909. Dec(pr);
  1910. end else begin
  1911. if (pu^.DecompositionID = -1) then begin
  1912. pr^ := pp^;
  1913. if locIsSurrogate then begin
  1914. Inc(pp);
  1915. Inc(pr);
  1916. Inc(i);
  1917. pr^ := pp^;
  1918. end;
  1919. end else begin
  1920. k := Decompose(pu^.DecompositionID,pr);
  1921. pr := pr + (k - 1);
  1922. if locIsSurrogate then begin
  1923. Inc(pp);
  1924. Inc(i);
  1925. end;
  1926. end;
  1927. end;
  1928. Inc(pp);
  1929. Inc(pr);
  1930. Inc(i);
  1931. end;
  1932. Dec(pp);
  1933. i := ((PtrUInt(pr) - PtrUInt(@Result[1])) div SizeOf(UnicodeChar));
  1934. SetLength(Result,i);
  1935. CanonicalOrder(@Result[1],Length(Result));
  1936. end;
  1937. end;
  1938. { TUCA_PropItemContextTreeNodeRec }
  1939. function TUCA_PropItemContextTreeNodeRec.GetLeftNode: PUCA_PropItemContextTreeNodeRec;
  1940. begin
  1941. if (Self.Left = 0) then
  1942. Result := nil
  1943. else
  1944. Result := PUCA_PropItemContextTreeNodeRec(PtrUInt(@Self) + Self.Left);
  1945. end;
  1946. function TUCA_PropItemContextTreeNodeRec.GetRightNode: PUCA_PropItemContextTreeNodeRec;
  1947. begin
  1948. if (Self.Right = 0) then
  1949. Result := nil
  1950. else
  1951. Result := PUCA_PropItemContextTreeNodeRec(PtrUInt(@Self) + Self.Right);
  1952. end;
  1953. { TUCA_PropItemContextRec }
  1954. function TUCA_PropItemContextRec.GetCodePoints() : PUInt24;
  1955. begin
  1956. Result := PUInt24(
  1957. PtrUInt(@Self) + SizeOf(Self.CodePointCount) +
  1958. SizeOf(Self.WeightCount)
  1959. );
  1960. end;
  1961. function TUCA_PropItemContextRec.GetWeights: PUCA_PropWeights;
  1962. begin
  1963. Result := PUCA_PropWeights(
  1964. PtrUInt(@Self) +
  1965. SizeOf(Self.CodePointCount) + SizeOf(Self.WeightCount) +
  1966. (Self.CodePointCount*SizeOf(UInt24))
  1967. );
  1968. end;
  1969. { TUCA_PropItemContextTreeRec }
  1970. function TUCA_PropItemContextTreeRec.GetData: PUCA_PropItemContextTreeNodeRec;
  1971. begin
  1972. if (Size = 0) then
  1973. Result := nil
  1974. else
  1975. Result := PUCA_PropItemContextTreeNodeRec(
  1976. PtrUInt(
  1977. PtrUInt(@Self) + SizeOf(UInt24){Size}
  1978. )
  1979. );
  1980. end;
  1981. function CompareCodePoints(
  1982. A : PUInt24; LA : Integer;
  1983. B : PUInt24; LB : Integer
  1984. ) : Integer;
  1985. var
  1986. i, hb : Integer;
  1987. begin
  1988. if (A = B) then
  1989. exit(0);
  1990. Result := 1;
  1991. hb := LB - 1;
  1992. for i := 0 to LA - 1 do begin
  1993. if (i > hb) then
  1994. exit;
  1995. if (A[i] < B[i]) then
  1996. exit(-1);
  1997. if (A[i] > B[i]) then
  1998. exit(1);
  1999. end;
  2000. if (LA = LB) then
  2001. exit(0);
  2002. exit(-1);
  2003. end;
  2004. function TUCA_PropItemContextTreeRec.Find(
  2005. const AChars : PUInt24;
  2006. const ACharCount : Integer;
  2007. out ANode : PUCA_PropItemContextTreeNodeRec
  2008. ) : Boolean;
  2009. var
  2010. t : PUCA_PropItemContextTreeNodeRec;
  2011. begin
  2012. t := Data;
  2013. while (t <> nil) do begin
  2014. case CompareCodePoints(AChars,ACharCount,t^.Data.GetCodePoints(),t^.Data.CodePointCount) of
  2015. 0 : Break;
  2016. -1 : t := t^.GetLeftNode();
  2017. else
  2018. t := t^.GetRightNode();
  2019. end;
  2020. end;
  2021. Result := (t <> nil);
  2022. if Result then
  2023. ANode := t;
  2024. end;
  2025. { TUC_Prop }
  2026. function TUC_Prop.GetCategory: Byte;
  2027. begin
  2028. Result := Byte((C and Byte($F8)) shr 3);
  2029. end;
  2030. function TUC_Prop.GetNumericValue: Double;
  2031. begin
  2032. Result := UC_NUMERIC_ARRAY[NumericIndex];
  2033. end;
  2034. function TUC_Prop.GetUnifiedIdeograph : Boolean;
  2035. begin
  2036. Result := IsBitON(C,2);
  2037. end;
  2038. procedure TUC_Prop.SetCategory(AValue: Byte);
  2039. begin
  2040. C := Byte(C or Byte(AValue shl 3));
  2041. end;
  2042. function TUC_Prop.GetWhiteSpace: Boolean;
  2043. begin
  2044. Result := IsBitON(C,0);
  2045. end;
  2046. procedure TUC_Prop.SetWhiteSpace(AValue: Boolean);
  2047. begin
  2048. SetBit(C,0,AValue);
  2049. end;
  2050. function TUC_Prop.GetHangulSyllable: Boolean;
  2051. begin
  2052. Result := IsBitON(C,1);
  2053. end;
  2054. procedure TUC_Prop.SetHangulSyllable(AValue: Boolean);
  2055. begin
  2056. SetBit(C,1,AValue);
  2057. end;
  2058. { TUCA_DataBook }
  2059. function TUCA_DataBook.IsVariable(const AWeight: PUCA_PropWeights): Boolean;
  2060. begin
  2061. Result := (AWeight^.Weights[0] >= Self.VariableLowLimit) and
  2062. (AWeight^.Weights[0] <= Self.VariableHighLimit);
  2063. end;
  2064. { TUCA_PropItemRec }
  2065. function TUCA_PropItemRec.IsWeightCompress_1 : Boolean;
  2066. begin
  2067. Result := IsBitON(Flags,FLAG_COMPRESS_WEIGHT_1);
  2068. end;
  2069. function TUCA_PropItemRec.IsWeightCompress_2 : Boolean;
  2070. begin
  2071. Result := IsBitON(Flags,FLAG_COMPRESS_WEIGHT_2);
  2072. end;
  2073. function TUCA_PropItemRec.GetCodePoint() : UInt24;
  2074. begin
  2075. if HasCodePoint() then begin
  2076. if Contextual then
  2077. Result := {$IFDEF HAS_UNALIGNED}Unaligned{$ENDIF}(
  2078. PUInt24(
  2079. PtrUInt(@Self) + Self.GetSelfOnlySize()- SizeOf(UInt24) -
  2080. Cardinal(GetContext()^.Size)
  2081. )^
  2082. )
  2083. else
  2084. Result := {$IFDEF HAS_UNALIGNED}Unaligned{$ENDIF}(
  2085. PUInt24(PtrUInt(@Self) + Self.GetSelfOnlySize() - SizeOf(UInt24))^
  2086. )
  2087. end else begin
  2088. {$ifdef uni_debug}
  2089. raise EUnicodeException.Create('TUCA_PropItemRec.GetCodePoint : "No code point available."');
  2090. {$else uni_debug}
  2091. Result := ZERO_UINT24;
  2092. {$endif uni_debug}
  2093. end
  2094. end;
  2095. function TUCA_PropItemRec.HasCodePoint() : Boolean;
  2096. begin
  2097. Result := IsBitON(Flags,FLAG_CODEPOINT);
  2098. end;
  2099. function TUCA_PropItemRec.IsValid() : Boolean;
  2100. begin
  2101. Result := IsBitON(Flags,FLAG_VALID);
  2102. end;
  2103. {function TUCA_PropItemRec.GetWeightArray: PUCA_PropWeights;
  2104. begin
  2105. Result := PUCA_PropWeights(PtrUInt(@Self) + SizeOf(TUCA_PropItemRec));
  2106. end;}
  2107. procedure TUCA_PropItemRec.GetWeightArray(ADest: PUCA_PropWeights);
  2108. var
  2109. c : Integer;
  2110. p : PByte;
  2111. pd : PUCA_PropWeights;
  2112. begin
  2113. c := WeightLength;
  2114. p := PByte(PtrUInt(@Self) + SizeOf(TUCA_PropItemRec));
  2115. pd := ADest;
  2116. pd^.Weights[0] := {$IFDEF HAS_UNALIGNED}Unaligned{$ENDIF}(PWord(p)^);
  2117. p := p + 2;
  2118. if not IsWeightCompress_1() then begin
  2119. pd^.Weights[1] := {$IFDEF HAS_UNALIGNED}Unaligned{$ENDIF}(PWord(p)^);
  2120. p := p + 2;
  2121. end else begin
  2122. pd^.Weights[1] := p^;
  2123. p := p + 1;
  2124. end;
  2125. if not IsWeightCompress_2() then begin
  2126. pd^.Weights[2] := {$IFDEF HAS_UNALIGNED}Unaligned{$ENDIF}(PWord(p)^);
  2127. p := p + 2;
  2128. end else begin
  2129. pd^.Weights[2] := p^;
  2130. p := p + 1;
  2131. end;
  2132. if (c > 1) then
  2133. Move(p^, (pd+1)^, ((c-1)*SizeOf(TUCA_PropWeights)));
  2134. end;
  2135. function TUCA_PropItemRec.GetSelfOnlySize() : Cardinal;
  2136. begin
  2137. Result := SizeOf(TUCA_PropItemRec);
  2138. if (WeightLength > 0) then begin
  2139. Result := Result + (WeightLength * Sizeof(TUCA_PropWeights));
  2140. if IsWeightCompress_1() then
  2141. Result := Result - 1;
  2142. if IsWeightCompress_2() then
  2143. Result := Result - 1;
  2144. end;
  2145. if HasCodePoint() then
  2146. Result := Result + SizeOf(UInt24);
  2147. if Contextual then
  2148. Result := Result + Cardinal(GetContext()^.Size);
  2149. end;
  2150. function TUCA_PropItemRec.GetContextual: Boolean;
  2151. begin
  2152. Result := IsBitON(Flags,FLAG_CONTEXTUAL);
  2153. end;
  2154. function TUCA_PropItemRec.GetContext: PUCA_PropItemContextTreeRec;
  2155. var
  2156. p : PtrUInt;
  2157. begin
  2158. if not Contextual then
  2159. exit(nil);
  2160. p := PtrUInt(@Self) + SizeOf(TUCA_PropItemRec);
  2161. if IsBitON(Flags,FLAG_CODEPOINT) then
  2162. p := p + SizeOf(UInt24);
  2163. Result := PUCA_PropItemContextTreeRec(p);
  2164. end;
  2165. function TUCA_PropItemRec.IsDeleted() : Boolean;
  2166. begin
  2167. Result := IsBitON(Flags,FLAG_DELETION);
  2168. end;
  2169. function GetPropUCA(const AChar : UnicodeChar; const ABook : PUCA_DataBook) : PUCA_PropItemRec;
  2170. var
  2171. i : Cardinal;
  2172. begin
  2173. if (ABook^.BMP_Table2 = nil) then
  2174. exit(nil);
  2175. i := PUInt24(
  2176. PtrUInt(ABook^.BMP_Table2) +
  2177. ( ((ABook^.BMP_Table1[Hi(Word(AChar))] * 256) + Lo(Word(AChar))) *
  2178. SizeOf(UInt24)
  2179. )
  2180. )^;
  2181. {i := ABook^.BMP_Table2[
  2182. (ABook^.BMP_Table1[Hi(Word(AChar))] * 256) +
  2183. Lo(Word(AChar))
  2184. ];}
  2185. if (i > 0) then
  2186. Result:= PUCA_PropItemRec(PtrUInt(ABook^.Props) + i - 1)
  2187. else
  2188. Result := nil;
  2189. end;
  2190. function GetPropUCA(const AHighS, ALowS : UnicodeChar; const ABook : PUCA_DataBook): PUCA_PropItemRec;
  2191. var
  2192. i : Cardinal;
  2193. begin
  2194. if (ABook^.OBMP_Table2 = nil) then
  2195. exit(nil);
  2196. i := PUInt24(
  2197. PtrUInt(ABook^.OBMP_Table2) +
  2198. ( (ABook^.OBMP_Table1[Word(AHighS)-HIGH_SURROGATE_BEGIN] * HIGH_SURROGATE_COUNT) +
  2199. Word(ALowS) - LOW_SURROGATE_BEGIN
  2200. ) *
  2201. SizeOf(UInt24)
  2202. )^;
  2203. {i := ABook^.OBMP_Table2[
  2204. (ABook^.OBMP_Table1[Word(AHighS)-HIGH_SURROGATE_BEGIN] * HIGH_SURROGATE_COUNT) +
  2205. Word(ALowS) - LOW_SURROGATE_BEGIN
  2206. ]; }
  2207. if (i > 0) then
  2208. Result:= PUCA_PropItemRec(PtrUInt(ABook^.Props) + i - 1)
  2209. else
  2210. Result := nil;
  2211. end;
  2212. {$UNDEF UNI_BUILD_TIME}
  2213. {$include weight_derivation.inc}
  2214. function CompareSortKey(const A : TUCASortKey; const B : array of Word) : Integer;
  2215. var
  2216. bb : TUCASortKey;
  2217. begin
  2218. SetLength(bb,Length(B));
  2219. if (Length(bb) > 0) then
  2220. Move(B[0],bb[0],(Length(bb)*SizeOf(B[0])));
  2221. Result := CompareSortKey(A,bb);
  2222. end;
  2223. function CompareSortKey(const A, B : TUCASortKey) : Integer;
  2224. var
  2225. i, hb : Integer;
  2226. begin
  2227. if (Pointer(A) = Pointer(B)) then
  2228. exit(0);
  2229. Result := 1;
  2230. hb := Length(B) - 1;
  2231. for i := 0 to Length(A) - 1 do begin
  2232. if (i > hb) then
  2233. exit;
  2234. if (A[i] < B[i]) then
  2235. exit(-1);
  2236. if (A[i] > B[i]) then
  2237. exit(1);
  2238. end;
  2239. if (Length(A) = Length(B)) then
  2240. exit(0);
  2241. exit(-1);
  2242. end;
  2243. type
  2244. TUCA_PropWeightsArray = array of TUCA_PropWeights;
  2245. function FormKeyBlanked(const ACEList : TUCA_PropWeightsArray; const ACollation : PUCA_DataBook) : TUCASortKey;
  2246. var
  2247. r : TUCASortKey;
  2248. i, c, k, ral, levelCount : Integer;
  2249. pce : PUCA_PropWeights;
  2250. begin
  2251. c := Length(ACEList);
  2252. if (c = 0) then
  2253. exit(nil);
  2254. levelCount := Length(ACEList[0].Weights);
  2255. if (ACollation^.ComparisonStrength > 0) and
  2256. (ACollation^.ComparisonStrength < levelCount)
  2257. then begin
  2258. levelCount := ACollation^.ComparisonStrength;
  2259. end;
  2260. SetLength(r,(levelCount*c + levelCount));
  2261. ral := 0;
  2262. for i := 0 to levelCount - 1 do begin
  2263. if not ACollation^.Backwards[i] then begin
  2264. pce := @ACEList[0];
  2265. for k := 0 to c - 1 do begin
  2266. if not(ACollation^.IsVariable(pce)) and (pce^.Weights[i] <> 0) then begin
  2267. r[ral] := pce^.Weights[i];
  2268. ral := ral + 1;
  2269. end;
  2270. pce := pce + 1;
  2271. end;
  2272. end else begin
  2273. pce := @ACEList[c-1];
  2274. for k := 0 to c - 1 do begin
  2275. if not(ACollation^.IsVariable(pce)) and (pce^.Weights[i] <> 0) then begin
  2276. r[ral] := pce^.Weights[i];
  2277. ral := ral + 1;
  2278. end;
  2279. pce := pce - 1;
  2280. end;
  2281. end;
  2282. r[ral] := 0;
  2283. ral := ral + 1;
  2284. end;
  2285. ral := ral - 1;
  2286. SetLength(r,ral);
  2287. Result := r;
  2288. end;
  2289. function FormKeyNonIgnorable(const ACEList : TUCA_PropWeightsArray; const ACollation : PUCA_DataBook) : TUCASortKey;
  2290. var
  2291. r : TUCASortKey;
  2292. i, c, k, ral, levelCount : Integer;
  2293. pce : PUCA_PropWeights;
  2294. begin
  2295. c := Length(ACEList);
  2296. if (c = 0) then
  2297. exit(nil);
  2298. levelCount := Length(ACEList[0].Weights);
  2299. if (ACollation^.ComparisonStrength > 0) and
  2300. (ACollation^.ComparisonStrength < levelCount)
  2301. then begin
  2302. levelCount := ACollation^.ComparisonStrength;
  2303. end;
  2304. SetLength(r,(levelCount*c + levelCount));
  2305. ral := 0;
  2306. for i := 0 to levelCount - 1 do begin
  2307. if not ACollation^.Backwards[i] then begin
  2308. pce := @ACEList[0];
  2309. for k := 0 to c - 1 do begin
  2310. if (pce^.Weights[i] <> 0) then begin
  2311. r[ral] := pce^.Weights[i];
  2312. ral := ral + 1;
  2313. end;
  2314. pce := pce + 1;
  2315. end;
  2316. end else begin
  2317. pce := @ACEList[c-1];
  2318. for k := 0 to c - 1 do begin
  2319. if (pce^.Weights[i] <> 0) then begin
  2320. r[ral] := pce^.Weights[i];
  2321. ral := ral + 1;
  2322. end;
  2323. pce := pce - 1;
  2324. end;
  2325. end;
  2326. r[ral] := 0;
  2327. ral := ral + 1;
  2328. end;
  2329. ral := ral - 1;
  2330. SetLength(r,ral);
  2331. Result := r;
  2332. end;
  2333. function FormKeyShifted(const ACEList : TUCA_PropWeightsArray; const ACollation : PUCA_DataBook) : TUCASortKey;
  2334. var
  2335. r : TUCASortKey;
  2336. i, c, k, ral, levelCount : Integer;
  2337. pce : PUCA_PropWeights;
  2338. variableState : Boolean;
  2339. begin
  2340. c := Length(ACEList);
  2341. if (c = 0) then
  2342. exit(nil);
  2343. levelCount := Length(ACEList[0].Weights);
  2344. if (ACollation^.ComparisonStrength > 0) and
  2345. (ACollation^.ComparisonStrength < levelCount)
  2346. then begin
  2347. levelCount := ACollation^.ComparisonStrength;
  2348. end;
  2349. SetLength(r,(levelCount*c + levelCount));
  2350. ral := 0;
  2351. variableState := False;
  2352. for i := 0 to levelCount - 1 do begin
  2353. if not ACollation^.Backwards[i] then begin
  2354. variableState := False;
  2355. pce := @ACEList[0];
  2356. for k := 0 to c - 1 do begin
  2357. if not ACollation^.IsVariable(pce) then begin
  2358. if (pce^.Weights[0] <> 0) then
  2359. variableState := False;
  2360. if (pce^.Weights[i] <> 0) and not(variableState) then begin
  2361. r[ral] := pce^.Weights[i];
  2362. ral := ral + 1;
  2363. end;
  2364. end else begin
  2365. variableState := True;
  2366. end;
  2367. pce := pce + 1;
  2368. end;
  2369. end else begin
  2370. pce := @ACEList[c-1];
  2371. for k := 0 to c - 1 do begin
  2372. if not ACollation^.IsVariable(pce) then begin
  2373. if (pce^.Weights[0] <> 0) then
  2374. variableState := False;
  2375. if (pce^.Weights[i] <> 0) and not(variableState) then begin
  2376. r[ral] := pce^.Weights[i];
  2377. ral := ral + 1;
  2378. end;
  2379. end else begin
  2380. variableState := True;
  2381. end;
  2382. pce := pce - 1;
  2383. end;
  2384. end;
  2385. r[ral] := 0;
  2386. ral := ral + 1;
  2387. end;
  2388. ral := ral - 1;
  2389. SetLength(r,ral);
  2390. Result := r;
  2391. end;
  2392. function FormKeyShiftedTrimmed(
  2393. const ACEList : TUCA_PropWeightsArray;
  2394. const ACollation : PUCA_DataBook
  2395. ) : TUCASortKey;
  2396. var
  2397. i : Integer;
  2398. p : ^TUCASortKeyItem;
  2399. begin
  2400. Result := FormKeyShifted(ACEList,ACollation);
  2401. i := Length(Result) - 1;
  2402. if (i >= 0) then begin
  2403. p := @Result[i];
  2404. while (i >= 0) do begin
  2405. if (p^ <> $FFFF) then
  2406. Break;
  2407. Dec(i);
  2408. Dec(p);
  2409. end;
  2410. if ((i+1) < Length(Result)) then
  2411. SetLength(Result,(i+1));
  2412. end;
  2413. end;
  2414. function FindChild(
  2415. const ACodePoint : Cardinal;
  2416. const AParent : PUCA_PropItemRec
  2417. ) : PUCA_PropItemRec;inline;
  2418. var
  2419. k : Integer;
  2420. begin
  2421. Result := PUCA_PropItemRec(PtrUInt(AParent) + AParent^.GetSelfOnlySize());
  2422. for k := 0 to AParent^.ChildCount - 1 do begin
  2423. if (ACodePoint = Result^.CodePoint) then
  2424. exit;
  2425. Result := PUCA_PropItemRec(PtrUInt(Result) + Result^.Size);
  2426. end;
  2427. Result := nil;
  2428. end;
  2429. function ComputeSortKey(
  2430. const AString : UnicodeString;
  2431. const ACollation : PUCA_DataBook
  2432. ) : TUCASortKey;
  2433. begin
  2434. Result := ComputeSortKey(@AString[1],Length(AString),ACollation);
  2435. end;
  2436. function ComputeRawSortKey(
  2437. const AStr : PUnicodeChar;
  2438. const ALength : SizeInt;
  2439. const ACollation : PUCA_DataBook
  2440. ) : TUCA_PropWeightsArray;
  2441. var
  2442. r : TUCA_PropWeightsArray;
  2443. ral {used length of "r"}: Integer;
  2444. rl {capacity of "r"} : Integer;
  2445. procedure GrowKey(const AMinGrow : Integer = 0);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2446. begin
  2447. if (rl < AMinGrow) then
  2448. rl := rl + AMinGrow
  2449. else
  2450. rl := 2 * rl;
  2451. SetLength(r,rl);
  2452. end;
  2453. var
  2454. i : Integer;
  2455. s : UnicodeString;
  2456. psBase : PUnicodeChar;
  2457. ps : PUnicodeChar;
  2458. cp : Cardinal;
  2459. cl : PUCA_DataBook;
  2460. pp : PUCA_PropItemRec;
  2461. ppLevel : Byte;
  2462. removedCharIndex : array of DWord;
  2463. removedCharIndexLength : DWord;
  2464. locHistory : array[0..24] of record
  2465. i : Integer;
  2466. cl : PUCA_DataBook;
  2467. pp : PUCA_PropItemRec;
  2468. ppLevel : Byte;
  2469. cp : Cardinal;
  2470. removedCharIndexLength : DWord;
  2471. end;
  2472. locHistoryTop : Integer;
  2473. suppressState : record
  2474. cl : PUCA_DataBook;
  2475. CharCount : Integer;
  2476. end;
  2477. LastKeyOwner : record
  2478. Length : Integer;
  2479. Chars : array[0..24] of UInt24;
  2480. end;
  2481. procedure SaveKeyOwner();
  2482. var
  2483. k : Integer;
  2484. kppLevel : Byte;
  2485. begin
  2486. k := 0;
  2487. kppLevel := High(Byte);
  2488. while (k <= locHistoryTop) do begin
  2489. if (kppLevel <> locHistory[k].ppLevel) then begin
  2490. LastKeyOwner.Chars[k] := locHistory[k].cp;
  2491. kppLevel := locHistory[k].ppLevel;
  2492. end;
  2493. k := k + 1;
  2494. end;
  2495. if (k = 0) or (kppLevel <> ppLevel) then begin
  2496. LastKeyOwner.Chars[k] := cp;
  2497. k := k + 1;
  2498. end;
  2499. LastKeyOwner.Length := k;
  2500. end;
  2501. procedure AddWeights(AItem : PUCA_PropItemRec);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2502. begin
  2503. SaveKeyOwner();
  2504. if ((ral + AItem^.WeightLength) > rl) then
  2505. GrowKey(AItem^.WeightLength);
  2506. AItem^.GetWeightArray(@r[ral]);
  2507. ral := ral + AItem^.WeightLength;
  2508. end;
  2509. procedure AddContextWeights(AItem : PUCA_PropItemContextRec);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2510. begin
  2511. if ((ral + AItem^.WeightCount) > rl) then
  2512. GrowKey(AItem^.WeightCount);
  2513. Move(AItem^.GetWeights()^,r[ral],(AItem^.WeightCount*SizeOf(r[0])));
  2514. ral := ral + AItem^.WeightCount;
  2515. end;
  2516. procedure AddComputedWeights(ACodePoint : Cardinal);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2517. begin
  2518. SaveKeyOwner();
  2519. if ((ral + 2) > rl) then
  2520. GrowKey();
  2521. DeriveWeight(ACodePoint,@r[ral]);
  2522. ral := ral + 2;
  2523. end;
  2524. procedure RecordDeletion();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2525. begin
  2526. if pp^.IsValid() and pp^.IsDeleted() (*pp^.GetWeightLength() = 0*) then begin
  2527. if (suppressState.cl = nil) or
  2528. (suppressState.CharCount > ppLevel)
  2529. then begin
  2530. suppressState.cl := cl;
  2531. suppressState.CharCount := ppLevel;
  2532. end;
  2533. end;
  2534. end;
  2535. procedure RecordStep();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2536. begin
  2537. Inc(locHistoryTop);
  2538. locHistory[locHistoryTop].i := i;
  2539. locHistory[locHistoryTop].cl := cl;
  2540. locHistory[locHistoryTop].pp := pp;
  2541. locHistory[locHistoryTop].ppLevel := ppLevel;
  2542. locHistory[locHistoryTop].cp := cp;
  2543. locHistory[locHistoryTop].removedCharIndexLength := removedCharIndexLength;
  2544. RecordDeletion();
  2545. end;
  2546. procedure ClearHistory();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2547. begin
  2548. locHistoryTop := -1;
  2549. end;
  2550. function HasHistory() : Boolean;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2551. begin
  2552. Result := (locHistoryTop >= 0);
  2553. end;
  2554. function GetHistoryLength() : Integer;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2555. begin
  2556. Result := (locHistoryTop + 1);
  2557. end;
  2558. procedure GoBack();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2559. begin
  2560. Assert(locHistoryTop >= 0);
  2561. i := locHistory[locHistoryTop].i;
  2562. cp := locHistory[locHistoryTop].cp;
  2563. cl := locHistory[locHistoryTop].cl;
  2564. pp := locHistory[locHistoryTop].pp;
  2565. ppLevel := locHistory[locHistoryTop].ppLevel;
  2566. removedCharIndexLength := locHistory[locHistoryTop].removedCharIndexLength;
  2567. ps := psBase + (i-1);
  2568. Dec(locHistoryTop);
  2569. end;
  2570. var
  2571. c : Integer;
  2572. lastUnblockedNonstarterCCC : Byte;
  2573. function IsUnblockedNonstarter(const AStartFrom : Integer) : Boolean;
  2574. var
  2575. k : DWord;
  2576. pk : PUnicodeChar;
  2577. puk : PUC_Prop;
  2578. begin
  2579. k := AStartFrom;
  2580. if (k > c) then
  2581. exit(False);
  2582. if (removedCharIndexLength>0) and
  2583. (IndexInArrayDWord(removedCharIndex,k) >= 0)
  2584. then begin
  2585. exit(False);
  2586. end;
  2587. {if (k = (i+1)) or
  2588. ( (k = (i+2)) and UnicodeIsHighSurrogate(s[i]) )
  2589. then
  2590. lastUnblockedNonstarterCCC := 0;}
  2591. pk := psBase + k-1;
  2592. if UnicodeIsHighSurrogate(pk^) then begin
  2593. if (k = c) then
  2594. exit(False);
  2595. if UnicodeIsLowSurrogate(pk[1]) then
  2596. puk := GetProps(pk[0],pk[1])
  2597. else
  2598. puk := GetProps(Word(pk^));
  2599. end else begin
  2600. puk := GetProps(Word(pk^));
  2601. end;
  2602. if (puk^.C3 = 0) or (lastUnblockedNonstarterCCC >= puk^.C3) then
  2603. exit(False);
  2604. lastUnblockedNonstarterCCC := puk^.C3;
  2605. Result := True;
  2606. end;
  2607. procedure RemoveChar(APos : Integer);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2608. begin
  2609. if (removedCharIndexLength >= Length(removedCharIndex)) then
  2610. SetLength(removedCharIndex,(2*removedCharIndexLength + 2));
  2611. removedCharIndex[removedCharIndexLength] := APos;
  2612. Inc(removedCharIndexLength);
  2613. if UnicodeIsHighSurrogate(psBase[APos]) and (APos < c) and UnicodeIsLowSurrogate(psBase[APos+1]) then begin
  2614. if (removedCharIndexLength >= Length(removedCharIndex)) then
  2615. SetLength(removedCharIndex,(2*removedCharIndexLength + 2));
  2616. removedCharIndex[removedCharIndexLength] := APos+1;
  2617. Inc(removedCharIndexLength);
  2618. end;
  2619. end;
  2620. procedure Inc_I();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2621. begin
  2622. if (removedCharIndexLength = 0) then begin
  2623. Inc(i);
  2624. Inc(ps);
  2625. exit;
  2626. end;
  2627. while True do begin
  2628. Inc(i);
  2629. Inc(ps);
  2630. if (IndexInArrayDWord(removedCharIndex,i) = -1) then
  2631. Break;
  2632. end;
  2633. end;
  2634. var
  2635. surrogateState : Boolean;
  2636. function MoveToNextChar() : Boolean;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2637. begin
  2638. Result := True;
  2639. if UnicodeIsHighSurrogate(ps[0]) then begin
  2640. if (i = c) then
  2641. exit(False);
  2642. if UnicodeIsLowSurrogate(ps[1]) then begin
  2643. surrogateState := True;
  2644. cp := ToUCS4(ps[0],ps[1]);
  2645. end else begin
  2646. surrogateState := False;
  2647. cp := Word(ps[0]);
  2648. end;
  2649. end else begin
  2650. surrogateState := False;
  2651. cp := Word(ps[0]);
  2652. end;
  2653. end;
  2654. procedure ClearPP(const AClearSuppressInfo : Boolean = True);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2655. begin
  2656. cl := nil;
  2657. pp := nil;
  2658. ppLevel := 0;
  2659. if AClearSuppressInfo then begin
  2660. suppressState.cl := nil;
  2661. suppressState.CharCount := 0;
  2662. end;
  2663. end;
  2664. function FindPropUCA() : Boolean;
  2665. var
  2666. candidateCL : PUCA_DataBook;
  2667. begin
  2668. pp := nil;
  2669. if (cl = nil) then
  2670. candidateCL := ACollation
  2671. else
  2672. candidateCL := cl;
  2673. if surrogateState then begin
  2674. while (candidateCL <> nil) do begin
  2675. pp := GetPropUCA(ps[0],ps[1],candidateCL);
  2676. if (pp <> nil) then
  2677. break;
  2678. candidateCL := candidateCL^.Base;
  2679. end;
  2680. end else begin
  2681. while (candidateCL <> nil) do begin
  2682. pp := GetPropUCA(ps[0],candidateCL);
  2683. if (pp <> nil) then
  2684. break;
  2685. candidateCL := candidateCL^.Base;
  2686. end;
  2687. end;
  2688. cl := candidateCL;
  2689. Result := (pp <> nil);
  2690. end;
  2691. procedure AddWeightsAndClear();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2692. var
  2693. ctxNode : PUCA_PropItemContextTreeNodeRec;
  2694. begin
  2695. if (pp^.WeightLength > 0) then begin
  2696. AddWeights(pp);
  2697. end else
  2698. if (LastKeyOwner.Length > 0) and pp^.Contextual and
  2699. pp^.GetContext()^.Find(@LastKeyOwner.Chars[0],LastKeyOwner.Length,ctxNode) and
  2700. (ctxNode^.Data.WeightCount > 0)
  2701. then begin
  2702. AddContextWeights(@ctxNode^.Data);
  2703. end;
  2704. //AddWeights(pp);
  2705. ClearHistory();
  2706. ClearPP();
  2707. end;
  2708. procedure StartMatch();
  2709. procedure HandleLastChar();
  2710. var
  2711. ctxNode : PUCA_PropItemContextTreeNodeRec;
  2712. begin
  2713. while True do begin
  2714. if pp^.IsValid() then begin
  2715. if (pp^.WeightLength > 0) then
  2716. AddWeights(pp)
  2717. else
  2718. if (LastKeyOwner.Length > 0) and pp^.Contextual and
  2719. pp^.GetContext()^.Find(@LastKeyOwner.Chars[0],LastKeyOwner.Length,ctxNode) and
  2720. (ctxNode^.Data.WeightCount > 0)
  2721. then
  2722. AddContextWeights(@ctxNode^.Data)
  2723. else
  2724. AddComputedWeights(cp){handle deletion of code point};
  2725. break;
  2726. end;
  2727. if (cl^.Base = nil) then begin
  2728. AddComputedWeights(cp);
  2729. break;
  2730. end;
  2731. cl := cl^.Base;
  2732. if not FindPropUCA() then begin
  2733. AddComputedWeights(cp);
  2734. break;
  2735. end;
  2736. end;
  2737. end;
  2738. var
  2739. tmpCtxNode : PUCA_PropItemContextTreeNodeRec;
  2740. begin
  2741. ppLevel := 0;
  2742. if not FindPropUCA() then begin
  2743. AddComputedWeights(cp);
  2744. ClearHistory();
  2745. ClearPP();
  2746. end else begin
  2747. if (i = c) then begin
  2748. HandleLastChar();
  2749. end else begin
  2750. if pp^.IsValid()then begin
  2751. if (pp^.ChildCount = 0) then begin
  2752. if (pp^.WeightLength > 0) then
  2753. AddWeights(pp)
  2754. else
  2755. if (LastKeyOwner.Length > 0) and pp^.Contextual and
  2756. pp^.GetContext()^.Find(@LastKeyOwner.Chars[0],LastKeyOwner.Length,tmpCtxNode) and
  2757. (tmpCtxNode^.Data.WeightCount > 0)
  2758. then
  2759. AddContextWeights(@tmpCtxNode^.Data)
  2760. else
  2761. AddComputedWeights(cp){handle deletion of code point};
  2762. ClearPP();
  2763. ClearHistory();
  2764. end else begin
  2765. RecordStep();
  2766. end
  2767. end else begin
  2768. if (pp^.ChildCount = 0) then begin
  2769. AddComputedWeights(cp);
  2770. ClearPP();
  2771. ClearHistory();
  2772. end else begin
  2773. RecordStep();
  2774. end;
  2775. end ;
  2776. end;
  2777. end;
  2778. end;
  2779. function TryPermutation() : Boolean;
  2780. var
  2781. kk, kkidx : Integer;
  2782. b : Boolean;
  2783. puk : PUC_Prop;
  2784. ppk : PUCA_PropItemRec;
  2785. begin
  2786. Result := False;
  2787. puk := GetProps(cp);
  2788. if (puk^.C3 = 0) then
  2789. exit;
  2790. lastUnblockedNonstarterCCC := puk^.C3;
  2791. if surrogateState then
  2792. kk := i + 2
  2793. else
  2794. kk := i + 1;
  2795. while IsUnblockedNonstarter(kk) do begin
  2796. kkidx := kk-1;
  2797. b := UnicodeIsHighSurrogate(psBase[kkidx]) and (kk<c) and UnicodeIsLowSurrogate(psBase[kkidx+1]);
  2798. if b then
  2799. ppk := FindChild(ToUCS4(psBase[kkidx],psBase[kkidx+1]),pp)
  2800. else
  2801. ppk := FindChild(Word(psBase[kkidx]),pp);
  2802. if (ppk <> nil) then begin
  2803. pp := ppk;
  2804. RemoveChar(kk);
  2805. Inc(ppLevel);
  2806. RecordStep();
  2807. Result := True;
  2808. if (pp^.ChildCount = 0 ) then
  2809. Break;
  2810. end;
  2811. if b then
  2812. Inc(kk);
  2813. Inc(kk);
  2814. end;
  2815. end;
  2816. procedure AdvanceCharPos();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  2817. begin
  2818. if UnicodeIsHighSurrogate(ps[0]) and (i<c) and UnicodeIsLowSurrogate(ps[1]) then begin
  2819. Inc(i);
  2820. Inc(ps);
  2821. end;
  2822. Inc_I();
  2823. end;
  2824. var
  2825. ok : Boolean;
  2826. pp1 : PUCA_PropItemRec;
  2827. cltemp : PUCA_DataBook;
  2828. ctxNode : PUCA_PropItemContextTreeNodeRec;
  2829. begin
  2830. if (ALength = 0) then
  2831. exit(nil);
  2832. s := '';
  2833. if ACollation^.NoNormalization then begin
  2834. psBase := AStr;
  2835. c := ALength;
  2836. end else begin
  2837. s := NormalizeNFD(AStr,ALength);
  2838. c := Length(s);
  2839. psBase := @s[1];
  2840. end;
  2841. rl := 3*c;
  2842. SetLength(r,rl);
  2843. ral := 0;
  2844. ps := psBase;
  2845. ClearPP();
  2846. locHistoryTop := -1;
  2847. removedCharIndexLength := 0;
  2848. FillChar(suppressState,SizeOf(suppressState),#0);
  2849. LastKeyOwner.Length := 0;
  2850. i := 1;
  2851. while (i <= c) and MoveToNextChar() do begin
  2852. if (pp = nil) then begin // Start Matching
  2853. StartMatch();
  2854. end else begin
  2855. pp1 := FindChild(cp,pp);
  2856. if (pp1 <> nil) then begin
  2857. Inc(ppLevel);
  2858. pp := pp1;
  2859. if (pp^.ChildCount = 0) or (i = c) then begin
  2860. ok := False;
  2861. if pp^.IsValid() and (suppressState.CharCount = 0) then begin
  2862. if (pp^.WeightLength > 0) then begin
  2863. AddWeightsAndClear();
  2864. ok := True;
  2865. end else
  2866. if (LastKeyOwner.Length > 0) and pp^.Contextual and
  2867. pp^.GetContext()^.Find(@LastKeyOwner.Chars[0],LastKeyOwner.Length,ctxNode) and
  2868. (ctxNode^.Data.WeightCount > 0)
  2869. then begin
  2870. AddContextWeights(@ctxNode^.Data);
  2871. ClearHistory();
  2872. ClearPP();
  2873. ok := True;
  2874. end
  2875. end;
  2876. if not ok then begin
  2877. RecordDeletion();
  2878. ok := False;
  2879. while HasHistory() do begin
  2880. GoBack();
  2881. if pp^.IsValid() and
  2882. ( ( (cl = suppressState.cl) and (ppLevel <> suppressState.CharCount) ) or
  2883. ( (cl <> suppressState.cl) and (ppLevel < suppressState.CharCount) )
  2884. )
  2885. then begin
  2886. AddWeightsAndClear();
  2887. ok := True;
  2888. Break;
  2889. end;
  2890. end;
  2891. if not ok then begin
  2892. cltemp := cl^.Base;
  2893. if (cltemp <> nil) then begin
  2894. ClearPP(False);
  2895. cl := cltemp;
  2896. Continue;
  2897. end;
  2898. end;
  2899. if not ok then begin
  2900. AddComputedWeights(cp);
  2901. ClearHistory();
  2902. ClearPP();
  2903. end;
  2904. end;
  2905. end else begin
  2906. RecordStep();
  2907. end;
  2908. end else begin
  2909. // permutations !
  2910. ok := False;
  2911. if TryPermutation() and pp^.IsValid() then begin
  2912. if (suppressState.CharCount = 0) then begin
  2913. AddWeightsAndClear();
  2914. Continue;
  2915. end;
  2916. while True do begin
  2917. if pp^.IsValid() and
  2918. (pp^.WeightLength > 0) and
  2919. ( ( (cl = suppressState.cl) and (ppLevel <> suppressState.CharCount) ) or
  2920. ( (cl <> suppressState.cl) and (ppLevel < suppressState.CharCount) )
  2921. )
  2922. then begin
  2923. AddWeightsAndClear();
  2924. ok := True;
  2925. break;
  2926. end;
  2927. if not HasHistory() then
  2928. break;
  2929. GoBack();
  2930. if (pp = nil) then
  2931. break;
  2932. end;
  2933. end;
  2934. if not ok then begin
  2935. if pp^.IsValid() and (suppressState.CharCount = 0) then begin
  2936. if (pp^.WeightLength > 0) then begin
  2937. AddWeightsAndClear();
  2938. ok := True;
  2939. end else
  2940. if (LastKeyOwner.Length > 0) and pp^.Contextual and
  2941. pp^.GetContext()^.Find(@LastKeyOwner.Chars[0],LastKeyOwner.Length,ctxNode) and
  2942. (ctxNode^.Data.WeightCount > 0)
  2943. then begin
  2944. AddContextWeights(@ctxNode^.Data);
  2945. ClearHistory();
  2946. ClearPP();
  2947. ok := True;
  2948. end
  2949. end;
  2950. if ok then
  2951. Continue;
  2952. end;
  2953. if not ok then begin
  2954. if (cl^.Base <> nil) then begin
  2955. cltemp := cl^.Base;
  2956. while HasHistory() do
  2957. GoBack();
  2958. pp := nil;
  2959. ppLevel := 0;
  2960. cl := cltemp;
  2961. Continue;
  2962. end;
  2963. //walk back
  2964. ok := False;
  2965. while HasHistory() do begin
  2966. GoBack();
  2967. if pp^.IsValid() and
  2968. (pp^.WeightLength > 0) and
  2969. ( (suppressState.CharCount = 0) or
  2970. ( ( (cl = suppressState.cl) and (ppLevel <> suppressState.CharCount) ) or
  2971. ( (cl <> suppressState.cl) and (ppLevel < suppressState.CharCount) )
  2972. )
  2973. )
  2974. then begin
  2975. AddWeightsAndClear();
  2976. ok := True;
  2977. Break;
  2978. end;
  2979. end;
  2980. if ok then begin
  2981. AdvanceCharPos();
  2982. Continue;
  2983. end;
  2984. if (pp <> nil) then begin
  2985. AddComputedWeights(cp);
  2986. ClearHistory();
  2987. ClearPP();
  2988. end;
  2989. end;
  2990. end;
  2991. end;
  2992. if surrogateState then begin
  2993. Inc(ps);
  2994. Inc(i);
  2995. end;
  2996. //
  2997. Inc_I();
  2998. end;
  2999. SetLength(r,ral);
  3000. Result := r;
  3001. end;
  3002. type
  3003. TComputeKeyContext = record
  3004. Collation : PUCA_DataBook;
  3005. r : TUCA_PropWeightsArray;
  3006. ral {used length of "r"}: Integer;
  3007. rl {capacity of "r"} : Integer;
  3008. i : Integer;
  3009. s : UnicodeString;
  3010. ps : PUnicodeChar;
  3011. cp : Cardinal;
  3012. cl : PUCA_DataBook;
  3013. pp : PUCA_PropItemRec;
  3014. ppLevel : Byte;
  3015. removedCharIndex : array of DWord;
  3016. removedCharIndexLength : DWord;
  3017. locHistoryTop : Integer;
  3018. locHistory : array[0..24] of record
  3019. i : Integer;
  3020. cl : PUCA_DataBook;
  3021. pp : PUCA_PropItemRec;
  3022. ppLevel : Byte;
  3023. cp : Cardinal;
  3024. removedCharIndexLength : DWord;
  3025. end;
  3026. suppressState : record
  3027. cl : PUCA_DataBook;
  3028. CharCount : Integer;
  3029. end;
  3030. LastKeyOwner : record
  3031. Length : Integer;
  3032. Chars : array[0..24] of UInt24;
  3033. end;
  3034. c : Integer;
  3035. lastUnblockedNonstarterCCC : Byte;
  3036. surrogateState : Boolean;
  3037. Finished : Boolean;
  3038. end;
  3039. PComputeKeyContext = ^TComputeKeyContext;
  3040. procedure ClearPP(AContext : PComputeKeyContext; const AClearSuppressInfo : Boolean = True);inline;
  3041. begin
  3042. AContext^.cl := nil;
  3043. AContext^.pp := nil;
  3044. AContext^.ppLevel := 0;
  3045. if AClearSuppressInfo then begin
  3046. AContext^.suppressState.cl := nil;
  3047. AContext^.suppressState.CharCount := 0;
  3048. end;
  3049. end;
  3050. procedure InitContext(
  3051. AContext : PComputeKeyContext;
  3052. const AStr : PUnicodeChar;
  3053. const ALength : SizeInt;
  3054. const ACollation : PUCA_DataBook
  3055. );
  3056. begin
  3057. AContext^.Collation := ACollation;
  3058. AContext^.c := ALength;
  3059. AContext^.s := NormalizeNFD(AStr,AContext^.c);
  3060. AContext^.c := Length(AContext^.s);
  3061. AContext^.rl := 3*AContext^.c;
  3062. SetLength(AContext^.r,AContext^.rl);
  3063. AContext^.ral := 0;
  3064. AContext^.ps := @AContext^.s[1];
  3065. ClearPP(AContext);
  3066. AContext^.locHistoryTop := -1;
  3067. AContext^.removedCharIndexLength := 0;
  3068. FillChar(AContext^.suppressState,SizeOf(AContext^.suppressState),#0);
  3069. AContext^.LastKeyOwner.Length := 0;
  3070. AContext^.i := 1;
  3071. AContext^.Finished := False;
  3072. end;
  3073. function FormKey(
  3074. const AWeightArray : TUCA_PropWeightsArray;
  3075. const ACollation : PUCA_DataBook
  3076. ) : TUCASortKey;inline;
  3077. begin
  3078. case ACollation.VariableWeight of
  3079. TUCA_VariableKind.ucaShifted : Result := FormKeyShifted(AWeightArray,ACollation);
  3080. TUCA_VariableKind.ucaBlanked : Result := FormKeyBlanked(AWeightArray,ACollation);
  3081. TUCA_VariableKind.ucaNonIgnorable : Result := FormKeyNonIgnorable(AWeightArray,ACollation);
  3082. TUCA_VariableKind.ucaShiftedTrimmed : Result := FormKeyShiftedTrimmed(AWeightArray,ACollation);
  3083. else
  3084. Result := FormKeyShifted(AWeightArray,ACollation);
  3085. end;
  3086. end;
  3087. function ComputeRawSortKeyNextItem(
  3088. const AContext : PComputeKeyContext
  3089. ) : Boolean;forward;
  3090. function IncrementalCompareString_NonIgnorable(
  3091. const AStrA : PUnicodeChar;
  3092. const ALengthA : SizeInt;
  3093. const AStrB : PUnicodeChar;
  3094. const ALengthB : SizeInt;
  3095. const ACollation : PUCA_DataBook
  3096. ) : Integer;
  3097. var
  3098. ctxA, ctxB : TComputeKeyContext;
  3099. lastKeyIndexA, keyIndexA, lengthMaxA : Integer;
  3100. keyIndexB : Integer;
  3101. keyA, keyB : TUCASortKey;
  3102. begin
  3103. if ( (ALengthA = 0) and (ALengthB = 0) ) or
  3104. ( (PtrUInt(AStrA) = PtrUInt(AStrB)) and
  3105. (ALengthA = ALengthB)
  3106. )
  3107. then
  3108. exit(0);
  3109. if (ALengthA = 0) then
  3110. exit(-1);
  3111. if (ALengthB = 0) then
  3112. exit(1);
  3113. InitContext(@ctxA,AStrA,ALengthA,ACollation);
  3114. InitContext(@ctxB,AStrB,ALengthB,ACollation);
  3115. lastKeyIndexA := -1;
  3116. keyIndexA := -1;
  3117. lengthMaxA := 0;
  3118. keyIndexB := -1;
  3119. while True do begin
  3120. if not ComputeRawSortKeyNextItem(@ctxA) then
  3121. Break;
  3122. if (ctxA.ral = lengthMaxA) then
  3123. Continue;
  3124. lengthMaxA := ctxA.ral;
  3125. keyIndexA := lastKeyIndexA + 1;
  3126. while (keyIndexA < lengthMaxA) and (ctxA.r[keyIndexA].Weights[0] = 0) do begin
  3127. Inc(keyIndexA);
  3128. end;
  3129. if (keyIndexA = lengthMaxA) then begin
  3130. lastKeyIndexA := keyIndexA-1;
  3131. Continue;
  3132. end;
  3133. while (keyIndexA < lengthMaxA) do begin
  3134. if (ctxA.r[keyIndexA].Weights[0] = 0) then begin
  3135. Inc(keyIndexA);
  3136. Continue;
  3137. end;
  3138. Inc(keyIndexB);
  3139. while (ctxB.ral <= keyIndexB) or (ctxB.r[keyIndexB].Weights[0] = 0) do begin
  3140. if (ctxB.ral <= keyIndexB) then begin
  3141. if not ComputeRawSortKeyNextItem(@ctxB) then
  3142. Break;
  3143. Continue;
  3144. end;
  3145. Inc(keyIndexB);
  3146. end;
  3147. if (ctxB.ral <= keyIndexB) then
  3148. exit(1);
  3149. if (ctxA.r[keyIndexA].Weights[0] > ctxB.r[keyIndexB].Weights[0]) then
  3150. exit(1);
  3151. if (ctxA.r[keyIndexA].Weights[0] < ctxB.r[keyIndexB].Weights[0]) then
  3152. exit(-1);
  3153. Inc(keyIndexA);
  3154. end;
  3155. lastKeyIndexA := keyIndexA - 1;
  3156. end;
  3157. //Key(A) is completed !
  3158. Inc(keyIndexB);
  3159. while (ctxB.ral <= keyIndexB) or (ctxB.r[keyIndexB].Weights[0] = 0) do begin
  3160. if (ctxB.ral <= keyIndexB) then begin
  3161. if not ComputeRawSortKeyNextItem(@ctxB) then
  3162. Break;
  3163. Continue;
  3164. end;
  3165. Inc(keyIndexB);
  3166. end;
  3167. if (ctxB.ral > keyIndexB) then begin
  3168. //B has at least one more primary weight that A
  3169. exit(-1);
  3170. end;
  3171. while ComputeRawSortKeyNextItem(@ctxB) do begin
  3172. //
  3173. end;
  3174. //Key(B) is completed !
  3175. keyA := FormKey(ctxA.r,ctxA.Collation);
  3176. keyB := FormKey(ctxB.r,ctxB.Collation);
  3177. Result := CompareSortKey(keyA,keyB);
  3178. end;
  3179. function IncrementalCompareString_Shift(
  3180. const AStrA : PUnicodeChar;
  3181. const ALengthA : SizeInt;
  3182. const AStrB : PUnicodeChar;
  3183. const ALengthB : SizeInt;
  3184. const ACollation : PUCA_DataBook
  3185. ) : Integer;
  3186. var
  3187. ctxA, ctxB : TComputeKeyContext;
  3188. lastKeyIndexA, keyIndexA, lengthMaxA : Integer;
  3189. keyIndexB : Integer;
  3190. keyA, keyB : TUCASortKey;
  3191. begin
  3192. if ( (ALengthA = 0) and (ALengthB = 0) ) or
  3193. ( (PtrUInt(AStrA) = PtrUInt(AStrB)) and
  3194. (ALengthA = ALengthB)
  3195. )
  3196. then
  3197. exit(0);
  3198. if (ALengthA = 0) then
  3199. exit(-1);
  3200. if (ALengthB = 0) then
  3201. exit(1);
  3202. InitContext(@ctxA,AStrA,ALengthA,ACollation);
  3203. InitContext(@ctxB,AStrB,ALengthB,ACollation);
  3204. lastKeyIndexA := -1;
  3205. keyIndexA := -1;
  3206. lengthMaxA := 0;
  3207. keyIndexB := -1;
  3208. while True do begin
  3209. if not ComputeRawSortKeyNextItem(@ctxA) then
  3210. Break;
  3211. if (ctxA.ral = lengthMaxA) then
  3212. Continue;
  3213. lengthMaxA := ctxA.ral;
  3214. keyIndexA := lastKeyIndexA + 1;
  3215. while (keyIndexA < lengthMaxA) and
  3216. ( (ctxA.r[keyIndexA].Weights[0] = 0) or
  3217. ctxA.Collation^.IsVariable(@ctxA.r[keyIndexA].Weights)
  3218. )
  3219. do begin
  3220. Inc(keyIndexA);
  3221. end;
  3222. if (keyIndexA = lengthMaxA) then begin
  3223. lastKeyIndexA := keyIndexA-1;
  3224. Continue;
  3225. end;
  3226. while (keyIndexA < lengthMaxA) do begin
  3227. if (ctxA.r[keyIndexA].Weights[0] = 0) or
  3228. ctxA.Collation^.IsVariable(@ctxA.r[keyIndexA].Weights)
  3229. then begin
  3230. Inc(keyIndexA);
  3231. Continue;
  3232. end;
  3233. Inc(keyIndexB);
  3234. while (ctxB.ral <= keyIndexB) or
  3235. (ctxB.r[keyIndexB].Weights[0] = 0) or
  3236. ctxB.Collation^.IsVariable(@ctxB.r[keyIndexB].Weights)
  3237. do begin
  3238. if (ctxB.ral <= keyIndexB) then begin
  3239. if not ComputeRawSortKeyNextItem(@ctxB) then
  3240. Break;
  3241. Continue;
  3242. end;
  3243. Inc(keyIndexB);
  3244. end;
  3245. if (ctxB.ral <= keyIndexB) then
  3246. exit(1);
  3247. if (ctxA.r[keyIndexA].Weights[0] > ctxB.r[keyIndexB].Weights[0]) then
  3248. exit(1);
  3249. if (ctxA.r[keyIndexA].Weights[0] < ctxB.r[keyIndexB].Weights[0]) then
  3250. exit(-1);
  3251. Inc(keyIndexA);
  3252. end;
  3253. lastKeyIndexA := keyIndexA - 1;
  3254. end;
  3255. //Key(A) is completed !
  3256. Inc(keyIndexB);
  3257. while (ctxB.ral <= keyIndexB) or
  3258. (ctxB.r[keyIndexB].Weights[0] = 0) or
  3259. ctxB.Collation^.IsVariable(@ctxB.r[keyIndexB].Weights)
  3260. do begin
  3261. if (ctxB.ral <= keyIndexB) then begin
  3262. if not ComputeRawSortKeyNextItem(@ctxB) then
  3263. Break;
  3264. Continue;
  3265. end;
  3266. Inc(keyIndexB);
  3267. end;
  3268. if (ctxB.ral > keyIndexB) then begin
  3269. //B has at least one more primary weight that A
  3270. exit(-1);
  3271. end;
  3272. while ComputeRawSortKeyNextItem(@ctxB) do begin
  3273. //
  3274. end;
  3275. //Key(B) is completed !
  3276. keyA := FormKey(ctxA.r,ctxA.Collation);
  3277. keyB := FormKey(ctxB.r,ctxB.Collation);
  3278. Result := CompareSortKey(keyA,keyB);
  3279. end;
  3280. function IncrementalCompareString(
  3281. const AStrA : PUnicodeChar;
  3282. const ALengthA : SizeInt;
  3283. const AStrB : PUnicodeChar;
  3284. const ALengthB : SizeInt;
  3285. const ACollation : PUCA_DataBook
  3286. ) : Integer;
  3287. begin
  3288. case ACollation^.VariableWeight of
  3289. TUCA_VariableKind.ucaNonIgnorable :
  3290. begin
  3291. Result := IncrementalCompareString_NonIgnorable(
  3292. AStrA,ALengthA,AStrB,ALengthB,ACollation
  3293. );
  3294. end;
  3295. TUCA_VariableKind.ucaBlanked,
  3296. TUCA_VariableKind.ucaShiftedTrimmed,
  3297. TUCA_VariableKind.ucaIgnoreSP,
  3298. TUCA_VariableKind.ucaShifted:
  3299. begin
  3300. Result := IncrementalCompareString_Shift(
  3301. AStrA,ALengthA,AStrB,ALengthB,ACollation
  3302. );
  3303. end;
  3304. else
  3305. begin
  3306. Result := IncrementalCompareString_Shift(
  3307. AStrA,ALengthA,AStrB,ALengthB,ACollation
  3308. );
  3309. end;
  3310. end;
  3311. end;
  3312. function IncrementalCompareString(
  3313. const AStrA,
  3314. AStrB : UnicodeString;
  3315. const ACollation : PUCA_DataBook
  3316. ) : Integer;
  3317. begin
  3318. Result := IncrementalCompareString(
  3319. Pointer(AStrA),Length(AStrA),Pointer(AStrB),Length(AStrB),
  3320. ACollation
  3321. );
  3322. end;
  3323. function FilterString(
  3324. const AStr : PUnicodeChar;
  3325. const ALength : SizeInt;
  3326. const AExcludedMask : TCategoryMask
  3327. ) : UnicodeString;
  3328. var
  3329. i, c : SizeInt;
  3330. pp, pr : PUnicodeChar;
  3331. pu : PUC_Prop;
  3332. locIsSurrogate : Boolean;
  3333. begin
  3334. c := ALength;
  3335. SetLength(Result,(2*c));
  3336. if (c > 0) then begin
  3337. pp := AStr;
  3338. pr := @Result[1];
  3339. i := 1;
  3340. while (i <= c) do begin
  3341. pu := GetProps(Word(pp^));
  3342. locIsSurrogate := (pu^.Category = UGC_Surrogate);
  3343. if locIsSurrogate then begin
  3344. if (i = c) then
  3345. Break;
  3346. if not UnicodeIsSurrogatePair(pp[0],pp[1]) then begin
  3347. Inc(pp);
  3348. Inc(i);
  3349. Continue;
  3350. end;
  3351. pu := GetProps(pp[0],pp[1]);
  3352. end;
  3353. if not(pu^.Category in AExcludedMask) then begin
  3354. pr^ := pp^;
  3355. Inc(pr);
  3356. if locIsSurrogate then begin
  3357. Inc(pp);
  3358. Inc(pr);
  3359. Inc(i);
  3360. pr^ := pp^;
  3361. end;
  3362. end;
  3363. Inc(pp);
  3364. Inc(i);
  3365. end;
  3366. i := ((PtrUInt(pr) - PtrUInt(@Result[1])) div SizeOf(UnicodeChar));
  3367. SetLength(Result,i);
  3368. end;
  3369. end;
  3370. function FilterString(
  3371. const AStr : UnicodeString;
  3372. const AExcludedMask : TCategoryMask
  3373. ) : UnicodeString;
  3374. begin
  3375. if (AStr = '') then
  3376. Result := ''
  3377. else
  3378. Result := FilterString(@AStr[1],Length(AStr),AExcludedMask);
  3379. end;
  3380. function ComputeRawSortKeyNextItem(
  3381. const AContext : PComputeKeyContext
  3382. ) : Boolean;
  3383. var
  3384. ctx : PComputeKeyContext;
  3385. procedure GrowKey(const AMinGrow : Integer = 0);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3386. begin
  3387. if (ctx^.rl < AMinGrow) then
  3388. ctx^.rl := ctx^.rl + AMinGrow
  3389. else
  3390. ctx^.rl := 2 * ctx^.rl;
  3391. SetLength(ctx^.r,ctx^.rl);
  3392. end;
  3393. procedure SaveKeyOwner();
  3394. var
  3395. k : Integer;
  3396. kppLevel : Byte;
  3397. begin
  3398. k := 0;
  3399. kppLevel := High(Byte);
  3400. while (k <= ctx^.locHistoryTop) do begin
  3401. if (kppLevel <> ctx^.locHistory[k].ppLevel) then begin
  3402. ctx^.LastKeyOwner.Chars[k] := ctx^.locHistory[k].cp;
  3403. kppLevel := ctx^.locHistory[k].ppLevel;
  3404. end;
  3405. k := k + 1;
  3406. end;
  3407. if (k = 0) or (kppLevel <> ctx^.ppLevel) then begin
  3408. ctx^.LastKeyOwner.Chars[k] := ctx^.cp;
  3409. k := k + 1;
  3410. end;
  3411. ctx^.LastKeyOwner.Length := k;
  3412. end;
  3413. procedure AddWeights(AItem : PUCA_PropItemRec);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3414. begin
  3415. SaveKeyOwner();
  3416. if ((ctx^.ral + AItem^.WeightLength) > ctx^.rl) then
  3417. GrowKey(AItem^.WeightLength);
  3418. AItem^.GetWeightArray(@ctx^.r[ctx^.ral]);
  3419. ctx^.ral := ctx^.ral + AItem^.WeightLength;
  3420. end;
  3421. procedure AddContextWeights(AItem : PUCA_PropItemContextRec);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3422. begin
  3423. if ((ctx^.ral + AItem^.WeightCount) > ctx^.rl) then
  3424. GrowKey(AItem^.WeightCount);
  3425. Move(AItem^.GetWeights()^,ctx^.r[ctx^.ral],(AItem^.WeightCount*SizeOf(ctx^.r[0])));
  3426. ctx^.ral := ctx^.ral + AItem^.WeightCount;
  3427. end;
  3428. procedure AddComputedWeights(ACodePoint : Cardinal);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3429. begin
  3430. SaveKeyOwner();
  3431. if ((ctx^.ral + 2) > ctx^.rl) then
  3432. GrowKey();
  3433. DeriveWeight(ACodePoint,@ctx^.r[ctx^.ral]);
  3434. ctx^.ral := ctx^.ral + 2;
  3435. end;
  3436. procedure RecordDeletion();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3437. begin
  3438. if ctx^.pp^.IsValid() and ctx^.pp^.IsDeleted() (*pp^.GetWeightLength() = 0*) then begin
  3439. if (ctx^.suppressState.cl = nil) or
  3440. (ctx^.suppressState.CharCount > ctx^.ppLevel)
  3441. then begin
  3442. ctx^.suppressState.cl := ctx^.cl;
  3443. ctx^.suppressState.CharCount := ctx^.ppLevel;
  3444. end;
  3445. end;
  3446. end;
  3447. procedure RecordStep();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3448. begin
  3449. Inc(ctx^.locHistoryTop);
  3450. ctx^.locHistory[ctx^.locHistoryTop].i := ctx^.i;
  3451. ctx^.locHistory[ctx^.locHistoryTop].cl := ctx^.cl;
  3452. ctx^.locHistory[ctx^.locHistoryTop].pp := ctx^.pp;
  3453. ctx^.locHistory[ctx^.locHistoryTop].ppLevel := ctx^.ppLevel;
  3454. ctx^.locHistory[ctx^.locHistoryTop].cp := ctx^.cp;
  3455. ctx^.locHistory[ctx^.locHistoryTop].removedCharIndexLength := ctx^.removedCharIndexLength;
  3456. RecordDeletion();
  3457. end;
  3458. procedure ClearHistory();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3459. begin
  3460. ctx^.locHistoryTop := -1;
  3461. end;
  3462. function HasHistory() : Boolean;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3463. begin
  3464. Result := (ctx^.locHistoryTop >= 0);
  3465. end;
  3466. function GetHistoryLength() : Integer;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3467. begin
  3468. Result := (ctx^.locHistoryTop + 1);
  3469. end;
  3470. procedure GoBack();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3471. begin
  3472. Assert(ctx^.locHistoryTop >= 0);
  3473. ctx^.i := ctx^.locHistory[ctx^.locHistoryTop].i;
  3474. ctx^.cp := ctx^.locHistory[ctx^.locHistoryTop].cp;
  3475. ctx^.cl := ctx^.locHistory[ctx^.locHistoryTop].cl;
  3476. ctx^.pp := ctx^.locHistory[ctx^.locHistoryTop].pp;
  3477. ctx^.ppLevel := ctx^.locHistory[ctx^.locHistoryTop].ppLevel;
  3478. ctx^.removedCharIndexLength := ctx^.locHistory[ctx^.locHistoryTop].removedCharIndexLength;
  3479. ctx^.ps := @ctx^.s[ctx^.i];
  3480. Dec(ctx^.locHistoryTop);
  3481. end;
  3482. function IsUnblockedNonstarter(const AStartFrom : Integer) : Boolean;
  3483. var
  3484. k : DWord;
  3485. pk : PUnicodeChar;
  3486. puk : PUC_Prop;
  3487. begin
  3488. k := AStartFrom;
  3489. if (k > ctx^.c) then
  3490. exit(False);
  3491. if (ctx^.removedCharIndexLength>0) and
  3492. (IndexInArrayDWord(ctx^.removedCharIndex,k) >= 0)
  3493. then begin
  3494. exit(False);
  3495. end;
  3496. {if (k = (i+1)) or
  3497. ( (k = (i+2)) and UnicodeIsHighSurrogate(s[i]) )
  3498. then
  3499. lastUnblockedNonstarterCCC := 0;}
  3500. pk := @ctx^.s[k];
  3501. if UnicodeIsHighSurrogate(pk^) then begin
  3502. if (k = ctx^.c) then
  3503. exit(False);
  3504. if UnicodeIsLowSurrogate(pk[1]) then
  3505. puk := GetProps(pk[0],pk[1])
  3506. else
  3507. puk := GetProps(Word(pk^));
  3508. end else begin
  3509. puk := GetProps(Word(pk^));
  3510. end;
  3511. if (puk^.C3 = 0) or (ctx^.lastUnblockedNonstarterCCC >= puk^.C3) then
  3512. exit(False);
  3513. ctx^.lastUnblockedNonstarterCCC := puk^.C3;
  3514. Result := True;
  3515. end;
  3516. procedure RemoveChar(APos : Integer);{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3517. begin
  3518. if (ctx^.removedCharIndexLength >= Length(ctx^.removedCharIndex)) then
  3519. SetLength(ctx^.removedCharIndex,(2*ctx^.removedCharIndexLength + 2));
  3520. ctx^.removedCharIndex[ctx^.removedCharIndexLength] := APos;
  3521. Inc(ctx^.removedCharIndexLength);
  3522. if UnicodeIsHighSurrogate(ctx^.s[APos]) and (APos < ctx^.c) and UnicodeIsLowSurrogate(ctx^.s[APos+1]) then begin
  3523. if (ctx^.removedCharIndexLength >= Length(ctx^.removedCharIndex)) then
  3524. SetLength(ctx^.removedCharIndex,(2*ctx^.removedCharIndexLength + 2));
  3525. ctx^.removedCharIndex[ctx^.removedCharIndexLength] := APos+1;
  3526. Inc(ctx^.removedCharIndexLength);
  3527. end;
  3528. end;
  3529. procedure Inc_I();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3530. begin
  3531. if (ctx^.removedCharIndexLength = 0) then begin
  3532. Inc(ctx^.i);
  3533. Inc(ctx^.ps);
  3534. exit;
  3535. end;
  3536. while True do begin
  3537. Inc(ctx^.i);
  3538. Inc(ctx^.ps);
  3539. if (IndexInArrayDWord(ctx^.removedCharIndex,ctx^.i) = -1) then
  3540. Break;
  3541. end;
  3542. end;
  3543. function MoveToNextChar() : Boolean;{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3544. begin
  3545. Result := True;
  3546. if UnicodeIsHighSurrogate(ctx^.ps[0]) then begin
  3547. if (ctx^.i = ctx^.c) then
  3548. exit(False);
  3549. if UnicodeIsLowSurrogate(ctx^.ps[1]) then begin
  3550. ctx^.surrogateState := True;
  3551. ctx^.cp := ToUCS4(ctx^.ps[0],ctx^.ps[1]);
  3552. end else begin
  3553. ctx^.surrogateState := False;
  3554. ctx^.cp := Word(ctx^.ps[0]);
  3555. end;
  3556. end else begin
  3557. ctx^.surrogateState := False;
  3558. ctx^.cp := Word(ctx^.ps[0]);
  3559. end;
  3560. end;
  3561. function FindPropUCA() : Boolean;
  3562. var
  3563. candidateCL : PUCA_DataBook;
  3564. begin
  3565. ctx^.pp := nil;
  3566. if (ctx^.cl = nil) then
  3567. candidateCL := ctx^.Collation
  3568. else
  3569. candidateCL := ctx^.cl;
  3570. if ctx^.surrogateState then begin
  3571. while (candidateCL <> nil) do begin
  3572. ctx^.pp := GetPropUCA(ctx^.ps[0],ctx^.ps[1],candidateCL);
  3573. if (ctx^.pp <> nil) then
  3574. break;
  3575. candidateCL := candidateCL^.Base;
  3576. end;
  3577. end else begin
  3578. while (candidateCL <> nil) do begin
  3579. ctx^.pp := GetPropUCA(ctx^.ps[0],candidateCL);
  3580. if (ctx^.pp <> nil) then
  3581. break;
  3582. candidateCL := candidateCL^.Base;
  3583. end;
  3584. end;
  3585. ctx^.cl := candidateCL;
  3586. Result := (ctx^.pp <> nil);
  3587. end;
  3588. procedure AddWeightsAndClear();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3589. var
  3590. ctxNode : PUCA_PropItemContextTreeNodeRec;
  3591. begin
  3592. if (ctx^.pp^.WeightLength > 0) then begin
  3593. AddWeights(ctx^.pp);
  3594. end else
  3595. if (ctx^.LastKeyOwner.Length > 0) and ctx^.pp^.Contextual and
  3596. ctx^.pp^.GetContext()^.Find(@ctx^.LastKeyOwner.Chars[0],ctx^.LastKeyOwner.Length,ctxNode) and
  3597. (ctxNode^.Data.WeightCount > 0)
  3598. then begin
  3599. AddContextWeights(@ctxNode^.Data);
  3600. end;
  3601. //AddWeights(pp);
  3602. ClearHistory();
  3603. ClearPP(ctx);
  3604. end;
  3605. function StartMatch() : Boolean;
  3606. procedure HandleLastChar();
  3607. var
  3608. ctxNode : PUCA_PropItemContextTreeNodeRec;
  3609. begin
  3610. while True do begin
  3611. if ctx^.pp^.IsValid() then begin
  3612. if (ctx^.pp^.WeightLength > 0) then
  3613. AddWeights(ctx^.pp)
  3614. else
  3615. if (ctx^.LastKeyOwner.Length > 0) and ctx^.pp^.Contextual and
  3616. ctx^.pp^.GetContext()^.Find(@ctx^.LastKeyOwner.Chars[0],ctx^.LastKeyOwner.Length,ctxNode) and
  3617. (ctxNode^.Data.WeightCount > 0)
  3618. then
  3619. AddContextWeights(@ctxNode^.Data)
  3620. else
  3621. AddComputedWeights(ctx^.cp){handle deletion of code point};
  3622. break;
  3623. end;
  3624. if (ctx^.cl^.Base = nil) then begin
  3625. AddComputedWeights(ctx^.cp);
  3626. break;
  3627. end;
  3628. ctx^.cl := ctx^.cl^.Base;
  3629. if not FindPropUCA() then begin
  3630. AddComputedWeights(ctx^.cp);
  3631. break;
  3632. end;
  3633. end;
  3634. end;
  3635. var
  3636. tmpCtxNode : PUCA_PropItemContextTreeNodeRec;
  3637. begin
  3638. Result := False;
  3639. ctx^.ppLevel := 0;
  3640. if not FindPropUCA() then begin
  3641. AddComputedWeights(ctx^.cp);
  3642. ClearHistory();
  3643. ClearPP(ctx);
  3644. Result := True;
  3645. end else begin
  3646. if (ctx^.i = ctx^.c) then begin
  3647. HandleLastChar();
  3648. Result := True;
  3649. end else begin
  3650. if ctx^.pp^.IsValid()then begin
  3651. if (ctx^.pp^.ChildCount = 0) then begin
  3652. if (ctx^.pp^.WeightLength > 0) then
  3653. AddWeights(ctx^.pp)
  3654. else
  3655. if (ctx^.LastKeyOwner.Length > 0) and ctx^.pp^.Contextual and
  3656. ctx^.pp^.GetContext()^.Find(@ctx^.LastKeyOwner.Chars[0],ctx^.LastKeyOwner.Length,tmpCtxNode) and
  3657. (tmpCtxNode^.Data.WeightCount > 0)
  3658. then
  3659. AddContextWeights(@tmpCtxNode^.Data)
  3660. else
  3661. AddComputedWeights(ctx^.cp){handle deletion of code point};
  3662. ClearPP(ctx);
  3663. ClearHistory();
  3664. Result := True;
  3665. end else begin
  3666. RecordStep();
  3667. end
  3668. end else begin
  3669. if (ctx^.pp^.ChildCount = 0) then begin
  3670. AddComputedWeights(ctx^.cp);
  3671. ClearPP(ctx);
  3672. ClearHistory();
  3673. Result := True;
  3674. end else begin
  3675. RecordStep();
  3676. end;
  3677. end;
  3678. end;
  3679. end;
  3680. end;
  3681. function TryPermutation() : Boolean;
  3682. var
  3683. kk : Integer;
  3684. b : Boolean;
  3685. puk : PUC_Prop;
  3686. ppk : PUCA_PropItemRec;
  3687. begin
  3688. Result := False;
  3689. puk := GetProps(ctx^.cp);
  3690. if (puk^.C3 = 0) then
  3691. exit;
  3692. ctx^.lastUnblockedNonstarterCCC := puk^.C3;
  3693. if ctx^.surrogateState then
  3694. kk := ctx^.i + 2
  3695. else
  3696. kk := ctx^.i + 1;
  3697. while IsUnblockedNonstarter(kk) do begin
  3698. b := UnicodeIsHighSurrogate(ctx^.s[kk]) and (kk<ctx^.c) and UnicodeIsLowSurrogate(ctx^.s[kk+1]);
  3699. if b then
  3700. ppk := FindChild(ToUCS4(ctx^.s[kk],ctx^.s[kk+1]),ctx^.pp)
  3701. else
  3702. ppk := FindChild(Word(ctx^.s[kk]),ctx^.pp);
  3703. if (ppk <> nil) then begin
  3704. ctx^.pp := ppk;
  3705. RemoveChar(kk);
  3706. Inc(ctx^.ppLevel);
  3707. RecordStep();
  3708. Result := True;
  3709. if (ctx^.pp^.ChildCount = 0 ) then
  3710. Break;
  3711. end;
  3712. if b then
  3713. Inc(kk);
  3714. Inc(kk);
  3715. end;
  3716. end;
  3717. procedure AdvanceCharPos();{$IFDEF INLINE_SUPPORT_PRIVATE_VARS}inline;{$ENDIF}
  3718. begin
  3719. if UnicodeIsHighSurrogate(ctx^.ps[0]) and (ctx^.i<ctx^.c) and UnicodeIsLowSurrogate(ctx^.ps[1]) then begin
  3720. Inc(ctx^.i);
  3721. Inc(ctx^.ps);
  3722. end;
  3723. Inc_I();
  3724. end;
  3725. var
  3726. ok : Boolean;
  3727. pp1 : PUCA_PropItemRec;
  3728. cltemp : PUCA_DataBook;
  3729. ctxNode : PUCA_PropItemContextTreeNodeRec;
  3730. begin
  3731. if AContext^.Finished then
  3732. exit(False);
  3733. ctx := AContext;
  3734. while (ctx^.i <= ctx^.c) and MoveToNextChar() do begin
  3735. ok := False;
  3736. if (ctx^.pp = nil) then begin // Start Matching
  3737. ok := StartMatch();
  3738. end else begin
  3739. pp1 := FindChild(ctx^.cp,ctx^.pp);
  3740. if (pp1 <> nil) then begin
  3741. Inc(ctx^.ppLevel);
  3742. ctx^.pp := pp1;
  3743. if (ctx^.pp^.ChildCount = 0) or (ctx^.i = ctx^.c) then begin
  3744. ok := False;
  3745. if ctx^.pp^.IsValid() and (ctx^.suppressState.CharCount = 0) then begin
  3746. if (ctx^.pp^.WeightLength > 0) then begin
  3747. AddWeightsAndClear();
  3748. ok := True;
  3749. end else
  3750. if (ctx^.LastKeyOwner.Length > 0) and ctx^.pp^.Contextual and
  3751. ctx^.pp^.GetContext()^.Find(@ctx^.LastKeyOwner.Chars[0],ctx^.LastKeyOwner.Length,ctxNode) and
  3752. (ctxNode^.Data.WeightCount > 0)
  3753. then begin
  3754. AddContextWeights(@ctxNode^.Data);
  3755. ClearHistory();
  3756. ClearPP(ctx);
  3757. ok := True;
  3758. end
  3759. end;
  3760. if not ok then begin
  3761. RecordDeletion();
  3762. while HasHistory() do begin
  3763. GoBack();
  3764. if ctx^.pp^.IsValid() and
  3765. ( ( (ctx^.cl = ctx^.suppressState.cl) and (ctx^.ppLevel <> ctx^.suppressState.CharCount) ) or
  3766. ( (ctx^.cl <> ctx^.suppressState.cl) and (ctx^.ppLevel < ctx^.suppressState.CharCount) )
  3767. )
  3768. then begin
  3769. AddWeightsAndClear();
  3770. ok := True;
  3771. Break;
  3772. end;
  3773. end;
  3774. if not ok then begin
  3775. cltemp := ctx^.cl^.Base;
  3776. if (cltemp <> nil) then begin
  3777. ClearPP(ctx,False);
  3778. ctx^.cl := cltemp;
  3779. Continue;
  3780. end;
  3781. end;
  3782. if not ok then begin
  3783. AddComputedWeights(ctx^.cp);
  3784. ClearHistory();
  3785. ClearPP(ctx);
  3786. ok := True;
  3787. end;
  3788. end;
  3789. end else begin
  3790. RecordStep();
  3791. end;
  3792. end else begin
  3793. // permutations !
  3794. ok := False;
  3795. if TryPermutation() and ctx^.pp^.IsValid() then begin
  3796. if (ctx^.suppressState.CharCount = 0) then begin
  3797. AddWeightsAndClear();
  3798. //ok := True;
  3799. exit(True);// Continue;
  3800. end;
  3801. while True do begin
  3802. if ctx^.pp^.IsValid() and
  3803. (ctx^.pp^.WeightLength > 0) and
  3804. ( ( (ctx^.cl = ctx^.suppressState.cl) and (ctx^.ppLevel <> ctx^.suppressState.CharCount) ) or
  3805. ( (ctx^.cl <> ctx^.suppressState.cl) and (ctx^.ppLevel < ctx^.suppressState.CharCount) )
  3806. )
  3807. then begin
  3808. AddWeightsAndClear();
  3809. ok := True;
  3810. break;
  3811. end;
  3812. if not HasHistory() then
  3813. break;
  3814. GoBack();
  3815. if (ctx^.pp = nil) then
  3816. break;
  3817. end;
  3818. end;
  3819. if not ok then begin
  3820. if ctx^.pp^.IsValid() and (ctx^.suppressState.CharCount = 0) then begin
  3821. if (ctx^.pp^.WeightLength > 0) then begin
  3822. AddWeightsAndClear();
  3823. ok := True;
  3824. end else
  3825. if (ctx^.LastKeyOwner.Length > 0) and ctx^.pp^.Contextual and
  3826. ctx^.pp^.GetContext()^.Find(@ctx^.LastKeyOwner.Chars[0],ctx^.LastKeyOwner.Length,ctxNode) and
  3827. (ctxNode^.Data.WeightCount > 0)
  3828. then begin
  3829. AddContextWeights(@ctxNode^.Data);
  3830. ClearHistory();
  3831. ClearPP(ctx);
  3832. ok := True;
  3833. end
  3834. end;
  3835. if ok then
  3836. exit(True);// Continue;
  3837. end;
  3838. if not ok then begin
  3839. if (ctx^.cl^.Base <> nil) then begin
  3840. cltemp := ctx^.cl^.Base;
  3841. while HasHistory() do
  3842. GoBack();
  3843. ctx^.pp := nil;
  3844. ctx^.ppLevel := 0;
  3845. ctx^.cl := cltemp;
  3846. Continue;
  3847. end;
  3848. //walk back
  3849. ok := False;
  3850. while HasHistory() do begin
  3851. GoBack();
  3852. if ctx^.pp^.IsValid() and
  3853. (ctx^.pp^.WeightLength > 0) and
  3854. ( (ctx^.suppressState.CharCount = 0) or
  3855. ( ( (ctx^.cl = ctx^.suppressState.cl) and (ctx^.ppLevel <> ctx^.suppressState.CharCount) ) or
  3856. ( (ctx^.cl <> ctx^.suppressState.cl) and (ctx^.ppLevel < ctx^.suppressState.CharCount) )
  3857. )
  3858. )
  3859. then begin
  3860. AddWeightsAndClear();
  3861. ok := True;
  3862. Break;
  3863. end;
  3864. end;
  3865. if ok then begin
  3866. AdvanceCharPos();
  3867. exit(True);// Continue;
  3868. end;
  3869. if (ctx^.pp <> nil) then begin
  3870. AddComputedWeights(ctx^.cp);
  3871. ClearHistory();
  3872. ClearPP(ctx);
  3873. ok := True;
  3874. end;
  3875. end;
  3876. end;
  3877. end;
  3878. if ctx^.surrogateState then begin
  3879. Inc(ctx^.ps);
  3880. Inc(ctx^.i);
  3881. end;
  3882. //
  3883. Inc_I();
  3884. if ok then
  3885. exit(True);
  3886. end;
  3887. SetLength(ctx^.r,ctx^.ral);
  3888. ctx^.Finished := True;
  3889. Result := True;
  3890. end;
  3891. function ComputeSortKey(
  3892. const AStr : PUnicodeChar;
  3893. const ALength : SizeInt;
  3894. const ACollation : PUCA_DataBook
  3895. ) : TUCASortKey;
  3896. var
  3897. r : TUCA_PropWeightsArray;
  3898. begin
  3899. r := ComputeRawSortKey(AStr,ALength,ACollation);
  3900. Result := FormKey(r,ACollation);
  3901. end;
  3902. end.