cwstring.pp 17 KB

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