wstrings.inc 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525
  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. if S2<>nil then
  320. begin
  321. S1:=NewWidestring(length(WideString(S2)));
  322. move(s2^,s1^,length(WideString(s1))*sizeof(widechar));
  323. end
  324. else
  325. S1:=nil;
  326. {$else FPC_WINLIKEWIDESTRING}
  327. If S2<>nil then
  328. If PWideRec(S2-WideFirstOff)^.Ref>0 then
  329. inclocked(PWideRec(S2-WideFirstOff)^.ref);
  330. { Decrease the reference count on the old S1 }
  331. fpc_widestr_decr_ref (S1);
  332. s1:=s2;
  333. {$endif FPC_WINLIKEWIDESTRING}
  334. end;
  335. { alias for internal use }
  336. Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN'];
  337. {$ifndef STR_CONCAT_PROCS}
  338. function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc;
  339. Var
  340. Size,Location : SizeInt;
  341. pc : pwidechar;
  342. begin
  343. { only assign if s1 or s2 is empty }
  344. if (S1='') then
  345. begin
  346. result:=s2;
  347. exit;
  348. end;
  349. if (S2='') then
  350. begin
  351. result:=s1;
  352. exit;
  353. end;
  354. Location:=Length(S1);
  355. Size:=length(S2);
  356. SetLength(result,Size+Location);
  357. pc:=pwidechar(result);
  358. Move(S1[1],pc^,Location*sizeof(WideChar));
  359. inc(pc,location);
  360. Move(S2[1],pc^,(Size+1)*sizeof(WideChar));
  361. end;
  362. function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc;
  363. Var
  364. i : Longint;
  365. p : pointer;
  366. pc : pwidechar;
  367. Size,NewSize : SizeInt;
  368. begin
  369. { First calculate size of the result so we can do
  370. a single call to SetLength() }
  371. NewSize:=0;
  372. for i:=low(sarr) to high(sarr) do
  373. inc(Newsize,length(sarr[i]));
  374. SetLength(result,NewSize);
  375. pc:=pwidechar(result);
  376. for i:=low(sarr) to high(sarr) do
  377. begin
  378. p:=pointer(sarr[i]);
  379. if assigned(p) then
  380. begin
  381. Size:=length(widestring(p));
  382. Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar));
  383. inc(pc,size);
  384. end;
  385. end;
  386. end;
  387. {$else STR_CONCAT_PROCS}
  388. procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc;
  389. Var
  390. Size,Location : SizeInt;
  391. begin
  392. { only assign if s1 or s2 is empty }
  393. if (S1='') then
  394. begin
  395. DestS:=s2;
  396. exit;
  397. end;
  398. if (S2='') then
  399. begin
  400. DestS:=s1;
  401. exit;
  402. end;
  403. Location:=Length(S1);
  404. Size:=length(S2);
  405. { Use Pointer() typecasts to prevent extra conversion code }
  406. if Pointer(DestS)=Pointer(S1) then
  407. begin
  408. SetLength(DestS,Size+Location);
  409. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  410. end
  411. else if Pointer(DestS)=Pointer(S2) then
  412. begin
  413. SetLength(DestS,Size+Location);
  414. Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  415. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  416. end
  417. else
  418. begin
  419. DestS:='';
  420. SetLength(DestS,Size+Location);
  421. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  422. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  423. end;
  424. end;
  425. procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc;
  426. Var
  427. lowstart,i : Longint;
  428. p,pc : pointer;
  429. Size,NewLen,
  430. OldDestLen : SizeInt;
  431. begin
  432. if high(sarr)=0 then
  433. begin
  434. DestS:='';
  435. exit;
  436. end;
  437. lowstart:=low(sarr);
  438. if Pointer(DestS)=Pointer(sarr[lowstart]) then
  439. begin
  440. inc(lowstart);
  441. { Check for another reuse, then we can't use
  442. the append optimization }
  443. for i:=lowstart to high(sarr) do
  444. begin
  445. if Pointer(DestS)=Pointer(sarr[i]) then
  446. begin
  447. lowstart:=low(sarr);
  448. break;
  449. end;
  450. end;
  451. end;
  452. { Start with empty DestS if we start with concatting
  453. the first array element }
  454. if lowstart=low(sarr) then
  455. DestS:='';
  456. OldDestLen:=length(DestS);
  457. { Calculate size of the result so we can do
  458. a single call to SetLength() }
  459. NewLen:=0;
  460. for i:=low(sarr) to high(sarr) do
  461. inc(NewLen,length(sarr[i]));
  462. SetLength(DestS,NewLen);
  463. { Concat all strings, except the string we already
  464. copied in DestS }
  465. pc:=Pointer(DestS)+OldDestLen*sizeof(WideChar);
  466. for i:=lowstart to high(sarr) do
  467. begin
  468. p:=pointer(sarr[i]);
  469. if assigned(p) then
  470. begin
  471. Size:=length(widestring(p));
  472. Move(p^,pc^,(Size+1)*sizeof(WideChar));
  473. inc(pc,size*sizeof(WideChar));
  474. end;
  475. end;
  476. end;
  477. {$endif STR_CONCAT_PROCS}
  478. Function fpc_Char_To_WideStr(const c : WideChar): WideString; compilerproc;
  479. {
  480. Converts a Char to a WideString;
  481. }
  482. begin
  483. if c = #0 then
  484. { result is automatically set to '' }
  485. exit;
  486. Setlength(fpc_Char_To_WideStr,1);
  487. fpc_Char_To_WideStr[1]:=c;
  488. { Terminating Zero }
  489. PWideChar(Pointer(fpc_Char_To_WideStr)+sizeof(WideChar))^:=#0;
  490. end;
  491. Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc;
  492. Var
  493. L : SizeInt;
  494. begin
  495. if (not assigned(p)) or (p[0]=#0) Then
  496. { result is automatically set to '' }
  497. exit;
  498. l:=IndexChar(p^,-1,#0);
  499. widestringmanager.Ansi2WideMoveProc(P,fpc_PChar_To_WideStr,l);
  500. end;
  501. Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc;
  502. var
  503. i : SizeInt;
  504. begin
  505. if (zerobased) then
  506. begin
  507. if (arr[0]=#0) Then
  508. { result is automatically set to '' }
  509. exit;
  510. i:=IndexChar(arr,high(arr)+1,#0);
  511. if i = -1 then
  512. i := high(arr)+1;
  513. end
  514. else
  515. i := high(arr)+1;
  516. SetLength(fpc_CharArray_To_WideStr,i);
  517. widestringmanager.Ansi2WideMoveProc (pchar(@arr),fpc_CharArray_To_WideStr,i);
  518. end;
  519. function fpc_WideCharArray_To_ShortStr(const arr: array of widechar; zerobased: boolean = true): shortstring;[public,alias:'FPC_WIDECHARARRAY_TO_SHORTSTR']; compilerproc;
  520. var
  521. l: longint;
  522. index: longint;
  523. len: byte;
  524. temp: ansistring;
  525. begin
  526. l := high(arr)+1;
  527. if l>=256 then
  528. l:=255
  529. else if l<0 then
  530. l:=0;
  531. if zerobased then
  532. begin
  533. index:=IndexWord(arr[0],l,0);
  534. if (index < 0) then
  535. len := l
  536. else
  537. len := index;
  538. end
  539. else
  540. len := l;
  541. widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),temp,len);
  542. fpc_WideCharArray_To_ShortStr := temp;
  543. end;
  544. Function fpc_WideCharArray_To_AnsiStr(const arr: array of widechar; zerobased: boolean = true): AnsiString; compilerproc;
  545. var
  546. i : SizeInt;
  547. begin
  548. if (zerobased) then
  549. begin
  550. i:=IndexWord(arr,high(arr)+1,0);
  551. if i = -1 then
  552. i := high(arr)+1;
  553. end
  554. else
  555. i := high(arr)+1;
  556. SetLength(fpc_WideCharArray_To_AnsiStr,i);
  557. widestringmanager.Wide2AnsiMoveProc (pwidechar(@arr),fpc_WideCharArray_To_AnsiStr,i);
  558. end;
  559. Function fpc_WideCharArray_To_WideStr(const arr: array of widechar; zerobased: boolean = true): WideString; compilerproc;
  560. var
  561. i : SizeInt;
  562. begin
  563. if (zerobased) then
  564. begin
  565. i:=IndexWord(arr,high(arr)+1,0);
  566. if i = -1 then
  567. i := high(arr)+1;
  568. end
  569. else
  570. i := high(arr)+1;
  571. SetLength(fpc_WideCharArray_To_WideStr,i);
  572. Move(pwidechar(@arr)^, PWideChar(Pointer(@fpc_WideCharArray_To_WideStr[1]))^,i*sizeof(WideChar));
  573. { Terminating Zero }
  574. PWideChar(Pointer(@fpc_WideCharArray_To_WideStr[1])+i*sizeof(WideChar))^:=#0;
  575. end;
  576. { inside the compiler, the resulttype is modified to that of the actual }
  577. { chararray we're converting to (JM) }
  578. function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc;
  579. var
  580. len: SizeInt;
  581. temp: ansistring;
  582. begin
  583. len := length(src);
  584. { make sure we don't dereference src if it can be nil (JM) }
  585. if len > 0 then
  586. widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len);
  587. len := length(temp);
  588. if len > arraysize then
  589. len := arraysize;
  590. move(temp[1],fpc_widestr_to_chararray[0],len);
  591. fillchar(fpc_widestr_to_chararray[len],arraysize-len,0);
  592. end;
  593. { inside the compiler, the resulttype is modified to that of the actual }
  594. { widechararray we're converting to (JM) }
  595. function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc;
  596. var
  597. len: SizeInt;
  598. begin
  599. len := length(src);
  600. if len > arraysize then
  601. len := arraysize;
  602. { make sure we don't try to access element 1 of the ansistring if it's nil }
  603. if len > 0 then
  604. move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar));
  605. fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  606. end;
  607. { inside the compiler, the resulttype is modified to that of the actual }
  608. { chararray we're converting to (JM) }
  609. function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc;
  610. var
  611. len: SizeInt;
  612. temp: widestring;
  613. begin
  614. len := length(src);
  615. { make sure we don't dereference src if it can be nil (JM) }
  616. if len > 0 then
  617. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  618. len := length(temp);
  619. if len > arraysize then
  620. len := arraysize;
  621. move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar));
  622. fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  623. end;
  624. function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc;
  625. var
  626. len: longint;
  627. temp : widestring;
  628. begin
  629. len := length(src);
  630. { make sure we don't access char 1 if length is 0 (JM) }
  631. if len > 0 then
  632. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  633. len := length(temp);
  634. if len > arraysize then
  635. len := arraysize;
  636. move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar));
  637. fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  638. end;
  639. Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc;
  640. {
  641. Compares 2 WideStrings;
  642. The result is
  643. <0 if S1<S2
  644. 0 if S1=S2
  645. >0 if S1>S2
  646. }
  647. Var
  648. MaxI,Temp : SizeInt;
  649. begin
  650. if pointer(S1)=pointer(S2) then
  651. begin
  652. fpc_WideStr_Compare:=0;
  653. exit;
  654. end;
  655. Maxi:=Length(S1);
  656. temp:=Length(S2);
  657. If MaxI>Temp then
  658. MaxI:=Temp;
  659. Temp:=CompareWord(S1[1],S2[1],MaxI);
  660. if temp=0 then
  661. temp:=Length(S1)-Length(S2);
  662. fpc_WideStr_Compare:=Temp;
  663. end;
  664. Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc;
  665. begin
  666. if p=nil then
  667. HandleErrorFrame(201,get_frame);
  668. end;
  669. Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc;
  670. begin
  671. if (index>len) or (Index<1) then
  672. HandleErrorFrame(201,get_frame);
  673. end;
  674. Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc;
  675. {
  676. Sets The length of string S to L.
  677. Makes sure S is unique, and contains enough room.
  678. }
  679. Var
  680. Temp : Pointer;
  681. movelen: SizeInt;
  682. begin
  683. if (l>0) then
  684. begin
  685. if Pointer(S)=nil then
  686. begin
  687. { Need a complete new string...}
  688. Pointer(s):=NewWideString(l);
  689. end
  690. { windows doesn't support reallocing widestrings, this code
  691. is anyways subject to be removed because widestrings shouldn't be
  692. ref. counted anymore (FK) }
  693. else
  694. {$ifndef FPC_WINLIKEWIDESTRING}
  695. if
  696. {$ifdef MSWINDOWS}
  697. not winwidestringalloc and
  698. {$endif MSWINDOWS}
  699. (PWideRec(Pointer(S)-WideFirstOff)^.Ref = 1) then
  700. begin
  701. Dec(Pointer(S),WideFirstOff);
  702. if L*sizeof(WideChar)+WideRecLen>MemSize(Pointer(S)) then
  703. reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen);
  704. Inc(Pointer(S), WideFirstOff);
  705. end
  706. else
  707. {$endif FPC_WINLIKEWIDESTRING}
  708. begin
  709. { Reallocation is needed... }
  710. Temp:=Pointer(NewWideString(L));
  711. if Length(S)>0 then
  712. begin
  713. if l < succ(length(s)) then
  714. movelen := l
  715. { also move terminating null }
  716. else
  717. movelen := succ(length(s));
  718. Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar));
  719. end;
  720. fpc_widestr_decr_ref(Pointer(S));
  721. Pointer(S):=Temp;
  722. end;
  723. { Force nil termination in case it gets shorter }
  724. PWord(Pointer(S)+l*sizeof(WideChar))^:=0;
  725. {$ifndef FPC_WINLIKEWIDESTRING}
  726. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar);
  727. {$endif FPC_WINLIKEWIDESTRING}
  728. end
  729. else
  730. begin
  731. { Length=0 }
  732. if Pointer(S)<>nil then
  733. fpc_widestr_decr_ref (Pointer(S));
  734. Pointer(S):=Nil;
  735. end;
  736. end;
  737. {*****************************************************************************
  738. Public functions, In interface.
  739. *****************************************************************************}
  740. function WideCharToString(S : PWideChar) : AnsiString;
  741. begin
  742. result:=WideCharLenToString(s,Length(WideString(s)));
  743. end;
  744. function StringToWideChar(const Src : AnsiString;Dest : PWideChar;DestSize : SizeInt) : PWideChar;
  745. var
  746. temp:widestring;
  747. begin
  748. widestringmanager.Ansi2WideMoveProc(PChar(Src),temp,Length(Src));
  749. if Length(temp)<DestSize then
  750. move(temp[1],Dest^,Length(temp)*SizeOf(WideChar))
  751. else
  752. move(temp[1],Dest^,(DestSize-1)*SizeOf(WideChar));
  753. Dest[DestSize-1]:=#0;
  754. result:=Dest;
  755. end;
  756. function WideCharLenToString(S : PWideChar;Len : SizeInt) : AnsiString;
  757. begin
  758. //SetLength(result,Len);
  759. widestringmanager.Wide2AnsiMoveproc(S,result,Len);
  760. end;
  761. procedure WideCharLenToStrVar(Src : PWideChar;Len : SizeInt;out Dest : AnsiString);
  762. begin
  763. Dest:=WideCharLenToString(Src,Len);
  764. end;
  765. procedure WideCharToStrVar(S : PWideChar;out Dest : AnsiString);
  766. begin
  767. Dest:=WideCharToString(S);
  768. end;
  769. Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc;
  770. {$ifdef FPC_WINLIKEWIDESTRING}
  771. begin
  772. pointer(result) := pointer(s);
  773. end;
  774. {$else FPC_WINLIKEWIDESTRING}
  775. {
  776. Make sure reference count of S is 1,
  777. using copy-on-write semantics.
  778. }
  779. Var
  780. SNew : Pointer;
  781. L : SizeInt;
  782. begin
  783. pointer(result) := pointer(s);
  784. If Pointer(S)=Nil then
  785. exit;
  786. if PWideRec(Pointer(S)-WideFirstOff)^.Ref<>1 then
  787. begin
  788. L:=PWideRec(Pointer(S)-WideFirstOff)^.len div sizeof(WideChar);
  789. SNew:=NewWideString (L);
  790. Move (PWideChar(S)^,SNew^,(L+1)*sizeof(WideChar));
  791. PWideRec(SNew-WideFirstOff)^.len:=L * sizeof(WideChar);
  792. fpc_widestr_decr_ref (Pointer(S)); { Thread safe }
  793. pointer(S):=SNew;
  794. pointer(result):=SNew;
  795. end;
  796. end;
  797. {$endif FPC_WINLIKEWIDESTRING}
  798. Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc;
  799. var
  800. ResultAddress : Pointer;
  801. begin
  802. ResultAddress:=Nil;
  803. dec(index);
  804. if Index < 0 then
  805. Index := 0;
  806. { Check Size. Accounts for Zero-length S, the double check is needed because
  807. Size can be maxint and will get <0 when adding index }
  808. if (Size>Length(S)) or
  809. (Index+Size>Length(S)) then
  810. Size:=Length(S)-Index;
  811. If Size>0 then
  812. begin
  813. If Index<0 Then
  814. Index:=0;
  815. ResultAddress:=Pointer(NewWideString (Size));
  816. if ResultAddress<>Nil then
  817. begin
  818. Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar));
  819. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar);
  820. PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0;
  821. end;
  822. end;
  823. Pointer(fpc_widestr_Copy):=ResultAddress;
  824. end;
  825. Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt;
  826. var
  827. i,MaxLen : SizeInt;
  828. pc : pwidechar;
  829. begin
  830. Pos:=0;
  831. if Length(SubStr)>0 then
  832. begin
  833. MaxLen:=Length(source)-Length(SubStr);
  834. i:=0;
  835. pc:=@source[1];
  836. while (i<=MaxLen) do
  837. begin
  838. inc(i);
  839. if (SubStr[1]=pc^) and
  840. (CompareWord(Substr[1],pc^,Length(SubStr))=0) then
  841. begin
  842. Pos:=i;
  843. exit;
  844. end;
  845. inc(pc);
  846. end;
  847. end;
  848. end;
  849. { Faster version for a widechar alone }
  850. Function Pos (c : WideChar; Const s : WideString) : SizeInt;
  851. var
  852. i: SizeInt;
  853. pc : pwidechar;
  854. begin
  855. pc:=@s[1];
  856. for i:=1 to length(s) do
  857. begin
  858. if pc^=c then
  859. begin
  860. pos:=i;
  861. exit;
  862. end;
  863. inc(pc);
  864. end;
  865. pos:=0;
  866. end;
  867. Function Pos (c : WideChar; Const s : AnsiString) : SizeInt;
  868. var
  869. i: SizeInt;
  870. pc : pchar;
  871. begin
  872. pc:=@s[1];
  873. for i:=1 to length(s) do
  874. begin
  875. if widechar(pc^)=c then
  876. begin
  877. pos:=i;
  878. exit;
  879. end;
  880. inc(pc);
  881. end;
  882. pos:=0;
  883. end;
  884. Function Pos (c : AnsiString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  885. begin
  886. result:=Pos(WideString(c),s);
  887. end;
  888. Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  889. begin
  890. result:=Pos(WideString(c),s);
  891. end;
  892. Function Pos (c : WideString; Const s : AnsiString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  893. begin
  894. result:=Pos(c,WideString(s));
  895. end;
  896. { Faster version for a char alone. Must be implemented because }
  897. { pos(c: char; const s: shortstring) also exists, so otherwise }
  898. { using pos(char,pchar) will always call the shortstring version }
  899. { (exact match for first argument), also with $h+ (JM) }
  900. Function Pos (c : Char; Const s : WideString) : SizeInt;
  901. var
  902. i: SizeInt;
  903. wc : widechar;
  904. pc : pwidechar;
  905. begin
  906. wc:=c;
  907. pc:=@s[1];
  908. for i:=1 to length(s) do
  909. begin
  910. if pc^=wc then
  911. begin
  912. pos:=i;
  913. exit;
  914. end;
  915. inc(pc);
  916. end;
  917. pos:=0;
  918. end;
  919. Procedure Delete (Var S : WideString; Index,Size: SizeInt);
  920. Var
  921. LS : SizeInt;
  922. begin
  923. If Length(S)=0 then
  924. exit;
  925. if index<=0 then
  926. exit;
  927. LS:=PWideRec(Pointer(S)-WideFirstOff)^.Len div sizeof(WideChar);
  928. if (Index<=LS) and (Size>0) then
  929. begin
  930. UniqueString (S);
  931. if Size+Index>LS then
  932. Size:=LS-Index+1;
  933. if Index+Size<=LS then
  934. begin
  935. Dec(Index);
  936. Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index+1)*sizeof(WideChar));
  937. end;
  938. Setlength(s,LS-Size);
  939. end;
  940. end;
  941. Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt);
  942. var
  943. Temp : WideString;
  944. LS : SizeInt;
  945. begin
  946. If Length(Source)=0 then
  947. exit;
  948. if index <= 0 then
  949. index := 1;
  950. Ls:=Length(S);
  951. if index > LS then
  952. index := LS+1;
  953. Dec(Index);
  954. Pointer(Temp) := NewWideString(Length(Source)+LS);
  955. SetLength(Temp,Length(Source)+LS);
  956. If Index>0 then
  957. move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar));
  958. Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar));
  959. If (LS-Index)>0 then
  960. Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar));
  961. S:=Temp;
  962. end;
  963. function UpCase(const s : WideString) : WideString;
  964. begin
  965. result:=widestringmanager.UpperWideStringProc(s);
  966. end;
  967. Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt);
  968. var
  969. BufLen: SizeInt;
  970. begin
  971. SetLength(S,Len);
  972. If (Buf<>Nil) and (Len>0) then
  973. begin
  974. BufLen := IndexWord(Buf^, Len+1, 0);
  975. If (BufLen>0) and (BufLen < Len) then
  976. Len := BufLen;
  977. Move (Buf[0],S[1],Len*sizeof(WideChar));
  978. PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0;
  979. end;
  980. end;
  981. Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt);
  982. var
  983. BufLen: SizeInt;
  984. begin
  985. SetLength(S,Len);
  986. If (Buf<>Nil) and (Len>0) then
  987. begin
  988. BufLen := IndexByte(Buf^, Len+1, 0);
  989. If (BufLen>0) and (BufLen < Len) then
  990. Len := BufLen;
  991. widestringmanager.Ansi2WideMoveProc(Buf,S,Len);
  992. //PWideChar(Pointer(S)+Len*sizeof(WideChar))^:=#0;
  993. end;
  994. end;
  995. Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc;
  996. Var
  997. SS : String;
  998. begin
  999. fpc_Val_Real_WideStr := 0;
  1000. if length(S) > 255 then
  1001. code := 256
  1002. else
  1003. begin
  1004. SS := S;
  1005. Val(SS,fpc_Val_Real_WideStr,code);
  1006. end;
  1007. end;
  1008. Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc;
  1009. Var
  1010. SS : ShortString;
  1011. begin
  1012. fpc_Val_UInt_WideStr := 0;
  1013. if length(S) > 255 then
  1014. code := 256
  1015. else
  1016. begin
  1017. SS := S;
  1018. Val(SS,fpc_Val_UInt_WideStr,code);
  1019. end;
  1020. end;
  1021. Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc;
  1022. Var
  1023. SS : ShortString;
  1024. begin
  1025. fpc_Val_SInt_WideStr:=0;
  1026. if length(S)>255 then
  1027. code:=256
  1028. else
  1029. begin
  1030. SS := S;
  1031. fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code);
  1032. end;
  1033. end;
  1034. {$ifndef CPU64}
  1035. Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc;
  1036. Var
  1037. SS : ShortString;
  1038. begin
  1039. fpc_Val_qword_WideStr:=0;
  1040. if length(S)>255 then
  1041. code:=256
  1042. else
  1043. begin
  1044. SS := S;
  1045. Val(SS,fpc_Val_qword_WideStr,Code);
  1046. end;
  1047. end;
  1048. Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc;
  1049. Var
  1050. SS : ShortString;
  1051. begin
  1052. fpc_Val_int64_WideStr:=0;
  1053. if length(S)>255 then
  1054. code:=256
  1055. else
  1056. begin
  1057. SS := S;
  1058. Val(SS,fpc_Val_int64_WideStr,Code);
  1059. end;
  1060. end;
  1061. {$endif CPU64}
  1062. procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc;
  1063. var
  1064. ss : shortstring;
  1065. begin
  1066. str_real(len,fr,d,treal_type(rt),ss);
  1067. s:=ss;
  1068. end;
  1069. Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc;
  1070. Var
  1071. SS : ShortString;
  1072. begin
  1073. Str (v:Len,SS);
  1074. S:=SS;
  1075. end;
  1076. Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc;
  1077. Var
  1078. SS : ShortString;
  1079. begin
  1080. str(v:Len,SS);
  1081. S:=SS;
  1082. end;
  1083. {$ifndef CPU64}
  1084. Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc;
  1085. Var
  1086. SS : ShortString;
  1087. begin
  1088. Str (v:Len,SS);
  1089. S:=SS;
  1090. end;
  1091. Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc;
  1092. Var
  1093. SS : ShortString;
  1094. begin
  1095. str(v:Len,SS);
  1096. S:=SS;
  1097. end;
  1098. {$endif CPU64}
  1099. function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1100. begin
  1101. if assigned(Source) then
  1102. Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0))
  1103. else
  1104. Result:=0;
  1105. end;
  1106. function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt;
  1107. var
  1108. i,j : SizeUInt;
  1109. w : word;
  1110. begin
  1111. result:=0;
  1112. if source=nil then
  1113. exit;
  1114. i:=0;
  1115. j:=0;
  1116. if assigned(Dest) then
  1117. begin
  1118. while (i<SourceChars) and (j<MaxDestBytes) do
  1119. begin
  1120. w:=word(Source[i]);
  1121. case w of
  1122. 0..$7f:
  1123. begin
  1124. Dest[j]:=char(w);
  1125. inc(j);
  1126. end;
  1127. $80..$7ff:
  1128. begin
  1129. if j+1>=MaxDestBytes then
  1130. break;
  1131. Dest[j]:=char($c0 or (w shr 6));
  1132. Dest[j+1]:=char($80 or (w and $3f));
  1133. inc(j,2);
  1134. end;
  1135. else
  1136. begin
  1137. if j+2>=MaxDestBytes then
  1138. break;
  1139. Dest[j]:=char($e0 or (w shr 12));
  1140. Dest[j+1]:=char($80 or ((w shr 6)and $3f));
  1141. Dest[j+2]:=char($80 or (w and $3f));
  1142. inc(j,3);
  1143. end;
  1144. end;
  1145. inc(i);
  1146. end;
  1147. if j>MaxDestBytes-1 then
  1148. j:=MaxDestBytes-1;
  1149. Dest[j]:=#0;
  1150. end
  1151. else
  1152. begin
  1153. while i<SourceChars do
  1154. begin
  1155. case word(Source[i]) of
  1156. $0..$7f:
  1157. inc(j);
  1158. $80..$7ff:
  1159. inc(j,2);
  1160. else
  1161. inc(j,3);
  1162. end;
  1163. end;
  1164. end;
  1165. result:=j+1;
  1166. end;
  1167. function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1168. begin
  1169. if assigned(Source) then
  1170. Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source))
  1171. else
  1172. Result:=0;
  1173. end;
  1174. function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt;
  1175. var
  1176. i,j : SizeUInt;
  1177. w: SizeUInt;
  1178. b : byte;
  1179. begin
  1180. if not assigned(Source) then
  1181. begin
  1182. result:=0;
  1183. exit;
  1184. end;
  1185. result:=SizeUInt(-1);
  1186. i:=0;
  1187. j:=0;
  1188. if assigned(Dest) then
  1189. begin
  1190. while (j<MaxDestChars) and (i<SourceBytes) do
  1191. begin
  1192. b:=byte(Source[i]);
  1193. w:=b;
  1194. inc(i);
  1195. // 2 or 3 bytes?
  1196. if b>=$80 then
  1197. begin
  1198. w:=b and $3f;
  1199. if i>=SourceBytes then
  1200. exit;
  1201. // 3 bytes?
  1202. if (b and $20)<>0 then
  1203. begin
  1204. b:=byte(Source[i]);
  1205. inc(i);
  1206. if i>=SourceBytes then
  1207. exit;
  1208. if (b and $c0)<>$80 then
  1209. exit;
  1210. w:=(w shl 6) or (b and $3f);
  1211. end;
  1212. b:=byte(Source[i]);
  1213. w:=(w shl 6) or (b and $3f);
  1214. if (b and $c0)<>$80 then
  1215. exit;
  1216. inc(i);
  1217. end;
  1218. Dest[j]:=WideChar(w);
  1219. inc(j);
  1220. end;
  1221. if j>=MaxDestChars then j:=MaxDestChars-1;
  1222. Dest[j]:=#0;
  1223. end
  1224. else
  1225. begin
  1226. while i<SourceBytes do
  1227. begin
  1228. b:=byte(Source[i]);
  1229. inc(i);
  1230. // 2 or 3 bytes?
  1231. if b>=$80 then
  1232. begin
  1233. if i>=SourceBytes then
  1234. exit;
  1235. // 3 bytes?
  1236. b := b and $3f;
  1237. if (b and $20)<>0 then
  1238. begin
  1239. b:=byte(Source[i]);
  1240. inc(i);
  1241. if i>=SourceBytes then
  1242. exit;
  1243. if (b and $c0)<>$80 then
  1244. exit;
  1245. end;
  1246. if (byte(Source[i]) and $c0)<>$80 then
  1247. exit;
  1248. inc(i);
  1249. end;
  1250. inc(j);
  1251. end;
  1252. end;
  1253. result:=j+1;
  1254. end;
  1255. function UTF8Encode(const s : WideString) : UTF8String;
  1256. var
  1257. i : SizeInt;
  1258. hs : UTF8String;
  1259. begin
  1260. result:='';
  1261. if s='' then
  1262. exit;
  1263. SetLength(hs,length(s)*3);
  1264. i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s));
  1265. if i>0 then
  1266. begin
  1267. SetLength(hs,i-1);
  1268. result:=hs;
  1269. end;
  1270. end;
  1271. function UTF8Decode(const s : UTF8String): WideString;
  1272. var
  1273. i : SizeInt;
  1274. hs : WideString;
  1275. begin
  1276. result:='';
  1277. if s='' then
  1278. exit;
  1279. SetLength(hs,length(s));
  1280. i:=Utf8ToUnicode(PWideChar(hs),length(hs)+1,pchar(s),length(s));
  1281. if i>0 then
  1282. begin
  1283. SetLength(hs,i-1);
  1284. result:=hs;
  1285. end;
  1286. end;
  1287. function AnsiToUtf8(const s : ansistring): UTF8String;{$ifdef SYSTEMINLINE}inline;{$endif}
  1288. begin
  1289. Result:=Utf8Encode(s);
  1290. end;
  1291. function Utf8ToAnsi(const s : UTF8String) : ansistring;{$ifdef SYSTEMINLINE}inline;{$endif}
  1292. begin
  1293. Result:=Utf8Decode(s);
  1294. end;
  1295. function WideStringToUCS4String(const s : WideString) : UCS4String;
  1296. var
  1297. i : SizeInt;
  1298. begin
  1299. setlength(result,length(s)+1);
  1300. for i:=1 to length(s) do
  1301. result[i-1]:=UCS4Char(s[i]);
  1302. result[length(s)]:=UCS4Char(0);
  1303. end;
  1304. function UCS4StringToWideString(const s : UCS4String) : WideString;
  1305. var
  1306. i : SizeInt;
  1307. begin
  1308. setlength(result,length(s)-1);
  1309. for i:=1 to length(s)-1 do
  1310. result[i]:=WideChar(s[i-1]);
  1311. end;
  1312. procedure unimplementedwidestring;
  1313. begin
  1314. HandleErrorFrame(215,get_frame);
  1315. end;
  1316. {$warnings off}
  1317. function GenericWideCase(const s : WideString) : WideString;
  1318. begin
  1319. unimplementedwidestring;
  1320. end;
  1321. function CompareWideString(const s1, s2 : WideString) : PtrInt;
  1322. begin
  1323. unimplementedwidestring;
  1324. end;
  1325. function CompareTextWideString(const s1, s2 : WideString): PtrInt;
  1326. begin
  1327. unimplementedwidestring;
  1328. end;
  1329. function CharLengthPChar(const Str: PChar): PtrInt;
  1330. begin
  1331. unimplementedwidestring;
  1332. end;
  1333. {$warnings on}
  1334. procedure initwidestringmanager;
  1335. begin
  1336. fillchar(widestringmanager,sizeof(widestringmanager),0);
  1337. widestringmanager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
  1338. widestringmanager.Ansi2WideMoveProc:=@defaultAnsi2WideMove;
  1339. widestringmanager.UpperWideStringProc:=@GenericWideCase;
  1340. widestringmanager.LowerWideStringProc:=@GenericWideCase;
  1341. widestringmanager.CompareWideStringProc:=@CompareWideString;
  1342. widestringmanager.CompareTextWideStringProc:=@CompareTextWideString;
  1343. widestringmanager.CharLengthPCharProc:=@CharLengthPChar;
  1344. end;