iosxwstr.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2015 by Jonas Maebe,
  4. member of the Free Pascal development team.
  5. CoreFoundation-based wide string support
  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. {$implicitexceptions off}
  14. {$IFNDEF FPC_DOTTEDUNITS}
  15. unit iosxwstr;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. interface
  18. {$linkframework CoreFoundation}
  19. procedure SetCFWidestringManager;
  20. implementation
  21. {$IFDEF FPC_DOTTEDUNITS}
  22. uses
  23. UnixApi.CP,
  24. { for access to libiconv-based routines }
  25. UnixApi.CWString,
  26. MacOsApi.MacTypes,
  27. MacOsApi.CFBase,MacOsApi.CFString,MacOsApi.CFStringEncodingExt,MacOsApi.CFLocale;
  28. {$ELSE FPC_DOTTEDUNITS}
  29. uses
  30. unixcp,
  31. { for access to libiconv-based routines }
  32. cwstring,
  33. MacTypes,
  34. CFBase,CFString,CFStringEncodingExt,CFLocale;
  35. {$ENDIF FPC_DOTTEDUNITS}
  36. procedure fpc_rangeerror; [external name 'FPC_RANGEERROR'];
  37. var
  38. CWStringWideStringManager: TUnicodeStringManager;
  39. procedure InitThread;
  40. begin
  41. { we don't need anything special, but since we may use cwstring itself,
  42. call through to it }
  43. CWStringWideStringManager.ThreadInitProc;
  44. end;
  45. procedure FiniThread;
  46. begin
  47. { we don't need anything special, but since we may use cwstring itself,
  48. call through to it }
  49. CWStringWideStringManager.ThreadFiniProc;
  50. end;
  51. function get_cfencoding_for_cp(cp: TSystemCodePage): CFStringEncoding;
  52. var
  53. defscp: TSystemCodePage;
  54. begin
  55. { translate placeholder code pages }
  56. if (cp=CP_ACP) or
  57. (cp=CP_OEMCP) then
  58. cp:=DefaultSystemCodePage;
  59. result:=CFStringConvertWindowsCodepageToEncoding(cp);
  60. end;
  61. procedure GetAnsiDataFromCFString(str: CFstringRef; cfcp: CFStringEncoding; estimated_length: SizeInt; var dest: RawByteString);
  62. var
  63. range: CFRange;
  64. encodedlen,convertedchars: CFIndex;
  65. strlen: SizeInt;
  66. begin
  67. { first rough estimate for the length }
  68. setlength(dest,estimated_length);
  69. { try to convert }
  70. range.location:=0;
  71. strlen:=CFStringGetLength(str);
  72. range.length:=strlen;
  73. convertedchars:=CFStringGetBytes(str,range,cfcp,ByteParameter('?'),false,UInt8Ptr(dest),estimated_length,encodedlen);
  74. { failed -> bail out }
  75. if convertedchars<0 then
  76. begin
  77. CFRelease(str);
  78. runerror(231);
  79. end
  80. { if partially succesful, recreate with the required len }
  81. else if convertedchars<strlen then
  82. begin
  83. setlength(dest,encodedlen);
  84. { try again }
  85. convertedchars:=CFStringGetBytes(str,range,cfcp,ByteParameter('?'),false,UInt8Ptr(dest),encodedlen,encodedlen);
  86. { failed again ? }
  87. if convertedchars<>strlen then
  88. begin
  89. CFRelease(str);
  90. runerror(231);
  91. end;
  92. end;
  93. { truncate }
  94. setlength(dest,encodedlen);
  95. end;
  96. function CFStringCreateFromAnsiData(data: PAnsiChar; len: SizeInt; cp: TSystemCodePage): CFStringRef;
  97. var
  98. strlen,encodedlen: CFIndex;
  99. range: CFRange;
  100. cfcp: CFStringEncoding;
  101. begin
  102. result:=nil;
  103. { get source cf codepage }
  104. cfcp:=get_cfencoding_for_cp(cp);
  105. { unsupported encoding -> try libiconv instead }
  106. if cfcp=kCFStringEncodingInvalidId then
  107. exit;
  108. { make a cfstring from the original data }
  109. result:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(data),len,cfcp,false,kCFAllocatorNull);
  110. end;
  111. function CFStringCreateFromAnsiDataOptionallyViaUnicodeString(data: PAnsiChar; len: SizeInt; cp: TSystemCodePage; out wtemp: UnicodeString): CFStringRef;
  112. begin
  113. result:=CFStringCreateFromAnsiData(data,len,cp);
  114. { failed -> translate via libiconv and then create using the unicodestring
  115. characters; since we use the no-copy constructor for performance
  116. reasons, the unicodestring has to survive this routine }
  117. if not assigned(result) then
  118. begin
  119. CWStringWideStringManager.Ansi2UnicodeMoveProc(data,cp,wtemp,len);
  120. result:=CFStringCreateWithCharactersNoCopy(nil,UniCharPtr(wtemp),len,kCFAllocatorNull);
  121. end;
  122. end;
  123. function CFStringCreateFromWideData(data: pwidechar; len: SizeInt): CFStringRef; inline;
  124. begin
  125. { make a cfstring from the utf-16 data }
  126. result:=CFStringCreateWithCharactersNoCopy(nil,UniCharPtr(data),len,kCFAllocatorNull);
  127. end;
  128. function CFStringCreateFromWideDataOptionallyViaUUTF8String(data: pwidechar; len: SizeInt; out temp: RawByteString): CFStringRef;
  129. begin
  130. result:=CFStringCreateFromWideData(data,len);
  131. { failed -> translate to UTF-8 via libiconv to filter out any
  132. potentially invalid characters and then create using the unicodestring
  133. characters; since we use the no-copy constructor for performance
  134. reasons, the unicodestring has to survive this routine }
  135. if not assigned(result) then
  136. begin
  137. CWStringWideStringManager.Unicode2AnsiMoveProc(data,temp,CP_UTF8,len);
  138. result:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(temp),length(temp),kCFStringEncodingUTF8,false,kCFAllocatorNull);
  139. if not assigned(result) then
  140. runerror(231)
  141. end;
  142. end;
  143. procedure Wide2AnsiMove(source:pwidechar; var dest:RawByteString; cp:TSystemCodePage; len:SizeInt);
  144. var
  145. str: CFStringRef;
  146. strlen,estimatedlen: CFIndex;
  147. cfcp: CFStringEncoding;
  148. begin
  149. str:=nil;
  150. { get target cf codepage }
  151. cfcp:=get_cfencoding_for_cp(cp);
  152. { unsupported encoding -> default move }
  153. if cfcp<>kCFStringEncodingInvalidId then
  154. { make a cfstring from the utf-16 data }
  155. str:=CFStringCreateFromWideData(source,len);
  156. { You cannot create a CFString for a sequence that contains an error :/
  157. We want to replace the error positions with '?' -> fall back to libiconv
  158. }
  159. if not assigned(str) then
  160. begin
  161. CWStringWideStringManager.Unicode2AnsiMoveProc(source,dest,cp,len);
  162. exit;
  163. end;
  164. GetAnsiDataFromCFString(str,cfcp,len*3,dest);
  165. { set code page }
  166. SetCodePage(dest,cp,false);
  167. { release cfstring }
  168. CFRelease(str);
  169. end;
  170. procedure Ansi2WideMove(source:PAnsiChar; cp:TSystemCodePage; var dest:widestring; len:SizeInt);
  171. var
  172. str: CFStringRef;
  173. strlen,encodedlen: CFIndex;
  174. range: CFRange;
  175. cfcp: CFStringEncoding;
  176. begin
  177. str:=CFStringCreateFromAnsiData(source,len,cp);
  178. { You cannot create a CFString for a sequence that contains an error :/
  179. We want to replace the error positions with '?' -> fall back to libiconv
  180. }
  181. if not assigned(str) then
  182. begin
  183. CWStringWideStringManager.Ansi2UnicodeMoveProc(source,cp,dest,len);
  184. exit;
  185. end;
  186. { convert }
  187. range.location:=0;
  188. strlen:=CFStringGetLength(str);
  189. range.length:=strlen;
  190. setlength(dest,strlen);
  191. CFStringGetCharacters(str,range,UniCharPtr(dest));
  192. { release cfstring }
  193. CFRelease(str);
  194. end;
  195. function LowerWideString(const s : WideString) : WideString;
  196. var
  197. str: CFStringRef;
  198. mstr: CFMutableStringRef;
  199. range: CFRange;
  200. encodedlen: CFIndex;
  201. locale: CFLocaleRef;
  202. temp: RawByteString;
  203. begin
  204. { empty string -> exit }
  205. if s='' then
  206. begin
  207. result:='';
  208. exit;
  209. end;
  210. { create cfstring from the string data }
  211. str:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s),length(s),temp);
  212. { convert to mutable cfstring }
  213. mstr:=CFStringCreateMutableCopy(nil,0,str);
  214. { lowercase }
  215. locale:=CFLocaleCopyCurrent;
  216. CFStringLowercase(mstr,locale);
  217. CFRelease(locale);
  218. { extract the data again }
  219. range.location:=0;
  220. range.length:=CFStringGetLength(CFStringRef(mstr));
  221. setlength(result,range.length);
  222. CFStringGetCharacters(mstr,range,UniCharPtr(result));
  223. CFRelease(mstr);
  224. CFRelease(str);
  225. end;
  226. function UpperWideString(const s : WideString) : WideString;
  227. var
  228. str: CFStringRef;
  229. mstr: CFMutableStringRef;
  230. range: CFRange;
  231. encodedlen: CFIndex;
  232. locale: CFLocaleRef;
  233. temp: RawByteString;
  234. begin
  235. { empty string -> exit }
  236. if s='' then
  237. begin
  238. result:='';
  239. exit;
  240. end;
  241. { create cfstring from the string data }
  242. str:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s),length(s),temp);
  243. { convert to mutable cfstring }
  244. mstr:=CFStringCreateMutableCopy(nil,0,str);
  245. { lowercase }
  246. locale:=CFLocaleCopyCurrent;
  247. CFStringUppercase(mstr,locale);
  248. CFRelease(locale);
  249. { extract the data again }
  250. range.location:=0;
  251. range.length:=CFStringGetLength(CFStringRef(mstr));
  252. setlength(result,range.length);
  253. CFStringGetCharacters(mstr,range,UniCharPtr(result));
  254. CFRelease(mstr);
  255. CFRelease(str);
  256. end;
  257. function UpperLowerAnsiString(const s: AnsiString; upper: boolean): AnsiString;
  258. var
  259. str: CFStringRef;
  260. mstr: CFMutableStringRef;
  261. cfcp: CFStringEncoding;
  262. locale: CFLocaleRef;
  263. wtemp: UnicodeString;
  264. range: CFRange;
  265. begin
  266. if s='' then
  267. begin
  268. result:='';
  269. exit
  270. end;
  271. str:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(PAnsiChar(s),length(s),StringCodePage(s),wtemp);
  272. { unsupported encoding for either CF or iconv -> return original string }
  273. if not assigned(str) then
  274. begin
  275. result:=s;
  276. exit;
  277. end;
  278. { convert to mutable cfstring }
  279. mstr:=CFStringCreateMutableCopy(nil,0,str);
  280. CFRelease(str);
  281. { upper/lowercase }
  282. locale:=CFLocaleCopyCurrent;
  283. if upper then
  284. CFStringUppercase(mstr,locale)
  285. else
  286. CFStringLowercase(mstr,locale);
  287. CFRelease(locale);
  288. { convert back to ansistring }
  289. cfcp:=get_cfencoding_for_cp(StringCodePage(s));
  290. if cfcp<>kCFStringEncodingInvalidId then
  291. begin
  292. GetAnsiDataFromCFString(CFStringRef(mstr),cfcp,length(s),RawByteString(result));
  293. SetCodePage(RawByteString(result),StringCodePage(s),false);
  294. end
  295. else
  296. begin
  297. { unsupported encoding -> use libiconv instead via UTF-16
  298. intermediate }
  299. range.location:=0;
  300. range.length:=CFStringGetLength(mstr);
  301. SetLength(wtemp,range.length);
  302. CFStringGetCharacters(mstr,range,UniCharPtr(wtemp));
  303. CWStringWideStringManager.Wide2AnsiMoveProc(pwidechar(wtemp),RawByteString(result),StringCodePage(s),range.length);
  304. end;
  305. CFRelease(mstr);
  306. end;
  307. function LowerAnsiString(const s: AnsiString): AnsiString;
  308. begin
  309. result:=UpperLowerAnsiString(s,false);
  310. end;
  311. function UpperAnsiString(const s: AnsiString): AnsiString;
  312. begin
  313. result:=UpperLowerAnsiString(s,true);
  314. end;
  315. function CompareCFStrings(const s1, s2: CFStringRef; case_insensitive: boolean): longint;
  316. var
  317. flags: CFStringCompareFlags;
  318. begin
  319. flags:=kCFCompareNonliteral;
  320. if case_insensitive then
  321. flags:=flags or kCFCompareCaseInsensitive;
  322. result:=CFStringCompare(s1,s2,flags)
  323. end;
  324. function CompareWideString(const s1, s2 : WideString; Options : TCompareOptions) : PtrInt;
  325. var
  326. cfstr1, cfstr2: CFStringRef;
  327. temp1, temp2: RawByteString;
  328. begin
  329. cfstr1:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s1),length(s1),temp1);
  330. cfstr2:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s2),length(s2),temp2);
  331. result:=CompareCFStrings(cfstr1,cfstr2,coIgnoreCase in Options);
  332. CFRelease(cfstr1);
  333. CFRelease(cfstr2);
  334. end;
  335. function InternalCodePointLength(const Str: PAnsiChar; cfcp: CFStringEncoding; maxlookahead: ptrint): PtrInt;
  336. var
  337. cfstr: CFStringRef;
  338. begin
  339. result:=0;
  340. { try creating a string with the first 1, 2, ... bytes until we find a
  341. valid one }
  342. while (str[result]<>#0) and
  343. (result<maxlookahead) do
  344. begin
  345. inc(result);
  346. cfstr:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(Str),result,cfcp,false,kCFAllocatorNull);
  347. if assigned(cfstr) then
  348. begin
  349. CFRelease(cfstr);
  350. exit;
  351. end;
  352. end;
  353. result:=-1;
  354. end;
  355. function CharLengthPChar(const Str: PAnsiChar): PtrInt;
  356. var
  357. cfstr: CFStringRef;
  358. cfcp: CFStringEncoding;
  359. s: PAnsiChar;
  360. tmplen: PtrInt;
  361. begin
  362. result:=0;
  363. if str[0]=#0 then
  364. exit;
  365. cfcp:=get_cfencoding_for_cp(DefaultSystemCodePage);
  366. if cfcp=kCFStringEncodingInvalidId then
  367. begin
  368. { or -1? }
  369. result:=strlen(Str);
  370. exit
  371. end;
  372. s:=str;
  373. repeat
  374. tmplen:=InternalCodePointLength(s,cfcp,8);
  375. { invalid -> skip }
  376. if tmplen=-1 then
  377. tmplen:=1;
  378. inc(s,tmplen);
  379. inc(result);
  380. until s[0]=#0;
  381. end;
  382. function CodePointLength(const Str: PAnsiChar; maxlookahead: ptrint): PtrInt;
  383. var
  384. cfstr: CFStringRef;
  385. cfcp: CFStringEncoding;
  386. begin
  387. result:=0;
  388. if str[0]=#0 then
  389. exit;
  390. cfcp:=get_cfencoding_for_cp(DefaultSystemCodePage);
  391. if cfcp=kCFStringEncodingInvalidId then
  392. begin
  393. { if we would return -1, then the caller would keep trying with
  394. longer and longer sequences, but that wouldn't change anything }
  395. result:=1;
  396. exit
  397. end;
  398. result:=InternalCodePointLength(str,cfcp,maxlookahead);
  399. end;
  400. function CompareStrAnsiString(const s1, s2: ansistring): PtrInt;
  401. var
  402. cfstr1, cfstr2: CFStringRef;
  403. wtemp1, wtemp2: UnicodeString;
  404. begin
  405. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(PAnsiChar(s1),length(s1),StringCodePage(s1),wtemp1);
  406. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(PAnsiChar(s2),length(s2),StringCodePage(s2),wtemp2);
  407. result:=CompareCFStrings(cfstr1,cfstr2,false);
  408. CFRelease(cfstr1);
  409. CFRelease(cfstr2);
  410. end;
  411. function StrCompAnsi(s1,s2 : PAnsiChar): PtrInt;
  412. var
  413. cfstr1, cfstr2: CFStringRef;
  414. wtemp1, wtemp2: UnicodeString;
  415. begin
  416. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,strlen(s1),DefaultSystemCodePage,wtemp1);
  417. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,strlen(s2),DefaultSystemCodePage,wtemp2);
  418. result:=CompareCFStrings(cfstr1,cfstr2,false);
  419. CFRelease(cfstr1);
  420. CFRelease(cfstr2);
  421. end;
  422. function AnsiCompareText(const S1, S2: ansistring): PtrInt;
  423. var
  424. cfstr1, cfstr2: CFStringRef;
  425. wtemp1, wtemp2: UnicodeString;
  426. begin
  427. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(PAnsiChar(s1),length(s1),DefaultSystemCodePage,wtemp1);
  428. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(PAnsiChar(s2),length(s2),DefaultSystemCodePage,wtemp2);
  429. result:=CompareCFStrings(cfstr1,cfstr2,true);
  430. CFRelease(cfstr1);
  431. CFRelease(cfstr2);
  432. end;
  433. function AnsiStrIComp(S1, S2: PAnsiChar): PtrInt;
  434. var
  435. cfstr1, cfstr2: CFStringRef;
  436. wtemp1, wtemp2: UnicodeString;
  437. begin
  438. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,strlen(s1),DefaultSystemCodePage,wtemp1);
  439. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,strlen(s2),DefaultSystemCodePage,wtemp2);
  440. result:=CompareCFStrings(cfstr1,cfstr2,true);
  441. CFRelease(cfstr1);
  442. CFRelease(cfstr2);
  443. end;
  444. function AnsiStrLComp(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  445. var
  446. cfstr1, cfstr2: CFStringRef;
  447. wtemp1, wtemp2: UnicodeString;
  448. begin
  449. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,MaxLen,StringCodePage(s1),wtemp1);
  450. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,MaxLen,StringCodePage(s2),wtemp2);
  451. result:=CompareCFStrings(cfstr1,cfstr2,false);
  452. CFRelease(cfstr1);
  453. CFRelease(cfstr2);
  454. end;
  455. function AnsiStrLIComp(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  456. var
  457. cfstr1, cfstr2: CFStringRef;
  458. wtemp1, wtemp2: UnicodeString;
  459. begin
  460. cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,MaxLen,StringCodePage(s1),wtemp1);
  461. cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,MaxLen,StringCodePage(s2),wtemp2);
  462. result:=CompareCFStrings(cfstr1,cfstr2,true);
  463. CFRelease(cfstr1);
  464. CFRelease(cfstr2);
  465. end;
  466. procedure ansi2pchar(const s: ansistring; const orgp: PAnsiChar; out p: PAnsiChar);
  467. var
  468. newlen: sizeint;
  469. begin
  470. newlen:=length(s);
  471. if newlen>strlen(orgp) then
  472. fpc_rangeerror;
  473. p:=orgp;
  474. if (newlen>0) then
  475. move(s[1],p[0],newlen);
  476. p[newlen]:=#0;
  477. end;
  478. function AnsiStrLower(Str: PAnsiChar): PAnsiChar;
  479. var
  480. temp: ansistring;
  481. begin
  482. temp:=loweransistring(str);
  483. ansi2pchar(temp,str,result);
  484. end;
  485. function AnsiStrUpper(Str: PAnsiChar): PAnsiChar;
  486. var
  487. temp: ansistring;
  488. begin
  489. temp:=upperansistring(str);
  490. ansi2pchar(temp,str,result);
  491. end;
  492. function GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage;
  493. var
  494. langinfo: PAnsiChar;
  495. begin
  496. { don't use CFStringGetSystemEncoding, that one returns MacRoman on e.g.
  497. an English system, which is definitely not what we want. Since there are
  498. no "ansi" interfaces on OS X and all APIs support all characters, always
  499. use UTF-8. Additionally,  Darwin always uses UTF-8 for file system
  500. operations }
  501. result:=CP_UTF8;
  502. end;
  503. procedure SetStdIOCodePage(var T: Text); inline;
  504. begin
  505. case TextRec(T).Mode of
  506. fmInput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleInput);
  507. fmOutput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleOutput);
  508. end;
  509. end;
  510. procedure SetStdIOCodePages; inline;
  511. begin
  512. SetStdIOCodePage(Input);
  513. SetStdIOCodePage(Output);
  514. SetStdIOCodePage(ErrOutput);
  515. SetStdIOCodePage(StdOut);
  516. SetStdIOCodePage(StdErr);
  517. end;
  518. procedure SetCFWideStringManager;
  519. var
  520. CFWideStringManager : TUnicodeStringManager;
  521. begin
  522. GetUnicodeStringManager(CWStringWideStringManager);
  523. CFWideStringManager:=CWStringWideStringManager;
  524. with CFWideStringManager do
  525. begin
  526. Wide2AnsiMoveProc:=@Wide2AnsiMove;
  527. Ansi2WideMoveProc:=@Ansi2WideMove;
  528. UpperWideStringProc:=@UpperWideString;
  529. LowerWideStringProc:=@LowerWideString;
  530. CompareWideStringProc:=@CompareWideString;
  531. CharLengthPCharProc:=@CharLengthPChar;
  532. CodePointLengthProc:=@CodePointLength;
  533. UpperAnsiStringProc:=@UpperAnsiString;
  534. LowerAnsiStringProc:=@LowerAnsiString;
  535. CompareStrAnsiStringProc:=@CompareStrAnsiString;
  536. CompareTextAnsiStringProc:=@AnsiCompareText;
  537. StrCompAnsiStringProc:=@StrCompAnsi;
  538. StrICompAnsiStringProc:=@AnsiStrIComp;
  539. StrLCompAnsiStringProc:=@AnsiStrLComp;
  540. StrLICompAnsiStringProc:=@AnsiStrLIComp;
  541. StrLowerAnsiStringProc:=@AnsiStrLower;
  542. StrUpperAnsiStringProc:=@AnsiStrUpper;
  543. ThreadInitProc:=@InitThread;
  544. ThreadFiniProc:=@FiniThread;
  545. { Unicode }
  546. Unicode2AnsiMoveProc:=@Wide2AnsiMove;
  547. Ansi2UnicodeMoveProc:=@Ansi2WideMove;
  548. UpperUnicodeStringProc:=@UpperWideString;
  549. LowerUnicodeStringProc:=@LowerWideString;
  550. CompareUnicodeStringProc:=@CompareWideString;
  551. { CodePage }
  552. GetStandardCodePageProc:=@GetStandardCodePage;
  553. end;
  554. SetUnicodeStringManager(CFWideStringManager);
  555. end;
  556. initialization
  557. SetCFWideStringManager;
  558. { set the DefaultSystemCodePage }
  559. DefaultSystemCodePage:=GetStandardCodePage(scpAnsi);
  560. DefaultFileSystemCodePage:=GetStandardCodePage(scpFileSystemSingleByte);
  561. DefaultRTLFileSystemCodePage:=DefaultFileSystemCodePage;
  562. SetStdIOCodePages;
  563. { don't call init, we don't need to do anything and the cwstring routine we
  564. call through has already been called from the init code of cwstring itself
  565. InitThread;
  566. }
  567. finalization
  568. { don't call for the same reason as not calling FiniThread
  569. FiniThread;
  570. }
  571. { restore previous widestring manager so that subsequent calls
  572. into the widestring manager won't trigger the finalized functionality }
  573. SetWideStringManager(CWStringWideStringManager);
  574. end.