cwstring.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2013 by Yury Sidorov,
  4. member of the Free Pascal development team.
  5. Wide string support for Android
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$inline on}
  14. {$implicitexceptions off}
  15. {$IFNDEF FPC_DOTTEDUNITS}
  16. unit cwstring;
  17. {$ENDIF FPC_DOTTEDUNITS}
  18. interface
  19. procedure SetCWidestringManager;
  20. implementation
  21. {$IFDEF FPC_DOTTEDUNITS}
  22. uses System.DynLibs;
  23. {$ELSE FPC_DOTTEDUNITS}
  24. uses dynlibs;
  25. {$ENDIF FPC_DOTTEDUNITS}
  26. type
  27. UErrorCode = SizeInt;
  28. int32_t = longint;
  29. uint32_t = longword;
  30. PUConverter = pointer;
  31. PUCollator = pointer;
  32. UBool = LongBool;
  33. var
  34. hlibICU: TLibHandle;
  35. hlibICUi18n: TLibHandle;
  36. LibVer: ansistring;
  37. ucnv_open: function (converterName: PAnsiChar; var pErrorCode: UErrorCode): PUConverter; cdecl;
  38. ucnv_close: procedure (converter: PUConverter); cdecl;
  39. ucnv_setSubstChars: procedure (converter: PUConverter; subChars: PAnsiChar; len: byte; var pErrorCode: UErrorCode); cdecl;
  40. ucnv_setFallback: procedure (cnv: PUConverter; usesFallback: UBool); cdecl;
  41. ucnv_fromUChars: function (cnv: PUConverter; dest: PAnsiChar; destCapacity: int32_t; src: PUnicodeChar; srcLength: int32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
  42. ucnv_toUChars: function (cnv: PUConverter; dest: PUnicodeChar; destCapacity: int32_t; src: PAnsiChar; srcLength: int32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
  43. u_strToUpper: function (dest: PUnicodeChar; destCapacity: int32_t; src: PUnicodeChar; srcLength: int32_t; locale: PAnsiChar; var pErrorCode: UErrorCode): int32_t; cdecl;
  44. u_strToLower: function (dest: PUnicodeChar; destCapacity: int32_t; src: PUnicodeChar; srcLength: int32_t; locale: PAnsiChar; var pErrorCode: UErrorCode): int32_t; cdecl;
  45. u_strCompare: function (s1: PUnicodeChar; length1: int32_t; s2: PUnicodeChar; length2: int32_t; codePointOrder: UBool): int32_t; cdecl;
  46. u_strCaseCompare: function (s1: PUnicodeChar; length1: int32_t; s2: PUnicodeChar; length2: int32_t; options: uint32_t; var pErrorCode: UErrorCode): int32_t; cdecl;
  47. u_getDataDirectory: function(): PAnsiChar; cdecl;
  48. u_setDataDirectory: procedure(directory: PAnsiChar); cdecl;
  49. u_init: procedure(var status: UErrorCode); cdecl;
  50. ucol_open: function(loc: PAnsiChar; var status: UErrorCode): PUCollator; cdecl;
  51. ucol_close: procedure (coll: PUCollator); cdecl;
  52. ucol_strcoll: function (coll: PUCollator; source: PUnicodeChar; sourceLength: int32_t; target: PUnicodeChar; targetLength: int32_t): int32_t; cdecl;
  53. ucol_setStrength: procedure (coll: PUCollator; strength: int32_t); cdecl;
  54. threadvar
  55. ThreadDataInited: boolean;
  56. DefConv, LastConv: PUConverter;
  57. LastCP: TSystemCodePage;
  58. DefColl: PUCollator;
  59. function MaskExceptions: dword;
  60. begin
  61. {$if defined(cpux86_64) or defined(cpui386)}
  62. Result:=GetMXCSR;
  63. SetMXCSR(Result or %0000000010000000 {MM_MaskInvalidOp} or %0001000000000000 {MM_MaskPrecision});
  64. {$else}
  65. Result:=0;
  66. {$endif}
  67. end;
  68. procedure UnmaskExceptions(oldmask: dword);
  69. begin
  70. {$if defined(cpux86_64) or defined(cpui386)}
  71. SetMXCSR(oldmask);
  72. {$endif}
  73. end;
  74. function OpenConverter(const name: ansistring): PUConverter;
  75. var
  76. err: UErrorCode;
  77. oldmask: dword;
  78. begin
  79. { ucnv_open() must be called with some SSE exception masked on x86_64-android. }
  80. oldmask:=MaskExceptions;
  81. err:=0;
  82. Result:=ucnv_open(PAnsiChar(name), err);
  83. if Result <> nil then begin
  84. ucnv_setSubstChars(Result, '?', 1, err);
  85. ucnv_setFallback(Result, True);
  86. end;
  87. UnmaskExceptions(oldmask);
  88. end;
  89. procedure InitThreadData;
  90. var
  91. err: UErrorCode;
  92. col: PUCollator;
  93. begin
  94. if (hlibICU = 0) or ThreadDataInited then
  95. exit;
  96. ThreadDataInited:=True;
  97. DefConv:=OpenConverter('utf8');
  98. err:=0;
  99. col:=ucol_open(nil, err);
  100. if col <> nil then
  101. ucol_setStrength(col, 2);
  102. DefColl:=col;
  103. end;
  104. function GetConverter(cp: TSystemCodePage): PUConverter;
  105. var
  106. s: ansistring;
  107. begin
  108. if hlibICU = 0 then begin
  109. Result:=nil;
  110. exit;
  111. end;
  112. InitThreadData;
  113. if (cp = CP_UTF8) or (cp = CP_ACP) then
  114. Result:=DefConv
  115. else begin
  116. if cp <> LastCP then begin
  117. Str(cp, s);
  118. LastConv:=OpenConverter('cp' + s);
  119. LastCP:=cp;
  120. end;
  121. Result:=LastConv;
  122. end;
  123. end;
  124. procedure Unicode2AnsiMove(source: PUnicodeChar; var dest: RawByteString; cp: TSystemCodePage; len: SizeInt);
  125. var
  126. len2: SizeInt;
  127. conv: PUConverter;
  128. err: UErrorCode;
  129. begin
  130. if len = 0 then begin
  131. dest:='';
  132. exit;
  133. end;
  134. conv:=GetConverter(cp);
  135. if (conv = nil) and not ( (cp = CP_UTF8) or (cp = CP_ACP) ) then begin
  136. // fallback implementation
  137. DefaultUnicode2AnsiMove(source,dest,cp,len);
  138. exit;
  139. end;
  140. len2:=len*3;
  141. SetLength(dest, len2);
  142. err:=0;
  143. if conv <> nil then
  144. len2:=ucnv_fromUChars(conv, PAnsiChar(dest), len2, source, len, err)
  145. else begin
  146. // Use UTF-8 conversion from RTL
  147. cp:=CP_UTF8;
  148. len2:=UnicodeToUtf8(PAnsiChar(dest), len2, source, len) - 1;
  149. end;
  150. if len2 > Length(dest) then begin
  151. SetLength(dest, len2);
  152. err:=0;
  153. if conv <> nil then
  154. len2:=ucnv_fromUChars(conv, PAnsiChar(dest), len2, source, len, err)
  155. else
  156. len2:=UnicodeToUtf8(PAnsiChar(dest), len2, source, len) - 1;
  157. end;
  158. if len2 < 0 then
  159. len2:=0;
  160. SetLength(dest, len2);
  161. SetCodePage(dest, cp, False);
  162. end;
  163. procedure Ansi2UnicodeMove(source:PAnsiChar;cp : TSystemCodePage;var dest:unicodestring;len:SizeInt);
  164. var
  165. len2: SizeInt;
  166. conv: PUConverter;
  167. err: UErrorCode;
  168. begin
  169. if len = 0 then begin
  170. dest:='';
  171. exit;
  172. end;
  173. conv:=GetConverter(cp);
  174. if (conv = nil) and not ( (cp = CP_UTF8) or (cp = CP_ACP) ) then begin
  175. // fallback implementation
  176. DefaultAnsi2UnicodeMove(source,cp,dest,len);
  177. exit;
  178. end;
  179. len2:=len;
  180. SetLength(dest, len2);
  181. err:=0;
  182. if conv <> nil then
  183. len2:=ucnv_toUChars(conv, PUnicodeChar(dest), len2, source, len, err)
  184. else
  185. // Use UTF-8 conversion from RTL
  186. len2:=Utf8ToUnicode(PUnicodeChar(dest), len2, source, len) - 1;
  187. if len2 > Length(dest) then begin
  188. SetLength(dest, len2);
  189. err:=0;
  190. if conv <> nil then
  191. len2:=ucnv_toUChars(conv, PUnicodeChar(dest), len2, source, len, err)
  192. else
  193. len2:=Utf8ToUnicode(PUnicodeChar(dest), len2, source, len) - 1;
  194. end;
  195. if len2 < 0 then
  196. len2:=0;
  197. SetLength(dest, len2);
  198. end;
  199. function UpperUnicodeString(const s : UnicodeString) : UnicodeString;
  200. var
  201. len, len2: SizeInt;
  202. err: UErrorCode;
  203. begin
  204. if hlibICU = 0 then begin
  205. // fallback implementation
  206. Result:=UnicodeString(UpCase(AnsiString(s)));
  207. exit;
  208. end;
  209. len:=Length(s);
  210. SetLength(Result, len);
  211. if len = 0 then
  212. exit;
  213. err:=0;
  214. len2:=u_strToUpper(PUnicodeChar(Result), len, PUnicodeChar(s), len, nil, err);
  215. if len2 > len then begin
  216. SetLength(Result, len2);
  217. err:=0;
  218. len2:=u_strToUpper(PUnicodeChar(Result), len2, PUnicodeChar(s), len, nil, err);
  219. end;
  220. SetLength(Result, len2);
  221. end;
  222. function LowerUnicodeString(const s : UnicodeString) : UnicodeString;
  223. var
  224. len, len2: SizeInt;
  225. err: UErrorCode;
  226. begin
  227. if hlibICU = 0 then begin
  228. // fallback implementation
  229. Result:=UnicodeString(LowerCase(AnsiString(s)));
  230. exit;
  231. end;
  232. len:=Length(s);
  233. SetLength(Result, len);
  234. if len = 0 then
  235. exit;
  236. err:=0;
  237. len2:=u_strToLower(PUnicodeChar(Result), len, PUnicodeChar(s), len, nil, err);
  238. if len2 > len then begin
  239. SetLength(Result, len2);
  240. err:=0;
  241. len2:=u_strToLower(PUnicodeChar(Result), len2, PUnicodeChar(s), len, nil, err);
  242. end;
  243. SetLength(Result, len2);
  244. end;
  245. function _CompareStr(const S1, S2: UnicodeString): PtrInt;
  246. var
  247. count, count1, count2: SizeInt;
  248. begin
  249. result := 0;
  250. Count1 := Length(S1);
  251. Count2 := Length(S2);
  252. if Count1>Count2 then
  253. Count:=Count2
  254. else
  255. Count:=Count1;
  256. result := CompareByte(PUnicodeChar(S1)^, PUnicodeChar(S2)^, Count*SizeOf(UnicodeChar));
  257. if result=0 then
  258. result:=Count1 - Count2;
  259. end;
  260. function CompareUnicodeString(const s1, s2 : UnicodeString; Options : TCompareOptions) : PtrInt;
  261. const
  262. U_COMPARE_CODE_POINT_ORDER = $8000;
  263. var
  264. err: UErrorCode;
  265. begin
  266. if hlibICU = 0 then begin
  267. // fallback implementation
  268. Result:=_CompareStr(s1, s2);
  269. exit;
  270. end;
  271. if (coIgnoreCase in Options) then begin
  272. err:=0;
  273. Result:=u_strCaseCompare(PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2), U_COMPARE_CODE_POINT_ORDER, err);
  274. end
  275. else begin
  276. InitThreadData;
  277. if DefColl <> nil then
  278. Result:=ucol_strcoll(DefColl, PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2))
  279. else
  280. Result:=u_strCompare(PUnicodeChar(s1), Length(s1), PUnicodeChar(s2), Length(s2), True);
  281. end;
  282. end;
  283. function UpperAnsiString(const s : AnsiString) : AnsiString;
  284. begin
  285. Result:=AnsiString(UpperUnicodeString(UnicodeString(s)));
  286. end;
  287. function LowerAnsiString(const s : AnsiString) : AnsiString;
  288. begin
  289. Result:=AnsiString(LowerUnicodeString(UnicodeString(s)));
  290. end;
  291. function CompareStrAnsiString(const s1, s2: ansistring): PtrInt;
  292. begin
  293. Result:=CompareUnicodeString(UnicodeString(s1), UnicodeString(s2), []);
  294. end;
  295. function StrCompAnsi(s1,s2 : PAnsiChar): PtrInt;
  296. begin
  297. Result:=CompareUnicodeString(UnicodeString(s1), UnicodeString(s2), []);
  298. end;
  299. function AnsiCompareText(const S1, S2: ansistring): PtrInt;
  300. begin
  301. Result:=CompareUnicodeString(UnicodeString(s1), UnicodeString(s2), [coIgnoreCase]);
  302. end;
  303. function AnsiStrIComp(S1, S2: PAnsiChar): PtrInt;
  304. begin
  305. Result:=CompareUnicodeString(UnicodeString(s1), UnicodeString(s2), [coIgnoreCase]);
  306. end;
  307. function AnsiStrLComp(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  308. var
  309. as1, as2: ansistring;
  310. begin
  311. SetString(as1, S1, MaxLen);
  312. SetString(as2, S2, MaxLen);
  313. Result:=CompareUnicodeString(UnicodeString(as1), UnicodeString(as2), []);
  314. end;
  315. function AnsiStrLIComp(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  316. var
  317. as1, as2: ansistring;
  318. begin
  319. SetString(as1, S1, MaxLen);
  320. SetString(as2, S2, MaxLen);
  321. Result:=CompareUnicodeString(UnicodeString(as1), UnicodeString(as2), [coIgnoreCase]);
  322. end;
  323. function AnsiStrLower(Str: PAnsiChar): PAnsiChar;
  324. var
  325. s, res: ansistring;
  326. begin
  327. s:=Str;
  328. res:=LowerAnsiString(s);
  329. if Length(res) > Length(s) then
  330. SetLength(res, Length(s));
  331. Move(PAnsiChar(res)^, Str, Length(res) + 1);
  332. Result:=Str;
  333. end;
  334. function AnsiStrUpper(Str: PAnsiChar): PAnsiChar;
  335. var
  336. s, res: ansistring;
  337. begin
  338. s:=Str;
  339. res:=UpperAnsiString(s);
  340. if Length(res) > Length(s) then
  341. SetLength(res, Length(s));
  342. Move(PAnsiChar(res)^, Str, Length(res) + 1);
  343. Result:=Str;
  344. end;
  345. function CodePointLength(const Str: PAnsiChar; MaxLookAead: PtrInt): Ptrint;
  346. var
  347. c: byte;
  348. begin
  349. // Only UTF-8 encoding is supported
  350. c:=byte(Str^);
  351. if c = 0 then
  352. Result:=0
  353. else begin
  354. Result:=1;
  355. if c < $80 then
  356. exit; // 1-byte ASCII char
  357. while c and $C0 = $C0 do begin
  358. Inc(Result);
  359. c:=c shl 1;
  360. end;
  361. if Result > 6 then
  362. Result:=1 // Invalid code point
  363. else
  364. if Result > MaxLookAead then
  365. Result:=-1; // Incomplete code point
  366. end;
  367. end;
  368. function GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  369. begin
  370. Result := CP_UTF8; // Android always uses UTF-8
  371. end;
  372. procedure SetStdIOCodePage(var T: Text); inline;
  373. begin
  374. case TextRec(T).Mode of
  375. fmInput:TextRec(T).CodePage:=DefaultSystemCodePage;
  376. fmOutput:TextRec(T).CodePage:=DefaultSystemCodePage;
  377. end;
  378. end;
  379. procedure SetStdIOCodePages; inline;
  380. begin
  381. SetStdIOCodePage(Input);
  382. SetStdIOCodePage(Output);
  383. SetStdIOCodePage(ErrOutput);
  384. SetStdIOCodePage(StdOut);
  385. SetStdIOCodePage(StdErr);
  386. end;
  387. procedure Ansi2WideMove(source:PAnsiChar; cp:TSystemCodePage; var dest:widestring; len:SizeInt);
  388. var
  389. us: UnicodeString;
  390. begin
  391. Ansi2UnicodeMove(source,cp,us,len);
  392. dest:=us;
  393. end;
  394. function UpperWideString(const s : WideString) : WideString;
  395. begin
  396. Result:=UpperUnicodeString(s);
  397. end;
  398. function LowerWideString(const s : WideString) : WideString;
  399. begin
  400. Result:=LowerUnicodeString(s);
  401. end;
  402. function CompareWideString(const s1, s2 : WideString; Options : TCompareOptions) : PtrInt;
  403. begin
  404. Result:=CompareUnicodeString(s1, s2, Options);
  405. end;
  406. Procedure SetCWideStringManager;
  407. Var
  408. CWideStringManager : TUnicodeStringManager;
  409. begin
  410. CWideStringManager:=widestringmanager;
  411. With CWideStringManager do
  412. begin
  413. Wide2AnsiMoveProc:=@Unicode2AnsiMove;
  414. Ansi2WideMoveProc:=@Ansi2WideMove;
  415. UpperWideStringProc:=@UpperWideString;
  416. LowerWideStringProc:=@LowerWideString;
  417. CompareWideStringProc:=@CompareWideString;
  418. UpperAnsiStringProc:=@UpperAnsiString;
  419. LowerAnsiStringProc:=@LowerAnsiString;
  420. CompareStrAnsiStringProc:=@CompareStrAnsiString;
  421. CompareTextAnsiStringProc:=@AnsiCompareText;
  422. StrCompAnsiStringProc:=@StrCompAnsi;
  423. StrICompAnsiStringProc:=@AnsiStrIComp;
  424. StrLCompAnsiStringProc:=@AnsiStrLComp;
  425. StrLICompAnsiStringProc:=@AnsiStrLIComp;
  426. StrLowerAnsiStringProc:=@AnsiStrLower;
  427. StrUpperAnsiStringProc:=@AnsiStrUpper;
  428. Unicode2AnsiMoveProc:=@Unicode2AnsiMove;
  429. Ansi2UnicodeMoveProc:=@Ansi2UnicodeMove;
  430. UpperUnicodeStringProc:=@UpperUnicodeString;
  431. LowerUnicodeStringProc:=@LowerUnicodeString;
  432. CompareUnicodeStringProc:=@CompareUnicodeString;
  433. GetStandardCodePageProc:=@GetStandardCodePage;
  434. CodePointLengthProc:=@CodePointLength;
  435. end;
  436. SetUnicodeStringManager(CWideStringManager);
  437. end;
  438. procedure UnloadICU;
  439. begin
  440. if DefColl <> nil then
  441. ucol_close(DefColl);
  442. if DefConv <> nil then
  443. ucnv_close(DefConv);
  444. if LastConv <> nil then
  445. ucnv_close(LastConv);
  446. if LibVer = '_3_8' then
  447. exit; // ICU v3.8 on Android 1.5-2.1 is buggy and can't be unloaded properly
  448. if hlibICU <> 0 then begin
  449. UnloadLibrary(hlibICU);
  450. hlibICU:=0;
  451. end;
  452. if hlibICUi18n <> 0 then begin
  453. UnloadLibrary(hlibICUi18n);
  454. hlibICUi18n:=0;
  455. end;
  456. end;
  457. function GetIcuProc(const Name: AnsiString; out ProcPtr; libId: longint = 0): boolean;
  458. var
  459. p: pointer;
  460. hLib: TLibHandle;
  461. begin
  462. Result:=False;
  463. if libId = 0 then
  464. hLib:=hlibICU
  465. else
  466. hLib:=hlibICUi18n;
  467. if hLib = 0 then
  468. exit;
  469. p:=GetProcedureAddress(hlib, Name + LibVer);
  470. if p = nil then
  471. exit;
  472. pointer(ProcPtr):=p;
  473. Result:=True;
  474. end;
  475. function LoadICU: boolean;
  476. const
  477. ICUver: array [1..15] of ansistring =
  478. ('3_8', '4_2', '44', '46', '48', '50', '51', '53', '55', '56', '58', '60',
  479. '63', '66', '68');
  480. TestProcName = 'ucnv_open';
  481. var
  482. i: longint;
  483. s: ansistring;
  484. dir: PAnsiChar;
  485. err: UErrorCode;
  486. begin
  487. Result:=False;
  488. {$ifdef android}
  489. hlibICU:=LoadLibrary('libicuuc.so');
  490. hlibICUi18n:=LoadLibrary('libicui18n.so');
  491. {$else}
  492. hlibICU:=LoadLibrary('icuuc40.dll');
  493. hlibICUi18n:=LoadLibrary('icuin40.dll');
  494. LibVer:='_4_0';
  495. {$endif android}
  496. if (hlibICU = 0) or (hlibICUi18n = 0) then begin
  497. UnloadICU;
  498. exit;
  499. end;
  500. // Finding ICU version using known versions table
  501. for i:=High(ICUver) downto Low(ICUver) do begin
  502. s:='_' + ICUver[i];
  503. if GetProcedureAddress(hlibICU, TestProcName + s) <> nil then begin
  504. LibVer:=s;
  505. break;
  506. end;
  507. end;
  508. if LibVer = '' then begin
  509. // Finding unknown ICU version
  510. Val(ICUver[High(ICUver)], i);
  511. repeat
  512. Inc(i);
  513. Str(i, s);
  514. s:='_' + s;
  515. if GetProcedureAddress(hlibICU, TestProcName + s) <> nil then begin
  516. LibVer:=s;
  517. break;
  518. end;
  519. until i >= 100;
  520. end;
  521. if LibVer = '' then begin
  522. // Trying versionless name
  523. if GetProcedureAddress(hlibICU, TestProcName) = nil then begin
  524. // Unable to get ICU version
  525. SysLogWrite(ANDROID_LOG_ERROR, 'cwstring: Unable to get ICU version.');
  526. UnloadICU;
  527. exit;
  528. end;
  529. end;
  530. if not GetIcuProc('ucnv_open', ucnv_open) then exit;
  531. if not GetIcuProc('ucnv_close', ucnv_close) then exit;
  532. if not GetIcuProc('ucnv_setSubstChars', ucnv_setSubstChars) then exit;
  533. if not GetIcuProc('ucnv_setFallback', ucnv_setFallback) then exit;
  534. if not GetIcuProc('ucnv_fromUChars', ucnv_fromUChars) then exit;
  535. if not GetIcuProc('ucnv_toUChars', ucnv_toUChars) then exit;
  536. if not GetIcuProc('u_strToUpper', u_strToUpper) then exit;
  537. if not GetIcuProc('u_strToLower', u_strToLower) then exit;
  538. if not GetIcuProc('u_strCompare', u_strCompare) then exit;
  539. if not GetIcuProc('u_strCaseCompare', u_strCaseCompare) then exit;
  540. if not GetIcuProc('u_getDataDirectory', u_getDataDirectory) then exit;
  541. if not GetIcuProc('u_setDataDirectory', u_setDataDirectory) then exit;
  542. if not GetIcuProc('u_init', u_init) then exit;
  543. if not GetIcuProc('ucol_open', ucol_open, 1) then exit;
  544. if not GetIcuProc('ucol_close', ucol_close, 1) then exit;
  545. if not GetIcuProc('ucol_strcoll', ucol_strcoll, 1) then exit;
  546. if not GetIcuProc('ucol_setStrength', ucol_setStrength, 1) then exit;
  547. // Checking if ICU data dir is set
  548. dir:=u_getDataDirectory();
  549. if (dir = nil) or (dir^ = #0) then
  550. u_setDataDirectory('/system/usr/icu');
  551. err:=0;
  552. u_init(err);
  553. Result:=True;
  554. end;
  555. var
  556. oldm: TUnicodeStringManager;
  557. {$ifdef android}
  558. SysGetIcuProc: pointer; external name 'ANDROID_GET_ICU_PROC';
  559. {$endif android}
  560. initialization
  561. GetUnicodeStringManager(oldm);
  562. DefaultSystemCodePage:=GetStandardCodePage(scpAnsi);
  563. DefaultUnicodeCodePage:=CP_UTF16;
  564. if LoadICU then begin
  565. SetCWideStringManager;
  566. {$ifdef android}
  567. SysGetIcuProc:=@GetIcuProc;
  568. SetStdIOCodePages;
  569. {$endif android}
  570. end
  571. else
  572. SysLogWrite(ANDROID_LOG_ERROR, 'cwstring: Failed to load ICU.');
  573. finalization
  574. SetUnicodeStringManager(oldm);
  575. UnloadICU;
  576. end.