unicodedata.pas 115 KB

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