unicodedata.pas 114 KB

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