cldrhelper.pas 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845
  1. { CLDR collation helper unit.
  2. Copyright (c) 2013-2015 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. unit cldrhelper;
  17. {$mode delphi}
  18. {$H+}
  19. {$PACKENUM 1}
  20. {$modeswitch advancedrecords}
  21. {$scopedenums on}
  22. {$typedaddress on}
  23. {$POINTERMATH on}
  24. {$macro on}
  25. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  26. {$define X_PACKED:=}
  27. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  28. {$define X_PACKED:=packed}
  29. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  30. interface
  31. uses
  32. SysUtils, Classes, helper;
  33. const
  34. COLLATION_FILE_PREFIX = 'collation_';
  35. COLLATION_ITEM_SEARCH = 'search';
  36. COLLATION_ITEM_STD = 'standard';
  37. COLLATION_ITEM_DEFAULT = COLLATION_ITEM_STD;
  38. type
  39. TAliasRec = record
  40. Name : UTF8String;
  41. Alias : UTF8String;
  42. end;
  43. const
  44. BCP47_COLLATION_TYPE_ALIAS : array[0..3] of TAliasRec = (
  45. (Name : 'dict'; Alias : 'dictionary'),
  46. (Name : 'gb2312'; Alias : 'gb2312han'),
  47. (Name : 'phonebk'; Alias : 'phonebook'),
  48. (Name : 'trad'; Alias : 'traditional')
  49. );
  50. type
  51. TUCA_LineRecArray = array of TUCA_LineRec;
  52. ECldrException = class(Exception)
  53. end;
  54. TReorderWeigthKind = (
  55. Primary, Secondary, Tertiary, Identity, Deletion
  56. );
  57. TReorderWeigthKinds = set of TReorderWeigthKind;
  58. TReorderLogicalReset = (
  59. None,// FirstVariable, LastVariable,
  60. FirstTertiaryIgnorable, LastTertiaryIgnorable,
  61. FirstSecondaryIgnorable, LastSecondaryIgnorable,
  62. FirstPrimaryIgnorable, LastPrimaryIgnorable,
  63. LastRegular,
  64. FirstNonIgnorable, LastNonIgnorable,
  65. FirstTrailing, LastTrailing
  66. );
  67. const
  68. FixableReorderLogicalSet = [
  69. TReorderLogicalReset.LastRegular,TReorderLogicalReset.FirstTrailing,
  70. TReorderLogicalReset.LastTrailing
  71. ];
  72. type
  73. TCollationField = (
  74. BackWards, VariableLowLimit, VariableHighLimit, Alternate, Normalization,
  75. Strength
  76. );
  77. TCollationFields = set of TCollationField;
  78. PReorderUnit = ^TReorderUnit;
  79. { TReorderUnit }
  80. TReorderUnit = X_PACKED record
  81. private
  82. FVirtualPosition : TReorderLogicalReset;
  83. public
  84. Context : TUnicodeCodePointArray;
  85. ExpansionChars : TUnicodeCodePointArray;
  86. Characters : TUnicodeCodePointArray;
  87. WeigthKind : TReorderWeigthKind;
  88. InitialPosition : Integer;
  89. Changed : Boolean;
  90. public
  91. property VirtualPosition : TReorderLogicalReset read FVirtualPosition;
  92. function IsVirtual() : Boolean;inline;
  93. public
  94. class function From(
  95. const AChars,
  96. AContext : array of TUnicodeCodePoint;
  97. const AWeigthKind : TReorderWeigthKind;
  98. const AInitialPosition : Integer
  99. ) : TReorderUnit;static;overload;
  100. class function From(
  101. const AChars : array of TUnicodeCodePoint;
  102. const AWeigthKind : TReorderWeigthKind;
  103. const AInitialPosition : Integer
  104. ) : TReorderUnit;static;overload;
  105. class function From(
  106. const AChar : TUnicodeCodePoint;
  107. const AWeigthKind : TReorderWeigthKind;
  108. const AInitialPosition : Integer
  109. ) : TReorderUnit;static;overload;
  110. class function From(
  111. const AChar : TUnicodeCodePoint;
  112. const AContext : array of TUnicodeCodePoint;
  113. const AWeigthKind : TReorderWeigthKind;
  114. const AInitialPosition : Integer
  115. ) : TReorderUnit;static;overload;
  116. class function From(
  117. const AReset : TReorderLogicalReset
  118. ) : TReorderUnit;static;overload;
  119. procedure SetExpansion(const AChars : array of TUnicodeCodePoint);overload;
  120. procedure SetExpansion(const AChar : TUnicodeCodePoint);overload;
  121. procedure Clear();
  122. procedure Assign(const AItem : PReorderUnit);
  123. function HasContext() : Boolean;
  124. function IsExpansion() : Boolean;
  125. end;
  126. PReorderSequence = ^TReorderSequence;
  127. { TReorderSequence }
  128. TReorderSequence = X_PACKED record
  129. public
  130. Reset : array of TUnicodeCodePoint;
  131. Elements : array of TReorderUnit;
  132. LogicalPosition : TReorderLogicalReset;
  133. Before : Boolean;
  134. public
  135. procedure Clear();
  136. procedure SetElementCount(const ALength : Integer);
  137. procedure Assign(ASource : PReorderSequence);
  138. end;
  139. TReorderSequenceArray = array of TReorderSequence;
  140. { TOrderedCharacters }
  141. TOrderedCharacters = record
  142. private
  143. FActualLength : Integer;
  144. private
  145. procedure EnsureSize(const AMinSize : Integer);
  146. public
  147. Data : array of TReorderUnit;
  148. property ActualLength : Integer read FActualLength;
  149. public
  150. class function Create(const ACapacity : Integer) : TOrderedCharacters;static;overload;
  151. class function Create() : TOrderedCharacters;static;overload;
  152. procedure Clear();
  153. function Clone() : TOrderedCharacters;
  154. function Insert(const AItem : TReorderUnit; const ADestPos : Integer) : Integer;
  155. function Append(const AItem : TReorderUnit) : Integer;
  156. procedure Delete(const AIndex : Integer);
  157. procedure ApplyStatement(const AStatement : PReorderSequence);
  158. end;
  159. POrderedCharacters = ^TOrderedCharacters;
  160. { TCldrImport }
  161. TCldrImport = class
  162. private
  163. FSource: string;
  164. FTypeName: string;
  165. public
  166. property Source : string read FSource;
  167. property TypeName : string read FTypeName;
  168. end;
  169. { TCldrImportList }
  170. TCldrImportList = class
  171. private
  172. FItems : array of TCldrImport;
  173. private
  174. function GetCount: Integer;
  175. function GetItem(AIndex : Integer): TCldrImport;
  176. public
  177. destructor Destroy();override;
  178. procedure Clear();
  179. function IndexOf(const ASource, AType : string) : Integer;
  180. function Find(const ASource, AType : string) : TCldrImport;
  181. function Add(const ASource, AType : string) : TCldrImport;
  182. property Count : Integer read GetCount;
  183. property Item[AIndex : Integer] : TCldrImport read GetItem;default;
  184. end;
  185. TComparisonStrength = (
  186. Primary, Secondary, Tertiary, Quaternary, Identity
  187. );
  188. TSettingOption = (
  189. Unknown, Strength, Alternate, Backwards, Normalization, CaseLevel, CaseFirst,
  190. HiraganaQ, NumericOrdering, Reorder, MaxVariable, Import,
  191. SuppressContractions, Optimize
  192. );
  193. PSettingRec = ^TSettingRec;
  194. { TSettingRec }
  195. TSettingRec = record
  196. public
  197. Name : UTF8String;
  198. Values : array of UTF8String;
  199. OptionValue : TSettingOption;
  200. Understood : Boolean;
  201. public
  202. class function From(
  203. const AName : UTF8String;
  204. const AValues : array of UTF8String;
  205. const AOption : TSettingOption
  206. ) : TSettingRec;static;
  207. procedure Assign(const AItem : PSettingRec);
  208. procedure Clear();
  209. end;
  210. TSettingRecArray = array of TSettingRec;
  211. TCldrCollationRuleKind = (Unknown, ReorderSequence, Import);
  212. TCldrCollationRule = record
  213. Kind : TCldrCollationRuleKind;
  214. Reorder : TReorderSequence;
  215. Import : TCldrImport;
  216. end;
  217. PCldrCollationRule = ^TCldrCollationRule;
  218. TCldrCollationRuleArray = array of TCldrCollationRule;
  219. TCldrCollation = class;
  220. TCldrParserMode = (HeaderParsing, FullParsing);
  221. { TCldrCollationItem }
  222. TCldrCollationItem = class
  223. private
  224. FAlt: string;
  225. FBackwards: Boolean;
  226. FBase: string;
  227. FChangedFields: TCollationFields;
  228. FImports: TCldrImportList;
  229. FMode : TCldrParserMode;
  230. FNormalization : Boolean;
  231. FParent: TCldrCollation;
  232. FRules: TCldrCollationRuleArray;
  233. FSettings : TSettingRecArray;
  234. FStrength : TComparisonStrength;
  235. FTypeName: string;
  236. FVariableWeight : TUCA_VariableKind;
  237. public
  238. class function FindAlias(const AName : UTF8String) : UTF8String;static;
  239. constructor Create();
  240. destructor Destroy;override;
  241. procedure Clear();
  242. function IsPrivate() : Boolean;
  243. property Mode : TCldrParserMode read FMode write FMode;
  244. property Parent : TCldrCollation read FParent;
  245. property TypeName : string read FTypeName write FTypeName;
  246. property Alt : string read FAlt write FAlt;
  247. property Base : string read FBase write FBase;
  248. property Backwards : Boolean read FBackwards write FBackwards;
  249. property Rules : TCldrCollationRuleArray read FRules write FRules;
  250. property ChangedFields : TCollationFields read FChangedFields write FChangedFields;
  251. property Imports : TCldrImportList read FImports;
  252. property Settings : TSettingRecArray read FSettings write FSettings;
  253. property VariableWeight : TUCA_VariableKind read FVariableWeight write FVariableWeight;
  254. property Normalization : Boolean read FNormalization write FNormalization;
  255. property Strength : TComparisonStrength read FStrength write FStrength;
  256. end;
  257. TCldrCollationRepository = class;
  258. { TCldrCollation }
  259. TCldrCollation = class
  260. private
  261. FItems : array of TCldrCollationItem;
  262. FLocalID: string;
  263. FDefaultType: string;
  264. FVersion: string;
  265. FLanguage: string;
  266. FMode: TCldrParserMode;
  267. FRepository: TCldrCollationRepository;
  268. private
  269. function GetItem(Index : Integer): TCldrCollationItem;
  270. function GetItemCount: Integer;
  271. public
  272. destructor Destroy();override;
  273. procedure Clear();
  274. function IndexOf(const AItemName : string) : Integer;overload;
  275. function IndexOf(const AItemName, AItemAlt : string) : Integer;overload;
  276. function Find(const AItemName : string) : TCldrCollationItem;overload;
  277. function Find(const AItemName, AItemAlt : string) : TCldrCollationItem;overload;
  278. function Add(AItem : TCldrCollationItem) : Integer;
  279. function FindPublicItemCount() : Integer;
  280. property Language : string read FLanguage write FLanguage;
  281. property LocalID : string read FLocalID write FLocalID;
  282. property Version : string read FVersion write FVersion;
  283. property DefaultType : string read FDefaultType write FDefaultType;
  284. property ItemCount : Integer read GetItemCount;
  285. property Items[Index : Integer] : TCldrCollationItem read GetItem;
  286. property Mode : TCldrParserMode read FMode write FMode;
  287. property Repository : TCldrCollationRepository read FRepository;
  288. end;
  289. ICldrCollationLoader = interface
  290. ['{117AAC84-06CE-4EC8-9B07-4E81EC23930C}']
  291. procedure LoadCollation(
  292. const ALanguage : string;
  293. ACollation : TCldrCollation;
  294. AMode : TCldrParserMode
  295. );
  296. procedure LoadCollationType(
  297. const ALanguage,
  298. ATypeName : string;
  299. AType : TCldrCollationItem
  300. );
  301. end;
  302. { TCldrCollationRepository }
  303. TCldrCollationRepository = class
  304. private
  305. FItems : array of TCldrCollation;
  306. FLoader: ICldrCollationLoader;
  307. private
  308. function GetItem(const AIndex : Integer): TCldrCollation;
  309. function GetItemCount: Integer;
  310. function IndexOfItem(AItem : TCldrCollation) : Integer;
  311. procedure Add(AItem : TCldrCollation);
  312. public
  313. constructor Create(ALoader : ICldrCollationLoader);
  314. destructor Destroy;override;
  315. procedure FreeItems();
  316. procedure Clear();
  317. procedure SetLoader(AValue : ICldrCollationLoader);
  318. function IndexOf(const ALanguage : string) : Integer;
  319. function Find(const ALanguage : string) : TCldrCollation;
  320. function Load(const ALanguage : string; const AMode : TCldrParserMode) : TCldrCollation;
  321. function LoadType(const ALanguage, AType, ATypeALT : string) : TCldrCollationItem;
  322. property ItemCount : Integer read GetItemCount;
  323. property Items[const AIndex : Integer] : TCldrCollation read GetItem;
  324. property Loader : ICldrCollationLoader read FLoader;
  325. end;
  326. TRuleVisiterFunction =
  327. function(
  328. ARule : PReorderSequence;
  329. AOwner : TCldrCollationItem;
  330. AData : Pointer
  331. ) : Boolean;
  332. function ForEachRule(
  333. ACollationType : TCldrCollationItem;
  334. AVisitFunc : TRuleVisiterFunction;
  335. ACustomData : Pointer
  336. ) : Boolean;
  337. function ComputeWeigths(
  338. const AData : PReorderUnit;
  339. const ADataLen : Integer;
  340. const ADataWeigths : TUCA_LineRecArray;
  341. const AUnifiedIdeographs : TCodePointRecArray;
  342. out AResult : TUCA_LineRecArray
  343. ) : Integer;
  344. function FindCollationDefaultItemName(ACollation : TCldrCollation) : string;
  345. procedure GenerateCdlrCollation(
  346. ACollation : TCldrCollation;
  347. AItemName : string;
  348. AStoreName : string;
  349. AStream,
  350. ANativeEndianStream,
  351. AOtherEndianStream,
  352. ABinaryNativeEndianStream,
  353. ABinaryOtherEndianStream : TStream;
  354. ARootChars : TOrderedCharacters;
  355. ARootWeigths : TUCA_LineRecArray;
  356. AUnifiedIdeographs : TCodePointRecArray
  357. );
  358. procedure GenerateUCA_CLDR_Head(
  359. ADest : TStream;
  360. ABook : PUCA_DataBook;
  361. AProps : PUCA_PropBook;
  362. ACollation : TCldrCollationItem
  363. );
  364. function FillInitialPositions(
  365. AData : PReorderUnit;
  366. const ADataLen : Integer;
  367. const ADataWeigths : TUCA_LineRecArray
  368. ) : Integer;
  369. function IndexOf(
  370. const APattern : array of TUnicodeCodePoint;
  371. const APatternContext : array of TUnicodeCodePoint;
  372. const ASequence : PReorderUnit;
  373. const ASequenceLength : Integer
  374. ) : Integer;overload;
  375. function TryStrToLogicalReorder(
  376. const AValue : string;
  377. out AResult : TReorderLogicalReset
  378. ) : Boolean;
  379. resourcestring
  380. sCaseNothandled = 'This case is not handled : "%s", Position = %d.';
  381. sCodePointExpected = 'Code Point node expected as child at this position "%d".';
  382. sCollationsExistsAlready = 'This collation already exists : "%s"';
  383. sCollationsNodeNotFound = '"collations" node not found.';
  384. sCollationTypeNotFound = 'collation "Type" not found : "%s".';
  385. sHexAttributeExpected = '"hex" attribute expected at this position "%d".';
  386. sInvalidAlternateStatement = 'Invalid "Alternate" statement, only one option is permit by statement :"%s".';
  387. sInvalidBackwardsStatement = 'Invalid "Backwards" statement, only one level is permit by statement :"%s".';
  388. sInvalidImportStatement = 'Invalid "Import" statement, only one collation is permit by statement :"%s".';
  389. sInvalidNormalizationStatement = 'Invalid "Normalization" statement, only one option is permit by statement :"%s".';
  390. sInvalidResetClause = 'Invalid "Reset" clause.';
  391. sInvalidSettingExpression = 'Invalid Setting expression, Line : "%s".';
  392. sInvalidSettingValue = 'Invalid Setting value, Setting : "%s", Value : "%s".';
  393. sInvalidStrengthStatement = 'Invalid "Strength" statement, only one option is permit by statement :"%s".';
  394. sInvalidSuppressContractionsStatement = 'Invalid "SuppressContractions" statement, only one UnicodeSet is permit by statement :"%s".';
  395. sInvalidUnicodeSetExpression = 'Invalid Unicode Set expression, Line : "%s".';
  396. sLoaderNotSet = 'The Repository''s Loader is not set.';
  397. sNodeNameAssertMessage = 'Expected NodeName "%s", got "%s".';
  398. sRepositoryNotSet = 'The Repository is not set.';
  399. sRulesNodeNotFound = '"rules" node not found.';
  400. sSpecialCharacterExpected = 'Special character expected but found "%s", line = "%s".';
  401. sTextNodeChildExpected = '(Child) text node expected at this position "%d", but got "%s".';
  402. sUnexpectedConditionsFailure = 'Unexpected conditions failure.';
  403. sUniqueChildNodeExpected = 'Unique child node expected at this position "%d".';
  404. sUnknownResetLogicalPosition = 'Unknown reset logical position : "%s".';
  405. sVirtualIsReadOnly = 'Virtual logical "Reset" items are read only.';
  406. implementation
  407. uses
  408. RtlConsts, typinfo;
  409. function TryStrToLogicalReorder(
  410. const AValue : string;
  411. out AResult : TReorderLogicalReset
  412. ) : Boolean;
  413. var
  414. s : string;
  415. i : Integer;
  416. begin
  417. s := StringReplace(AValue,' ','',[rfReplaceAll]);
  418. s := StringReplace(s,'_','',[rfReplaceAll]);
  419. i := GetEnumValue(TypeInfo(TReorderLogicalReset),s);
  420. Result := (i > -1);
  421. if Result then
  422. AResult := TReorderLogicalReset(i);
  423. end;
  424. function ToStr(const ACharacters : array of TUnicodeCodePoint): string;overload;
  425. var
  426. i : Integer;
  427. begin
  428. Result := '';
  429. for i := Low(ACharacters) to High(ACharacters) do begin
  430. if (ACharacters[i] > $FFFF) then
  431. Result := Result + ' ' + IntToHex(ACharacters[i],5)
  432. else
  433. Result := Result + ' ' + IntToHex(ACharacters[i],4);
  434. end;
  435. Result := Trim(Result);
  436. end;
  437. function ToStr(const AWeights : array of TUCA_WeightRec): string;overload;
  438. var
  439. i : Integer;
  440. p : ^TUCA_WeightRec;
  441. begin
  442. Result := '';
  443. p := @AWeights[Low(AWeights)];
  444. for i := 1 to Length(AWeights) do begin
  445. Result :=
  446. Format('%s {%s %s %s %s}',
  447. [ Result,IntToHex(p^.Weights[0],4),IntToHex(p^.Weights[1],4),
  448. IntToHex(p^.Weights[2],4), IntToHex(p^.Weights[3],4)
  449. ]
  450. );
  451. Inc(p);
  452. end;
  453. Result := Trim(Result);
  454. end;
  455. function IsZero(AItems : TUCA_WeightRecArray) : Boolean;
  456. const ZERO_ITEM : TUCA_WeightRec = (
  457. Weights : (0,0,0,0);
  458. Variable : False;
  459. );
  460. var
  461. c, i : Integer;
  462. begin
  463. c := Length(AItems);
  464. if (c < 1) then
  465. exit(True);
  466. Result := (AItems[0] = ZERO_ITEM);{
  467. for i := 0 to c-1 do begin
  468. if (AItems[i] <> ZERO_ITEM) then
  469. exit(False);
  470. end;
  471. Result := True;}
  472. end;
  473. function IndexOf(
  474. const APattern : array of TUnicodeCodePoint;
  475. const APatternContext : array of TUnicodeCodePoint;
  476. const ASequence : PReorderUnit;
  477. const ASequenceLength : Integer
  478. ) : Integer;
  479. var
  480. i, lp, sizep, lengthContext, sizeContext : Integer;
  481. p : PReorderUnit;
  482. begin
  483. Result := -1;
  484. if (ASequenceLength = 0) then
  485. exit;
  486. lp := Length(APattern);
  487. if (lp = 0) then
  488. exit;
  489. sizep := lp*SizeOf(TUnicodeCodePoint);
  490. lengthContext := Length(APatternContext);
  491. sizeContext := lengthContext*SizeOf(TUnicodeCodePoint);
  492. p := ASequence;
  493. for i := 0 to ASequenceLength - 1 do begin
  494. if (Length(p^.Characters) = lp) then begin
  495. if CompareMem(@APattern[0],@p^.Characters[0],sizep) then begin
  496. if (Length(p^.Context) = lengthContext) and
  497. ( (lengthContext = 0) or
  498. CompareMem(@p^.Context[0],@APatternContext[0],sizeContext)
  499. )
  500. then begin
  501. Result := i;
  502. Break;
  503. end;
  504. end;
  505. end;
  506. Inc(p);
  507. end;
  508. end;
  509. {procedure ApplyStatementToSequence(
  510. var ASequence : TOrderedCharacters;
  511. const AStatement : PReorderSequence;
  512. const AStatementCount : Integer
  513. );
  514. var
  515. pse, pd : PReorderUnit;
  516. kr : Integer;
  517. function GetNextInsertPos() : Integer;
  518. var
  519. kk : Integer;
  520. begin
  521. if (pse^.WeigthKind = rwkDeletion) then
  522. exit(0);
  523. if (pse^.WeigthKind = rwkIdentity) then
  524. exit(kr + 1);
  525. kk := kr + 1;
  526. pd := @ASequence.Data[kk];
  527. for kk := kk to ASequence.ActualLength - 1 do begin
  528. if (pd^.WeigthKind <= pse^.WeigthKind) then
  529. exit(kk);
  530. Inc(pd);
  531. end;
  532. Result := ASequence.ActualLength;
  533. end;
  534. var
  535. locResetPos, i, k, h : Integer;
  536. pst : PReorderSequence;
  537. begin
  538. pst := AStatement;
  539. for h := 0 to AStatementCount - 1 do begin
  540. locResetPos := -1;
  541. if (Length(pst^.Reset) > 0) then begin
  542. locResetPos := IndexOf(pst^.Reset,[],@ASequence.Data[0],ASequence.ActualLength);
  543. if (locResetPos = -1) then
  544. raise ECldrException.CreateFmt('Character(s) not found in sequence : "%s".',[ToStr(pst^.Reset)]);
  545. end;
  546. pse := @pst^.Elements[0];
  547. kr := locResetPos;
  548. k := GetNextInsertPos();
  549. for i := Low(pst^.Elements) to High(pst^.Elements) do begin
  550. k := ASequence.Insert(pse^,k)+1;
  551. Inc(pse);
  552. end;
  553. Inc(pst);
  554. end;
  555. end;}
  556. function FindLogicalPos(
  557. const ASequence : POrderedCharacters;
  558. const APosition : TReorderLogicalReset
  559. ) : Integer;
  560. var
  561. i, c : Integer;
  562. p : PReorderUnit;
  563. firstPos, lastPos : Integer;
  564. begin
  565. Result := 0;
  566. if (ASequence^.ActualLength = 0) then
  567. exit;
  568. p := @ASequence^.Data[0];
  569. c := ASequence^.ActualLength;
  570. if (APosition in FixableReorderLogicalSet) then begin
  571. for i := 0 to c - 1 do begin
  572. if (p^.VirtualPosition = APosition) then
  573. exit(i);
  574. Inc(p);
  575. end;
  576. p := @ASequence^.Data[0];
  577. end;
  578. if (APosition in [TReorderLogicalReset.FirstTertiaryIgnorable, TReorderLogicalReset.LastTertiaryIgnorable])
  579. then begin
  580. firstPos := -1;
  581. for i := 0 to c - 1 do begin
  582. if (p^.WeigthKind <= TReorderWeigthKind.Tertiary) then begin
  583. firstPos := i;
  584. Break;
  585. end;
  586. Inc(p);
  587. end;
  588. if (firstPos = -1) then
  589. exit(0);
  590. if (APosition = TReorderLogicalReset.FirstTertiaryIgnorable) then
  591. exit(firstPos);
  592. if (p^.WeigthKind < TReorderWeigthKind.Tertiary) then
  593. exit(firstPos);
  594. lastPos := -1;
  595. for i := firstPos + 1 to c - 1 do begin
  596. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  597. lastPos := i;
  598. Break;
  599. end;
  600. Inc(p);
  601. end;
  602. if (lastPos = -1) then
  603. exit(c);
  604. exit(lastPos);
  605. end;
  606. if (APosition in [TReorderLogicalReset.FirstSecondaryIgnorable, TReorderLogicalReset.LastSecondaryIgnorable])
  607. then begin
  608. firstPos := -1;
  609. for i := 0 to c - 1 do begin
  610. if (p^.WeigthKind <= TReorderWeigthKind.Secondary) then begin
  611. firstPos := i;
  612. Break;
  613. end;
  614. Inc(p);
  615. end;
  616. if (firstPos = -1) then
  617. exit(0);
  618. if (APosition = TReorderLogicalReset.FirstSecondaryIgnorable) then
  619. exit(firstPos);
  620. if (p^.WeigthKind < TReorderWeigthKind.Secondary) then
  621. exit(firstPos);
  622. lastPos := -1;
  623. for i := firstPos + 1 to c - 1 do begin
  624. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  625. lastPos := i;
  626. Break;
  627. end;
  628. Inc(p);
  629. end;
  630. if (lastPos = -1) then
  631. exit(c);
  632. exit(lastPos);
  633. end;
  634. if (APosition in [TReorderLogicalReset.FirstPrimaryIgnorable, TReorderLogicalReset.LastPrimaryIgnorable])
  635. then begin
  636. firstPos := -1;
  637. for i := 0 to c - 1 do begin
  638. if (p^.WeigthKind <= TReorderWeigthKind.Primary) then begin
  639. firstPos := i;
  640. Break;
  641. end;
  642. Inc(p);
  643. end;
  644. if (firstPos = -1) then
  645. exit(0);
  646. if (APosition = TReorderLogicalReset.FirstPrimaryIgnorable) then
  647. exit(firstPos);
  648. if (p^.WeigthKind < TReorderWeigthKind.Primary) then
  649. exit(firstPos);
  650. lastPos := -1;
  651. for i := firstPos + 1 to c - 1 do begin
  652. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  653. lastPos := i;
  654. Break;
  655. end;
  656. Inc(p);
  657. end;
  658. if (lastPos = -1) then
  659. exit(c);
  660. exit(lastPos);
  661. end;
  662. if (APosition = TReorderLogicalReset.FirstNonIgnorable) then begin
  663. firstPos := -1;
  664. for i := 0 to c - 1 do begin
  665. if (p^.WeigthKind <= TReorderWeigthKind.Primary) then begin
  666. firstPos := i;
  667. Break;
  668. end;
  669. Inc(p);
  670. end;
  671. if (firstPos = -1) then
  672. exit(0);
  673. exit(firstPos);
  674. end;
  675. if (APosition in [TReorderLogicalReset.LastNonIgnorable,TReorderLogicalReset.LastRegular])
  676. then begin
  677. exit(c);
  678. end;
  679. for i := 0 to c - 1 do begin
  680. if (p^.VirtualPosition = APosition) then
  681. exit(i);
  682. Inc(p);
  683. end;
  684. end;
  685. procedure ApplyStatementToSequence(
  686. var ASequence : TOrderedCharacters;
  687. const AStatement : PReorderSequence;
  688. const AStatementCount : Integer
  689. );
  690. var
  691. pse, pd : PReorderUnit;
  692. kr : Integer;
  693. pst : PReorderSequence;
  694. function GetNextInsertPos() : Integer;
  695. var
  696. kk : Integer;
  697. begin
  698. if (pse^.WeigthKind = TReorderWeigthKind.Deletion) then
  699. exit(0);
  700. if (pse^.WeigthKind = TReorderWeigthKind.Identity) then
  701. exit(kr + 1);
  702. if not pst^.Before then begin
  703. kk := kr + 1;
  704. if (kk >= ASequence.ActualLength) then
  705. exit(kk);
  706. pd := @ASequence.Data[kk];
  707. for kk := kk to ASequence.ActualLength - 1 do begin
  708. if (pd^.WeigthKind <= pse^.WeigthKind) then
  709. exit(kk);
  710. Inc(pd);
  711. end;
  712. Result := ASequence.ActualLength;
  713. end else begin
  714. if (kr = 0) then
  715. exit(0);
  716. pd := @ASequence.Data[kr];
  717. if pd^.IsVirtual() and (pd^.VirtualPosition in FixableReorderLogicalSet) then begin
  718. kr := kr-1;
  719. if (kr = 0) then
  720. exit;
  721. end;
  722. kk := kr;
  723. pd := @ASequence.Data[kk];
  724. if (pd^.WeigthKind = TReorderWeigthKind.Primary) then begin
  725. pd^.WeigthKind := pse^.WeigthKind;
  726. pse^.WeigthKind := TReorderWeigthKind.Primary;
  727. exit(kk);
  728. end;
  729. for kk := kk downto 0 do begin
  730. if (pd^.WeigthKind = TReorderWeigthKind.Deletion) or (pd^.WeigthKind <= pse^.WeigthKind) then begin
  731. if (pd^.WeigthKind > pse^.WeigthKind) then
  732. pd^.WeigthKind := pse^.WeigthKind;
  733. exit(kk);
  734. end;
  735. Dec(pd);
  736. end;
  737. Result := 0;
  738. end;
  739. end;
  740. var
  741. locResetPos, i, k, h : Integer;
  742. begin
  743. if (Length(AStatement^.Elements) = 0) then
  744. exit;
  745. pst := AStatement;
  746. for h := 0 to AStatementCount - 1 do begin
  747. locResetPos := -1;
  748. if (pst^.LogicalPosition > TReorderLogicalReset.None) then
  749. locResetPos := FindLogicalPos(@ASequence,pst^.LogicalPosition)
  750. else if (Length(pst^.Reset) > 0) then begin
  751. locResetPos := IndexOf(pst^.Reset,[],@ASequence.Data[0],ASequence.ActualLength);
  752. {if (locResetPos = -1) then
  753. raise ECldrException.CreateFmt('Character(s) not found in sequence : "%s".',[ToStr(pst^.Reset)]);}
  754. if (locResetPos = -1) then
  755. locResetPos := ASequence.ActualLength;
  756. end;
  757. if (pst^.LogicalPosition in FixableReorderLogicalSet) then begin
  758. if (locResetPos < 0) or
  759. (locResetPos >= ASequence.ActualLength) or
  760. not(ASequence.Data[locResetPos].VirtualPosition in FixableReorderLogicalSet)
  761. then begin
  762. locResetPos := ASequence.Append(TReorderUnit.From(pst^.LogicalPosition));
  763. end;
  764. end;
  765. pse := @pst^.Elements[0];
  766. kr := locResetPos;
  767. k := GetNextInsertPos();
  768. for i := Low(pst^.Elements) to High(pst^.Elements) do begin
  769. k := ASequence.Insert(pse^,k)+1;
  770. Inc(pse);
  771. end;
  772. Inc(pst);
  773. end;
  774. end;
  775. type
  776. PUCA_WeightRecArray = ^TUCA_WeightRecArray;
  777. TUCASortKey = array of Word;
  778. function SimpleFormKey(const ACEList : TUCA_WeightRecArray) : TUCASortKey;
  779. var
  780. r : TUCASortKey;
  781. i, c, k, ral, levelCount : Integer;
  782. pce : ^TUCA_WeightRec;
  783. begin
  784. c := Length(ACEList);
  785. if (c = 0) then
  786. exit(nil);
  787. //SetLength(r,((3+1{Level Separator})*c));
  788. levelCount := Length(ACEList[0].Weights);
  789. if (levelCount > 3) then
  790. levelCount := 3;
  791. SetLength(r,(levelCount*c + levelCount));
  792. ral := 0;
  793. for i := 0 to levelCount - 1 do begin
  794. for k := 0 to c - 1 do begin
  795. pce := @ACEList[k];
  796. if (pce^.Weights[i] <> 0) then begin
  797. r[ral] := pce^.Weights[i];
  798. ral := ral + 1;
  799. end;
  800. //pce := pce + 1;
  801. end;
  802. r[ral] := 0;
  803. ral := ral + 1;
  804. end;
  805. ral := ral - 1;
  806. SetLength(r,ral);
  807. Result := r;
  808. end;
  809. function CompareSortKey(const A, B : TUCASortKey) : Integer;
  810. var
  811. i, hb : Integer;
  812. begin
  813. if (Pointer(A) = Pointer(B)) then
  814. exit(0);
  815. Result := 1;
  816. hb := Length(B) - 1;
  817. for i := 0 to Length(A) - 1 do begin
  818. if (i > hb) then
  819. exit;
  820. if (A[i] < B[i]) then
  821. exit(-1);
  822. if (A[i] > B[i]) then
  823. exit(1);
  824. end;
  825. if (Length(A) = Length(B)) then
  826. exit(0);
  827. exit(-1);
  828. end;
  829. {function ComputeWeigths(
  830. const AData : PReorderUnit;
  831. const ADataLen : Integer;
  832. const ADataWeigths : TUCA_LineRecArray;
  833. out AResult : TUCA_LineRecArray
  834. ) : Integer;
  835. function GetWeigth(AItem : PReorderUnit) : PUCA_WeightRecArray;
  836. begin
  837. Result := nil;
  838. if (AItem^.InitialPosition < 1) or (AItem^.InitialPosition > Length(ADataWeigths)) then
  839. raise ECldrException.CreateFmt('Invalid "InitialPosition" value : %d.',[AItem^.InitialPosition]);
  840. Result := @ADataWeigths[(AItem^.InitialPosition-1)].Weights;
  841. end;
  842. var
  843. c, i, ral : Integer;
  844. p, q : PReorderUnit;
  845. r : TUCA_LineRecArray;
  846. pr : PUCA_LineRec;
  847. pbase : PReorderUnit;
  848. pw, pwb : PUCA_WeightRecArray;
  849. cw, ki : Integer;
  850. begin
  851. Result := 0;
  852. if (ADataLen < 1) then
  853. exit;
  854. c := ADataLen;
  855. ral := 0;
  856. SetLength(r,c);
  857. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  858. q := nil;
  859. pbase := nil;
  860. p := AData+1;
  861. pr := @r[0];
  862. i := 1;
  863. while (i < c) do begin
  864. if p^.Changed then begin
  865. if (pbase = nil) then begin
  866. pbase := p - 1;
  867. pwb := GetWeigth(pbase);
  868. end;
  869. if (p^.WeigthKind = rwkIdentity) then begin
  870. pr^.CodePoints := Copy(p^.Characters);
  871. q := p - 1;
  872. if (q = pbase) then
  873. pw := pwb
  874. else
  875. pw := @((pr-1)^.Weights);
  876. pr^.Weights := Copy(pw^);
  877. Inc(pr);
  878. Inc(ral);
  879. end else begin
  880. pr^.CodePoints := Copy(p^.Characters);
  881. q := p - 1;
  882. if (q = pbase) then begin
  883. pw := pwb;
  884. cw := (Length(pw^)+1);
  885. SetLength(pr^.Weights,cw);
  886. Move(pw^[0],pr^.Weights[0],((cw-1)*SizeOf(pw^[0])));
  887. FillByte(pr^.Weights[(cw-1)],SizeOf(pr^.Weights[0]),0);
  888. ki := Ord(p^.WeigthKind);
  889. pr^.Weights[(cw-1)].Weights[ki] := pr^.Weights[(cw-2)].Weights[ki]+1;
  890. end else begin
  891. pw := @((pr-1)^.Weights);
  892. pr^.Weights := Copy(pw^);
  893. cw := Length(pr^.Weights);
  894. ki := Ord(p^.WeigthKind);
  895. for ki := Ord(rwkPrimary) to Ord(rwkTertiary) do begin
  896. if (ki < Ord(p^.WeigthKind)) then
  897. pr^.Weights[(cw-1)].Weights[ki] := pw^[(cw-1)].Weights[ki]
  898. else if (ki = Ord(p^.WeigthKind)) then begin
  899. if (pw^[(cw-1)].Weights[ki] = 0) then
  900. pr^.Weights[(cw-1)].Weights[ki] := pwb^[(Length(pwb^)-1)].Weights[ki]+1
  901. else
  902. pr^.Weights[(cw-1)].Weights[ki] := pw^[(cw-1)].Weights[ki]+1;
  903. end else begin
  904. pr^.Weights[(cw-1)].Weights[ki] := 0;
  905. end;
  906. end;
  907. end;
  908. Inc(pr);
  909. Inc(ral);
  910. end;
  911. end else begin
  912. pbase := nil;
  913. pwb := nil;
  914. end;
  915. Inc(p);
  916. Inc(i);
  917. end;
  918. SetLength(r,ral);
  919. AResult := r;
  920. Result := Length(AResult);
  921. end;}
  922. function IndexOf(
  923. const APattern : array of TUnicodeCodePoint;
  924. const AList : PUCA_LineRec;
  925. const AListLen : Integer
  926. ) : Integer;overload;
  927. var
  928. i, lengthPattern, sizePattern : Integer;
  929. pl : PUCA_LineRec;
  930. begin
  931. Result := -1;
  932. if (Length(APattern) = 0) then
  933. exit;
  934. if (AListLen = 0) then
  935. exit;
  936. lengthPattern := Length(APattern);
  937. sizePattern := lengthPattern*SizeOf(TUnicodeCodePoint);
  938. pl := AList;
  939. for i := 0 to AListLen - 1 do begin
  940. if (Length(pl^.CodePoints) = lengthPattern) and
  941. CompareMem(@pl^.CodePoints[0],@APattern[0],sizePattern)
  942. then begin
  943. Result := i;
  944. Break;
  945. end;
  946. Inc(pl);
  947. end;
  948. end;
  949. function IsIgnorable(AWeight : TUCA_WeightRecArray) : Boolean;
  950. var
  951. i : Integer;
  952. begin
  953. if (Length(AWeight) = 0) then
  954. exit(True);
  955. for i := Low(AWeight) to High(AWeight) do begin
  956. if (AWeight[i].Weights[0] <> 0) or
  957. (AWeight[i].Weights[1] <> 0) or
  958. (AWeight[i].Weights[2] <> 0)
  959. then begin
  960. exit(False);
  961. end;
  962. end;
  963. Result := True;
  964. end;
  965. function RemoveIgnorables(
  966. AItem : TUnicodeCodePointArray;
  967. const AList : PUCA_LineRec;
  968. const AListLen : Integer
  969. ) : TUnicodeCodePointArray;
  970. var
  971. i, c, k : Integer;
  972. begin
  973. SetLength(Result,Length(AItem));
  974. c := 0;
  975. for i := 0 to Length(AItem) - 1 do begin
  976. k := IndexOf([AItem[i]],AList,AListLen);
  977. if (k >= 0) and
  978. IsIgnorable(AList[k].Weights)
  979. then
  980. k := -1;
  981. if (k >= 0) then begin
  982. Result[c] := AItem[i];
  983. c := c+1;
  984. end;
  985. end;
  986. SetLength(Result,c);
  987. end;
  988. function Compress(
  989. const AData : TUCA_LineRecArray;
  990. out AResult : TUCA_LineRecArray
  991. ) : Boolean;
  992. var
  993. r : TUCA_LineRecArray;
  994. pr, p : PUCA_LineRec;
  995. ral : Integer;
  996. function FindOutSlot() : Boolean;
  997. var
  998. k : Integer;
  999. begin
  1000. k := IndexOf(p^.CodePoints,@r[0],ral);
  1001. Result := (k >= 0);
  1002. if (k = -1) then begin
  1003. k := ral;
  1004. ral := ral + 1;
  1005. end;
  1006. pr := @r[k];
  1007. end;
  1008. procedure AddContextData();
  1009. var
  1010. k : Integer;
  1011. begin
  1012. if not p^.HasContext() then
  1013. exit;
  1014. k := Length(pr^.Context.Data);
  1015. SetLength(pr^.Context.Data,(k+1));
  1016. pr^.Context.Data[k].CodePoints := Copy(p^.Context.Data[0].CodePoints);
  1017. pr^.Context.Data[k].Weights := Copy(p^.Weights);
  1018. end;
  1019. procedure AddItem();
  1020. begin
  1021. pr^.Assign(p);
  1022. if p^.HasContext() then begin
  1023. SetLength(pr^.Context.Data,0);
  1024. pr^.Weights := nil;
  1025. AddContextData();
  1026. end;
  1027. end;
  1028. var
  1029. c, i : Integer;
  1030. begin
  1031. c := Length(AData);
  1032. if (c = 0) then
  1033. exit;
  1034. SetLength(r,c);
  1035. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1036. pr := @r[0];
  1037. p := @AData[0];
  1038. ral := 0;
  1039. i := 0;
  1040. AddItem();
  1041. ral := 1;
  1042. i := 1;
  1043. Inc(p);
  1044. while (i < c) do begin
  1045. if FindOutSlot() then
  1046. AddContextData()
  1047. else
  1048. AddItem();
  1049. Inc(p);
  1050. Inc(i);
  1051. end;
  1052. SetLength(r,ral);
  1053. AResult := r;
  1054. Result := (ral < Length(AData));
  1055. end;
  1056. function MarkSuffixAsChanged(
  1057. const AData : PReorderUnit;
  1058. const ADataLen : Integer
  1059. ) : Integer;
  1060. var
  1061. i, k : Integer;
  1062. p, q : PReorderUnit;
  1063. suffixChar : TUnicodeCodePoint;
  1064. begin
  1065. Result := 0;
  1066. if (ADataLen <= 1) then
  1067. exit;
  1068. q := AData;
  1069. p := AData;
  1070. for i := 0 to ADataLen - 1 do begin
  1071. if not(p^.IsVirtual()) and p^.Changed then begin
  1072. suffixChar := p^.Characters[0];
  1073. for k := 0 to ADataLen - 1 do begin
  1074. if not(q[k].Changed) and (q[k].Characters[0] = suffixChar) then begin
  1075. q[k].Changed := True;
  1076. Result := Result + 1;
  1077. end;
  1078. end;
  1079. end;
  1080. Inc(p);
  1081. end;
  1082. end;
  1083. function CountChangedPrimaries(APosition, AEnd : PReorderUnit) : Integer;
  1084. var
  1085. p : PReorderUnit;
  1086. begin
  1087. p := APosition+1;
  1088. while (p < AEnd) and
  1089. p^.Changed and (p^.WeigthKind = TReorderWeigthKind.Primary)
  1090. do begin
  1091. p := p+1;
  1092. end;
  1093. Result := (p-(APosition+1));
  1094. end;
  1095. function FindNextUnchangedPrimary(AStartPos, AEnd : PReorderUnit) : PReorderUnit;
  1096. var
  1097. p : PReorderUnit;
  1098. begin
  1099. p := AStartPos;
  1100. while (p < AEnd) and (p^.WeigthKind <> TReorderWeigthKind.Primary) do begin
  1101. p := p+1;
  1102. end;
  1103. if (p >= AEnd) or p^.Changed or
  1104. (p^.WeigthKind <> TReorderWeigthKind.Primary) or
  1105. (p^.InitialPosition < 1)
  1106. then begin
  1107. p := nil;
  1108. end;
  1109. Result := p;
  1110. end;
  1111. function ComputeWeigthItem(
  1112. ABase : PUCA_WeightRecArray;
  1113. APosition : PReorderUnit;
  1114. AEnd : PReorderUnit;
  1115. ADataWeigths : TUCA_LineRecArray
  1116. ) : TUCA_WeightRecArray;
  1117. var
  1118. r : TUCA_WeightRecArray;
  1119. c, i : Integer;
  1120. p : PReorderUnit;
  1121. changedPrimaryCount : Integer;
  1122. nextUnchangedPrimary : PReorderUnit;
  1123. begin
  1124. case APosition^.WeigthKind of
  1125. TReorderWeigthKind.Primary :
  1126. begin
  1127. if (Length(ABase^) = 2) and
  1128. (ABase^[1].Weights[1] = 0) and (ABase^[1].Weights[2] = 0)
  1129. then begin
  1130. r := Copy(ABase^);
  1131. Inc(r[1].Weights[0]);
  1132. end else begin
  1133. changedPrimaryCount := CountChangedPrimaries(APosition,AEnd);
  1134. nextUnchangedPrimary := FindNextUnchangedPrimary(APosition+changedPrimaryCount+1,AEnd);
  1135. if (nextUnchangedPrimary = nil) or
  1136. ( (ABase^[0].Weights[0]+changedPrimaryCount+1) >=
  1137. ADataWeigths[nextUnchangedPrimary^.InitialPosition-1].Weights[0].Weights[0]
  1138. )
  1139. then begin
  1140. p := nil;
  1141. if (nextUnchangedPrimary = nil) and (APosition < (AEnd-1)) then begin
  1142. p := APosition+1;
  1143. end;
  1144. if (nextUnchangedPrimary = nil) and
  1145. ( (p = nil) or (p^.WeigthKind = TReorderWeigthKind.Primary)) and
  1146. (Length(ABase^) = 1) and (ABase^[0].Weights[0] < $FFF0)
  1147. then begin
  1148. SetLength(r,1);
  1149. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1150. r[0].Weights[0] := (ABase^[0].Weights[0] + 1);
  1151. r[0].Variable := ABase^[0].Variable;
  1152. end else begin
  1153. SetLength(r,2);
  1154. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1155. r[0].Weights[0] := (ABase^[0].Weights[0] + 1);
  1156. r[0].Variable := ABase^[0].Variable;
  1157. r[1].Weights[0] := 1;
  1158. end;
  1159. end else begin
  1160. SetLength(r,2);
  1161. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1162. r[0].Weights[0] := (ABase^[0].Weights[0] + 1);
  1163. r[0].Variable := ABase^[0].Variable;
  1164. r[1] := r[0];
  1165. end;
  1166. end;
  1167. end;
  1168. TReorderWeigthKind.Secondary :
  1169. begin
  1170. c := Length(ABase^);
  1171. SetLength(r,c);
  1172. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1173. for i := 0 to c-1 do begin
  1174. r[i].Weights[0] := ABase^[i].Weights[0];
  1175. r[i].Variable := ABase^[i].Variable;
  1176. end;
  1177. r[0].Weights[1] := (ABase^[0].Weights[1] + 1);
  1178. end;
  1179. TReorderWeigthKind.Tertiary :
  1180. begin
  1181. c := Length(ABase^);
  1182. SetLength(r,c);
  1183. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  1184. for i := 0 to c-1 do begin
  1185. r[i].Weights[0] := ABase^[i].Weights[0];
  1186. r[i].Weights[1] := ABase^[i].Weights[1];
  1187. r[i].Variable := ABase^[i].Variable;
  1188. end;
  1189. r[0].Weights[2] := (ABase^[0].Weights[2] + 1);
  1190. end;
  1191. TReorderWeigthKind.Identity : r := Copy(ABase^);
  1192. else
  1193. r := nil;
  1194. end;
  1195. Result := r;
  1196. end;
  1197. {$DEFINE UNI_BUILD_TIME}
  1198. {$include weight_derivation.inc}
  1199. function InternalComputeWeigths(
  1200. const AData : PReorderUnit;
  1201. const ADataLen : Integer;
  1202. const ADataWeigths : TUCA_LineRecArray;
  1203. const AUnifiedIdeographs : TCodePointRecArray;
  1204. out AResult : TUCA_LineRecArray
  1205. ) : Integer;
  1206. function GetWeigth(AItem : PReorderUnit) : PUCA_WeightRecArray;
  1207. begin
  1208. Result := nil;
  1209. if (AItem^.InitialPosition < 1) or (AItem^.InitialPosition > Length(ADataWeigths)) then
  1210. raise ECldrException.CreateFmt('Invalid "InitialPosition" value : %d.',[AItem^.InitialPosition]);
  1211. Result := @ADataWeigths[(AItem^.InitialPosition-1)].Weights;
  1212. end;
  1213. var
  1214. r : TUCA_LineRecArray;
  1215. pr : PUCA_LineRec;
  1216. dataEnd : PReorderUnit;
  1217. procedure AddContext(const ACodePointPattern : TUnicodeCodePointArray);
  1218. var
  1219. k : Integer;
  1220. begin
  1221. k := Length(pr^.Context.Data);
  1222. SetLength(pr^.Context.Data,(k+1));
  1223. pr^.Context.Data[k].CodePoints := Copy(ACodePointPattern);
  1224. SetLength(pr^.Context.Data[k].Weights,0);
  1225. end;
  1226. var
  1227. ral : Integer;
  1228. i : Integer;
  1229. p : PReorderUnit;
  1230. pbase : PReorderUnit;
  1231. pwb : PUCA_WeightRecArray;
  1232. actualBegin : Boolean;
  1233. loopIndex : Integer;
  1234. procedure SkipDeletion();
  1235. begin
  1236. pr^.CodePoints := Copy(p^.Characters);
  1237. pr^.Deleted := True;
  1238. SetLength(pr^.Weights,0);
  1239. if p^.HasContext() then
  1240. AddContext(p^.Context);
  1241. Inc(pr);
  1242. Inc(ral);
  1243. Inc(p);
  1244. Inc(i);
  1245. end;
  1246. procedure FindBaseItem();
  1247. begin
  1248. if (pbase = nil) or (pwb^ = nil) then begin
  1249. if actualBegin then begin
  1250. pwb := @ADataWeigths[0].Weights;
  1251. end else begin
  1252. pbase := p - 1;
  1253. if pbase^.Changed then
  1254. pwb := @((pr-1)^.Weights)
  1255. else
  1256. pwb := GetWeigth(pbase);
  1257. if (pwb^ = nil) and (pbase = AData) then
  1258. pwb := @ADataWeigths[0].Weights;
  1259. end;
  1260. end;
  1261. end;
  1262. function InternalComputeWeights(const AList : array of TUnicodeCodePointArray) : TUCA_WeightRecArray;
  1263. var
  1264. kral : Integer;
  1265. kres : TUCA_WeightRecArray;
  1266. procedure EnsureResultLength(const APlus : Integer);//inline;
  1267. begin
  1268. if ((kral+APlus) > Length(kres)) then
  1269. SetLength(kres,(2*(kral+APlus)));
  1270. end;
  1271. procedure AddToResult(const AValue : TUCA_WeightRecArray);//inline;
  1272. begin
  1273. if not IsZero(AValue) then begin
  1274. EnsureResultLength(Length(AValue));
  1275. Move(AValue[0],kres[kral],(Length(AValue)*SizeOf(kres[0])));
  1276. kral := kral + Length(AValue);
  1277. end;
  1278. end;
  1279. var
  1280. kc, k, ktempIndex, ki : Integer;
  1281. tmpWeight : array of TUCA_PropWeights;
  1282. cp : TUnicodeCodePoint;
  1283. begin
  1284. kc := Length(AList);
  1285. kral := 0;
  1286. SetLength(kres,(10*kc));
  1287. FillChar(kres[0],(Length(kres)*SizeOf(kres[0])),0);
  1288. for k := 0 to kc - 1 do begin
  1289. ktempIndex := IndexOf(AList[k],@r[0],ral);
  1290. if (ktempIndex <> -1) then begin
  1291. AddToResult(r[ktempIndex].Weights);
  1292. Continue;
  1293. end;
  1294. ktempIndex := IndexOf(AList[k],[],AData,ADataLen);
  1295. if (ktempIndex <> -1) then begin
  1296. if not AData[ktempIndex].Changed then begin
  1297. AddToResult(ADataWeigths[AData[ktempIndex].InitialPosition-1].Weights);
  1298. Continue;
  1299. end;
  1300. end;
  1301. if (Length(AList[k]) > 1) then begin
  1302. for ki := 0 to Length(AList[k]) - 1 do begin
  1303. ktempIndex := IndexOf([AList[k][ki]],@r[0],ral);
  1304. if (ktempIndex <> -1) then begin
  1305. AddToResult(r[ktempIndex].Weights);
  1306. Continue;
  1307. end;
  1308. cp := AList[k][ki];
  1309. ktempIndex := IndexOf([cp],[],AData,ADataLen); //ktempIndex := IndexOf([AList[k][ki]],[],AData,ADataLen);
  1310. if (ktempIndex <> -1) then begin
  1311. //if not AData[ktempIndex].Changed then begin
  1312. AddToResult(ADataWeigths[AData[ktempIndex].InitialPosition-1].Weights);
  1313. Continue;
  1314. //end;
  1315. end;
  1316. SetLength(tmpWeight,2);
  1317. DeriveWeight(AList[k][ki],@tmpWeight[0],AUnifiedIdeographs);
  1318. EnsureResultLength(2);
  1319. kres[kral].Weights[0] := tmpWeight[0].Weights[0];
  1320. kres[kral].Weights[1] := tmpWeight[0].Weights[1];
  1321. kres[kral].Weights[2] := tmpWeight[0].Weights[2];
  1322. kres[kral+1].Weights[0] := tmpWeight[1].Weights[0];
  1323. kres[kral+1].Weights[1] := tmpWeight[1].Weights[1];
  1324. kres[kral+1].Weights[2] := tmpWeight[1].Weights[2];
  1325. kral := kral + 2;
  1326. tmpWeight := nil;
  1327. end;
  1328. Continue;// ??????????????
  1329. end;
  1330. SetLength(tmpWeight,2);
  1331. DeriveWeight(AList[k][0],@tmpWeight[0],AUnifiedIdeographs);
  1332. EnsureResultLength(2);
  1333. kres[kral].Weights[0] := tmpWeight[0].Weights[0];
  1334. kres[kral].Weights[1] := tmpWeight[0].Weights[1];
  1335. kres[kral].Weights[2] := tmpWeight[0].Weights[2];
  1336. kres[kral+1].Weights[0] := tmpWeight[1].Weights[0];
  1337. kres[kral+1].Weights[1] := tmpWeight[1].Weights[1];
  1338. kres[kral+1].Weights[2] := tmpWeight[1].Weights[2];
  1339. kral := kral + 2;
  1340. tmpWeight := nil;
  1341. end;
  1342. SetLength(kres,kral);
  1343. Result := kres;
  1344. end;
  1345. procedure Handle_Expansion();
  1346. var
  1347. expChars : array[0..1] of TUnicodeCodePointArray;
  1348. kres : TUCA_WeightRecArray;
  1349. begin
  1350. expChars[0] := (p-1)^.Characters;
  1351. expChars[1] := p^.ExpansionChars;
  1352. kres := InternalComputeWeights(expChars);
  1353. pr^.Weights := ComputeWeigthItem(@kres,p,dataEnd,ADataWeigths);
  1354. end;
  1355. function FindLastNotEmptyWeigth() : PUCA_LineRec;
  1356. var
  1357. p0, pk : PUCA_LineRec;
  1358. begin
  1359. p0 := @r[0];
  1360. pk := pr-1;
  1361. while (pk >= p0) do begin
  1362. if (Length(pk^.Weights) > 0) then
  1363. exit(pk);
  1364. pk := pk-1;
  1365. end;
  1366. Result := nil;
  1367. end;
  1368. procedure CheckWeight(AItem : TUCA_WeightRecArray);
  1369. begin
  1370. if (Length(AItem) = 0) then
  1371. raise ECldrException.Create(sUnexpectedConditionsFailure);
  1372. end;
  1373. var
  1374. c, ti : Integer;
  1375. q : PReorderUnit;
  1376. pw : PUCA_WeightRecArray;
  1377. pt : PUCA_LineRec;
  1378. begin
  1379. Result := 0;
  1380. if (ADataLen < 1) then
  1381. exit;
  1382. SetLength(AResult,0);
  1383. dataEnd := AData+ADataLen;
  1384. while True do begin
  1385. for loopIndex := 0 to 1 do begin
  1386. c := ADataLen;
  1387. ral := 0;
  1388. SetLength(r,c);
  1389. pr := @r[0];
  1390. for i := Low(r) to High(r) do begin
  1391. pr^.Clear();
  1392. Inc(pr);
  1393. end;
  1394. q := nil;
  1395. pbase := nil;
  1396. pr := @r[0];
  1397. p := AData;
  1398. i := 0;
  1399. while (i < c) do begin
  1400. if (p^.WeigthKind = TReorderWeigthKind.Deletion) then begin
  1401. SkipDeletion();
  1402. Continue;
  1403. end;
  1404. if p^.Changed then begin
  1405. actualBegin := (i = 0) or (((p-1)^.WeigthKind = TReorderWeigthKind.Deletion));
  1406. FindBaseItem();
  1407. if p^.IsExpansion() then begin
  1408. if (loopIndex = 0) then begin
  1409. q := p;
  1410. Inc(p);
  1411. Inc(i);
  1412. while (i < c) do begin
  1413. if (p^.WeigthKind = TReorderWeigthKind.Primary) then
  1414. Break;
  1415. Inc(p);
  1416. Inc(i);
  1417. end;
  1418. Continue;
  1419. end;
  1420. pr^.CodePoints := Copy(p^.Characters);
  1421. Handle_Expansion();
  1422. if p^.HasContext() then
  1423. AddContext(p^.Context);
  1424. Inc(pr);
  1425. Inc(ral);
  1426. end else if actualBegin then begin
  1427. pr^.CodePoints := Copy(p^.Characters);
  1428. pw := pwb;
  1429. CheckWeight(pw^);
  1430. pr^.Weights := Copy(pw^);
  1431. if p^.HasContext() then
  1432. AddContext(p^.Context);
  1433. Inc(pr);
  1434. Inc(ral);
  1435. end else if (p^.WeigthKind = TReorderWeigthKind.Identity) then begin
  1436. pr^.CodePoints := Copy(p^.Characters);
  1437. q := p - 1;
  1438. if (q = pbase) then
  1439. pw := pwb
  1440. else
  1441. pw := @((pr-1)^.Weights);
  1442. CheckWeight(pw^);
  1443. pr^.Weights := Copy(pw^);
  1444. if p^.HasContext() then
  1445. AddContext(p^.Context);
  1446. Inc(pr);
  1447. Inc(ral);
  1448. end else begin
  1449. CheckWeight(pwb^);
  1450. pr^.CodePoints := Copy(p^.Characters);
  1451. if ((p - 1) = pbase) then begin
  1452. pr^.Weights := ComputeWeigthItem(pwb,p,dataEnd,ADataWeigths);
  1453. end else begin
  1454. if (Length(pr^.Weights) = 0) then begin
  1455. pt := FindLastNotEmptyWeigth();
  1456. if (pt = nil) then
  1457. raise ECldrException.Create(sUnexpectedConditionsFailure);
  1458. CheckWeight(pt^.Weights);
  1459. end;
  1460. pr^.Weights := ComputeWeigthItem(@pt^.Weights,p,dataEnd,ADataWeigths);
  1461. end;
  1462. if p^.HasContext() then
  1463. AddContext(p^.Context);
  1464. Inc(pr);
  1465. Inc(ral);
  1466. end;
  1467. end else begin
  1468. if (i > 0) and ((p-1)^.WeigthKind <> TReorderWeigthKind.Deletion) and (p-1)^.Changed and
  1469. (ral > 0)
  1470. then begin
  1471. pw := GetWeigth(p);
  1472. CheckWeight(pw^);
  1473. ti := CompareSortKey(SimpleFormKey((pr-1)^.Weights),SimpleFormKey(pw^));
  1474. if ( (p^.WeigthKind = TReorderWeigthKind.Identity) and (ti > 0) ) or
  1475. ( (p^.WeigthKind >= TReorderWeigthKind.Primary) and (ti >= 0) )
  1476. then begin
  1477. p^.Changed := True;
  1478. Continue;
  1479. end;
  1480. end;
  1481. pbase := nil;
  1482. pwb := nil;
  1483. end;
  1484. Inc(p);
  1485. Inc(i);
  1486. end;
  1487. end;
  1488. SetLength(r,ral);
  1489. if (MarkSuffixAsChanged(AData,ADataLen) = 0) then
  1490. Break;
  1491. end;
  1492. Compress(r,AResult);
  1493. Result := Length(AResult);
  1494. end;
  1495. function ComputeWeigths(
  1496. const AData : PReorderUnit;
  1497. const ADataLen : Integer;
  1498. const ADataWeigths : TUCA_LineRecArray;
  1499. const AUnifiedIdeographs : TCodePointRecArray;
  1500. out AResult : TUCA_LineRecArray
  1501. ) : Integer;
  1502. var
  1503. locData : array of TReorderUnit;
  1504. i, actualLength : Integer;
  1505. p : PReorderUnit;
  1506. begin
  1507. SetLength(AResult,0);
  1508. SetLength(locData,ADataLen);
  1509. actualLength := 0;
  1510. p := AData;
  1511. for i := 0 to ADataLen-1 do begin
  1512. if not p^.IsVirtual() then begin
  1513. locData[actualLength].Assign(p);
  1514. actualLength := actualLength+1;
  1515. end;
  1516. Inc(p);
  1517. end;
  1518. if (Length(locData) <> actualLength) then
  1519. SetLength(locData,actualLength);
  1520. Result := InternalComputeWeigths(@locData[0],actualLength,ADataWeigths,AUnifiedIdeographs,AResult);
  1521. p := AData;
  1522. for i := 0 to actualLength-1 do begin
  1523. while p^.IsVirtual() do begin
  1524. Inc(p);
  1525. end;
  1526. p^.Assign(@locData[i]);
  1527. Inc(p);
  1528. end;
  1529. end;
  1530. const
  1531. // Bidirectional Ordering Controls : Unicode 9 => Page 833
  1532. ARABIC_LETTER_MARK = $061C;// ALM arabic letter mark alm
  1533. LEFT_TO_RIGHT_MARK = $200E;// LRM left-to-right mark lrm
  1534. RIGHT_TO_LEFT_MARK = $200F;// RLM right-to-left mark rlm
  1535. LEFT_TO_RIGHT_EMBEDDING = $202A;// LRE left-to-right embedding lre
  1536. RIGHT_TO_LEFT_EMBEDDING = $202B;// RLE right-to-left embedding rle
  1537. POP_DIRECTIONAL_FORMATTING = $202C;// PDF pop directional formatting pdf
  1538. LEFT_TO_RIGHT_OVERRIDE = $202D;// LRO left-to-right override lro
  1539. RIGHT_TO_LEFT_OVERRIDE = $202E;// RLO right-to-left override rlo
  1540. LEFT_TO_RIGHT_ISOLATE = $2066;// LRI left-to-right isolate lri
  1541. RIGHT_TO_LEFT_ISOLATE = $2067;// RLI right-to-left isolate rli
  1542. FIRST_STRONG_ISOLATE = $2068;// FSI first strong isolate fsi
  1543. POP_DIRECTIONAL_ISOLATE = $2069;// PDI pop directional isolate pdi
  1544. BIDIRECTIONAL_ORDERING_CONTROLS : array[0..11] of DWord = (
  1545. ARABIC_LETTER_MARK, LEFT_TO_RIGHT_MARK, RIGHT_TO_LEFT_MARK,
  1546. LEFT_TO_RIGHT_EMBEDDING, RIGHT_TO_LEFT_EMBEDDING,
  1547. POP_DIRECTIONAL_FORMATTING, LEFT_TO_RIGHT_OVERRIDE, RIGHT_TO_LEFT_OVERRIDE,
  1548. LEFT_TO_RIGHT_ISOLATE, RIGHT_TO_LEFT_ISOLATE, FIRST_STRONG_ISOLATE,
  1549. POP_DIRECTIONAL_ISOLATE
  1550. );
  1551. function IsBidirectionalOrderingControls(const ACodePoint : DWord) : Boolean;inline;
  1552. begin
  1553. Result :=
  1554. IndexDWord(
  1555. BIDIRECTIONAL_ORDERING_CONTROLS, SizeOf(BIDIRECTIONAL_ORDERING_CONTROLS),
  1556. ACodePoint
  1557. ) >= 0;
  1558. end;
  1559. function RemoveBidirectionalOrderingControls(
  1560. AItem : TUnicodeCodePointArray
  1561. ) : TUnicodeCodePointArray;
  1562. var
  1563. i, c, k : Integer;
  1564. begin
  1565. SetLength(Result,Length(AItem));
  1566. c := 0;
  1567. for i := 0 to Length(AItem) - 1 do begin
  1568. if not IsBidirectionalOrderingControls(AItem[i]) then begin
  1569. Result[c] := AItem[i];
  1570. c := c+1;
  1571. end;
  1572. end;
  1573. SetLength(Result,c);
  1574. end;
  1575. function FillInitialPositions(
  1576. AData : PReorderUnit;
  1577. const ADataLen : Integer;
  1578. const ADataWeigths : TUCA_LineRecArray
  1579. ) : Integer;
  1580. var
  1581. locNotFound, i, cw : Integer;
  1582. p : PReorderUnit;
  1583. pw : PUCA_LineRec;
  1584. chars : TUnicodeCodePointArray;
  1585. k : Integer;
  1586. begin
  1587. locNotFound := 0;
  1588. cw := Length(ADataWeigths);
  1589. if (cw > 0) then
  1590. pw := @ADataWeigths[0]
  1591. else
  1592. pw := nil;
  1593. p := AData;
  1594. for i := 0 to ADataLen - 1 do begin
  1595. if not p^.IsVirtual() then begin
  1596. p^.InitialPosition := IndexOf(p^.Characters,pw,cw) + 1;
  1597. if (p^.InitialPosition = 0) then begin
  1598. chars := RemoveBidirectionalOrderingControls(p^.Characters);
  1599. p^.InitialPosition := IndexOf(chars,pw,cw) + 1;
  1600. if (p^.InitialPosition > 0) then begin
  1601. k := IndexOf(chars,[],AData,ADataLen);
  1602. if (k < 0) then
  1603. p^.Characters := chars;
  1604. end;
  1605. if (p^.InitialPosition = 0) then begin
  1606. chars := RemoveIgnorables(p^.Characters,pw,cw);
  1607. p^.InitialPosition := IndexOf(chars,pw,cw) + 1;
  1608. end;
  1609. end;
  1610. if (p^.InitialPosition = 0) then
  1611. Inc(locNotFound);
  1612. end;
  1613. Inc(p);
  1614. end;
  1615. Result := locNotFound;
  1616. end;
  1617. { TSettingRec }
  1618. class function TSettingRec.From(
  1619. const AName : UTF8String;
  1620. const AValues : array of UTF8String;
  1621. const AOption : TSettingOption
  1622. ) : TSettingRec;
  1623. var
  1624. i : Integer;
  1625. begin
  1626. Result.Name := AName;
  1627. SetLength(Result.Values,Length(AValues));
  1628. for i := 0 to Length(AValues)-1 do
  1629. Result.Values[i] := AValues[i];
  1630. Result.OptionValue := AOption;
  1631. end;
  1632. procedure TSettingRec.Assign(const AItem : PSettingRec);
  1633. begin
  1634. if (AItem = nil) then begin
  1635. Clear();
  1636. end else begin
  1637. Self.Name := AItem^.Name;
  1638. Self.Values := Copy(AItem^.Values);
  1639. Self.OptionValue := AItem^.OptionValue;
  1640. Self.Understood := AItem^.Understood;
  1641. end;
  1642. end;
  1643. procedure TSettingRec.Clear;
  1644. begin
  1645. Name := '';
  1646. Values := nil;
  1647. OptionValue := TSettingOption.Unknown;
  1648. Understood := False;
  1649. end;
  1650. { TCldrImportList }
  1651. function TCldrImportList.GetCount: Integer;
  1652. begin
  1653. Result := Length(FItems);
  1654. end;
  1655. function TCldrImportList.GetItem(AIndex : Integer): TCldrImport;
  1656. begin
  1657. if (AIndex < 0) or (AIndex >= Length(FItems)) then
  1658. raise ERangeError.CreateFmt(SListIndexError,[AIndex]);
  1659. Result := FItems[AIndex];
  1660. end;
  1661. destructor TCldrImportList.Destroy();
  1662. begin
  1663. Clear();
  1664. inherited;
  1665. end;
  1666. procedure TCldrImportList.Clear();
  1667. var
  1668. i : Integer;
  1669. begin
  1670. for i := Low(FItems) to High(FItems) do
  1671. FreeAndNil(FItems[i]);
  1672. SetLength(FItems,0);
  1673. end;
  1674. function TCldrImportList.IndexOf(const ASource, AType: string): Integer;
  1675. var
  1676. i : Integer;
  1677. begin
  1678. for i := Low(FItems) to High(FItems) do begin
  1679. if (FItems[i].Source = ASource) and (FItems[i].TypeName = AType) then begin
  1680. Result := i;
  1681. exit;
  1682. end;
  1683. end;
  1684. Result := -1;
  1685. end;
  1686. function TCldrImportList.Find(const ASource, AType: string): TCldrImport;
  1687. var
  1688. i : Integer;
  1689. begin
  1690. i := IndexOf(ASource,AType);
  1691. if (i >= 0) then
  1692. Result := FItems[i]
  1693. else
  1694. Result := nil;
  1695. end;
  1696. function TCldrImportList.Add(const ASource, AType: string): TCldrImport;
  1697. var
  1698. i : Integer;
  1699. begin
  1700. i := IndexOf(ASource,AType);
  1701. if (i >= 0) then begin
  1702. Result := FItems[i];
  1703. end else begin
  1704. Result := TCldrImport.Create();
  1705. Result.FSource := ASource;
  1706. Result.FTypeName := AType;
  1707. i := Length(FItems);
  1708. SetLength(FItems,(i+1));
  1709. FItems[i] := Result;
  1710. end;
  1711. end;
  1712. { TCldrCollationRepository }
  1713. function TCldrCollationRepository.GetItem(const AIndex : Integer): TCldrCollation;
  1714. begin
  1715. if (AIndex < 0) or (AIndex >= Length(FItems)) then
  1716. raise ERangeError.CreateFmt(SListIndexError,[AIndex]);
  1717. Result := FItems[AIndex];
  1718. end;
  1719. function TCldrCollationRepository.GetItemCount: Integer;
  1720. begin
  1721. Result := Length(FItems);
  1722. end;
  1723. function TCldrCollationRepository.IndexOfItem(AItem: TCldrCollation): Integer;
  1724. var
  1725. i : Integer;
  1726. begin
  1727. for i := Low(FItems) to High(FItems) do begin
  1728. if (FItems[i] = AItem) then begin
  1729. Result := i;
  1730. exit;
  1731. end;
  1732. end;
  1733. Result := -1;
  1734. end;
  1735. procedure TCldrCollationRepository.Add(AItem: TCldrCollation);
  1736. var
  1737. i : Integer;
  1738. begin
  1739. if (AItem = nil) then
  1740. raise EArgumentException.CreateFmt(SParamIsNil,['AItem: TCldrCollation']);
  1741. if (IndexOfItem(AItem) >= 0) then
  1742. raise EArgumentException.CreateFmt(sCollationsExistsAlready,[AItem.Language]);
  1743. i := Length(FItems);
  1744. SetLength(FItems,(i+1));
  1745. AItem.FRepository := Self;
  1746. FItems[i] := AItem;
  1747. end;
  1748. constructor TCldrCollationRepository.Create(ALoader: ICldrCollationLoader);
  1749. begin
  1750. if (ALoader = nil) then
  1751. raise EArgumentException.CreateFmt(SInvalidPropertyElement,['Loader']);
  1752. SetLoader(ALoader);
  1753. end;
  1754. destructor TCldrCollationRepository.Destroy;
  1755. begin
  1756. Clear();
  1757. inherited Destroy;
  1758. end;
  1759. procedure TCldrCollationRepository.FreeItems();
  1760. var
  1761. i : Integer;
  1762. begin
  1763. for i := 0 to Length(FItems) - 1 do
  1764. FreeAndNil(FItems[i]);
  1765. SetLength(FItems,0);
  1766. end;
  1767. procedure TCldrCollationRepository.Clear();
  1768. begin
  1769. FreeItems();
  1770. end;
  1771. procedure TCldrCollationRepository.SetLoader(AValue: ICldrCollationLoader);
  1772. begin
  1773. if (FLoader <> AValue) then
  1774. FLoader := AValue;
  1775. end;
  1776. function TCldrCollationRepository.IndexOf(const ALanguage: string): Integer;
  1777. var
  1778. i : Integer;
  1779. begin
  1780. for i := Low(FItems) to High(FItems) do begin
  1781. if (FItems[i].Language = ALanguage) then begin
  1782. Result := i;
  1783. exit;
  1784. end
  1785. end;
  1786. Result := -1;
  1787. end;
  1788. function TCldrCollationRepository.Find(const ALanguage: string): TCldrCollation;
  1789. var
  1790. i : Integer;
  1791. begin
  1792. i := IndexOf(ALanguage);
  1793. if (i >= 0) then
  1794. Result := FItems[i]
  1795. else
  1796. Result := nil;
  1797. end;
  1798. function TCldrCollationRepository.Load(
  1799. const ALanguage : string;
  1800. const AMode : TCldrParserMode
  1801. ) : TCldrCollation;
  1802. var
  1803. isnew : Boolean;
  1804. begin
  1805. Result := Find(ALanguage);
  1806. if (Result <> nil) then begin
  1807. if (Result.Mode = TCldrParserMode.FullParsing) or (Result.Mode = AMode) then
  1808. exit;
  1809. end;
  1810. isnew := (Result = nil);
  1811. if isnew then
  1812. Result := TCldrCollation.Create();
  1813. try
  1814. Loader.LoadCollation(ALanguage,Result,AMode);
  1815. if isnew then
  1816. Add(Result);
  1817. except
  1818. if isnew then
  1819. FreeAndNil(Result);
  1820. raise;
  1821. end;
  1822. end;
  1823. function TCldrCollationRepository.LoadType(
  1824. const ALanguage, AType, ATypeALT : string
  1825. ) : TCldrCollationItem;
  1826. var
  1827. item : TCldrCollationItem;
  1828. col : TCldrCollation;
  1829. newItem : Boolean;
  1830. begin
  1831. col := Find(ALanguage);
  1832. if (col = nil) then
  1833. col := Load(ALanguage,TCldrParserMode.HeaderParsing);
  1834. if (ATypeALT <> '') then
  1835. item := col.Find(AType,ATypeALT)
  1836. else
  1837. item := col.Find(AType);
  1838. newItem := (item = nil);
  1839. try
  1840. if newItem then
  1841. item := TCldrCollationItem.Create();
  1842. if newItem or (item.Mode = TCldrParserMode.HeaderParsing) then
  1843. Loader.LoadCollationType(ALanguage,AType,item);
  1844. if newItem then
  1845. col.Add(item);
  1846. except
  1847. if newItem then
  1848. item.Free();
  1849. raise;
  1850. end;
  1851. Result := item;
  1852. end;
  1853. { TCldrCollationItem }
  1854. class function TCldrCollationItem.FindAlias(
  1855. const AName : UTF8String
  1856. ) : UTF8String;
  1857. var
  1858. s : UTF8String;
  1859. i : Integer;
  1860. begin
  1861. Result := '';
  1862. if (AName <> '') then begin
  1863. s := LowerCase(AName);
  1864. for i := Low(BCP47_COLLATION_TYPE_ALIAS) to High(BCP47_COLLATION_TYPE_ALIAS) do begin
  1865. if (s = BCP47_COLLATION_TYPE_ALIAS[i].Name) then begin
  1866. Result := BCP47_COLLATION_TYPE_ALIAS[i].Alias;
  1867. break;
  1868. end;
  1869. end;
  1870. end;
  1871. end;
  1872. constructor TCldrCollationItem.Create;
  1873. begin
  1874. FImports := TCldrImportList.Create();
  1875. FNormalization := True;
  1876. FStrength := TComparisonStrength.Tertiary;
  1877. end;
  1878. destructor TCldrCollationItem.Destroy;
  1879. begin
  1880. FImports.Free();
  1881. inherited Destroy;
  1882. end;
  1883. procedure TCldrCollationItem.Clear();
  1884. begin
  1885. FBackwards := False;
  1886. FNormalization := True;
  1887. FStrength := TComparisonStrength.Tertiary;
  1888. FVariableWeight := Low(TUCA_VariableKind);
  1889. FAlt := '';
  1890. FBase := '';
  1891. FTypeName := '';
  1892. FChangedFields := [];
  1893. SetLength(FRules,0);
  1894. SetLength(FSettings,0);
  1895. FImports.Clear();
  1896. end;
  1897. function TCldrCollationItem.IsPrivate() : Boolean;
  1898. begin
  1899. Result := (Pos('private-',TypeName) = 1);
  1900. end;
  1901. { TCldrCollation }
  1902. function TCldrCollation.GetItem(Index : Integer): TCldrCollationItem;
  1903. begin
  1904. if (Index < 0) or (Index >= Length(FItems)) then
  1905. raise ERangeError.CreateFmt(SListIndexError,[Index]);
  1906. Result := FItems[Index];
  1907. end;
  1908. function TCldrCollation.GetItemCount: Integer;
  1909. begin
  1910. Result := Length(FItems);
  1911. end;
  1912. destructor TCldrCollation.Destroy;
  1913. begin
  1914. Clear();
  1915. inherited Destroy;
  1916. end;
  1917. procedure TCldrCollation.Clear();
  1918. var
  1919. i : Integer;
  1920. begin
  1921. for i := 0 to Length(FItems) - 1 do
  1922. FreeAndNil(FItems[i]);
  1923. SetLength(FItems,0);
  1924. FLocalID := '';
  1925. FDefaultType := '';
  1926. FVersion := '';
  1927. FLanguage := '';
  1928. FMode := Low(TCldrParserMode);
  1929. end;
  1930. function TCldrCollation.IndexOf(const AItemName: string): Integer;
  1931. var
  1932. i : Integer;
  1933. begin
  1934. for i := 0 to ItemCount - 1 do begin
  1935. if SameText(AItemName,Items[i].TypeName) then
  1936. exit(i);
  1937. end;
  1938. Result := -1;
  1939. end;
  1940. function TCldrCollation.IndexOf(const AItemName, AItemAlt: string): Integer;
  1941. var
  1942. i : Integer;
  1943. begin
  1944. for i := 0 to ItemCount - 1 do begin
  1945. if SameText(AItemName,Items[i].TypeName) and
  1946. SameText(AItemAlt,Items[i].Alt)
  1947. then begin
  1948. exit(i);
  1949. end;
  1950. end;
  1951. Result := -1;
  1952. end;
  1953. function TCldrCollation.Find(const AItemName: string): TCldrCollationItem;
  1954. var
  1955. i : Integer;
  1956. s : UTF8String;
  1957. begin
  1958. i := IndexOf(AItemName);
  1959. if (i = - 1) then begin
  1960. s := TCldrCollationItem.FindAlias(AItemName);
  1961. if (s <> '') then
  1962. i := IndexOf(s);
  1963. end;
  1964. if (i = - 1) then
  1965. Result := nil
  1966. else
  1967. Result := Items[i];
  1968. end;
  1969. function TCldrCollation.Find(const AItemName, AItemAlt: string): TCldrCollationItem;
  1970. var
  1971. i : Integer;
  1972. begin
  1973. i := IndexOf(AItemName,AItemAlt);
  1974. if (i = - 1) then
  1975. Result := nil
  1976. else
  1977. Result := Items[i];
  1978. end;
  1979. function TCldrCollation.Add(AItem: TCldrCollationItem): Integer;
  1980. begin
  1981. Result := Length(FItems);
  1982. SetLength(FItems,(Result+1));
  1983. FItems[Result] := AItem;
  1984. AItem.FParent := Self;
  1985. end;
  1986. function TCldrCollation.FindPublicItemCount() : Integer;
  1987. var
  1988. r, i : Integer;
  1989. begin
  1990. r := 0;
  1991. for i := 0 to ItemCount-1 do begin
  1992. if not Items[i].IsPrivate() then
  1993. r := r+1;
  1994. end;
  1995. Result := r;
  1996. end;
  1997. { TReorderSequence }
  1998. procedure TReorderSequence.Clear();
  1999. begin
  2000. Reset := nil;
  2001. Elements := nil;
  2002. LogicalPosition := TReorderLogicalReset(0);
  2003. Before := False;
  2004. end;
  2005. procedure TReorderSequence.SetElementCount(const ALength: Integer);
  2006. begin
  2007. SetLength(Elements,ALength);
  2008. end;
  2009. procedure TReorderSequence.Assign(ASource: PReorderSequence);
  2010. var
  2011. c, i : Integer;
  2012. begin
  2013. if (ASource = nil) then begin
  2014. Self.Clear();
  2015. exit;
  2016. end;
  2017. Self.Reset := Copy(ASource^.Reset);
  2018. c := Length(ASource^.Elements);
  2019. SetLength(Self.Elements,c);
  2020. for i := 0 to c-1 do
  2021. Self.Elements[i].Assign(@ASource^.Elements[i]);
  2022. Self.Before := ASource^.Before;
  2023. Self.LogicalPosition := ASource^.LogicalPosition;
  2024. end;
  2025. { TReorderUnit }
  2026. function TReorderUnit.IsVirtual() : Boolean;
  2027. begin
  2028. Result := (FVirtualPosition > TReorderLogicalReset.None);
  2029. end;
  2030. class function TReorderUnit.From(
  2031. const AChars,
  2032. AContext : array of TUnicodeCodePoint;
  2033. const AWeigthKind : TReorderWeigthKind;
  2034. const AInitialPosition : Integer
  2035. ) : TReorderUnit;
  2036. var
  2037. c : Integer;
  2038. begin
  2039. Result.Clear();
  2040. c := Length(AChars);
  2041. SetLength(Result.Characters,c);
  2042. if (c > 0) then
  2043. Move(AChars[0],Result.Characters[0],(c*SizeOf(Result.Characters[0])));
  2044. Result.WeigthKind := AWeigthKind;
  2045. Result.InitialPosition := AInitialPosition;
  2046. Result.Changed := False;
  2047. c := Length(AContext);
  2048. SetLength(Result.Context,c);
  2049. if (c > 0) then
  2050. Move(AContext[0],Result.Context[0],(c*SizeOf(Result.Context[0])));
  2051. end;
  2052. class function TReorderUnit.From(
  2053. const AChars : array of TUnicodeCodePoint;
  2054. const AWeigthKind : TReorderWeigthKind;
  2055. const AInitialPosition : Integer
  2056. ) : TReorderUnit;
  2057. begin
  2058. Result := From(AChars,[],AWeigthKind,AInitialPosition);
  2059. end;
  2060. class function TReorderUnit.From(
  2061. const AChar : TUnicodeCodePoint;
  2062. const AWeigthKind : TReorderWeigthKind;
  2063. const AInitialPosition : Integer
  2064. ) : TReorderUnit;
  2065. begin
  2066. Result := From([AChar],AWeigthKind,AInitialPosition);
  2067. end;
  2068. class function TReorderUnit.From(
  2069. const AChar : TUnicodeCodePoint;
  2070. const AContext : array of TUnicodeCodePoint;
  2071. const AWeigthKind : TReorderWeigthKind;
  2072. const AInitialPosition : Integer
  2073. ) : TReorderUnit;
  2074. begin
  2075. Result := From([AChar],AContext,AWeigthKind,AInitialPosition);
  2076. end;
  2077. class function TReorderUnit.From(const AReset: TReorderLogicalReset): TReorderUnit;
  2078. begin
  2079. Result.Clear();
  2080. Result.FVirtualPosition := AReset;
  2081. end;
  2082. procedure TReorderUnit.SetExpansion(const AChars: array of TUnicodeCodePoint);
  2083. var
  2084. c : Integer;
  2085. begin
  2086. if IsVirtual() then
  2087. raise ECldrException.Create(sVirtualIsReadOnly);
  2088. c := Length(AChars);
  2089. SetLength(ExpansionChars,c);
  2090. if (c > 0) then
  2091. Move(AChars[0],ExpansionChars[0],(c*SizeOf(AChars[0])));
  2092. end;
  2093. procedure TReorderUnit.SetExpansion(const AChar: TUnicodeCodePoint);
  2094. begin
  2095. if IsVirtual() then
  2096. raise ECldrException.Create(sVirtualIsReadOnly);
  2097. SetExpansion([AChar]);
  2098. end;
  2099. procedure TReorderUnit.Clear();
  2100. begin
  2101. Self.FVirtualPosition := TReorderLogicalReset(0);
  2102. Self.Characters := nil;
  2103. Self.Context := nil;
  2104. Self.ExpansionChars := nil;
  2105. Self.InitialPosition := 0;
  2106. Self.WeigthKind := TReorderWeigthKind(0);
  2107. Self.Changed := False;
  2108. end;
  2109. procedure TReorderUnit.Assign(const AItem : PReorderUnit);
  2110. begin
  2111. Clear();
  2112. if (AItem <> nil) then begin
  2113. Self.FVirtualPosition := AItem^.VirtualPosition;
  2114. Self.Characters := Copy(AItem^.Characters);
  2115. //SetLength(Self.Context,Length(AItem^.Context));
  2116. Self.Context := Copy(AItem^.Context);
  2117. Self.ExpansionChars := Copy(AItem^.ExpansionChars);
  2118. Self.WeigthKind := AItem^.WeigthKind;
  2119. Self.InitialPosition := AItem^.InitialPosition;
  2120. Self.Changed := AItem^.Changed;
  2121. end;
  2122. end;
  2123. function TReorderUnit.HasContext() : Boolean;
  2124. begin
  2125. Result := (Length(Context) > 0);
  2126. end;
  2127. function TReorderUnit.IsExpansion() : Boolean;
  2128. begin
  2129. Result := (Length(ExpansionChars) > 0);
  2130. end;
  2131. { TOrderedCharacters }
  2132. procedure TOrderedCharacters.EnsureSize(const AMinSize : Integer);
  2133. var
  2134. c : Integer;
  2135. begin
  2136. if (AMinSize > Length(Data)) then begin
  2137. if (AMinSize > 1000) then
  2138. c := AMinSize + 100
  2139. else
  2140. c := (3*AMinSize) div 2 ;
  2141. SetLength(Data,c);
  2142. end;
  2143. FActualLength := AMinSize;
  2144. end;
  2145. class function TOrderedCharacters.Create(const ACapacity : Integer) : TOrderedCharacters;
  2146. begin
  2147. if (ACapacity < 0) then
  2148. raise ERangeError.Create(SRangeError);
  2149. Result.FActualLength := 0;
  2150. SetLength(Result.Data,ACapacity);
  2151. end;
  2152. class function TOrderedCharacters.Create() : TOrderedCharacters;
  2153. begin
  2154. Result := Create(0);
  2155. end;
  2156. procedure TOrderedCharacters.Clear;
  2157. begin
  2158. Data := nil;
  2159. FActualLength := 0;
  2160. end;
  2161. function TOrderedCharacters.Clone() : TOrderedCharacters;
  2162. var
  2163. i : Integer;
  2164. begin
  2165. Result.Clear();
  2166. SetLength(Result.Data,Self.ActualLength);
  2167. for i := 0 to Length(Result.Data) - 1 do
  2168. Result.Data[i].Assign(@Self.Data[i]);
  2169. Result.FActualLength := Self.FActualLength;
  2170. end;
  2171. function TOrderedCharacters.Insert(
  2172. const AItem : TReorderUnit;
  2173. const ADestPos : Integer
  2174. ) : Integer;
  2175. var
  2176. k, finalPos : Integer;
  2177. p : PReorderUnit;
  2178. i, c : Integer;
  2179. begin
  2180. if (ActualLength=0) then begin
  2181. EnsureSize(ActualLength + 1);
  2182. p := @Data[0];
  2183. p^.Assign(@AItem);
  2184. p^.Changed := True;
  2185. exit(0);
  2186. end;
  2187. k := IndexOf(AItem.Characters,AItem.Context,@Data[0],ActualLength);
  2188. if (k = ADestPos) then begin
  2189. Data[ADestPos].Assign(@AItem);
  2190. Data[ADestPos].Changed := True;
  2191. exit(k);
  2192. end;
  2193. finalPos := ADestPos;
  2194. if (finalPos > ActualLength) then
  2195. finalPos := ActualLength;
  2196. c := ActualLength;
  2197. EnsureSize(c + 1);
  2198. Data[c].Clear();
  2199. p := @Data[finalPos];
  2200. if (finalPos = ActualLength-1) then begin
  2201. p^.Assign(@AItem);
  2202. p^.Changed := True;
  2203. end else begin
  2204. if (c > 0) then begin
  2205. p := @Data[c-1];
  2206. for i := finalPos to c - 1 do begin
  2207. Move(Pointer(p)^,Pointer(p+1)^,SizeOf(p^));
  2208. Dec(p);
  2209. end;
  2210. end;
  2211. p := @Data[finalPos];
  2212. {Move(
  2213. Pointer(p)^,Pointer(@p[1])^,
  2214. (ActualLength-(finalPos+1))*SizeOf(TReorderUnit)
  2215. );}
  2216. FillChar(Pointer(p)^,SizeOf(TReorderUnit),0);
  2217. p^.Assign(@AItem);
  2218. p^.Changed := True;
  2219. end;
  2220. if (k >= 0) then begin
  2221. if (k > finalPos) then
  2222. Inc(k);
  2223. Delete(k);
  2224. end;
  2225. Result := finalPos;
  2226. end;
  2227. function TOrderedCharacters.Append(const AItem : TReorderUnit) : Integer;
  2228. begin
  2229. Result := Insert(AItem,ActualLength);
  2230. end;
  2231. procedure TOrderedCharacters.Delete(const AIndex : Integer);
  2232. var
  2233. i : Integer;
  2234. p : PReorderUnit;
  2235. begin
  2236. if (AIndex < 0) or (AIndex >= ActualLength) then
  2237. raise ERangeError.CreateFmt(SListIndexError,[AIndex]);
  2238. if (AIndex = (ActualLength-1)) then begin
  2239. Data[AIndex].Clear();
  2240. end else begin
  2241. //Data[AIndex].Clear();
  2242. p := @Data[AIndex];
  2243. p^.Clear();
  2244. for i := AIndex to ActualLength-2 do begin
  2245. Move((p+1)^,p^,SizeOf(p^));
  2246. Inc(p);
  2247. end;
  2248. {Move(
  2249. Pointer(@Data[(AIndex+1)])^,Pointer(@Data[AIndex])^,
  2250. (ActualLength-(AIndex+1))*SizeOf(TReorderUnit)
  2251. );}
  2252. FillChar(Pointer(@Data[(FActualLength-1)])^,SizeOf(TReorderUnit),0);
  2253. end;
  2254. FActualLength := FActualLength - 1;
  2255. end;
  2256. procedure TOrderedCharacters.ApplyStatement(const AStatement : PReorderSequence);
  2257. begin
  2258. ApplyStatementToSequence(Self,AStatement,1);
  2259. end;
  2260. function FindCollationDefaultItemName(ACollation : TCldrCollation) : string;
  2261. begin
  2262. if (ACollation.ItemCount = 0) then
  2263. exit('');
  2264. if (ACollation.IndexOf(ACollation.DefaultType) <> -1) then
  2265. exit(ACollation.DefaultType);
  2266. Result := COLLATION_ITEM_STD;
  2267. if (ACollation.IndexOf(Result) <> -1) then
  2268. exit;
  2269. Result := COLLATION_ITEM_SEARCH;
  2270. if (ACollation.IndexOf(Result) <> -1) then
  2271. exit;
  2272. if (ACollation.ItemCount > 0) then
  2273. Result := ACollation.Items[0].TypeName;
  2274. end;
  2275. procedure GenerateUCA_CLDR_Head(
  2276. ADest : TStream;
  2277. ABook : PUCA_DataBook;
  2278. AProps : PUCA_PropBook;
  2279. ACollation : TCldrCollationItem
  2280. );
  2281. procedure AddLine(const ALine : ansistring);
  2282. var
  2283. buffer : ansistring;
  2284. begin
  2285. buffer := ALine + sLineBreak;
  2286. ADest.Write(buffer[1],Length(buffer));
  2287. end;
  2288. procedure AddFields();
  2289. var
  2290. kc : Integer;
  2291. e : TCollationField;
  2292. ks : string;
  2293. ti : PTypeInfo;
  2294. begin
  2295. ti := TypeInfo(TCollationField);
  2296. ks := '';
  2297. kc := 0;
  2298. for e := Low(TCollationField) to High(TCollationField) do begin
  2299. if (e in ACollation.ChangedFields) then begin
  2300. ks := ks + ti^.Name + '.' +
  2301. GetEnumName(ti,Ord(e)) + ', ';
  2302. kc := kc + 1;
  2303. end
  2304. end;
  2305. if (AProps <> nil) then begin
  2306. if (AProps^.VariableLowLimit < High(Word)) then begin
  2307. ks := ks + ti^.Name + '.' +
  2308. GetEnumName(ti,Ord(TCollationField.VariableLowLimit)) + ', ';
  2309. kc := kc + 1;
  2310. end;
  2311. if (AProps^.VariableHighLimit > 0) then begin
  2312. ks := ks + ti^.Name + '.' +
  2313. GetEnumName(ti,Ord(TCollationField.VariableHighLimit)) + ', ';
  2314. kc := kc + 1;
  2315. end;
  2316. end;
  2317. if (kc > 0) then
  2318. ks := Copy(ks,1,(Length(ks)-2));
  2319. AddLine(' UPDATED_FIELDS = [ ' + ks + ' ];');
  2320. end;
  2321. begin
  2322. AddLine('{$IFDEF FPC}');
  2323. AddLine(' {$mode DELPHI}{$H+}');
  2324. AddLine('{$ENDIF FPC}');
  2325. AddLine('');
  2326. AddLine('{$IFNDEF FPC}');
  2327. AddLine(' {$DEFINE ENDIAN_LITTLE}');
  2328. AddLine('{$ENDIF !FPC}');
  2329. AddLine('');
  2330. AddLine('unit ' + COLLATION_FILE_PREFIX + LowerCase(ACollation.Parent.LocalID)+ ';'+sLineBreak);
  2331. AddLine('interface'+sLineBreak);
  2332. AddLine('implementation');
  2333. AddLine('uses');
  2334. AddLine(' unicodedata, unicodeducet;'+sLineBreak);
  2335. AddLine('const');
  2336. AddFields();
  2337. AddLine(' COLLATION_NAME = ' + QuotedStr(ACollation.Parent.LocalID) + ';');
  2338. AddLine(' BASE_COLLATION = ' + QuotedStr(ACollation.Base) + ';');
  2339. if (AProps <> nil) then begin
  2340. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(AProps^.VariableLowLimit) + ';');
  2341. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(AProps^.VariableHighLimit) + ';');
  2342. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(Ord(ABook^.VariableWeight)) + ';');
  2343. end else begin
  2344. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(High(Word)) + ';');
  2345. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(0) + ';');
  2346. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(0) + ';');
  2347. end;
  2348. AddLine(' BACKWARDS_0 = ' + BoolToStr(ABook^.Backwards[0],'True','False') + ';');
  2349. AddLine(' BACKWARDS_1 = ' + BoolToStr(ABook^.Backwards[1],'True','False') + ';');
  2350. AddLine(' BACKWARDS_2 = ' + BoolToStr(ABook^.Backwards[2],'True','False') + ';');
  2351. AddLine(' BACKWARDS_3 = ' + BoolToStr(ABook^.Backwards[3],'True','False') + ';');
  2352. if (AProps <> nil) then
  2353. AddLine(' PROP_COUNT = ' + IntToStr(Ord(AProps^.ItemSize)) + ';');
  2354. AddLine(' NO_STRING_NORMALIZATION = ' + BoolToStr(not(ACollation.Normalization),'True','False') + ';');
  2355. AddLine(' COMPARISON_STRENGTH = ' + IntToStr(Ord(ACollation.Strength)+1) + ';');
  2356. AddLine('');
  2357. end;
  2358. procedure GenerateUCA_CLDR_Registration(
  2359. ADest : TStream;
  2360. ABook : PUCA_DataBook;
  2361. ACollation : TCldrCollationItem
  2362. );
  2363. procedure AddLine(const ALine : ansistring);
  2364. var
  2365. buffer : ansistring;
  2366. begin
  2367. buffer := ALine + sLineBreak;
  2368. ADest.Write(buffer[1],Length(buffer));
  2369. end;
  2370. procedure GenerateStrBuffer(AStr : AnsiString; const ALength : Integer);
  2371. const LINE_ELEMENT = 8;
  2372. var
  2373. kc, k : Integer;
  2374. buffer : ansistring;
  2375. begin
  2376. kc := Length(AStr);
  2377. if (kc > ALength) then
  2378. kc := ALength;
  2379. buffer := ' ';
  2380. for k := 1 to kc do begin
  2381. buffer := buffer + 'Ord('''+AStr[k]+''')';
  2382. if (k < kc) then begin
  2383. buffer := buffer + ',';
  2384. if ((k mod LINE_ELEMENT) = 0) then
  2385. buffer := buffer+sLineBreak + ' ';
  2386. end;
  2387. end;
  2388. if (kc < ALength) then begin
  2389. buffer := buffer + ',' + sLineBreak+ ' ';
  2390. for k := kc+1 to ALength do begin
  2391. buffer := buffer + '0';
  2392. if (k < ALength) then begin
  2393. buffer := buffer + ',';
  2394. if (((k-kc) mod 30) = 0) then
  2395. buffer := buffer+sLineBreak + ' ';
  2396. end;
  2397. end;
  2398. end;
  2399. AddLine(buffer);
  2400. end;
  2401. begin
  2402. AddLine('var');
  2403. AddLine(' CLDR_Collation : TUCA_DataBook = (');
  2404. AddLine(' Base : nil;');
  2405. AddLine(' Version : ');
  2406. AddLine(' (');
  2407. GenerateStrBuffer(ABook^.Version,128);
  2408. AddLine(' );');
  2409. AddLine(' CollationName : ');
  2410. AddLine(' (');
  2411. GenerateStrBuffer(ACollation.Parent.LocalID,128);
  2412. AddLine(' );');
  2413. AddLine(' VariableWeight : TUCA_VariableKind(VARIABLE_WEIGHT);');
  2414. AddLine(' Backwards : (BACKWARDS_0,BACKWARDS_1,BACKWARDS_2,BACKWARDS_3);');
  2415. if (Length(ABook^.Lines) > 0) then begin
  2416. AddLine(' BMP_Table1 : @UCA_TABLE_1[0];');
  2417. AddLine(' BMP_Table2 : @UCA_TABLE_2[0];');
  2418. AddLine(' OBMP_Table1 : @UCAO_TABLE_1[0];');
  2419. AddLine(' OBMP_Table2 : @UCAO_TABLE_2[0];');
  2420. AddLine(' PropCount : PROP_COUNT;');
  2421. AddLine(' Props : @UCA_PROPS[0];');
  2422. end else begin
  2423. AddLine(' BMP_Table1 : nil;');
  2424. AddLine(' BMP_Table2 : nil;');
  2425. AddLine(' OBMP_Table1 : nil;');
  2426. AddLine(' OBMP_Table2 : nil;');
  2427. AddLine(' PropCount : 0;');
  2428. AddLine(' Props : nil;');
  2429. end;
  2430. AddLine(' VariableLowLimit : VARIABLE_LOW_LIMIT;');
  2431. AddLine(' VariableHighLimit : VARIABLE_HIGH_LIMIT;');
  2432. AddLine(' NoNormalization : NO_STRING_NORMALIZATION;');
  2433. AddLine(' ComparisonStrength : COMPARISON_STRENGTH;');
  2434. AddLine(' Dynamic : False;');
  2435. AddLine(' );');
  2436. AddLine('');
  2437. AddLine('procedure Register();');
  2438. AddLine('begin');
  2439. AddLine(' PrepareCollation(@CLDR_Collation,BASE_COLLATION,UPDATED_FIELDS);');
  2440. AddLine(' RegisterCollation(@CLDR_Collation);');
  2441. AddLine('end;');
  2442. AddLine('');
  2443. AddLine('initialization');
  2444. AddLine(' Register();');
  2445. AddLine('');
  2446. AddLine('finalization');
  2447. AddLine(' UnregisterCollation(COLLATION_NAME);');
  2448. AddLine('');
  2449. AddLine('end.');
  2450. end;
  2451. procedure CheckEndianTransform(const ASource : PUCA_PropBook);
  2452. var
  2453. x, y : array of Byte;
  2454. px, py : PUCA_PropItemRec;
  2455. begin
  2456. if (ASource = nil) or (ASource^.ItemSize = 0) then
  2457. exit;
  2458. SetLength(x,ASource^.ItemSize);
  2459. px := PUCA_PropItemRec(@x[0]);
  2460. ReverseFromNativeEndian(ASource^.Items,ASource^.ItemSize,px);
  2461. SetLength(y,ASource^.ItemSize);
  2462. py := PUCA_PropItemRec(@y[0]);
  2463. ReverseToNativeEndian(px,ASource^.ItemSize,py);
  2464. if not CompareMem(ASource^.Items,@y[0],Length(x)) then
  2465. CompareProps(ASource^.Items, PUCA_PropItemRec(@y[0]),ASource^.ItemSize);
  2466. end;
  2467. function ForEachRule(
  2468. ACollationType : TCldrCollationItem;
  2469. AVisitFunc : TRuleVisiterFunction;
  2470. ACustomData : Pointer
  2471. ) : Boolean;
  2472. var
  2473. i : Integer;
  2474. locImport : TCldrImport;
  2475. locRep : TCldrCollationRepository;
  2476. locCollation : TCldrCollation;
  2477. locType : TCldrCollationItem;
  2478. locRules : TCldrCollationRuleArray;
  2479. locRule : PCldrCollationRule;
  2480. begin
  2481. Result := False;
  2482. if not Assigned(AVisitFunc) then
  2483. exit;
  2484. locRules := ACollationType.Rules;
  2485. for i := Low(locRules) to High(locRules) do begin
  2486. locRule := @locRules[i];
  2487. if (locRule^.Kind = TCldrCollationRuleKind.ReorderSequence) then begin
  2488. if not AVisitFunc(@locRule^.Reorder,ACollationType,ACustomData) then
  2489. exit;
  2490. end else if (locRule^.Kind = TCldrCollationRuleKind.Import) then begin
  2491. locImport := locRule^.Import;
  2492. locRep := ACollationType.Parent.Repository;
  2493. locCollation := locRep.Load(locImport.Source,TCldrParserMode.FullParsing);
  2494. locType := locCollation.Find(locImport.TypeName);
  2495. if (locType = nil) then begin
  2496. if (locType = nil) then
  2497. raise ECldrException.CreateFmt(sCollationTypeNotFound,[locImport.TypeName]);
  2498. end;
  2499. if not ForEachRule(locType,AVisitFunc,ACustomData) then
  2500. exit;
  2501. end;
  2502. end;
  2503. Result := True;
  2504. end;
  2505. function ApplyStatementVisitorFunc(
  2506. ARule : PReorderSequence;
  2507. AOwner : TCldrCollationItem;
  2508. AData : Pointer
  2509. ) : Boolean;
  2510. var
  2511. locSequence : POrderedCharacters;
  2512. begin
  2513. locSequence := POrderedCharacters(AData);
  2514. locSequence^.ApplyStatement(ARule);
  2515. Result := True;
  2516. end;
  2517. procedure GenerateCdlrCollation(
  2518. ACollation : TCldrCollation;
  2519. AItemName : string;
  2520. AStoreName : string;
  2521. AStream,
  2522. ANativeEndianStream,
  2523. AOtherEndianStream,
  2524. ABinaryNativeEndianStream,
  2525. ABinaryOtherEndianStream : TStream;
  2526. ARootChars : TOrderedCharacters;
  2527. ARootWeigths : TUCA_LineRecArray;
  2528. AUnifiedIdeographs : TCodePointRecArray
  2529. );
  2530. procedure AddLine(const ALine : ansistring; ADestStream : TStream);
  2531. var
  2532. buffer : ansistring;
  2533. begin
  2534. buffer := ALine + sLineBreak;
  2535. ADestStream.Write(buffer[1],Length(buffer));
  2536. end;
  2537. var
  2538. locUcaBook : TUCA_DataBook;
  2539. locSequence : TOrderedCharacters;
  2540. locItem : TCldrCollationItem;
  2541. i : Integer;
  2542. locUcaProps : PUCA_PropBook;
  2543. ucaFirstTable : TucaBmpFirstTable;
  2544. ucaSecondTable : TucaBmpSecondTable;
  2545. ucaoFirstTable : TucaoBmpFirstTable;
  2546. ucaoSecondTable : TucaOBmpSecondTable;
  2547. locHasProps : Boolean;
  2548. s : string;
  2549. serializedHeader : TSerializedCollationHeader;
  2550. e : TCollationField;
  2551. begin
  2552. locItem := ACollation.Find(AItemName);
  2553. if (locItem = nil) then
  2554. raise Exception.CreateFmt('Collation Item not found : "%s".',[AItemName]);
  2555. locSequence := ARootChars.Clone();
  2556. ForEachRule(locItem,ApplyStatementVisitorFunc,@locSequence);
  2557. {for i := 0 to Length(locItem.Rules) - 1 do
  2558. locSequence.ApplyStatement(@locItem.Rules[i]);}
  2559. FillChar(locUcaBook,SizeOf(locUcaBook),0);
  2560. locUcaBook.Version := ACollation.Version;
  2561. locUcaBook.Backwards[1] := locItem.Backwards;
  2562. locUcaBook.VariableWeight := locItem.VariableWeight;
  2563. ComputeWeigths(@locSequence.Data[0],locSequence.ActualLength,ARootWeigths,AUnifiedIdeographs,locUcaBook.Lines);
  2564. for i := 0 to Length(locUcaBook.Lines) - 1 do
  2565. locUcaBook.Lines[i].Stored := True;
  2566. locHasProps := (Length(locUcaBook.Lines) > 0);
  2567. if not locHasProps then
  2568. locUcaProps := nil
  2569. else
  2570. MakeUCA_Props(@locUcaBook,locUcaProps);
  2571. try
  2572. CheckEndianTransform(locUcaProps);
  2573. if locHasProps then begin
  2574. MakeUCA_BmpTables(ucaFirstTable,ucaSecondTable,locUcaProps);
  2575. SetLength(ucaoSecondTable,100);
  2576. MakeUCA_OBmpTables(ucaoFirstTable,ucaoSecondTable,locUcaProps);
  2577. end;
  2578. GenerateLicenceText(AStream);
  2579. GenerateUCA_CLDR_Head(AStream,@locUcaBook,locUcaProps,locItem);
  2580. if locHasProps then begin
  2581. GenerateUCA_BmpTables(AStream,ANativeEndianStream,AOtherEndianStream,ucaFirstTable,ucaSecondTable);
  2582. GenerateUCA_OBmpTables(AStream,ANativeEndianStream,AOtherEndianStream,ucaoFirstTable,ucaoSecondTable);
  2583. GenerateUCA_PropTable(ANativeEndianStream,locUcaProps,ENDIAN_NATIVE);
  2584. GenerateUCA_PropTable(AOtherEndianStream,locUcaProps,ENDIAN_NON_NATIVE);
  2585. AddLine('{$ifdef ENDIAN_LITTLE}',AStream);
  2586. s := GenerateEndianIncludeFileName(AStoreName,ekLittle);
  2587. AddLine(Format(' {$include %s}',[ExtractFileName(s)]),AStream);
  2588. AddLine('{$else ENDIAN_LITTLE}',AStream);
  2589. s := GenerateEndianIncludeFileName(AStoreName,ekBig);
  2590. AddLine(Format(' {$include %s}',[ExtractFileName(s)]),AStream);
  2591. AddLine('{$endif ENDIAN_LITTLE}',AStream);
  2592. end;
  2593. GenerateUCA_CLDR_Registration(AStream,@locUcaBook,locItem);
  2594. FillChar(serializedHeader,SizeOf(TSerializedCollationHeader),0);
  2595. StringToByteArray(locItem.Base,serializedHeader.Base);
  2596. StringToByteArray(ACollation.Version,serializedHeader.Version);
  2597. StringToByteArray(ACollation.Language,serializedHeader.CollationName);
  2598. serializedHeader.VariableWeight := Ord(locUcaBook.VariableWeight);
  2599. SetBit(serializedHeader.Backwards,0,locUcaBook.Backwards[0]);
  2600. SetBit(serializedHeader.Backwards,1,locUcaBook.Backwards[1]);
  2601. SetBit(serializedHeader.Backwards,2,locUcaBook.Backwards[2]);
  2602. SetBit(serializedHeader.Backwards,3,locUcaBook.Backwards[3]);
  2603. serializedHeader.NoNormalization := Ord(not locItem.Normalization);
  2604. if locHasProps then begin
  2605. serializedHeader.BMP_Table1Length := Length(ucaFirstTable);
  2606. serializedHeader.BMP_Table2Length := Length(TucaBmpSecondTableItem) *
  2607. (Length(ucaSecondTable) * SizeOf(UInt24));
  2608. serializedHeader.OBMP_Table1Length := Length(ucaoFirstTable) * SizeOf(Word);
  2609. serializedHeader.OBMP_Table2Length := Length(TucaOBmpSecondTableItem) *
  2610. (Length(ucaoSecondTable) * SizeOf(UInt24));
  2611. serializedHeader.PropCount := locUcaProps^.ItemSize;
  2612. serializedHeader.VariableLowLimit := locUcaProps^.VariableLowLimit;
  2613. serializedHeader.VariableHighLimit := locUcaProps^.VariableHighLimit;
  2614. end else begin
  2615. serializedHeader.VariableLowLimit := High(Word);
  2616. serializedHeader.VariableHighLimit := 0;
  2617. end;
  2618. serializedHeader.ChangedFields := 0;
  2619. for e := Low(TCollationField) to High(TCollationField) do begin
  2620. if (e in locItem.ChangedFields) then
  2621. SetBit(serializedHeader.ChangedFields,Ord(e),True);
  2622. end;
  2623. ABinaryNativeEndianStream.Write(serializedHeader,SizeOf(serializedHeader));
  2624. ReverseRecordBytes(serializedHeader);
  2625. ABinaryOtherEndianStream.Write(serializedHeader,SizeOf(serializedHeader));
  2626. if locHasProps then begin
  2627. GenerateBinaryUCA_BmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaFirstTable,ucaSecondTable);
  2628. GenerateBinaryUCA_OBmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaoFirstTable,ucaoSecondTable);
  2629. GenerateBinaryUCA_PropTable(ABinaryNativeEndianStream,ABinaryOtherEndianStream,locUcaProps);
  2630. end;
  2631. finally
  2632. locSequence.Clear();
  2633. FreeUcaBook(locUcaProps);
  2634. end;
  2635. end;
  2636. end.