cldrhelper.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759
  1. { CLDR collation helper unit.
  2. Copyright (c) 2013 by Inoussa OUEDRAOGO
  3. The source code is distributed under the Library GNU
  4. General Public License with the following modification:
  5. - object files and libraries linked into an application may be
  6. distributed without source code.
  7. If you didn't receive a copy of the file COPYING, contact:
  8. Free Software Foundation
  9. 675 Mass Ave
  10. Cambridge, MA 02139
  11. USA
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. }
  16. unit cldrhelper;
  17. {$mode objfpc}
  18. {$H+}
  19. {$PACKENUM 1}
  20. {$modeswitch advancedrecords}
  21. {$scopedenums on}
  22. {$typedaddress on}
  23. {$macro on}
  24. {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT}
  25. {$define X_PACKED:=}
  26. {$else FPC_REQUIRES_PROPER_ALIGNMENT}
  27. {$define X_PACKED:=packed}
  28. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  29. interface
  30. uses
  31. SysUtils, Classes, helper;
  32. const
  33. COLLATION_FILE_PREFIX = 'collation_';
  34. type
  35. TUCA_LineRecArray = array of TUCA_LineRec;
  36. //----------------------------------------------------
  37. ECldrException = class(Exception)
  38. end;
  39. TReorderWeigthKind = (
  40. Primary, Secondary, Tertiary, Identity, Deletion
  41. );
  42. TReorderWeigthKinds = set of TReorderWeigthKind;
  43. TReorderLogicalReset = (
  44. None,// FirstVariable, LastVariable,
  45. FirstTertiaryIgnorable, LastTertiaryIgnorable,
  46. FirstSecondaryIgnorable, LastSecondaryIgnorable,
  47. FirstPrimaryIgnorable, LastPrimaryIgnorable,
  48. LastRegular,
  49. FirstNonIgnorable, LastNonIgnorable,
  50. FirstTrailing, LastTrailing
  51. );
  52. TCollationField = (BackWard, VariableLowLimit, VariableHighLimit);
  53. TCollationFields = set of TCollationField;
  54. { TReorderUnit }
  55. TReorderUnit = X_PACKED record
  56. public
  57. Context : TUnicodeCodePointArray;
  58. ExpansionChars : TUnicodeCodePointArray;
  59. Characters : TUnicodeCodePointArray;
  60. WeigthKind : TReorderWeigthKind;
  61. InitialPosition : Integer;
  62. Changed : Boolean;
  63. public
  64. class function From(
  65. const AChars,
  66. AContext : array of TUnicodeCodePoint;
  67. const AWeigthKind : TReorderWeigthKind;
  68. const AInitialPosition : Integer
  69. ) : TReorderUnit;static;overload;
  70. class function From(
  71. const AChars : array of TUnicodeCodePoint;
  72. const AWeigthKind : TReorderWeigthKind;
  73. const AInitialPosition : Integer
  74. ) : TReorderUnit;static;overload;
  75. class function From(
  76. const AChar : TUnicodeCodePoint;
  77. const AWeigthKind : TReorderWeigthKind;
  78. const AInitialPosition : Integer
  79. ) : TReorderUnit;static;overload;
  80. class function From(
  81. const AChar : TUnicodeCodePoint;
  82. const AContext : array of TUnicodeCodePoint;
  83. const AWeigthKind : TReorderWeigthKind;
  84. const AInitialPosition : Integer
  85. ) : TReorderUnit;static;overload;
  86. procedure SetExpansion(const AChars : array of TUnicodeCodePoint);
  87. procedure SetExpansion(const AChar : TUnicodeCodePoint);
  88. procedure Clear();
  89. procedure Assign(const AItem : TReorderUnit);
  90. function HasContext() : Boolean;
  91. function IsExpansion() : Boolean;
  92. end;
  93. PReorderUnit = ^TReorderUnit;
  94. { TReorderSequence }
  95. TReorderSequence = X_PACKED record
  96. public
  97. Reset : array of TUnicodeCodePoint;
  98. Elements : array of TReorderUnit;
  99. LogicalPosition : TReorderLogicalReset;
  100. Before : Boolean;
  101. public
  102. procedure Clear();
  103. end;
  104. PReorderSequence = ^TReorderSequence;
  105. TReorderSequenceArray = array of TReorderSequence;
  106. { TOrderedCharacters }
  107. TOrderedCharacters = record
  108. private
  109. FActualLength : Integer;
  110. private
  111. procedure EnsureSize(const AMinSize : Integer);
  112. public
  113. Data : array of TReorderUnit;
  114. property ActualLength : Integer read FActualLength;
  115. public
  116. class function Create(const ACapacity : Integer) : TOrderedCharacters;static;overload;
  117. class function Create() : TOrderedCharacters;static;overload;
  118. procedure Clear();
  119. function Clone() : TOrderedCharacters;
  120. function Insert(const AItem : TReorderUnit; const ADestPos : Integer) : Integer;
  121. function Append(const AItem : TReorderUnit) : Integer;
  122. procedure Delete(const AIndex : Integer);
  123. procedure ApplyStatement(const AStatement : PReorderSequence);
  124. end;
  125. POrderedCharacters = ^TOrderedCharacters;
  126. TCldrCollation = class;
  127. { TCldrCollationItem }
  128. TCldrCollationItem = class
  129. private
  130. FBackwards: Boolean;
  131. FBase: string;
  132. FChangedFields: TCollationFields;
  133. FParent: TCldrCollation;
  134. FRules: TReorderSequenceArray;
  135. FTypeName: string;
  136. public
  137. procedure Clear();
  138. property Parent : TCldrCollation read FParent;
  139. property TypeName : string read FTypeName write FTypeName;
  140. property Base : string read FBase write FBase;
  141. property Backwards : Boolean read FBackwards write FBackwards;
  142. property Rules : TReorderSequenceArray read FRules write FRules;
  143. property ChangedFields : TCollationFields read FChangedFields write FChangedFields;
  144. end;
  145. { TCldrCollation }
  146. TCldrCollation = class
  147. private
  148. FItems : array of TCldrCollationItem;
  149. FLocalID: string;
  150. FDefaultType: string;
  151. FVersion: string;
  152. FLanguage: string;
  153. private
  154. function GetItem(Index : Integer): TCldrCollationItem;
  155. function GetItemCount: Integer;
  156. public
  157. destructor Destroy();override;
  158. procedure Clear();
  159. function IndexOf(const AItemName : string) : Integer;
  160. function Find(const AItemName : string) : TCldrCollationItem;
  161. function Add(AItem : TCldrCollationItem) : Integer;
  162. property Language : string read FLanguage write FLanguage;
  163. property LocalID : string read FLocalID write FLocalID;
  164. property Version : string read FVersion write FVersion;
  165. property DefaultType : string read FDefaultType write FDefaultType;
  166. property ItemCount : Integer read GetItemCount;
  167. property Items[Index : Integer] : TCldrCollationItem read GetItem;
  168. end;
  169. TCldrParserMode = (HeaderParsing, FullParsing);
  170. function ComputeWeigths(
  171. const AData : PReorderUnit;
  172. const ADataLen : Integer;
  173. const ADataWeigths : TUCA_LineRecArray;
  174. out AResult : TUCA_LineRecArray
  175. ) : Integer;
  176. function FindCollationDefaultItemName(ACollation : TCldrCollation) : string;
  177. procedure GenerateCdlrCollation(
  178. ACollation : TCldrCollation;
  179. AItemName : string;
  180. AStoreName : string;
  181. AStream,
  182. ANativeEndianStream,
  183. AOtherEndianStream,
  184. ABinaryNativeEndianStream,
  185. ABinaryOtherEndianStream : TStream;
  186. ARootChars : TOrderedCharacters;
  187. ARootWeigths : TUCA_LineRecArray
  188. );
  189. procedure GenerateUCA_CLDR_Head(
  190. ADest : TStream;
  191. ABook : PUCA_DataBook;
  192. AProps : PUCA_PropBook;
  193. ACollation : TCldrCollationItem
  194. );
  195. function FillInitialPositions(
  196. AData : PReorderUnit;
  197. const ADataLen : Integer;
  198. const ADataWeigths : TUCA_LineRecArray
  199. ) : Integer;
  200. function IndexOf(
  201. const APattern : array of TUnicodeCodePoint;
  202. const APatternContext : array of TUnicodeCodePoint;
  203. const ASequence : PReorderUnit;
  204. const ASequenceLength : Integer
  205. ) : Integer;
  206. implementation
  207. uses
  208. RtlConsts, typinfo;
  209. function ToStr(const ACharacters : array of TUnicodeCodePoint): string;
  210. var
  211. i : Integer;
  212. begin
  213. Result := '';
  214. for i := Low(ACharacters) to High(ACharacters) do begin
  215. if (ACharacters[i] > $FFFF) then
  216. Result := Result + ' ' + IntToHex(ACharacters[i],5)
  217. else
  218. Result := Result + ' ' + IntToHex(ACharacters[i],4);
  219. end;
  220. Result := Trim(Result);
  221. end;
  222. function IndexOf(
  223. const APattern : array of TUnicodeCodePoint;
  224. const APatternContext : array of TUnicodeCodePoint;
  225. const ASequence : PReorderUnit;
  226. const ASequenceLength : Integer
  227. ) : Integer;
  228. var
  229. i, lp, sizep, lengthContext, sizeContext : Integer;
  230. p : PReorderUnit;
  231. begin
  232. Result := -1;
  233. if (ASequenceLength = 0) then
  234. exit;
  235. lp := Length(APattern);
  236. if (lp = 0) then
  237. exit;
  238. sizep := lp*SizeOf(TUnicodeCodePoint);
  239. lengthContext := Length(APatternContext);
  240. sizeContext := lengthContext*SizeOf(TUnicodeCodePoint);
  241. p := ASequence;
  242. for i := 0 to ASequenceLength - 1 do begin
  243. if (Length(p^.Characters) = lp) then begin
  244. if CompareMem(@APattern[0],@p^.Characters[0],sizep) then begin
  245. if (Length(p^.Context) = lengthContext) and
  246. ( (lengthContext = 0) or
  247. CompareMem(@p^.Context[0],@APatternContext[0],sizeContext)
  248. )
  249. then begin
  250. Result := i;
  251. Break;
  252. end;
  253. end;
  254. end;
  255. Inc(p);
  256. end;
  257. end;
  258. {procedure ApplyStatementToSequence(
  259. var ASequence : TOrderedCharacters;
  260. const AStatement : PReorderSequence;
  261. const AStatementCount : Integer
  262. );
  263. var
  264. pse, pd : PReorderUnit;
  265. kr : Integer;
  266. function GetNextInsertPos() : Integer;
  267. var
  268. kk : Integer;
  269. begin
  270. if (pse^.WeigthKind = rwkDeletion) then
  271. exit(0);
  272. if (pse^.WeigthKind = rwkIdentity) then
  273. exit(kr + 1);
  274. kk := kr + 1;
  275. pd := @ASequence.Data[kk];
  276. for kk := kk to ASequence.ActualLength - 1 do begin
  277. if (pd^.WeigthKind <= pse^.WeigthKind) then
  278. exit(kk);
  279. Inc(pd);
  280. end;
  281. Result := ASequence.ActualLength;
  282. end;
  283. var
  284. locResetPos, i, k, h : Integer;
  285. pst : PReorderSequence;
  286. begin
  287. pst := AStatement;
  288. for h := 0 to AStatementCount - 1 do begin
  289. locResetPos := -1;
  290. if (Length(pst^.Reset) > 0) then begin
  291. locResetPos := IndexOf(pst^.Reset,[],@ASequence.Data[0],ASequence.ActualLength);
  292. if (locResetPos = -1) then
  293. raise ECldrException.CreateFmt('Character(s) not found in sequence : "%s".',[ToStr(pst^.Reset)]);
  294. end;
  295. pse := @pst^.Elements[0];
  296. kr := locResetPos;
  297. k := GetNextInsertPos();
  298. for i := Low(pst^.Elements) to High(pst^.Elements) do begin
  299. k := ASequence.Insert(pse^,k)+1;
  300. Inc(pse);
  301. end;
  302. Inc(pst);
  303. end;
  304. end;}
  305. function FindLogicalPos(
  306. const ASequence : POrderedCharacters;
  307. const APosition : TReorderLogicalReset
  308. ) : Integer;
  309. var
  310. i, c : Integer;
  311. p : PReorderUnit;
  312. firstPos, lastPos : Integer;
  313. begin
  314. Result := 0;
  315. if (ASequence^.ActualLength = 0) then
  316. exit;
  317. p := @ASequence^.Data[0];
  318. c := ASequence^.ActualLength;
  319. if (APosition in [TReorderLogicalReset.FirstTertiaryIgnorable, TReorderLogicalReset.LastTertiaryIgnorable])
  320. then begin
  321. firstPos := -1;
  322. for i := 0 to c - 1 do begin
  323. if (p^.WeigthKind <= TReorderWeigthKind.Tertiary) then begin
  324. firstPos := i;
  325. Break;
  326. end;
  327. Inc(p);
  328. end;
  329. if (firstPos = -1) then
  330. exit(0);
  331. if (APosition = TReorderLogicalReset.FirstTertiaryIgnorable) then
  332. exit(firstPos);
  333. if (p^.WeigthKind < TReorderWeigthKind.Tertiary) then
  334. exit(firstPos);
  335. lastPos := -1;
  336. for i := firstPos + 1 to c - 1 do begin
  337. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  338. lastPos := i;
  339. Break;
  340. end;
  341. Inc(p);
  342. end;
  343. if (lastPos = -1) then
  344. exit(c);
  345. exit(lastPos);
  346. end;
  347. if (APosition in [TReorderLogicalReset.FirstSecondaryIgnorable, TReorderLogicalReset.LastSecondaryIgnorable])
  348. then begin
  349. firstPos := -1;
  350. for i := 0 to c - 1 do begin
  351. if (p^.WeigthKind <= TReorderWeigthKind.Secondary) then begin
  352. firstPos := i;
  353. Break;
  354. end;
  355. Inc(p);
  356. end;
  357. if (firstPos = -1) then
  358. exit(0);
  359. if (APosition = TReorderLogicalReset.FirstSecondaryIgnorable) then
  360. exit(firstPos);
  361. if (p^.WeigthKind < TReorderWeigthKind.Secondary) then
  362. exit(firstPos);
  363. lastPos := -1;
  364. for i := firstPos + 1 to c - 1 do begin
  365. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  366. lastPos := i;
  367. Break;
  368. end;
  369. Inc(p);
  370. end;
  371. if (lastPos = -1) then
  372. exit(c);
  373. exit(lastPos);
  374. end;
  375. if (APosition in [TReorderLogicalReset.FirstPrimaryIgnorable, TReorderLogicalReset.LastPrimaryIgnorable])
  376. then begin
  377. firstPos := -1;
  378. for i := 0 to c - 1 do begin
  379. if (p^.WeigthKind <= TReorderWeigthKind.Primary) then begin
  380. firstPos := i;
  381. Break;
  382. end;
  383. Inc(p);
  384. end;
  385. if (firstPos = -1) then
  386. exit(0);
  387. if (APosition = TReorderLogicalReset.FirstPrimaryIgnorable) then
  388. exit(firstPos);
  389. if (p^.WeigthKind < TReorderWeigthKind.Primary) then
  390. exit(firstPos);
  391. lastPos := -1;
  392. for i := firstPos + 1 to c - 1 do begin
  393. if (p^.WeigthKind <> TReorderWeigthKind.Identity) then begin
  394. lastPos := i;
  395. Break;
  396. end;
  397. Inc(p);
  398. end;
  399. if (lastPos = -1) then
  400. exit(c);
  401. exit(lastPos);
  402. end;
  403. if (APosition = TReorderLogicalReset.FirstNonIgnorable) then begin
  404. firstPos := -1;
  405. for i := 0 to c - 1 do begin
  406. if (p^.WeigthKind <= TReorderWeigthKind.Primary) then begin
  407. firstPos := i;
  408. Break;
  409. end;
  410. Inc(p);
  411. end;
  412. if (firstPos = -1) then
  413. exit(0);
  414. exit(firstPos);
  415. end;
  416. if (APosition = TReorderLogicalReset.LastNonIgnorable) then
  417. exit(c);
  418. end;
  419. procedure ApplyStatementToSequence(
  420. var ASequence : TOrderedCharacters;
  421. const AStatement : PReorderSequence;
  422. const AStatementCount : Integer
  423. );
  424. var
  425. pse, pd : PReorderUnit;
  426. kr : Integer;
  427. pst : PReorderSequence;
  428. function GetNextInsertPos() : Integer;
  429. var
  430. kk : Integer;
  431. begin
  432. if (pse^.WeigthKind = TReorderWeigthKind.Deletion) then
  433. exit(0);
  434. if (pse^.WeigthKind = TReorderWeigthKind.Identity) then
  435. exit(kr + 1);
  436. if not pst^.Before then begin
  437. kk := kr + 1;
  438. if (kk >= ASequence.ActualLength) then
  439. exit(kk);
  440. pd := @ASequence.Data[kk];
  441. for kk := kk to ASequence.ActualLength - 1 do begin
  442. if (pd^.WeigthKind <= pse^.WeigthKind) then
  443. exit(kk);
  444. Inc(pd);
  445. end;
  446. Result := ASequence.ActualLength;
  447. end else begin
  448. if (kr = 0) then
  449. exit(0);
  450. kk := kr;
  451. pd := @ASequence.Data[kk];
  452. if (pd^.WeigthKind = TReorderWeigthKind.Primary) then begin
  453. pd^.WeigthKind := pse^.WeigthKind;
  454. pse^.WeigthKind := TReorderWeigthKind.Primary;
  455. exit(kk);
  456. end;
  457. for kk := kk downto 0 do begin
  458. if (pd^.WeigthKind = TReorderWeigthKind.Deletion) or (pd^.WeigthKind <= pse^.WeigthKind) then begin
  459. if (pd^.WeigthKind > pse^.WeigthKind) then
  460. pd^.WeigthKind := pse^.WeigthKind;
  461. exit(kk);
  462. end;
  463. Dec(pd);
  464. end;
  465. Result := 0;
  466. end;
  467. end;
  468. var
  469. locResetPos, i, k, h : Integer;
  470. begin
  471. if (Length(AStatement^.Elements) = 0) then
  472. exit;
  473. pst := AStatement;
  474. for h := 0 to AStatementCount - 1 do begin
  475. locResetPos := -1;
  476. if (AStatement^.LogicalPosition > TReorderLogicalReset.None) then
  477. locResetPos := FindLogicalPos(@ASequence,AStatement^.LogicalPosition)
  478. else if (Length(pst^.Reset) > 0) then begin
  479. locResetPos := IndexOf(pst^.Reset,[],@ASequence.Data[0],ASequence.ActualLength);
  480. {if (locResetPos = -1) then
  481. raise ECldrException.CreateFmt('Character(s) not found in sequence : "%s".',[ToStr(pst^.Reset)]);}
  482. if (locResetPos = -1) then
  483. locResetPos := ASequence.ActualLength;
  484. end;
  485. pse := @pst^.Elements[0];
  486. kr := locResetPos;
  487. k := GetNextInsertPos();
  488. for i := Low(pst^.Elements) to High(pst^.Elements) do begin
  489. k := ASequence.Insert(pse^,k)+1;
  490. Inc(pse);
  491. end;
  492. Inc(pst);
  493. end;
  494. end;
  495. type
  496. PUCA_WeightRecArray = ^TUCA_WeightRecArray;
  497. TUCASortKey = array of Word;
  498. function SimpleFormKey(const ACEList : TUCA_WeightRecArray) : TUCASortKey;
  499. var
  500. r : TUCASortKey;
  501. i, c, k, ral, levelCount : Integer;
  502. pce : ^TUCA_WeightRec;
  503. begin
  504. c := Length(ACEList);
  505. if (c = 0) then
  506. exit(nil);
  507. //SetLength(r,((3+1{Level Separator})*c));
  508. levelCount := Length(ACEList[0].Weights);
  509. if (levelCount > 3) then
  510. levelCount := 3;
  511. SetLength(r,(levelCount*c + levelCount));
  512. ral := 0;
  513. for i := 0 to levelCount - 1 do begin
  514. for k := 0 to c - 1 do begin
  515. pce := @ACEList[k];
  516. if (pce^.Weights[i] <> 0) then begin
  517. r[ral] := pce^.Weights[i];
  518. ral := ral + 1;
  519. end;
  520. //pce := pce + 1;
  521. end;
  522. r[ral] := 0;
  523. ral := ral + 1;
  524. end;
  525. ral := ral - 1;
  526. SetLength(r,ral);
  527. Result := r;
  528. end;
  529. function CompareSortKey(const A, B : TUCASortKey) : Integer;
  530. var
  531. i, hb : Integer;
  532. begin
  533. if (Pointer(A) = Pointer(B)) then
  534. exit(0);
  535. Result := 1;
  536. hb := Length(B) - 1;
  537. for i := 0 to Length(A) - 1 do begin
  538. if (i > hb) then
  539. exit;
  540. if (A[i] < B[i]) then
  541. exit(-1);
  542. if (A[i] > B[i]) then
  543. exit(1);
  544. end;
  545. if (Length(A) = Length(B)) then
  546. exit(0);
  547. exit(-1);
  548. end;
  549. {function ComputeWeigths(
  550. const AData : PReorderUnit;
  551. const ADataLen : Integer;
  552. const ADataWeigths : TUCA_LineRecArray;
  553. out AResult : TUCA_LineRecArray
  554. ) : Integer;
  555. function GetWeigth(AItem : PReorderUnit) : PUCA_WeightRecArray;
  556. begin
  557. Result := nil;
  558. if (AItem^.InitialPosition < 1) or (AItem^.InitialPosition > Length(ADataWeigths)) then
  559. raise ECldrException.CreateFmt('Invalid "InitialPosition" value : %d.',[AItem^.InitialPosition]);
  560. Result := @ADataWeigths[(AItem^.InitialPosition-1)].Weights;
  561. end;
  562. var
  563. c, i, ral : Integer;
  564. p, q : PReorderUnit;
  565. r : TUCA_LineRecArray;
  566. pr : PUCA_LineRec;
  567. pbase : PReorderUnit;
  568. pw, pwb : PUCA_WeightRecArray;
  569. cw, ki : Integer;
  570. begin
  571. Result := 0;
  572. if (ADataLen < 1) then
  573. exit;
  574. c := ADataLen;
  575. ral := 0;
  576. SetLength(r,c);
  577. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  578. q := nil;
  579. pbase := nil;
  580. p := AData+1;
  581. pr := @r[0];
  582. i := 1;
  583. while (i < c) do begin
  584. if p^.Changed then begin
  585. if (pbase = nil) then begin
  586. pbase := p - 1;
  587. pwb := GetWeigth(pbase);
  588. end;
  589. if (p^.WeigthKind = rwkIdentity) then begin
  590. pr^.CodePoints := Copy(p^.Characters);
  591. q := p - 1;
  592. if (q = pbase) then
  593. pw := pwb
  594. else
  595. pw := @((pr-1)^.Weights);
  596. pr^.Weights := Copy(pw^);
  597. Inc(pr);
  598. Inc(ral);
  599. end else begin
  600. pr^.CodePoints := Copy(p^.Characters);
  601. q := p - 1;
  602. if (q = pbase) then begin
  603. pw := pwb;
  604. cw := (Length(pw^)+1);
  605. SetLength(pr^.Weights,cw);
  606. Move(pw^[0],pr^.Weights[0],((cw-1)*SizeOf(pw^[0])));
  607. FillByte(pr^.Weights[(cw-1)],SizeOf(pr^.Weights[0]),0);
  608. ki := Ord(p^.WeigthKind);
  609. pr^.Weights[(cw-1)].Weights[ki] := pr^.Weights[(cw-2)].Weights[ki]+1;
  610. end else begin
  611. pw := @((pr-1)^.Weights);
  612. pr^.Weights := Copy(pw^);
  613. cw := Length(pr^.Weights);
  614. ki := Ord(p^.WeigthKind);
  615. for ki := Ord(rwkPrimary) to Ord(rwkTertiary) do begin
  616. if (ki < Ord(p^.WeigthKind)) then
  617. pr^.Weights[(cw-1)].Weights[ki] := pw^[(cw-1)].Weights[ki]
  618. else if (ki = Ord(p^.WeigthKind)) then begin
  619. if (pw^[(cw-1)].Weights[ki] = 0) then
  620. pr^.Weights[(cw-1)].Weights[ki] := pwb^[(Length(pwb^)-1)].Weights[ki]+1
  621. else
  622. pr^.Weights[(cw-1)].Weights[ki] := pw^[(cw-1)].Weights[ki]+1;
  623. end else begin
  624. pr^.Weights[(cw-1)].Weights[ki] := 0;
  625. end;
  626. end;
  627. end;
  628. Inc(pr);
  629. Inc(ral);
  630. end;
  631. end else begin
  632. pbase := nil;
  633. pwb := nil;
  634. end;
  635. Inc(p);
  636. Inc(i);
  637. end;
  638. SetLength(r,ral);
  639. AResult := r;
  640. Result := Length(AResult);
  641. end;}
  642. function IndexOf(
  643. const APattern : array of TUnicodeCodePoint;
  644. const AList : PUCA_LineRec;
  645. const AListLen : Integer
  646. ) : Integer;
  647. var
  648. i, lengthPattern, sizePattern : Integer;
  649. pl : PUCA_LineRec;
  650. begin
  651. Result := -1;
  652. if (Length(APattern) = 0) then
  653. exit;
  654. if (AListLen = 0) then
  655. exit;
  656. lengthPattern := Length(APattern);
  657. sizePattern := lengthPattern*SizeOf(TUnicodeCodePoint);
  658. pl := AList;
  659. for i := 0 to AListLen - 1 do begin
  660. if (Length(pl^.CodePoints) = lengthPattern) and
  661. CompareMem(@pl^.CodePoints[0],@APattern[0],sizePattern)
  662. then begin
  663. Result := i;
  664. Break;
  665. end;
  666. Inc(pl);
  667. end;
  668. end;
  669. function Compress(
  670. const AData : TUCA_LineRecArray;
  671. out AResult : TUCA_LineRecArray
  672. ) : Boolean;
  673. var
  674. r : TUCA_LineRecArray;
  675. pr, p : PUCA_LineRec;
  676. ral : Integer;
  677. function FindOutSlot() : Boolean;
  678. var
  679. k : Integer;
  680. begin
  681. k := IndexOf(p^.CodePoints,@r[0],ral);
  682. Result := (k >= 0);
  683. if (k = -1) then begin
  684. k := ral;
  685. ral := ral + 1;
  686. end;
  687. pr := @r[k];
  688. end;
  689. procedure AddContextData();
  690. var
  691. k : Integer;
  692. begin
  693. if not p^.HasContext() then
  694. exit;
  695. k := Length(pr^.Context.Data);
  696. SetLength(pr^.Context.Data,(k+1));
  697. pr^.Context.Data[k].CodePoints := Copy(p^.Context.Data[0].CodePoints);
  698. pr^.Context.Data[k].Weights := Copy(p^.Weights);
  699. end;
  700. procedure AddItem();
  701. begin
  702. pr^.Assign(p^);
  703. if p^.HasContext() then begin
  704. SetLength(pr^.Context.Data,0);
  705. pr^.Weights := nil;
  706. AddContextData();
  707. end;
  708. end;
  709. var
  710. c, i : Integer;
  711. begin
  712. c := Length(AData);
  713. if (c = 0) then
  714. exit;
  715. SetLength(r,c);
  716. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  717. pr := @r[0];
  718. p := @AData[0];
  719. ral := 0;
  720. i := 0;
  721. AddItem();
  722. ral := 1;
  723. i := 1;
  724. Inc(p);
  725. while (i < c) do begin
  726. if FindOutSlot() then
  727. AddContextData()
  728. else
  729. AddItem();
  730. Inc(p);
  731. Inc(i);
  732. end;
  733. SetLength(r,ral);
  734. AResult := r;
  735. Result := (ral < Length(AData));
  736. end;
  737. function MarkSuffixAsChanged(
  738. const AData : PReorderUnit;
  739. const ADataLen : Integer
  740. ) : Integer;
  741. var
  742. i, k : Integer;
  743. p, q : PReorderUnit;
  744. suffixChar : TUnicodeCodePoint;
  745. begin
  746. Result := 0;
  747. if (ADataLen <= 1) then
  748. exit;
  749. q := AData;
  750. p := AData;
  751. for i := 0 to ADataLen - 1 do begin
  752. if p^.Changed then begin
  753. suffixChar := p^.Characters[0];
  754. for k := 0 to ADataLen - 1 do begin
  755. if not(q[k].Changed) and (q[k].Characters[0] = suffixChar) then begin
  756. q[k].Changed := True;
  757. Result := Result + 1;
  758. end;
  759. end;
  760. end;
  761. Inc(p);
  762. end;
  763. end;
  764. {$include weight_derivation.inc}
  765. function ComputeWeigths(
  766. const AData : PReorderUnit;
  767. const ADataLen : Integer;
  768. const ADataWeigths : TUCA_LineRecArray;
  769. out AResult : TUCA_LineRecArray
  770. ) : Integer;
  771. function GetWeigth(AItem : PReorderUnit) : PUCA_WeightRecArray;
  772. begin
  773. Result := nil;
  774. if (AItem^.InitialPosition < 1) or (AItem^.InitialPosition > Length(ADataWeigths)) then
  775. raise ECldrException.CreateFmt('Invalid "InitialPosition" value : %d.',[AItem^.InitialPosition]);
  776. Result := @ADataWeigths[(AItem^.InitialPosition-1)].Weights;
  777. end;
  778. var
  779. r : TUCA_LineRecArray;
  780. pr : PUCA_LineRec;
  781. procedure AddContext(const ACodePointPattern : TUnicodeCodePointArray);
  782. var
  783. k : Integer;
  784. begin
  785. k := Length(pr^.Context.Data);
  786. SetLength(pr^.Context.Data,(k+1));
  787. pr^.Context.Data[k].CodePoints := Copy(ACodePointPattern);
  788. SetLength(pr^.Context.Data[k].Weights,0);
  789. end;
  790. var
  791. ral : Integer;
  792. i : Integer;
  793. p : PReorderUnit;
  794. pbase : PReorderUnit;
  795. pwb : PUCA_WeightRecArray;
  796. actualBegin : Boolean;
  797. loopIndex : Integer;
  798. procedure SkipDeletion();
  799. begin
  800. pr^.CodePoints := Copy(p^.Characters);
  801. pr^.Deleted := True;
  802. SetLength(pr^.Weights,0);
  803. if p^.HasContext() then
  804. AddContext(p^.Context);
  805. Inc(pr);
  806. Inc(ral);
  807. Inc(p);
  808. Inc(i);
  809. end;
  810. procedure FindBaseItem();
  811. begin
  812. if (pbase = nil) or (pwb^ = nil) then begin
  813. if actualBegin then begin
  814. pwb := @ADataWeigths[0].Weights;
  815. end else begin
  816. pbase := p - 1;
  817. if pbase^.Changed then
  818. pwb := @((pr-1)^.Weights)
  819. else
  820. pwb := GetWeigth(pbase);
  821. if (pwb^ = nil) and (pbase = AData) then
  822. pwb := @ADataWeigths[0].Weights;
  823. end;
  824. end;
  825. end;
  826. function InternalComputeWeights(const AList : array of TUnicodeCodePointArray) : TUCA_WeightRecArray;
  827. var
  828. kral : Integer;
  829. kres : TUCA_WeightRecArray;
  830. procedure EnsureResultLength(const APlus : Integer);//inline;
  831. begin
  832. if ((kral+APlus) > Length(kres)) then
  833. SetLength(kres,(2*(kral+APlus)));
  834. end;
  835. procedure AddToResult(const AValue : TUCA_WeightRecArray);//inline;
  836. begin
  837. EnsureResultLength(Length(AValue));
  838. Move(AValue[0],kres[kral],(Length(AValue)*SizeOf(kres[0])));
  839. kral := kral + Length(AValue);
  840. end;
  841. var
  842. kc, k, ktempIndex, ki : Integer;
  843. tmpWeight : array of TUCA_PropWeights;
  844. begin
  845. kc := Length(AList);
  846. kral := 0;
  847. SetLength(kres,(10*kc));
  848. FillChar(kres[0],(Length(kres)*SizeOf(kres[0])),0);
  849. for k := 0 to kc - 1 do begin
  850. ktempIndex := IndexOf(AList[k],@r[0],ral);
  851. if (ktempIndex <> -1) then begin
  852. AddToResult(r[ktempIndex].Weights);
  853. Continue;
  854. end;
  855. ktempIndex := IndexOf(AList[k],[],AData,ADataLen);
  856. if (ktempIndex <> -1) then begin
  857. if not AData[ktempIndex].Changed then begin
  858. AddToResult(ADataWeigths[AData[ktempIndex].InitialPosition-1].Weights);
  859. Continue;
  860. end;
  861. end;
  862. if (Length(AList[k]) > 1) then begin
  863. for ki := 0 to Length(AList[k]) - 1 do begin
  864. ktempIndex := IndexOf([AList[k][ki]],@r[0],ral);
  865. if (ktempIndex <> -1) then begin
  866. AddToResult(r[ktempIndex].Weights);
  867. Continue;
  868. end;
  869. ktempIndex := IndexOf([AList[k][ki]],[],AData,ADataLen);
  870. if (ktempIndex <> -1) then begin
  871. if not AData[ktempIndex].Changed then begin
  872. AddToResult(ADataWeigths[AData[ktempIndex].InitialPosition-1].Weights);
  873. Continue;
  874. end;
  875. end;
  876. SetLength(tmpWeight,2);
  877. DeriveWeight(AList[k][ki],@tmpWeight[0]);
  878. EnsureResultLength(2);
  879. kres[kral].Weights[0] := tmpWeight[0].Weights[0];
  880. kres[kral].Weights[1] := tmpWeight[0].Weights[1];
  881. kres[kral].Weights[2] := tmpWeight[0].Weights[2];
  882. kres[kral+1].Weights[0] := tmpWeight[1].Weights[0];
  883. kres[kral+1].Weights[1] := tmpWeight[1].Weights[1];
  884. kres[kral+1].Weights[2] := tmpWeight[1].Weights[2];
  885. kral := kral + 2;
  886. tmpWeight := nil;
  887. end
  888. end;
  889. SetLength(tmpWeight,2);
  890. DeriveWeight(AList[k][0],@tmpWeight[0]);
  891. EnsureResultLength(2);
  892. kres[kral].Weights[0] := tmpWeight[0].Weights[0];
  893. kres[kral].Weights[1] := tmpWeight[0].Weights[1];
  894. kres[kral].Weights[2] := tmpWeight[0].Weights[2];
  895. kres[kral+1].Weights[0] := tmpWeight[1].Weights[0];
  896. kres[kral+1].Weights[1] := tmpWeight[1].Weights[1];
  897. kres[kral+1].Weights[2] := tmpWeight[1].Weights[2];
  898. kral := kral + 2;
  899. tmpWeight := nil;
  900. end;
  901. SetLength(kres,kral);
  902. Result := kres;
  903. end;
  904. procedure Handle_Expansion();
  905. var
  906. expChars : array[0..1] of TUnicodeCodePointArray;
  907. kres : TUCA_WeightRecArray;
  908. begin
  909. expChars[0] := (p-1)^.Characters;
  910. expChars[1] := p^.ExpansionChars;
  911. kres := InternalComputeWeights(expChars);
  912. if (p^.WeigthKind <= TReorderWeigthKind.Tertiary) then
  913. Inc(kres[Length(kres)-1].Weights[Ord(p^.WeigthKind)]);
  914. pr^.Weights := Copy(kres);
  915. end;
  916. var
  917. c, ti : Integer;
  918. q : PReorderUnit;
  919. pw : PUCA_WeightRecArray;
  920. begin
  921. Result := 0;
  922. if (ADataLen < 1) then
  923. exit;
  924. while True do begin
  925. for loopIndex := 0 to 1 do begin
  926. c := ADataLen;
  927. ral := 0;
  928. SetLength(r,c);
  929. FillByte(r[0],(Length(r)*SizeOf(r[0])),0);
  930. q := nil;
  931. pbase := nil;
  932. pr := @r[0];
  933. p := AData;
  934. i := 0;
  935. while (i < c) do begin
  936. if (p^.WeigthKind = TReorderWeigthKind.Deletion) then begin
  937. SkipDeletion();
  938. Continue;
  939. end;
  940. if p^.Changed then begin
  941. actualBegin := (i = 0) or (((p-1)^.WeigthKind = TReorderWeigthKind.Deletion));
  942. FindBaseItem();
  943. if p^.IsExpansion() then begin
  944. if (loopIndex = 0) then begin
  945. Inc(p);
  946. Inc(i);
  947. while (i < c) do begin
  948. if (p^.WeigthKind = TReorderWeigthKind.Primary) then
  949. Break;
  950. Inc(p);
  951. Inc(i);
  952. end;
  953. Continue;
  954. end;
  955. pr^.CodePoints := Copy(p^.Characters);
  956. Handle_Expansion();
  957. if p^.HasContext() then
  958. AddContext(p^.Context);
  959. Inc(pr);
  960. Inc(ral);
  961. end else if actualBegin then begin
  962. pr^.CodePoints := Copy(p^.Characters);
  963. pw := pwb;
  964. pr^.Weights := Copy(pw^);
  965. if p^.HasContext() then
  966. AddContext(p^.Context);
  967. Inc(pr);
  968. Inc(ral);
  969. end else if (p^.WeigthKind = TReorderWeigthKind.Identity) then begin
  970. pr^.CodePoints := Copy(p^.Characters);
  971. q := p - 1;
  972. if (q = pbase) then
  973. pw := pwb
  974. else
  975. pw := @((pr-1)^.Weights);
  976. pr^.Weights := Copy(pw^);
  977. if p^.HasContext() then
  978. AddContext(p^.Context);
  979. Inc(pr);
  980. Inc(ral);
  981. end else begin
  982. pr^.CodePoints := Copy(p^.Characters);
  983. if ((p - 1) = pbase) then begin
  984. if (p^.WeigthKind = TReorderWeigthKind.Primary) then begin
  985. SetLength(pr^.Weights,2);
  986. FillByte(pr^.Weights[0],(Length(pr^.Weights)*SizeOf(pr^.Weights[0])),0);
  987. pr^.Weights[0].Weights[0] := (pwb^[0].Weights[0] + 1);
  988. pr^.Weights[0].Variable := pwb^[0].Variable;
  989. pr^.Weights[1] := pr^.Weights[0];
  990. end else if (p^.WeigthKind = TReorderWeigthKind.Secondary) then begin
  991. SetLength(pr^.Weights,2);
  992. FillByte(pr^.Weights[0],(Length(pr^.Weights)*SizeOf(pr^.Weights[0])),0);
  993. pr^.Weights[0].Weights[0] := pwb^[0].Weights[0];
  994. pr^.Weights[0].Weights[1] := (pwb^[0].Weights[1] + 1);
  995. pr^.Weights[0].Variable := pwb^[0].Variable;
  996. pr^.Weights[1].Weights[0] := pr^.Weights[0].Weights[0];
  997. pr^.Weights[1].Variable := pr^.Weights[0].Variable;
  998. end else if (p^.WeigthKind = TReorderWeigthKind.Tertiary) then begin
  999. SetLength(pr^.Weights,2);
  1000. FillByte(pr^.Weights[0],(Length(pr^.Weights)*SizeOf(pr^.Weights[0])),0);
  1001. pr^.Weights[0].Weights[0] := pwb^[0].Weights[0];
  1002. pr^.Weights[0].Weights[1] := pwb^[0].Weights[1];
  1003. pr^.Weights[0].Weights[2] := (pwb^[0].Weights[2] + 1);
  1004. pr^.Weights[0].Variable := pwb^[0].Variable;
  1005. pr^.Weights[1].Weights[0] := pr^.Weights[0].Weights[0];
  1006. pr^.Weights[1].Variable := pr^.Weights[0].Variable;
  1007. end;
  1008. end else begin
  1009. pr^.Weights := Copy((pr-1)^.Weights);
  1010. if (p^.WeigthKind = TReorderWeigthKind.Primary) then
  1011. Inc(pr^.Weights[1].Weights[Ord(p^.WeigthKind)])
  1012. else
  1013. Inc(pr^.Weights[0].Weights[Ord(p^.WeigthKind)]);
  1014. end;
  1015. if p^.HasContext() then
  1016. AddContext(p^.Context);
  1017. Inc(pr);
  1018. Inc(ral);
  1019. end;
  1020. end else begin
  1021. if (i > 0) and ((p-1)^.WeigthKind <> TReorderWeigthKind.Deletion) and (p-1)^.Changed and
  1022. (ral > 0)
  1023. then begin
  1024. pw := GetWeigth(p);
  1025. ti := CompareSortKey(SimpleFormKey((pr-1)^.Weights),SimpleFormKey(pw^));
  1026. if ( (p^.WeigthKind = TReorderWeigthKind.Identity) and (ti > 0) ) or
  1027. ( (p^.WeigthKind >= TReorderWeigthKind.Primary) and (ti >= 0) )
  1028. then begin
  1029. p^.Changed := True;
  1030. Continue;
  1031. end;
  1032. end;
  1033. pbase := nil;
  1034. pwb := nil;
  1035. end;
  1036. Inc(p);
  1037. Inc(i);
  1038. end;
  1039. end;
  1040. SetLength(r,ral);
  1041. if (MarkSuffixAsChanged(AData,ADataLen) = 0) then
  1042. Break;
  1043. end;
  1044. Compress(r,AResult);
  1045. Result := Length(AResult);
  1046. end;
  1047. function FillInitialPositions(
  1048. AData : PReorderUnit;
  1049. const ADataLen : Integer;
  1050. const ADataWeigths : TUCA_LineRecArray
  1051. ) : Integer;
  1052. var
  1053. locNotFound, i, cw : Integer;
  1054. p : PReorderUnit;
  1055. pw : PUCA_LineRec;
  1056. begin
  1057. locNotFound := 0;
  1058. cw := Length(ADataWeigths);
  1059. if (cw > 0) then
  1060. pw := @ADataWeigths[0]
  1061. else
  1062. pw := nil;
  1063. p := AData;
  1064. for i := 0 to ADataLen - 1 do begin
  1065. p^.InitialPosition := IndexOf(p^.Characters,pw,cw) + 1;
  1066. if (p^.InitialPosition = 0) then
  1067. Inc(locNotFound);
  1068. Inc(p);
  1069. end;
  1070. Result := locNotFound;
  1071. end;
  1072. { TCldrCollationItem }
  1073. procedure TCldrCollationItem.Clear();
  1074. begin
  1075. FBackwards := False;
  1076. FBase := '';
  1077. FChangedFields := [];
  1078. SetLength(FRules,0);
  1079. FTypeName := '';
  1080. end;
  1081. { TCldrCollation }
  1082. function TCldrCollation.GetItem(Index : Integer): TCldrCollationItem;
  1083. begin
  1084. if (Index < 0) or (Index >= Length(FItems)) then
  1085. raise ERangeError.CreateFmt(SListIndexError,[Index]);
  1086. Result := FItems[Index];
  1087. end;
  1088. function TCldrCollation.GetItemCount: Integer;
  1089. begin
  1090. Result := Length(FItems);
  1091. end;
  1092. destructor TCldrCollation.Destroy;
  1093. begin
  1094. Clear();
  1095. inherited Destroy;
  1096. end;
  1097. procedure TCldrCollation.Clear();
  1098. var
  1099. i : Integer;
  1100. begin
  1101. for i := 0 to Length(FItems) - 1 do
  1102. FreeAndNil(FItems[i]);
  1103. SetLength(FItems,0);
  1104. FLocalID := '';
  1105. FDefaultType := '';
  1106. end;
  1107. function TCldrCollation.IndexOf(const AItemName: string): Integer;
  1108. var
  1109. i : Integer;
  1110. begin
  1111. for i := 0 to ItemCount - 1 do begin
  1112. if SameText(AItemName,Items[i].TypeName) then
  1113. exit(i);
  1114. end;
  1115. Result := -1;
  1116. end;
  1117. function TCldrCollation.Find(const AItemName: string): TCldrCollationItem;
  1118. var
  1119. i : Integer;
  1120. begin
  1121. i := IndexOf(AItemName);
  1122. if (i = - 1) then
  1123. Result := nil
  1124. else
  1125. Result := Items[i];
  1126. end;
  1127. function TCldrCollation.Add(AItem: TCldrCollationItem): Integer;
  1128. begin
  1129. Result := Length(FItems);
  1130. SetLength(FItems,(Result+1));
  1131. FItems[Result] := AItem;
  1132. AItem.FParent := Self;
  1133. end;
  1134. { TReorderSequence }
  1135. procedure TReorderSequence.Clear();
  1136. begin
  1137. Reset := nil;
  1138. Elements := nil;
  1139. LogicalPosition := TReorderLogicalReset(0);
  1140. Before := False;
  1141. end;
  1142. { TReorderUnit }
  1143. class function TReorderUnit.From(
  1144. const AChars,
  1145. AContext : array of TUnicodeCodePoint;
  1146. const AWeigthKind : TReorderWeigthKind;
  1147. const AInitialPosition : Integer
  1148. ) : TReorderUnit;
  1149. var
  1150. c : Integer;
  1151. begin
  1152. c := Length(AChars);
  1153. SetLength(Result.Characters,c);
  1154. if (c > 0) then
  1155. Move(AChars[0],Result.Characters[0],(c*SizeOf(Result.Characters[0])));
  1156. Result.WeigthKind := AWeigthKind;
  1157. Result.InitialPosition := AInitialPosition;
  1158. Result.Changed := False;
  1159. c := Length(AContext);
  1160. SetLength(Result.Context,c);
  1161. if (c > 0) then
  1162. Move(AContext[0],Result.Context[0],(c*SizeOf(Result.Context[0])));
  1163. end;
  1164. class function TReorderUnit.From(
  1165. const AChars : array of TUnicodeCodePoint;
  1166. const AWeigthKind : TReorderWeigthKind;
  1167. const AInitialPosition : Integer
  1168. ) : TReorderUnit;
  1169. begin
  1170. Result := From(AChars,[],AWeigthKind,AInitialPosition);
  1171. end;
  1172. class function TReorderUnit.From(
  1173. const AChar : TUnicodeCodePoint;
  1174. const AWeigthKind : TReorderWeigthKind;
  1175. const AInitialPosition : Integer
  1176. ) : TReorderUnit;
  1177. begin
  1178. Result := From([AChar],AWeigthKind,AInitialPosition);
  1179. end;
  1180. class function TReorderUnit.From(
  1181. const AChar : TUnicodeCodePoint;
  1182. const AContext : array of TUnicodeCodePoint;
  1183. const AWeigthKind : TReorderWeigthKind;
  1184. const AInitialPosition : Integer
  1185. ) : TReorderUnit;
  1186. begin
  1187. Result := From([AChar],AContext,AWeigthKind,AInitialPosition);
  1188. end;
  1189. procedure TReorderUnit.SetExpansion(const AChars: array of TUnicodeCodePoint);
  1190. var
  1191. c : Integer;
  1192. begin
  1193. c := Length(AChars);
  1194. SetLength(ExpansionChars,c);
  1195. if (c > 0) then
  1196. Move(AChars[0],ExpansionChars[0],(c*SizeOf(AChars[0])));
  1197. end;
  1198. procedure TReorderUnit.SetExpansion(const AChar: TUnicodeCodePoint);
  1199. begin
  1200. SetExpansion([AChar]);
  1201. end;
  1202. procedure TReorderUnit.Clear();
  1203. begin
  1204. Self.Characters := nil;
  1205. Self.Context := nil;
  1206. Self.ExpansionChars := nil;
  1207. Self.InitialPosition := 0;
  1208. Self.WeigthKind := TReorderWeigthKind(0);
  1209. Self.Changed := False;
  1210. end;
  1211. procedure TReorderUnit.Assign(const AItem : TReorderUnit);
  1212. begin
  1213. Clear();
  1214. Self.Characters := Copy(AItem.Characters);
  1215. //SetLength(Self.Context,Length(AItem.Context));
  1216. Self.Context := Copy(AItem.Context);
  1217. Self.ExpansionChars := Copy(AItem.ExpansionChars);
  1218. Self.WeigthKind := AItem.WeigthKind;
  1219. Self.InitialPosition := AItem.InitialPosition;
  1220. Self.Changed := AItem.Changed;
  1221. end;
  1222. function TReorderUnit.HasContext() : Boolean;
  1223. begin
  1224. Result := (Length(Context) > 0);
  1225. end;
  1226. function TReorderUnit.IsExpansion() : Boolean;
  1227. begin
  1228. Result := (Length(ExpansionChars) > 0);
  1229. end;
  1230. { TOrderedCharacters }
  1231. procedure TOrderedCharacters.EnsureSize(const AMinSize : Integer);
  1232. var
  1233. c : Integer;
  1234. begin
  1235. if (AMinSize > Length(Data)) then begin
  1236. if (AMinSize > 1000) then
  1237. c := AMinSize + 100
  1238. else
  1239. c := (3*AMinSize) div 2 ;
  1240. SetLength(Data,c);
  1241. end;
  1242. FActualLength := AMinSize;
  1243. end;
  1244. class function TOrderedCharacters.Create(const ACapacity : Integer) : TOrderedCharacters;
  1245. begin
  1246. if (ACapacity < 0) then
  1247. raise ERangeError.Create(SRangeError);
  1248. Result.FActualLength := 0;
  1249. SetLength(Result.Data,ACapacity);
  1250. end;
  1251. class function TOrderedCharacters.Create() : TOrderedCharacters;
  1252. begin
  1253. Result := Create(0);
  1254. end;
  1255. procedure TOrderedCharacters.Clear;
  1256. begin
  1257. Data := nil;
  1258. FActualLength := 0;
  1259. end;
  1260. function TOrderedCharacters.Clone() : TOrderedCharacters;
  1261. var
  1262. i : Integer;
  1263. begin
  1264. Result.Clear();
  1265. SetLength(Result.Data,Self.ActualLength);
  1266. for i := 0 to Length(Result.Data) - 1 do
  1267. Result.Data[i].Assign(Self.Data[i]);
  1268. Result.FActualLength := Self.FActualLength;
  1269. end;
  1270. function TOrderedCharacters.Insert(
  1271. const AItem : TReorderUnit;
  1272. const ADestPos : Integer
  1273. ) : Integer;
  1274. var
  1275. k, finalPos : Integer;
  1276. p : PReorderUnit;
  1277. i, c : Integer;
  1278. begin
  1279. if (ActualLength=0) then begin
  1280. EnsureSize(ActualLength + 1);
  1281. p := @Data[0];
  1282. p^.Assign(AItem);
  1283. p^.Changed := True;
  1284. exit(0);
  1285. end;
  1286. k := IndexOf(AItem.Characters,AItem.Context,@Data[0],ActualLength);
  1287. if (k = ADestPos) then begin
  1288. Data[ADestPos].Assign(AItem);
  1289. Data[ADestPos].Changed := True;
  1290. exit(k);
  1291. end;
  1292. finalPos := ADestPos;
  1293. if (finalPos > ActualLength) then
  1294. finalPos := ActualLength;
  1295. c := ActualLength;
  1296. EnsureSize(ActualLength + 1);
  1297. Data[c].Clear();
  1298. p := @Data[finalPos];
  1299. if (finalPos = ActualLength) then begin
  1300. p^.Assign(AItem);
  1301. p^.Changed := True;
  1302. end else begin
  1303. if (c > 0) then begin
  1304. p := @Data[c-1];
  1305. for i := finalPos to c - 1 do begin
  1306. Move(p^,(p+1)^,SizeOf(p^));
  1307. Dec(p);
  1308. end;
  1309. end;
  1310. p := @Data[finalPos];
  1311. {Move(
  1312. Pointer(p)^,Pointer(@p[1])^,
  1313. (ActualLength-(finalPos+1))*SizeOf(TReorderUnit)
  1314. );}
  1315. FillChar(Pointer(p)^,SizeOf(TReorderUnit),0);
  1316. p^.Assign(AItem);
  1317. p^.Changed := True;
  1318. end;
  1319. if (k >= 0) then begin
  1320. if (k > finalPos) then
  1321. Inc(k);
  1322. Delete(k);
  1323. end;
  1324. Result := finalPos;
  1325. end;
  1326. function TOrderedCharacters.Append(const AItem : TReorderUnit) : Integer;
  1327. begin
  1328. Result := Insert(AItem,ActualLength);
  1329. end;
  1330. procedure TOrderedCharacters.Delete(const AIndex : Integer);
  1331. var
  1332. i : Integer;
  1333. p : PReorderUnit;
  1334. begin
  1335. if (AIndex < 0) or (AIndex >= ActualLength) then
  1336. raise ERangeError.CreateFmt(SListIndexError,[AIndex]);
  1337. if (AIndex = (ActualLength-1)) then begin
  1338. Data[AIndex].Clear();
  1339. end else begin
  1340. //Data[AIndex].Clear();
  1341. p := @Data[AIndex];
  1342. p^.Clear();
  1343. for i := AIndex to ActualLength-2 do begin
  1344. Move((p+1)^,p^,SizeOf(p^));
  1345. Inc(p);
  1346. end;
  1347. {Move(
  1348. Pointer(@Data[(AIndex+1)])^,Pointer(@Data[AIndex])^,
  1349. (ActualLength-(AIndex+1))*SizeOf(TReorderUnit)
  1350. );}
  1351. FillChar(Pointer(@Data[(FActualLength-1)])^,SizeOf(TReorderUnit),0);
  1352. end;
  1353. FActualLength := FActualLength - 1;
  1354. end;
  1355. procedure TOrderedCharacters.ApplyStatement(const AStatement : PReorderSequence);
  1356. begin
  1357. ApplyStatementToSequence(Self,AStatement,1);
  1358. end;
  1359. function FindCollationDefaultItemName(ACollation : TCldrCollation) : string;
  1360. begin
  1361. if (ACollation.ItemCount = 0) then
  1362. exit('');
  1363. if (ACollation.IndexOf(ACollation.DefaultType) <> -1) then
  1364. exit(ACollation.DefaultType);
  1365. Result := 'standard';
  1366. if (ACollation.IndexOf(Result) <> -1) then
  1367. exit;
  1368. Result := 'search';
  1369. if (ACollation.IndexOf(Result) <> -1) then
  1370. exit;
  1371. if (ACollation.ItemCount > 0) then
  1372. Result := ACollation.Items[0].TypeName;
  1373. end;
  1374. procedure GenerateUCA_CLDR_Head(
  1375. ADest : TStream;
  1376. ABook : PUCA_DataBook;
  1377. AProps : PUCA_PropBook;
  1378. ACollation : TCldrCollationItem
  1379. );
  1380. procedure AddLine(const ALine : ansistring);
  1381. var
  1382. buffer : ansistring;
  1383. begin
  1384. buffer := ALine + sLineBreak;
  1385. ADest.Write(buffer[1],Length(buffer));
  1386. end;
  1387. procedure AddFields();
  1388. var
  1389. kc : Integer;
  1390. e : TCollationField;
  1391. ks : string;
  1392. ti : PTypeInfo;
  1393. begin
  1394. ti := TypeInfo(TCollationField);
  1395. ks := '';
  1396. kc := 0;
  1397. for e := Low(TCollationField) to High(TCollationField) do begin
  1398. if (e in ACollation.ChangedFields) then begin
  1399. ks := ks + ti^.Name + '.' +
  1400. GetEnumName(ti,Ord(e)) + ', ';
  1401. kc := kc + 1;
  1402. end
  1403. end;
  1404. if (AProps <> nil) then begin
  1405. if (AProps^.VariableLowLimit < High(Word)) then begin
  1406. ks := ks + ti^.Name + '.' +
  1407. GetEnumName(ti,Ord(TCollationField.VariableLowLimit)) + ', ';
  1408. kc := kc + 1;
  1409. end;
  1410. if (AProps^.VariableHighLimit > 0) then begin
  1411. ks := ks + ti^.Name + '.' +
  1412. GetEnumName(ti,Ord(TCollationField.VariableHighLimit)) + ', ';
  1413. kc := kc + 1;
  1414. end;
  1415. end;
  1416. if (kc > 0) then
  1417. ks := Copy(ks,1,(Length(ks)-2));
  1418. AddLine(' UPDATED_FIELDS = [ ' + ks + ' ];');
  1419. end;
  1420. begin
  1421. AddLine('{$mode objfpc}{$H+}');
  1422. AddLine('unit ' + COLLATION_FILE_PREFIX + LowerCase(ACollation.Parent.LocalID)+ ';'+sLineBreak);
  1423. AddLine('interface'+sLineBreak);
  1424. AddLine('implementation');
  1425. AddLine('uses');
  1426. AddLine(' unicodedata, unicodeducet;'+sLineBreak);
  1427. AddLine('const');
  1428. AddFields();
  1429. AddLine(' COLLATION_NAME = ' + QuotedStr(ACollation.Parent.Language) + ';');
  1430. AddLine(' BASE_COLLATION = ' + QuotedStr(ACollation.Base) + ';');
  1431. AddLine(' VERSION_STRING = ' + QuotedStr(ABook^.Version) + ';');
  1432. if (AProps <> nil) then begin
  1433. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(AProps^.VariableLowLimit) + ';');
  1434. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(AProps^.VariableHighLimit) + ';');
  1435. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(Ord(ABook^.VariableWeight)) + ';');
  1436. end else begin
  1437. AddLine(' VARIABLE_LOW_LIMIT = ' + IntToStr(High(Word)) + ';');
  1438. AddLine(' VARIABLE_HIGH_LIMIT = ' + IntToStr(0) + ';');
  1439. AddLine(' VARIABLE_WEIGHT = ' + IntToStr(0) + ';');
  1440. end;
  1441. AddLine(' BACKWARDS_0 = ' + BoolToStr(ABook^.Backwards[0],'True','False') + ';');
  1442. AddLine(' BACKWARDS_1 = ' + BoolToStr(ABook^.Backwards[1],'True','False') + ';');
  1443. AddLine(' BACKWARDS_2 = ' + BoolToStr(ABook^.Backwards[2],'True','False') + ';');
  1444. AddLine(' BACKWARDS_3 = ' + BoolToStr(ABook^.Backwards[3],'True','False') + ';');
  1445. if (AProps <> nil) then
  1446. AddLine(' PROP_COUNT = ' + IntToStr(Ord(AProps^.ItemSize)) + ';');
  1447. AddLine('');
  1448. end;
  1449. procedure GenerateUCA_CLDR_Registration(
  1450. ADest : TStream;
  1451. ABook : PUCA_DataBook
  1452. );
  1453. procedure AddLine(const ALine : ansistring);
  1454. var
  1455. buffer : ansistring;
  1456. begin
  1457. buffer := ALine + sLineBreak;
  1458. ADest.Write(buffer[1],Length(buffer));
  1459. end;
  1460. begin
  1461. AddLine('var');
  1462. AddLine(' CLDR_Collation : TUCA_DataBook = (');
  1463. AddLine(' Base : nil;');
  1464. AddLine(' Version : VERSION_STRING;');
  1465. AddLine(' CollationName : COLLATION_NAME;');
  1466. AddLine(' VariableWeight : TUCA_VariableKind(VARIABLE_WEIGHT);');
  1467. AddLine(' Backwards : (BACKWARDS_0,BACKWARDS_1,BACKWARDS_2,BACKWARDS_3);');
  1468. if (Length(ABook^.Lines) > 0) then begin
  1469. AddLine(' BMP_Table1 : @UCA_TABLE_1[0];');
  1470. AddLine(' BMP_Table2 : @UCA_TABLE_2[0];');
  1471. AddLine(' OBMP_Table1 : @UCAO_TABLE_1[0];');
  1472. AddLine(' OBMP_Table2 : @UCAO_TABLE_2[0];');
  1473. AddLine(' PropCount : PROP_COUNT;');
  1474. AddLine(' Props : PUCA_PropItemRec(@UCA_PROPS[0]);');
  1475. end else begin
  1476. AddLine(' BMP_Table1 : nil;');
  1477. AddLine(' BMP_Table2 : nil;');
  1478. AddLine(' OBMP_Table1 : nil;');
  1479. AddLine(' OBMP_Table2 : nil;');
  1480. AddLine(' PropCount : 0;');
  1481. AddLine(' Props : nil;');
  1482. end;
  1483. AddLine(' VariableLowLimit : VARIABLE_LOW_LIMIT;');
  1484. AddLine(' VariableHighLimit : VARIABLE_HIGH_LIMIT;');
  1485. AddLine(' );');
  1486. AddLine('');
  1487. AddLine('procedure Register();');
  1488. AddLine('begin');
  1489. AddLine(' PrepareCollation(@CLDR_Collation,BASE_COLLATION,UPDATED_FIELDS);');
  1490. AddLine(' RegisterCollation(@CLDR_Collation);');
  1491. AddLine('end;');
  1492. AddLine('');
  1493. AddLine('initialization');
  1494. AddLine(' Register();');
  1495. AddLine('');
  1496. AddLine('finalization');
  1497. AddLine(' UnregisterCollation(COLLATION_NAME);');
  1498. AddLine('');
  1499. AddLine('end.');
  1500. end;
  1501. procedure CheckEndianTransform(const ASource : PUCA_PropBook);
  1502. var
  1503. x, y : array of Byte;
  1504. px, py : PUCA_PropItemRec;
  1505. begin
  1506. if (ASource = nil) or (ASource^.ItemSize = 0) then
  1507. exit;
  1508. SetLength(x,ASource^.ItemSize);
  1509. px := PUCA_PropItemRec(@x[0]);
  1510. ReverseFromNativeEndian(ASource^.Items,ASource^.ItemSize,px);
  1511. SetLength(y,ASource^.ItemSize);
  1512. py := PUCA_PropItemRec(@y[0]);
  1513. ReverseToNativeEndian(px,ASource^.ItemSize,py);
  1514. if not CompareMem(ASource^.Items,@y[0],Length(x)) then
  1515. CompareProps(ASource^.Items, PUCA_PropItemRec(@y[0]),ASource^.ItemSize);
  1516. end;
  1517. procedure GenerateCdlrCollation(
  1518. ACollation : TCldrCollation;
  1519. AItemName : string;
  1520. AStoreName : string;
  1521. AStream,
  1522. ANativeEndianStream,
  1523. AOtherEndianStream,
  1524. ABinaryNativeEndianStream,
  1525. ABinaryOtherEndianStream : TStream;
  1526. ARootChars : TOrderedCharacters;
  1527. ARootWeigths : TUCA_LineRecArray
  1528. );
  1529. procedure AddLine(const ALine : ansistring; ADestStream : TStream);
  1530. var
  1531. buffer : ansistring;
  1532. begin
  1533. buffer := ALine + sLineBreak;
  1534. ADestStream.Write(buffer[1],Length(buffer));
  1535. end;
  1536. var
  1537. locUcaBook : TUCA_DataBook;
  1538. locSequence : TOrderedCharacters;
  1539. locItem : TCldrCollationItem;
  1540. i : Integer;
  1541. locUcaProps : PUCA_PropBook;
  1542. ucaFirstTable : TucaBmpFirstTable;
  1543. ucaSecondTable : TucaBmpSecondTable;
  1544. ucaoFirstTable : TucaoBmpFirstTable;
  1545. ucaoSecondTable : TucaOBmpSecondTable;
  1546. locHasProps : Boolean;
  1547. s : string;
  1548. serializedHeader : TSerializedCollationHeader;
  1549. e : TCollationField;
  1550. begin
  1551. locItem := ACollation.Find(AItemName);
  1552. if (locItem = nil) then
  1553. raise Exception.CreateFmt('Collation Item not found : "%s".',[AItemName]);
  1554. locSequence := ARootChars.Clone();
  1555. for i := 0 to Length(locItem.Rules) - 1 do
  1556. locSequence.ApplyStatement(@locItem.Rules[i]);
  1557. FillChar(locUcaBook,SizeOf(locUcaBook),0);
  1558. locUcaBook.Version := ACollation.Version;
  1559. locUcaBook.Backwards[1] := locItem.Backwards;
  1560. ComputeWeigths(@locSequence.Data[0],locSequence.ActualLength,ARootWeigths,locUcaBook.Lines);
  1561. for i := 0 to Length(locUcaBook.Lines) - 1 do
  1562. locUcaBook.Lines[i].Stored := True;
  1563. locHasProps := (Length(locUcaBook.Lines) > 0);
  1564. if not locHasProps then
  1565. locUcaProps := nil
  1566. else
  1567. MakeUCA_Props(@locUcaBook,locUcaProps);
  1568. try
  1569. CheckEndianTransform(locUcaProps);
  1570. if locHasProps then begin
  1571. MakeUCA_BmpTables(ucaFirstTable,ucaSecondTable,locUcaProps);
  1572. SetLength(ucaoSecondTable,100);
  1573. MakeUCA_OBmpTables(ucaoFirstTable,ucaoSecondTable,locUcaProps);
  1574. end;
  1575. GenerateLicenceText(AStream);
  1576. GenerateUCA_CLDR_Head(AStream,@locUcaBook,locUcaProps,locItem);
  1577. if locHasProps then begin
  1578. GenerateUCA_BmpTables(AStream,ANativeEndianStream,AOtherEndianStream,ucaFirstTable,ucaSecondTable);
  1579. GenerateUCA_OBmpTables(AStream,ANativeEndianStream,AOtherEndianStream,ucaoFirstTable,ucaoSecondTable);
  1580. GenerateUCA_PropTable(ANativeEndianStream,locUcaProps,ENDIAN_NATIVE);
  1581. GenerateUCA_PropTable(AOtherEndianStream,locUcaProps,ENDIAN_NON_NATIVE);
  1582. AddLine('{$ifdef FPC_LITTLE_ENDIAN}',AStream);
  1583. s := GenerateEndianIncludeFileName(AStoreName,ekLittle);
  1584. AddLine(Format(' {$include %s}',[ExtractFileName(s)]),AStream);
  1585. AddLine('{$else FPC_LITTLE_ENDIAN}',AStream);
  1586. s := GenerateEndianIncludeFileName(AStoreName,ekBig);
  1587. AddLine(Format(' {$include %s}',[ExtractFileName(s)]),AStream);
  1588. AddLine('{$endif FPC_LITTLE_ENDIAN}',AStream);
  1589. end;
  1590. GenerateUCA_CLDR_Registration(AStream,@locUcaBook);
  1591. FillChar(serializedHeader,SizeOf(TSerializedCollationHeader),0);
  1592. serializedHeader.Base := locItem.Base;
  1593. serializedHeader.Version := ACollation.Version;
  1594. serializedHeader.CollationName := ACollation.Language;
  1595. serializedHeader.VariableWeight := Ord(locUcaBook.VariableWeight);
  1596. SetBit(serializedHeader.Backwards,0,locUcaBook.Backwards[0]);
  1597. SetBit(serializedHeader.Backwards,1,locUcaBook.Backwards[1]);
  1598. SetBit(serializedHeader.Backwards,2,locUcaBook.Backwards[2]);
  1599. SetBit(serializedHeader.Backwards,3,locUcaBook.Backwards[3]);
  1600. if locHasProps then begin
  1601. serializedHeader.BMP_Table1Length := Length(ucaFirstTable);
  1602. serializedHeader.BMP_Table2Length := Length(TucaBmpSecondTableItem) *
  1603. (Length(ucaSecondTable) * SizeOf(UInt24));
  1604. serializedHeader.OBMP_Table1Length := Length(ucaoFirstTable) * SizeOf(Word);
  1605. serializedHeader.OBMP_Table2Length := Length(TucaOBmpSecondTableItem) *
  1606. (Length(ucaoSecondTable) * SizeOf(UInt24));
  1607. serializedHeader.PropCount := locUcaProps^.ItemSize;
  1608. serializedHeader.VariableLowLimit := locUcaProps^.VariableLowLimit;
  1609. serializedHeader.VariableHighLimit := locUcaProps^.VariableHighLimit;
  1610. end else begin
  1611. serializedHeader.VariableLowLimit := High(Word);
  1612. serializedHeader.VariableHighLimit := 0;
  1613. end;
  1614. serializedHeader.ChangedFields := 0;
  1615. for e := Low(TCollationField) to High(TCollationField) do begin
  1616. if (e in locItem.ChangedFields) then
  1617. SetBit(serializedHeader.ChangedFields,Ord(e),True);
  1618. end;
  1619. ABinaryNativeEndianStream.Write(serializedHeader,SizeOf(serializedHeader));
  1620. ReverseRecordBytes(serializedHeader);
  1621. ABinaryOtherEndianStream.Write(serializedHeader,SizeOf(serializedHeader));
  1622. if locHasProps then begin
  1623. GenerateBinaryUCA_BmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaFirstTable,ucaSecondTable);
  1624. GenerateBinaryUCA_OBmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaoFirstTable,ucaoSecondTable);
  1625. GenerateBinaryUCA_PropTable(ABinaryNativeEndianStream,ABinaryOtherEndianStream,locUcaProps);
  1626. end;
  1627. finally
  1628. locSequence.Clear();
  1629. FreeUcaBook(locUcaProps);
  1630. end;
  1631. end;
  1632. end.