cldrhelper.pas 80 KB

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