wstrings.inc 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2005 by Florian Klaempfl,
  4. member of the Free Pascal development team.
  5. This file implements support routines for WideStrings/Unicode with FPC
  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. {
  13. This file contains the implementation of the WideString type,
  14. and all things that are needed for it.
  15. WideString is defined as a 'silent' pwidechar :
  16. a pwidechar that points to :
  17. @-8 : SizeInt for reference count;
  18. @-4 : SizeInt for size; size=number of bytes, not the number of chars. Divide or multiply
  19. with sizeof(WideChar) to convert. This is needed to be compatible with Delphi and
  20. Windows COM BSTR.
  21. @ : String + Terminating #0;
  22. Pwidechar(Widestring) is a valid typecast.
  23. So WS[i] is converted to the address @WS+i-1.
  24. Constants should be assigned a reference count of -1
  25. Meaning that they can't be disposed of.
  26. }
  27. Type
  28. PWideRec = ^TWideRec;
  29. TWideRec = Packed Record
  30. {$ifdef FPC_WINLIKEWIDESTRING}
  31. Len : DWord;
  32. {$else FPC_WINLIKEWIDESTRING}
  33. Ref : SizeInt;
  34. Len : SizeInt;
  35. {$endif FPC_WINLIKEWIDESTRING}
  36. First : WideChar;
  37. end;
  38. Const
  39. WideRecLen = SizeOf(TWideRec);
  40. WideFirstOff = SizeOf(TWideRec)-sizeof(WideChar);
  41. {
  42. Default WideChar <-> Char conversion is to only convert the
  43. lower 127 chars, all others are translated to spaces.
  44. These routines can be overwritten for the Current Locale
  45. }
  46. procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  47. var
  48. i : SizeInt;
  49. begin
  50. setlength(dest,len);
  51. for i:=1 to len do
  52. begin
  53. if word(source^)<256 then
  54. dest[i]:=char(word(source^))
  55. else
  56. dest[i]:='?';
  57. inc(source);
  58. end;
  59. end;
  60. procedure DefaultAnsi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  61. var
  62. i : SizeInt;
  63. begin
  64. setlength(dest,len);
  65. for i:=1 to len do
  66. begin
  67. dest[i]:=widechar(byte(source^));
  68. inc(source);
  69. end;
  70. end;
  71. Procedure GetWideStringManager (Var Manager : TWideStringManager);
  72. begin
  73. manager:=widestringmanager;
  74. end;
  75. Procedure SetWideStringManager (Const New : TWideStringManager; Var Old: TWideStringManager);
  76. begin
  77. Old:=widestringmanager;
  78. widestringmanager:=New;
  79. end;
  80. Procedure SetWideStringManager (Const New : TWideStringManager);
  81. begin
  82. widestringmanager:=New;
  83. end;
  84. (*
  85. Procedure UniqueWideString(Var S : WideString); [Public,Alias : 'FPC_WIDESTR_UNIQUE'];
  86. {
  87. Make sure reference count of S is 1,
  88. using copy-on-write semantics.
  89. }
  90. begin
  91. end;
  92. *)
  93. {****************************************************************************
  94. Internal functions, not in interface.
  95. ****************************************************************************}
  96. procedure WideStringError;
  97. begin
  98. HandleErrorFrame(204,get_frame);
  99. end;
  100. {$ifdef WideStrDebug}
  101. Procedure DumpWideRec(S : Pointer);
  102. begin
  103. If S=Nil then
  104. Writeln ('String is nil')
  105. Else
  106. Begin
  107. With PWideRec(S-WideFirstOff)^ do
  108. begin
  109. Write ('(Len:',len);
  110. Writeln (' Ref: ',ref,')');
  111. end;
  112. end;
  113. end;
  114. {$endif}
  115. Function NewWideString(Len : SizeInt) : Pointer;
  116. {
  117. Allocate a new WideString on the heap.
  118. initialize it to zero length and reference count 1.
  119. }
  120. Var
  121. P : Pointer;
  122. begin
  123. {$ifdef MSWINDOWS}
  124. if winwidestringalloc then
  125. P:=SysAllocStringLen(nil,Len)
  126. else
  127. {$endif MSWINDOWS}
  128. begin
  129. GetMem(P,Len*sizeof(WideChar)+WideRecLen);
  130. If P<>Nil then
  131. begin
  132. PWideRec(P)^.Len:=Len*2; { Initial length }
  133. {$ifndef FPC_WINLIKEWIDESTRING}
  134. PWideRec(P)^.Ref:=1; { Initial Refcount }
  135. {$endif FPC_WINLIKEWIDESTRING}
  136. PWideRec(P)^.First:=#0; { Terminating #0 }
  137. inc(p,WideFirstOff); { Points to string now }
  138. end
  139. else
  140. WideStringError;
  141. end;
  142. NewWideString:=P;
  143. end;
  144. Procedure DisposeWideString(Var S : Pointer);
  145. {
  146. Deallocates a WideString From the heap.
  147. }
  148. begin
  149. If S=Nil then
  150. exit;
  151. {$ifndef MSWINDOWS}
  152. Dec (S,WideFirstOff);
  153. {$else MSWINDOWS}
  154. if winwidestringalloc then
  155. SysFreeString(S)
  156. else
  157. {$endif MSWINDOWS}
  158. FreeMem (S);
  159. S:=Nil;
  160. end;
  161. Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF']; compilerproc;
  162. {
  163. Decreases the ReferenceCount of a non constant widestring;
  164. If the reference count is zero, deallocate the string;
  165. }
  166. Type
  167. pSizeInt = ^SizeInt;
  168. {$ifndef FPC_WINLIKEWIDESTRING}
  169. Var
  170. l : pSizeInt;
  171. {$endif FPC_WINLIKEWIDESTRING}
  172. Begin
  173. { Zero string }
  174. if S=Nil then
  175. exit;
  176. {$ifndef FPC_WINLIKEWIDESTRING}
  177. { check for constant strings ...}
  178. l:=@PWideRec(S-WideFirstOff)^.Ref;
  179. if l^<0 then
  180. exit;
  181. { declocked does a MT safe dec and returns true, if the counter is 0 }
  182. if declocked(l^) then
  183. { Ref count dropped to zero ...
  184. ... remove }
  185. {$endif FPC_WINLIKEWIDESTRING}
  186. DisposeWideString(S);
  187. end;
  188. { alias for internal use }
  189. Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_DECR_REF'];
  190. Procedure fpc_WideStr_Incr_Ref(Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF']; compilerproc;
  191. {$ifdef FPC_WINLIKEWIDESTRING}
  192. var
  193. p : pointer;
  194. {$endif FPC_WINLIKEWIDESTRING}
  195. Begin
  196. If S=Nil then
  197. exit;
  198. {$ifdef FPC_WINLIKEWIDESTRING}
  199. p:=s;
  200. fpc_WideStr_SetLength(WideString(s),length(WideString(p)));
  201. move(p^,s^,length(WideString(p))*sizeof(widechar));
  202. {$else FPC_WINLIKEWIDESTRING}
  203. { Let's be paranoid : Constant string ??}
  204. If PWideRec(S-WideFirstOff)^.Ref<0 then exit;
  205. inclocked(PWideRec(S-WideFirstOff)^.Ref);
  206. {$endif FPC_WINLIKEWIDESTRING}
  207. end;
  208. { alias for internal use }
  209. Procedure fpc_WideStr_Incr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_INCR_REF'];
  210. function fpc_WideStr_To_ShortStr (high_of_res: SizeInt;const S2 : WideString): shortstring;[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR']; compilerproc;
  211. {
  212. Converts a WideString to a ShortString;
  213. }
  214. Var
  215. Size : SizeInt;
  216. temp : ansistring;
  217. begin
  218. result:='';
  219. Size:=Length(S2);
  220. if Size>0 then
  221. begin
  222. If Size>high_of_res then
  223. Size:=high_of_res;
  224. widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size);
  225. result:=temp;
  226. end;
  227. end;
  228. Function fpc_ShortStr_To_WideStr (Const S2 : ShortString): WideString;compilerproc;
  229. {
  230. Converts a ShortString to a WideString;
  231. }
  232. Var
  233. Size : SizeInt;
  234. begin
  235. result:='';
  236. Size:=Length(S2);
  237. if Size>0 then
  238. begin
  239. widestringmanager.Ansi2WideMoveProc(PChar(@S2[1]),result,Size);
  240. { Terminating Zero }
  241. PWideChar(Pointer(fpc_ShortStr_To_WideStr)+Size*sizeof(WideChar))^:=#0;
  242. end;
  243. end;
  244. Function fpc_WideStr_To_AnsiStr (const S2 : WideString): AnsiString; compilerproc;
  245. {
  246. Converts a WideString to an AnsiString
  247. }
  248. Var
  249. Size : SizeInt;
  250. begin
  251. result:='';
  252. Size:=Length(S2);
  253. if Size>0 then
  254. widestringmanager.Wide2AnsiMoveProc(PWideChar(Pointer(S2)),result,Size);
  255. end;
  256. Function fpc_AnsiStr_To_WideStr (Const S2 : AnsiString): WideString; compilerproc;
  257. {
  258. Converts an AnsiString to a WideString;
  259. }
  260. Var
  261. Size : SizeInt;
  262. begin
  263. result:='';
  264. Size:=Length(S2);
  265. if Size>0 then
  266. widestringmanager.Ansi2WideMoveProc(PChar(S2),result,Size);
  267. end;
  268. Function fpc_PWideChar_To_AnsiStr(const p : pwidechar): ansistring; compilerproc;
  269. var
  270. Size : SizeInt;
  271. begin
  272. result:='';
  273. if p=nil then
  274. exit;
  275. Size := IndexWord(p^, -1, 0);
  276. if Size>0 then
  277. widestringmanager.Wide2AnsiMoveProc(P,result,Size);
  278. end;
  279. Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc;
  280. var
  281. Size : SizeInt;
  282. begin
  283. result:='';
  284. if p=nil then
  285. exit;
  286. Size := IndexWord(p^, -1, 0);
  287. Setlength(result,Size);
  288. if Size>0 then
  289. begin
  290. Move(p^,PWideChar(Pointer(result))^,Size*sizeof(WideChar));
  291. { Terminating Zero }
  292. PWideChar(Pointer(result)+Size*sizeof(WideChar))^:=#0;
  293. end;
  294. end;
  295. Function fpc_PWideChar_To_ShortStr(const p : pwidechar): shortstring; compilerproc;
  296. var
  297. Size : SizeInt;
  298. temp: ansistring;
  299. begin
  300. result:='';
  301. if p=nil then
  302. exit;
  303. Size := IndexWord(p^, $7fffffff, 0);
  304. if Size>0 then
  305. begin
  306. widestringmanager.Wide2AnsiMoveProc(p,temp,Size);
  307. result:=temp;
  308. end;
  309. end;
  310. { checked against the ansistring routine, 2001-05-27 (FK) }
  311. Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN']; compilerproc;
  312. {
  313. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  314. }
  315. begin
  316. {$ifdef FPC_WINLIKEWIDESTRING}
  317. { Decrease the reference count on the old S1 }
  318. fpc_widestr_decr_ref (S1);
  319. S1:=NewWidestring(length(WideString(S2)));
  320. move(s2^,s1^,length(WideString(s1))*sizeof(widechar));
  321. {$else FPC_WINLIKEWIDESTRING}
  322. If S2<>nil then
  323. If PWideRec(S2-WideFirstOff)^.Ref>0 then
  324. inclocked(PWideRec(S2-WideFirstOff)^.ref);
  325. { Decrease the reference count on the old S1 }
  326. fpc_widestr_decr_ref (S1);
  327. s1:=s2;
  328. {$endif FPC_WINLIKEWIDESTRING}
  329. end;
  330. { alias for internal use }
  331. Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN'];
  332. {$ifndef STR_CONCAT_PROCS}
  333. function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc;
  334. Var
  335. Size,Location : SizeInt;
  336. pc : pwidechar;
  337. begin
  338. { only assign if s1 or s2 is empty }
  339. if (S1='') then
  340. begin
  341. result:=s2;
  342. exit;
  343. end;
  344. if (S2='') then
  345. begin
  346. result:=s1;
  347. exit;
  348. end;
  349. Location:=Length(S1);
  350. Size:=length(S2);
  351. SetLength(result,Size+Location);
  352. pc:=pwidechar(result);
  353. Move(S1[1],pc^,Location*sizeof(WideChar));
  354. inc(pc,location);
  355. Move(S2[1],pc^,(Size+1)*sizeof(WideChar));
  356. end;
  357. function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc;
  358. Var
  359. i : Longint;
  360. p : pointer;
  361. pc : pwidechar;
  362. Size,NewSize : SizeInt;
  363. begin
  364. { First calculate size of the result so we can do
  365. a single call to SetLength() }
  366. NewSize:=0;
  367. for i:=low(sarr) to high(sarr) do
  368. inc(Newsize,length(sarr[i]));
  369. SetLength(result,NewSize);
  370. pc:=pwidechar(result);
  371. for i:=low(sarr) to high(sarr) do
  372. begin
  373. p:=pointer(sarr[i]);
  374. if assigned(p) then
  375. begin
  376. Size:=length(widestring(p));
  377. Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar));
  378. inc(pc,size);
  379. end;
  380. end;
  381. end;
  382. {$else STR_CONCAT_PROCS}
  383. procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc;
  384. Var
  385. Size,Location : SizeInt;
  386. pc : pwidechar;
  387. begin
  388. { only assign if s1 or s2 is empty }
  389. if (S1='') then
  390. begin
  391. DestS:=s2;
  392. exit;
  393. end;
  394. if (S2='') then
  395. begin
  396. DestS:=s1;
  397. exit;
  398. end;
  399. Location:=Length(S1);
  400. Size:=length(S2);
  401. { Use Pointer() typecasts to prevent extra conversion code }
  402. if Pointer(DestS)=Pointer(S1) then
  403. begin
  404. SetLength(DestS,Size+Location);
  405. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  406. end
  407. else if Pointer(DestS)=Pointer(S2) then
  408. begin
  409. SetLength(DestS,Size+Location);
  410. Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  411. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  412. end
  413. else
  414. begin
  415. DestS:='';
  416. SetLength(DestS,Size+Location);
  417. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  418. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  419. end;
  420. end;
  421. procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc;
  422. Var
  423. lowstart,i : Longint;
  424. p,pc : pointer;
  425. Size,NewLen,
  426. OldDestLen : SizeInt;
  427. begin
  428. if high(sarr)=0 then
  429. begin
  430. DestS:='';
  431. exit;
  432. end;
  433. lowstart:=low(sarr);
  434. if Pointer(DestS)=Pointer(sarr[lowstart]) then
  435. begin
  436. inc(lowstart);
  437. { Check for another reuse, then we can't use
  438. the append optimization }
  439. for i:=lowstart to high(sarr) do
  440. begin
  441. if Pointer(DestS)=Pointer(sarr[i]) then
  442. begin
  443. lowstart:=low(sarr);
  444. break;
  445. end;
  446. end;
  447. end;
  448. { Start with empty DestS if we start with concatting
  449. the first array element }
  450. if lowstart=low(sarr) then
  451. DestS:='';
  452. OldDestLen:=length(DestS);
  453. { Calculate size of the result so we can do
  454. a single call to SetLength() }
  455. NewLen:=0;
  456. for i:=low(sarr) to high(sarr) do
  457. inc(NewLen,length(sarr[i]));
  458. SetLength(DestS,NewLen);
  459. { Concat all strings, except the string we already
  460. copied in DestS }
  461. pc:=Pointer(DestS)+OldDestLen*sizeof(WideChar);
  462. for i:=lowstart to high(sarr) do
  463. begin
  464. p:=pointer(sarr[i]);
  465. if assigned(p) then
  466. begin
  467. Size:=length(widestring(p));
  468. Move(p^,pc^,(Size+1)*sizeof(WideChar));
  469. inc(pc,size*sizeof(WideChar));
  470. end;
  471. end;
  472. end;
  473. {$endif STR_CONCAT_PROCS}
  474. Function fpc_Char_To_WideStr(const c : WideChar): WideString; compilerproc;
  475. {
  476. Converts a Char to a WideString;
  477. }
  478. begin
  479. if c = #0 then
  480. { result is automatically set to '' }
  481. exit;
  482. Setlength(fpc_Char_To_WideStr,1);
  483. fpc_Char_To_WideStr[1]:=c;
  484. { Terminating Zero }
  485. PWideChar(Pointer(fpc_Char_To_WideStr)+sizeof(WideChar))^:=#0;
  486. end;
  487. Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc;
  488. Var
  489. L : SizeInt;
  490. begin
  491. if (not assigned(p)) or (p[0]=#0) Then
  492. { result is automatically set to '' }
  493. exit;
  494. l:=IndexChar(p^,-1,#0);
  495. widestringmanager.Ansi2WideMoveProc(P,fpc_PChar_To_WideStr,l);
  496. end;
  497. Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc;
  498. var
  499. i : SizeInt;
  500. begin
  501. if (zerobased) then
  502. begin
  503. if (arr[0]=#0) Then
  504. { result is automatically set to '' }
  505. exit;
  506. i:=IndexChar(arr,high(arr)+1,#0);
  507. if i = -1 then
  508. i := high(arr)+1;
  509. end
  510. else
  511. i := high(arr)+1;
  512. SetLength(fpc_CharArray_To_WideStr,i);
  513. widestringmanager.Ansi2WideMoveProc (pchar(@arr),fpc_CharArray_To_WideStr,i);
  514. end;
  515. function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc;
  516. var
  517. l: longint;
  518. index: longint;
  519. len: byte;
  520. temp: ansistring;
  521. begin
  522. l := high(arr)+1;
  523. if l>=256 then
  524. l:=255
  525. else if l<0 then
  526. l:=0;
  527. if zerobased then
  528. begin
  529. index:=IndexWord(arr[0],l,0);
  530. if (index < 0) then
  531. len := l
  532. else
  533. len := index;
  534. end
  535. else
  536. len := l;
  537. widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len);
  538. fpc_WideCharArray_To_ShortStr := temp;
  539. end;
  540. Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc;
  541. var
  542. i : SizeInt;
  543. begin
  544. if (zerobased) then
  545. begin
  546. i:=IndexWord(arr,high(arr)+1,0);
  547. if i = -1 then
  548. i := high(arr)+1;
  549. end
  550. else
  551. i := high(arr)+1;
  552. SetLength(fpc_WideCharArray_To_AnsiStr,i);
  553. widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),fpc_WideCharArray_To_AnsiStr,i);
  554. end;
  555. Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc;
  556. var
  557. i : SizeInt;
  558. begin
  559. if (zerobased) then
  560. begin
  561. i:=IndexWord(arr,high(arr)+1,0);
  562. if i = -1 then
  563. i := high(arr)+1;
  564. end
  565. else
  566. i := high(arr)+1;
  567. SetLength(fpc_WideCharArray_To_WideStr,i);
  568. Move(pwidechar(@arr)^, PWideChar(Pointer(@fpc_WideCharArray_To_WideStr[1]))^,i*sizeof(WideChar));
  569. { Terminating Zero }
  570. PWideChar(Pointer(@fpc_WideCharArray_To_WideStr[1])+i*sizeof(WideChar))^:=#0;
  571. end;
  572. { inside the compiler, the resulttype is modified to that of the actual }
  573. { chararray we're converting to (JM) }
  574. function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc;
  575. var
  576. len: SizeInt;
  577. temp: ansistring;
  578. begin
  579. len := length(src);
  580. { make sure we don't dereference src if it can be nil (JM) }
  581. if len > 0 then
  582. widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len);
  583. len := length(temp);
  584. if len > arraysize then
  585. len := arraysize;
  586. move(temp[1],fpc_widestr_to_chararray[0],len);
  587. fillchar(fpc_widestr_to_chararray[len],arraysize-len,0);
  588. end;
  589. { inside the compiler, the resulttype is modified to that of the actual }
  590. { widechararray we're converting to (JM) }
  591. function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc;
  592. var
  593. len: SizeInt;
  594. begin
  595. len := length(src);
  596. if len > arraysize then
  597. len := arraysize;
  598. { make sure we don't try to access element 1 of the ansistring if it's nil }
  599. if len > 0 then
  600. move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar));
  601. fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  602. end;
  603. { inside the compiler, the resulttype is modified to that of the actual }
  604. { chararray we're converting to (JM) }
  605. function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc;
  606. var
  607. len: SizeInt;
  608. temp: widestring;
  609. begin
  610. len := length(src);
  611. { make sure we don't dereference src if it can be nil (JM) }
  612. if len > 0 then
  613. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  614. len := length(temp);
  615. if len > arraysize then
  616. len := arraysize;
  617. move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar));
  618. fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  619. end;
  620. function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc;
  621. var
  622. len: longint;
  623. temp : widestring;
  624. begin
  625. len := length(src);
  626. { make sure we don't access char 1 if length is 0 (JM) }
  627. if len > 0 then
  628. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  629. len := length(temp);
  630. if len > arraysize then
  631. len := arraysize;
  632. move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar));
  633. fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  634. end;
  635. Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc;
  636. {
  637. Compares 2 WideStrings;
  638. The result is
  639. <0 if S1<S2
  640. 0 if S1=S2
  641. >0 if S1>S2
  642. }
  643. Var
  644. MaxI,Temp : SizeInt;
  645. begin
  646. if pointer(S1)=pointer(S2) then
  647. begin
  648. fpc_WideStr_Compare:=0;
  649. exit;
  650. end;
  651. Maxi:=Length(S1);
  652. temp:=Length(S2);
  653. If MaxI>Temp then
  654. MaxI:=Temp;
  655. Temp:=CompareWord(S1[1],S2[1],MaxI);
  656. if temp=0 then
  657. temp:=Length(S1)-Length(S2);
  658. fpc_WideStr_Compare:=Temp;
  659. end;
  660. Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc;
  661. begin
  662. if p=nil then
  663. HandleErrorFrame(201,get_frame);
  664. end;
  665. Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc;
  666. begin
  667. if (index>len) or (Index<1) then
  668. HandleErrorFrame(201,get_frame);
  669. end;
  670. Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc;
  671. {
  672. Sets The length of string S to L.
  673. Makes sure S is unique, and contains enough room.
  674. }
  675. Var
  676. Temp : Pointer;
  677. movelen: SizeInt;
  678. begin
  679. if (l>0) then
  680. begin
  681. if Pointer(S)=nil then
  682. begin
  683. { Need a complete new string...}
  684. Pointer(s):=NewWideString(l);
  685. end
  686. { windows doesn't support reallocing widestrings, this code
  687. is anyways subject to be removed because widestrings shouldn't be
  688. ref. counted anymore (FK) }
  689. else
  690. {$ifndef FPC_WINLIKEWIDESTRING}
  691. if
  692. {$ifdef MSWINDOWS}
  693. not winwidestringalloc and
  694. {$endif MSWINDOWS}
  695. (PWideRec(Pointer(S)-WideFirstOff)^.Ref = 1) then
  696. begin
  697. Dec(Pointer(S),WideFirstOff);
  698. if L*sizeof(WideChar)+WideRecLen>MemSize(Pointer(S)) then
  699. reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen);
  700. Inc(Pointer(S), WideFirstOff);
  701. end
  702. else
  703. {$endif FPC_WINLIKEWIDESTRING}
  704. begin
  705. { Reallocation is needed... }
  706. Temp:=Pointer(NewWideString(L));
  707. if Length(S)>0 then
  708. begin
  709. if l < succ(length(s)) then
  710. movelen := l
  711. { also move terminating null }
  712. else
  713. movelen := succ(length(s));
  714. Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar));
  715. end;
  716. fpc_widestr_decr_ref(Pointer(S));
  717. Pointer(S):=Temp;
  718. end;
  719. { Force nil termination in case it gets shorter }
  720. PWord(Pointer(S)+l*sizeof(WideChar))^:=0;
  721. {$ifndef FPC_WINLIKEWIDESTRING}
  722. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar);
  723. {$endif FPC_WINLIKEWIDESTRING}
  724. end
  725. else
  726. begin
  727. { Length=0 }
  728. if Pointer(S)<>nil then
  729. fpc_widestr_decr_ref (Pointer(S));
  730. Pointer(S):=Nil;
  731. end;
  732. end;
  733. {*****************************************************************************
  734. Public functions, In interface.
  735. *****************************************************************************}
  736. function WideCharToString(S : PWideChar) : AnsiString;
  737. begin
  738. result:=WideCharLenToString(s,Length(WideString(s)));
  739. end;
  740. function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar;
  741. var
  742. temp:widestring;
  743. begin
  744. widestringmanager.Ansi2WideMoveProc(PChar(Src),temp,Length(Src));
  745. if Length(temp)<DestSize then
  746. move(temp[1],Dest^,Length(temp)*SizeOf(WideChar))
  747. else
  748. move(temp[1],Dest^,(DestSize-1)*SizeOf(WideChar));
  749. Dest[DestSize-1]:=#0;
  750. result:=Dest;
  751. end;
  752. function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString;
  753. begin
  754. //SetLength(result,Len);
  755. widestringmanager.Wide2AnsiMoveproc(S,result,Len);
  756. end;
  757. procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString);
  758. begin
  759. Dest:=WideCharLenToString(Src,Len);
  760. end;
  761. procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString);
  762. begin
  763. Dest:=WideCharToString(S);
  764. end;
  765. Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc;
  766. {$ifdef FPC_WINLIKEWIDESTRING}
  767. begin
  768. pointer(result) := pointer(s);
  769. end;
  770. {$else FPC_WINLIKEWIDESTRING}
  771. {
  772. Make sure reference count of S is 1,
  773. using copy-on-write semantics.
  774. }
  775. Var
  776. SNew : Pointer;
  777. L : SizeInt;
  778. begin
  779. pointer(result) := pointer(s);
  780. If Pointer(S)=Nil then
  781. exit;
  782. if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then
  783. begin
  784. L:=PWideRec(Pointer(S)-WideFirstOff)^.len div sizeof(WideChar);
  785. SNew:=NewWideString (L);
  786. Move (PWideChar(S)^,SNew^,(L+1)*sizeof(WideChar));
  787. PWideRec(SNew-WideFirstOff)^.len:=L * sizeof(WideChar);
  788. fpc_widestr_decr_ref (Pointer(S)); { Thread safe }
  789. pointer(S):=SNew;
  790. pointer(result):=SNew;
  791. end;
  792. end;
  793. {$endif FPC_WINLIKEWIDESTRING}
  794. Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc;
  795. var
  796. ResultAddress : Pointer;
  797. begin
  798. ResultAddress:=Nil;
  799. dec(index);
  800. if Index < 0 then
  801. Index := 0;
  802. { Check Size. Accounts for Zero-length S, the double check is needed because
  803. Size can be maxint and will get <0 when adding index }
  804. if (Size>Length(S)) or
  805. (Index+Size>Length(S)) then
  806. Size:=Length(S)-Index;
  807. If Size>0 then
  808. begin
  809. If Index<0 Then
  810. Index:=0;
  811. ResultAddress:=Pointer(NewWideString (Size));
  812. if ResultAddress<>Nil then
  813. begin
  814. Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar));
  815. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar);
  816. PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0;
  817. end;
  818. end;
  819. Pointer(fpc_widestr_Copy):=ResultAddress;
  820. end;
  821. Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt;
  822. var
  823. i,MaxLen : SizeInt;
  824. pc : pwidechar;
  825. begin
  826. Pos:=0;
  827. if Length(SubStr)>0 then
  828. begin
  829. MaxLen:=Length(source)-Length(SubStr);
  830. i:=0;
  831. pc:=@source[1];
  832. while (i<=MaxLen) do
  833. begin
  834. inc(i);
  835. if (SubStr[1]=pc^) and
  836. (CompareWord(Substr[1],pc^,Length(SubStr))=0) then
  837. begin
  838. Pos:=i;
  839. exit;
  840. end;
  841. inc(pc);
  842. end;
  843. end;
  844. end;
  845. { Faster version for a widechar alone }
  846. Function Pos (c : WideChar; Const s : WideString) : SizeInt;
  847. var
  848. i: SizeInt;
  849. pc : pwidechar;
  850. begin
  851. pc:=@s[1];
  852. for i:=1 to length(s) do
  853. begin
  854. if pc^=c then
  855. begin
  856. pos:=i;
  857. exit;
  858. end;
  859. inc(pc);
  860. end;
  861. pos:=0;
  862. end;
  863. Function Pos (c : WideChar; Const s : AnsiString) : SizeInt;
  864. var
  865. i: SizeInt;
  866. pc : pchar;
  867. begin
  868. pc:=@s[1];
  869. for i:=1 to length(s) do
  870. begin
  871. if widechar(pc^)=c then
  872. begin
  873. pos:=i;
  874. exit;
  875. end;
  876. inc(pc);
  877. end;
  878. pos:=0;
  879. end;
  880. Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  881. begin
  882. result:=Pos(WideString(c),s);
  883. end;
  884. Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  885. begin
  886. result:=Pos(WideString(c),s);
  887. end;
  888. Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  889. begin
  890. result:=Pos(c,WideString(s));
  891. end;
  892. { Faster version for a char alone. Must be implemented because }
  893. { pos(c: char; const s: shortstring) also exists, so otherwise }
  894. { using pos(char,pchar) will always call the shortstring version }
  895. { (exact match for first argument), also with $h+ (JM) }
  896. Function Pos (c : Char; Const s : WideString) : SizeInt;
  897. var
  898. i: SizeInt;
  899. wc : widechar;
  900. pc : pwidechar;
  901. begin
  902. wc:=c;
  903. pc:=@s[1];
  904. for i:=1 to length(s) do
  905. begin
  906. if pc^=wc then
  907. begin
  908. pos:=i;
  909. exit;
  910. end;
  911. inc(pc);
  912. end;
  913. pos:=0;
  914. end;
  915. Procedure Delete (Var S : WideString; Index,Size: SizeInt);
  916. Var
  917. LS : SizeInt;
  918. begin
  919. If Length(S)=0 then
  920. exit;
  921. if index<=0 then
  922. exit;
  923. LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len div sizeof(WideChar);
  924. if (Index<=LS) and (Size>0) then
  925. begin
  926. UniqueString (S);
  927. if Size+Index>LS then
  928. Size:=LS-Index+1;
  929. if Index+Size<=LS then
  930. begin
  931. Dec(Index);
  932. Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index+1)*sizeof(WideChar));
  933. end;
  934. Setlength(s,LS-Size);
  935. end;
  936. end;
  937. Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt);
  938. var
  939. Temp : WideString;
  940. LS : SizeInt;
  941. begin
  942. If Length(Source)=0 then
  943. exit;
  944. if index <= 0 then
  945. index := 1;
  946. Ls:=Length(S);
  947. if index > LS then
  948. index := LS+1;
  949. Dec(Index);
  950. Pointer(Temp) := NewWideString(Length(Source)+LS);
  951. SetLength(Temp,Length(Source)+LS);
  952. If Index>0 then
  953. move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar));
  954. Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar));
  955. If (LS-Index)>0 then
  956. Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar));
  957. S:=Temp;
  958. end;
  959. function UpCase(const s : WideString) : WideString;
  960. begin
  961. result:=widestringmanager.UpperWideStringProc(s);
  962. end;
  963. Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt);
  964. var
  965. BufLen: SizeInt;
  966. begin
  967. SetLength(S,Len);
  968. If (Buf<>Nil) and (Len>0) then
  969. begin
  970. BufLen := IndexWord(Buf^, Len+1, 0);
  971. If (BufLen>0) and (BufLen < Len) then
  972. Len := BufLen;
  973. Move (Buf[0],S[1],Len*sizeof(WideChar));
  974. PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0;
  975. end;
  976. end;
  977. Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt);
  978. var
  979. BufLen: SizeInt;
  980. begin
  981. SetLength(S,Len);
  982. If (Buf<>Nil) and (Len>0) then
  983. begin
  984. BufLen := IndexByte(Buf^, Len+1, 0);
  985. If (BufLen>0) and (BufLen < Len) then
  986. Len := BufLen;
  987. widestringmanager.Ansi2WideMoveProc(Buf,S,Len);
  988. //PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0;
  989. end;
  990. end;
  991. Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc;
  992. Var
  993. SS : String;
  994. begin
  995. fpc_Val_Real_WideStr := 0;
  996. if length(S) > 255 then
  997. code := 256
  998. else
  999. begin
  1000. SS := S;
  1001. Val(SS,fpc_Val_Real_WideStr,code);
  1002. end;
  1003. end;
  1004. Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc;
  1005. Var
  1006. SS : ShortString;
  1007. begin
  1008. fpc_Val_UInt_WideStr := 0;
  1009. if length(S) > 255 then
  1010. code := 256
  1011. else
  1012. begin
  1013. SS := S;
  1014. Val(SS,fpc_Val_UInt_WideStr,code);
  1015. end;
  1016. end;
  1017. Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc;
  1018. Var
  1019. SS : ShortString;
  1020. begin
  1021. fpc_Val_SInt_WideStr:=0;
  1022. if length(S)>255 then
  1023. code:=256
  1024. else
  1025. begin
  1026. SS := S;
  1027. fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code);
  1028. end;
  1029. end;
  1030. {$ifndef CPU64}
  1031. Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc;
  1032. Var
  1033. SS : ShortString;
  1034. begin
  1035. fpc_Val_qword_WideStr:=0;
  1036. if length(S)>255 then
  1037. code:=256
  1038. else
  1039. begin
  1040. SS := S;
  1041. Val(SS,fpc_Val_qword_WideStr,Code);
  1042. end;
  1043. end;
  1044. Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc;
  1045. Var
  1046. SS : ShortString;
  1047. begin
  1048. fpc_Val_int64_WideStr:=0;
  1049. if length(S)>255 then
  1050. code:=256
  1051. else
  1052. begin
  1053. SS := S;
  1054. Val(SS,fpc_Val_int64_WideStr,Code);
  1055. end;
  1056. end;
  1057. {$endif CPU64}
  1058. procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc;
  1059. var
  1060. ss : shortstring;
  1061. begin
  1062. str_real(len,fr,d,treal_type(rt),ss);
  1063. s:=ss;
  1064. end;
  1065. Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc;
  1066. Var
  1067. SS : ShortString;
  1068. begin
  1069. Str (v:Len,SS);
  1070. S:=SS;
  1071. end;
  1072. Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc;
  1073. Var
  1074. SS : ShortString;
  1075. begin
  1076. str(v:Len,SS);
  1077. S:=SS;
  1078. end;
  1079. {$ifndef CPU64}
  1080. Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc;
  1081. Var
  1082. SS : ShortString;
  1083. begin
  1084. Str (v:Len,SS);
  1085. S:=SS;
  1086. end;
  1087. Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc;
  1088. Var
  1089. SS : ShortString;
  1090. begin
  1091. str(v:Len,SS);
  1092. S:=SS;
  1093. end;
  1094. {$endif CPU64}
  1095. function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1096. begin
  1097. if assigned(Source) then
  1098. Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0))
  1099. else
  1100. Result:=0;
  1101. end;
  1102. function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt;
  1103. var
  1104. i,j : SizeUInt;
  1105. w : word;
  1106. begin
  1107. result:=0;
  1108. if source=nil then
  1109. exit;
  1110. i:=0;
  1111. j:=0;
  1112. if assigned(Dest) then
  1113. begin
  1114. while (i<SourceChars) and (j<MaxDestBytes) do
  1115. begin
  1116. w:=word(Source[i]);
  1117. case w of
  1118. 0..$7f:
  1119. begin
  1120. Dest[j]:=char(w);
  1121. inc(j);
  1122. end;
  1123. $80..$7ff:
  1124. begin
  1125. if j+1>=MaxDestBytes then
  1126. break;
  1127. Dest[j]:=char($c0 or (w shr 6));
  1128. Dest[j+1]:=char($80 or (w and $3f));
  1129. inc(j,2);
  1130. end;
  1131. else
  1132. begin
  1133. if j+2>=MaxDestBytes then
  1134. break;
  1135. Dest[j]:=char($e0 or (w shr 12));
  1136. Dest[j+1]:=char($80 or ((w shr 6)and $3f));
  1137. Dest[j+2]:=char($80 or (w and $3f));
  1138. inc(j,3);
  1139. end;
  1140. end;
  1141. inc(i);
  1142. end;
  1143. if j>MaxDestBytes-1 then
  1144. j:=MaxDestBytes-1;
  1145. Dest[j]:=#0;
  1146. end
  1147. else
  1148. begin
  1149. while i<SourceChars do
  1150. begin
  1151. case word(Source[i]) of
  1152. $0..$7f:
  1153. inc(j);
  1154. $80..$7ff:
  1155. inc(j,2);
  1156. else
  1157. inc(j,3);
  1158. end;
  1159. end;
  1160. end;
  1161. result:=j+1;
  1162. end;
  1163. function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1164. begin
  1165. if assigned(Source) then
  1166. Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source))
  1167. else
  1168. Result:=0;
  1169. end;
  1170. function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt;
  1171. var
  1172. i,j : SizeUInt;
  1173. w: SizeUInt;
  1174. b : byte;
  1175. begin
  1176. if not assigned(Source) then
  1177. begin
  1178. result:=0;
  1179. exit;
  1180. end;
  1181. result:=SizeUInt(-1);
  1182. i:=0;
  1183. j:=0;
  1184. if assigned(Dest) then
  1185. begin
  1186. while (j<MaxDestChars) and (i<SourceBytes) do
  1187. begin
  1188. b:=byte(Source[i]);
  1189. w:=b;
  1190. inc(i);
  1191. // 2 or 3 bytes?
  1192. if b>=$80 then
  1193. begin
  1194. w:=b and $3f;
  1195. if i>=SourceBytes then
  1196. exit;
  1197. // 3 bytes?
  1198. if (b and $20)<>0 then
  1199. begin
  1200. b:=byte(Source[i]);
  1201. inc(i);
  1202. if i>=SourceBytes then
  1203. exit;
  1204. if (b and $c0)<>$80 then
  1205. exit;
  1206. w:=(w shl 6) or (b and $3f);
  1207. end;
  1208. b:=byte(Source[i]);
  1209. w:=(w shl 6) or (b and $3f);
  1210. if (b and $c0)<>$80 then
  1211. exit;
  1212. inc(i);
  1213. end;
  1214. Dest[j]:=WideChar(w);
  1215. inc(j);
  1216. end;
  1217. if j>=MaxDestChars then j:=MaxDestChars-1;
  1218. Dest[j]:=#0;
  1219. end
  1220. else
  1221. begin
  1222. while i<SourceBytes do
  1223. begin
  1224. b:=byte(Source[i]);
  1225. inc(i);
  1226. // 2 or 3 bytes?
  1227. if b>=$80 then
  1228. begin
  1229. if i>=SourceBytes then
  1230. exit;
  1231. // 3 bytes?
  1232. b := b and $3f;
  1233. if (b and $20)<>0 then
  1234. begin
  1235. b:=byte(Source[i]);
  1236. inc(i);
  1237. if i>=SourceBytes then
  1238. exit;
  1239. if (b and $c0)<>$80 then
  1240. exit;
  1241. end;
  1242. if (byte(Source[i]) and $c0)<>$80 then
  1243. exit;
  1244. inc(i);
  1245. end;
  1246. inc(j);
  1247. end;
  1248. end;
  1249. result:=j+1;
  1250. end;
  1251. function UTF8Encode(const s : WideString) : UTF8String;
  1252. var
  1253. i : SizeInt;
  1254. hs : UTF8String;
  1255. begin
  1256. result:='';
  1257. if s='' then
  1258. exit;
  1259. SetLength(hs,length(s)*3);
  1260. i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s));
  1261. if i>0 then
  1262. begin
  1263. SetLength(hs,i-1);
  1264. result:=hs;
  1265. end;
  1266. end;
  1267. function UTF8Decode(const s : UTF8String): WideString;
  1268. var
  1269. i : SizeInt;
  1270. hs : WideString;
  1271. begin
  1272. result:='';
  1273. if s='' then
  1274. exit;
  1275. SetLength(hs,length(s));
  1276. i:=Utf8ToUnicode(PWideChar(hs),length(hs)+1,pchar(s),length(s));
  1277. if i>0 then
  1278. begin
  1279. SetLength(hs,i-1);
  1280. result:=hs;
  1281. end;
  1282. end;
  1283. function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif}
  1284. begin
  1285. Result:=Utf8Encode(s);
  1286. end;
  1287. function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif}
  1288. begin
  1289. Result:=Utf8Decode(s);
  1290. end;
  1291. function WideStringToUCS4String(const s : WideString) : UCS4String;
  1292. var
  1293. i : SizeInt;
  1294. begin
  1295. setlength(result,length(s)+1);
  1296. for i:=1 to length(s) do
  1297. result[i-1]:=UCS4Char(s[i]);
  1298. result[length(s)]:=UCS4Char(0);
  1299. end;
  1300. function UCS4StringToWideString(const s : UCS4String) : WideString;
  1301. var
  1302. i : SizeInt;
  1303. begin
  1304. setlength(result,length(s)-1);
  1305. for i:=1 to length(s)-1 do
  1306. result[i]:=WideChar(s[i-1]);
  1307. end;
  1308. procedure unimplementedwidestring;
  1309. begin
  1310. HandleErrorFrame(215,get_frame);
  1311. end;
  1312. {$warnings off}
  1313. function GenericWideCase(const s : WideString) : WideString;
  1314. begin
  1315. unimplementedwidestring;
  1316. end;
  1317. function CompareWideString(const s1, s2 : WideString) : PtrInt;
  1318. begin
  1319. unimplementedwidestring;
  1320. end;
  1321. function CompareTextWideString(const s1, s2 : WideString): PtrInt;
  1322. begin
  1323. unimplementedwidestring;
  1324. end;
  1325. function CharLengthPChar(const Str: PChar): PtrInt;
  1326. begin
  1327. unimplementedwidestring;
  1328. end;
  1329. {$warnings on}
  1330. procedure initwidestringmanager;
  1331. begin
  1332. fillchar(widestringmanager,sizeof(widestringmanager),0);
  1333. widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
  1334. widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove;
  1335. widestringmanager.UpperWideStringProc:=@GenericWideCase;
  1336. widestringmanager.LowerWideStringProc:=@GenericWideCase;
  1337. widestringmanager.CompareWideStringProc:=@CompareWideString;
  1338. widestringmanager.CompareTextWideStringProc:=@CompareTextWideString;
  1339. widestringmanager.CharLengthPCharProc:=@CharLengthPChar;
  1340. end;