2
0

wstrings.inc 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684
  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 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. Len : DWord;
  31. First : WideChar;
  32. end;
  33. Const
  34. WideRecLen = SizeOf(TWideRec);
  35. WideFirstOff = SizeOf(TWideRec)-sizeof(WideChar);
  36. {
  37. Default WideChar <-> Char conversion is to only convert the
  38. lower 127 chars, all others are translated to spaces.
  39. These routines can be overwritten for the Current Locale
  40. }
  41. procedure DefaultWide2AnsiMove(source:pwidechar;var dest:ansistring;cp : TSystemCodePage;len:SizeInt);
  42. var
  43. i : SizeInt;
  44. destp: PChar;
  45. begin
  46. setlength(dest,len);
  47. destp := PChar(Pointer(dest));
  48. for i:=1 to len do
  49. begin
  50. if word(source^)<256 then
  51. destp^:=char(word(source^))
  52. else
  53. destp^:='?';
  54. inc(source);
  55. inc(destp);
  56. end;
  57. end;
  58. procedure DefaultAnsi2WideMove(source:pchar;cp : TSystemCodePage;var dest:widestring;len:SizeInt);
  59. var
  60. i : SizeInt;
  61. begin
  62. setlength(dest,len);
  63. for i:=1 to len do
  64. begin
  65. dest[i]:=widechar(byte(source^));
  66. inc(source);
  67. end;
  68. end;
  69. {****************************************************************************
  70. Internal functions, not in interface.
  71. ****************************************************************************}
  72. procedure WideStringError;
  73. begin
  74. HandleErrorFrame(204,get_frame);
  75. end;
  76. {$ifdef WideStrDebug}
  77. Procedure DumpWideRec(S : Pointer);
  78. begin
  79. If S=Nil then
  80. Writeln ('String is nil')
  81. Else
  82. Begin
  83. With PWideRec(S-WideFirstOff)^ do
  84. begin
  85. Write ('(Len:',len);
  86. Writeln (' Ref: ',ref,')');
  87. end;
  88. end;
  89. end;
  90. {$endif}
  91. Function NewWideString(Len : SizeInt) : Pointer;
  92. {
  93. Allocate a new WideString on the heap.
  94. initialize it to zero length and reference count 1.
  95. }
  96. Var
  97. P : Pointer;
  98. begin
  99. {$ifdef MSWINDOWS}
  100. if winwidestringalloc then
  101. begin
  102. P:=SysAllocStringLen(nil,Len);
  103. if P=nil then
  104. WideStringError;
  105. end
  106. else
  107. {$endif MSWINDOWS}
  108. begin
  109. GetMem(P,Len*sizeof(WideChar)+WideRecLen);
  110. If P<>Nil then
  111. begin
  112. PWideRec(P)^.Len:=Len*2; { Initial length }
  113. PWideRec(P)^.First:=#0; { Terminating #0 }
  114. inc(p,WideFirstOff); { Points to string now }
  115. end
  116. else
  117. WideStringError;
  118. end;
  119. NewWideString:=P;
  120. end;
  121. Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[Public,Alias:'FPC_WIDESTR_DECR_REF']; compilerproc;
  122. {
  123. Decreases the ReferenceCount of a non constant widestring;
  124. If the reference count is zero, deallocate the string;
  125. }
  126. Begin
  127. If S=Nil then
  128. exit;
  129. {$ifdef MSWINDOWS}
  130. if winwidestringalloc then
  131. SysFreeString(S)
  132. else
  133. {$endif MSWINDOWS}
  134. begin
  135. Dec (S,WideFirstOff);
  136. Freemem(S);
  137. end;
  138. S:=Nil;
  139. end;
  140. { alias for internal use }
  141. Procedure fpc_WideStr_Decr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_DECR_REF'];
  142. Procedure fpc_WideStr_Incr_Ref(Var S : Pointer);[Public,Alias:'FPC_WIDESTR_INCR_REF']; compilerproc;
  143. var
  144. p : pointer;
  145. Begin
  146. If S=Nil then
  147. exit;
  148. p:=NewWidestring(length(WideString(S)));
  149. move(s^,p^,(length(WideString(s))+1)*sizeof(widechar)); // double #0 too
  150. s:=p;
  151. end;
  152. { alias for internal use }
  153. Procedure fpc_WideStr_Incr_Ref (Var S : Pointer);[external name 'FPC_WIDESTR_INCR_REF'];
  154. {$ifndef FPC_STRTOSHORTSTRINGPROC}
  155. function fpc_WideStr_To_ShortStr (high_of_res: SizeInt;const S2 : WideString): shortstring;[Public, alias: 'FPC_WIDESTR_TO_SHORTSTR']; compilerproc;
  156. {
  157. Converts a WideString to a ShortString;
  158. }
  159. Var
  160. Size : SizeInt;
  161. temp : ansistring;
  162. begin
  163. result:='';
  164. Size:=Length(S2);
  165. if Size>0 then
  166. begin
  167. If Size>high_of_res then
  168. Size:=high_of_res;
  169. widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,Size);
  170. result:=temp;
  171. end;
  172. end;
  173. {$else FPC_STRTOSHORTSTRINGPROC}
  174. procedure fpc_WideStr_To_ShortStr (out res: ShortString;const S2 : WideString); [Public, alias: 'FPC_WIDESTR_TO_SHORTSTR'];compilerproc;
  175. {
  176. Converts a WideString to a ShortString;
  177. }
  178. Var
  179. Size : SizeInt;
  180. temp : ansistring;
  181. begin
  182. res:='';
  183. Size:=Length(S2);
  184. if Size>0 then
  185. begin
  186. If Size>high(res) then
  187. Size:=high(res);
  188. widestringmanager.Wide2AnsiMoveProc(PWideChar(S2),temp,DefaultSystemCodePage,Size);
  189. res:=temp;
  190. end;
  191. end;
  192. {$endif FPC_STRTOSHORTSTRINGPROC}
  193. Function fpc_ShortStr_To_WideStr (Const S2 : ShortString): WideString;compilerproc;
  194. {
  195. Converts a ShortString to a WideString;
  196. }
  197. Var
  198. Size : SizeInt;
  199. begin
  200. result:='';
  201. Size:=Length(S2);
  202. if Size>0 then
  203. widestringmanager.Ansi2WideMoveProc(PChar(@S2[1]),DefaultSystemCodePage,result,Size);
  204. end;
  205. Function fpc_WideStr_To_AnsiStr (const S2 : WideString{$ifdef FPC_HAS_CPSTRING};cp : TSystemCodePage{$endif FPC_HAS_CPSTRING}): AnsiString; compilerproc;
  206. {
  207. Converts a WideString to an AnsiString
  208. }
  209. Var
  210. Size : SizeInt;
  211. {$ifndef FPC_HAS_CPSTRING}
  212. cp : TSystemCodePage;
  213. {$endif FPC_HAS_CPSTRING}
  214. begin
  215. {$ifndef FPC_HAS_CPSTRING}
  216. cp:=DefaultSystemCodePage;
  217. {$endif FPC_HAS_CPSTRING}
  218. result:='';
  219. Size:=Length(S2);
  220. if Size>0 then
  221. begin
  222. if (cp=CP_NONE) or (cp=0) then
  223. cp:=DefaultSystemCodePage;
  224. widestringmanager.Wide2AnsiMoveProc(PWideChar(Pointer(S2)),result,cp,Size);
  225. end;
  226. end;
  227. Function fpc_AnsiStr_To_WideStr (Const S2 : RawByteString): WideString; compilerproc;
  228. {
  229. Converts an AnsiString to a WideString;
  230. }
  231. Var
  232. Size : SizeInt;
  233. cp: TSystemCodePage;
  234. begin
  235. result:='';
  236. Size:=Length(S2);
  237. if Size>0 then
  238. begin
  239. cp:=StringCodePage(S2);
  240. if (cp=CP_NONE) or (cp=0) then
  241. cp:=DefaultSystemCodePage;
  242. widestringmanager.Ansi2WideMoveProc(PChar(S2),cp,result,Size);
  243. end;
  244. end;
  245. Function fpc_PWideChar_To_WideStr(const p : pwidechar): widestring; compilerproc;
  246. var
  247. Size : SizeInt;
  248. begin
  249. result:='';
  250. if p=nil then
  251. exit;
  252. Size := IndexWord(p^, -1, 0);
  253. Setlength(result,Size); // zero-terminates
  254. if Size>0 then
  255. Move(p^,PWideChar(Pointer(result))^,Size*sizeof(WideChar));
  256. end;
  257. { checked against the ansistring routine, 2001-05-27 (FK) }
  258. Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[Public,Alias:'FPC_WIDESTR_ASSIGN']; compilerproc;
  259. {
  260. Assigns S2 to S1 (S1:=S2), taking in account reference counts.
  261. }
  262. begin
  263. if S1=S2 then exit;
  264. if S2<>nil then
  265. begin
  266. {$ifdef MSWINDOWS}
  267. if winwidestringalloc then
  268. begin
  269. if SysReAllocStringLen(S1, S2, Length(WideString(S2))) = 0 then
  270. WideStringError;
  271. end
  272. else
  273. {$endif MSWINDOWS}
  274. begin
  275. SetLength(WideString(S1),length(WideString(S2)));
  276. move(s2^,s1^,(length(WideString(s1))+1)*sizeof(widechar));
  277. end;
  278. end
  279. else
  280. begin
  281. { Free S1 }
  282. fpc_widestr_decr_ref (S1);
  283. S1:=nil;
  284. end;
  285. end;
  286. { alias for internal use }
  287. Procedure fpc_WideStr_Assign (Var S1 : Pointer;S2 : Pointer);[external name 'FPC_WIDESTR_ASSIGN'];
  288. {$ifndef STR_CONCAT_PROCS}
  289. function fpc_WideStr_Concat (const S1,S2 : WideString): WideString; compilerproc;
  290. Var
  291. Size,Location : SizeInt;
  292. pc : pwidechar;
  293. begin
  294. { only assign if s1 or s2 is empty }
  295. if (S1='') then
  296. begin
  297. result:=s2;
  298. exit;
  299. end;
  300. if (S2='') then
  301. begin
  302. result:=s1;
  303. exit;
  304. end;
  305. Location:=Length(S1);
  306. Size:=length(S2);
  307. SetLength(result,Size+Location);
  308. pc:=pwidechar(result);
  309. Move(S1[1],pc^,Location*sizeof(WideChar));
  310. inc(pc,location);
  311. Move(S2[1],pc^,(Size+1)*sizeof(WideChar));
  312. end;
  313. function fpc_WideStr_Concat_multi (const sarr:array of Widestring): widestring; compilerproc;
  314. Var
  315. i : Longint;
  316. p : pointer;
  317. pc : pwidechar;
  318. Size,NewSize : SizeInt;
  319. begin
  320. { First calculate size of the result so we can do
  321. a single call to SetLength() }
  322. NewSize:=0;
  323. for i:=low(sarr) to high(sarr) do
  324. inc(Newsize,length(sarr[i]));
  325. SetLength(result,NewSize);
  326. pc:=pwidechar(result);
  327. for i:=low(sarr) to high(sarr) do
  328. begin
  329. p:=pointer(sarr[i]);
  330. if assigned(p) then
  331. begin
  332. Size:=length(widestring(p));
  333. Move(pwidechar(p)^,pc^,(Size+1)*sizeof(WideChar));
  334. inc(pc,size);
  335. end;
  336. end;
  337. end;
  338. {$else STR_CONCAT_PROCS}
  339. procedure fpc_WideStr_Concat (var DestS:Widestring;const S1,S2 : WideString); compilerproc;
  340. Var
  341. Size,Location : SizeInt;
  342. same : boolean;
  343. begin
  344. { only assign if s1 or s2 is empty }
  345. if (S1='') then
  346. begin
  347. DestS:=s2;
  348. exit;
  349. end;
  350. if (S2='') then
  351. begin
  352. DestS:=s1;
  353. exit;
  354. end;
  355. Location:=Length(S1);
  356. Size:=length(S2);
  357. { Use Pointer() typecasts to prevent extra conversion code }
  358. if Pointer(DestS)=Pointer(S1) then
  359. begin
  360. same:=Pointer(S1)=Pointer(S2);
  361. SetLength(DestS,Size+Location);
  362. if same then
  363. Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size)*sizeof(WideChar))
  364. else
  365. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  366. end
  367. else if Pointer(DestS)=Pointer(S2) then
  368. begin
  369. SetLength(DestS,Size+Location);
  370. Move(Pointer(DestS)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  371. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  372. end
  373. else
  374. begin
  375. DestS:='';
  376. SetLength(DestS,Size+Location);
  377. Move(Pointer(S1)^,Pointer(DestS)^,Location*sizeof(WideChar));
  378. Move(Pointer(S2)^,(Pointer(DestS)+Location*sizeof(WideChar))^,(Size+1)*sizeof(WideChar));
  379. end;
  380. end;
  381. procedure fpc_WideStr_Concat_multi (var DestS:Widestring;const sarr:array of Widestring); compilerproc;
  382. Var
  383. i : Longint;
  384. p,pc : pointer;
  385. Size,NewLen : SizeInt;
  386. DestTmp : Widestring;
  387. begin
  388. if high(sarr)=0 then
  389. begin
  390. DestS:='';
  391. exit;
  392. end;
  393. { First calculate size of the result so we can do
  394. a single call to SetLength() }
  395. NewLen:=0;
  396. for i:=low(sarr) to high(sarr) do
  397. inc(NewLen,length(sarr[i]));
  398. SetLength(DestTmp,NewLen);
  399. pc:=pwidechar(DestTmp);
  400. for i:=low(sarr) to high(sarr) do
  401. begin
  402. p:=pointer(sarr[i]);
  403. if assigned(p) then
  404. begin
  405. Size:=length(widestring(p));
  406. Move(p^,pc^,(Size+1)*sizeof(WideChar));
  407. inc(pc,size*sizeof(WideChar));
  408. end;
  409. end;
  410. DestS:=DestTmp;
  411. end;
  412. {$endif STR_CONCAT_PROCS}
  413. Function fpc_Char_To_WideStr(const c : Char): WideString; compilerproc;
  414. {
  415. Converts a Char to a WideString;
  416. }
  417. begin
  418. Setlength(fpc_Char_To_WideStr,1);
  419. fpc_Char_To_WideStr[1]:=c;
  420. end;
  421. Function fpc_WChar_To_WideStr(const c : WideChar): WideString; compilerproc;
  422. {
  423. Converts a WideChar to a WideString;
  424. }
  425. begin
  426. Setlength (fpc_WChar_To_WideStr,1);
  427. fpc_WChar_To_WideStr[1]:= c;
  428. end;
  429. Function fpc_WChar_To_AnsiStr(const c : WideChar{$ifdef FPC_HAS_CPSTRING};cp : TSystemCodePage{$endif FPC_HAS_CPSTRING}): AnsiString; compilerproc;
  430. {
  431. Converts a WideChar to a AnsiString;
  432. }
  433. begin
  434. widestringmanager.Wide2AnsiMoveProc(@c, fpc_WChar_To_AnsiStr,{$ifdef FPC_HAS_CPSTRING}cp{$else}TSystemCodePage(0){$endif FPC_HAS_CPSTRING}, 1);
  435. end;
  436. Function fpc_UChar_To_WideStr(const c : WideChar): WideString; compilerproc;
  437. {
  438. Converts a WideChar to a WideString;
  439. }
  440. begin
  441. Setlength (fpc_UChar_To_WideStr,1);
  442. fpc_UChar_To_WideStr[1]:= c;
  443. end;
  444. Function fpc_PChar_To_WideStr(const p : pchar): WideString; compilerproc;
  445. Var
  446. L : SizeInt;
  447. begin
  448. if (not assigned(p)) or (p[0]=#0) Then
  449. begin
  450. fpc_pchar_to_widestr := '';
  451. exit;
  452. end;
  453. l:=IndexChar(p^,-1,#0);
  454. widestringmanager.Ansi2WideMoveProc(P,DefaultSystemCodePage,fpc_PChar_To_WideStr,l);
  455. end;
  456. Function fpc_CharArray_To_WideStr(const arr: array of char; zerobased: boolean = true): WideString; compilerproc;
  457. var
  458. i : SizeInt;
  459. begin
  460. if (zerobased) then
  461. begin
  462. if (arr[0]=#0) Then
  463. begin
  464. fpc_chararray_to_widestr := '';
  465. exit;
  466. end;
  467. i:=IndexChar(arr,high(arr)+1,#0);
  468. if i = -1 then
  469. i := high(arr)+1;
  470. end
  471. else
  472. i := high(arr)+1;
  473. widestringmanager.Ansi2WideMoveProc(pchar(@arr),DefaultSystemCodePage,fpc_CharArray_To_WideStr,i);
  474. end;
  475. {$ifndef FPC_STRTOCHARARRAYPROC}
  476. { inside the compiler, the resulttype is modified to that of the actual }
  477. { chararray we're converting to (JM) }
  478. function fpc_widestr_to_chararray(arraysize: SizeInt; const src: WideString): fpc_big_chararray;[public,alias: 'FPC_WIDESTR_TO_CHARARRAY']; compilerproc;
  479. var
  480. len: SizeInt;
  481. temp: ansistring;
  482. begin
  483. len := length(src);
  484. { make sure we don't dereference src if it can be nil (JM) }
  485. if len > 0 then
  486. widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,len);
  487. len := length(temp);
  488. if len > arraysize then
  489. len := arraysize;
  490. {$push}
  491. {$r-}
  492. move(temp[1],fpc_widestr_to_chararray[0],len);
  493. fillchar(fpc_widestr_to_chararray[len],arraysize-len,0);
  494. {$pop}
  495. end;
  496. { inside the compiler, the resulttype is modified to that of the actual }
  497. { widechararray we're converting to (JM) }
  498. function fpc_widestr_to_widechararray(arraysize: SizeInt; const src: WideString): fpc_big_widechararray;[public,alias: 'FPC_WIDESTR_TO_WIDECHARARRAY']; compilerproc;
  499. var
  500. len: SizeInt;
  501. begin
  502. len := length(src);
  503. if len > arraysize then
  504. len := arraysize;
  505. {$push}
  506. {$r-}
  507. { make sure we don't try to access element 1 of the ansistring if it's nil }
  508. if len > 0 then
  509. move(src[1],fpc_widestr_to_widechararray[0],len*SizeOf(WideChar));
  510. fillchar(fpc_widestr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  511. {$pop}
  512. end;
  513. { inside the compiler, the resulttype is modified to that of the actual }
  514. { chararray we're converting to (JM) }
  515. function fpc_ansistr_to_widechararray(arraysize: SizeInt; const src: AnsiString): fpc_big_widechararray;[public,alias: 'FPC_ANSISTR_TO_WIDECHARARRAY']; compilerproc;
  516. var
  517. len: SizeInt;
  518. temp: widestring;
  519. begin
  520. len := length(src);
  521. { make sure we don't dereference src if it can be nil (JM) }
  522. if len > 0 then
  523. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  524. len := length(temp);
  525. if len > arraysize then
  526. len := arraysize;
  527. {$push}
  528. {$r-}
  529. move(temp[1],fpc_ansistr_to_widechararray[0],len*sizeof(widechar));
  530. fillchar(fpc_ansistr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  531. {$pop}
  532. end;
  533. function fpc_shortstr_to_widechararray(arraysize: SizeInt; const src: ShortString): fpc_big_widechararray;[public,alias: 'FPC_SHORTSTR_TO_WIDECHARARRAY']; compilerproc;
  534. var
  535. len: longint;
  536. temp : widestring;
  537. begin
  538. len := length(src);
  539. { make sure we don't access char 1 if length is 0 (JM) }
  540. if len > 0 then
  541. widestringmanager.ansi2widemoveproc(pchar(@src[1]),temp,len);
  542. len := length(temp);
  543. if len > arraysize then
  544. len := arraysize;
  545. {$push}
  546. {$r-}
  547. move(temp[1],fpc_shortstr_to_widechararray[0],len*sizeof(widechar));
  548. fillchar(fpc_shortstr_to_widechararray[len],(arraysize-len)*SizeOf(WideChar),0);
  549. {$pop}
  550. end;
  551. {$else ndef FPC_STRTOCHARARRAYPROC}
  552. procedure fpc_widestr_to_chararray(out res: array of char; const src: WideString); compilerproc;
  553. var
  554. len: SizeInt;
  555. temp: ansistring;
  556. begin
  557. len := length(src);
  558. { make sure we don't dereference src if it can be nil (JM) }
  559. if len > 0 then
  560. widestringmanager.wide2ansimoveproc(pwidechar(@src[1]),temp,DefaultSystemCodePage,len);
  561. len := length(temp);
  562. if len > length(res) then
  563. len := length(res);
  564. {$push}
  565. {$r-}
  566. move(temp[1],res[0],len);
  567. fillchar(res[len],length(res)-len,0);
  568. {$pop}
  569. end;
  570. procedure fpc_widestr_to_widechararray(out res: array of widechar; const src: WideString); compilerproc;
  571. var
  572. len: SizeInt;
  573. begin
  574. len := length(src);
  575. if len > length(res) then
  576. len := length(res);
  577. {$push}
  578. {$r-}
  579. { make sure we don't try to access element 1 of the ansistring if it's nil }
  580. if len > 0 then
  581. move(src[1],res[0],len*SizeOf(WideChar));
  582. fillchar(res[len],(length(res)-len)*SizeOf(WideChar),0);
  583. {$pop}
  584. end;
  585. {$endif ndef FPC_STRTOCHARARRAYPROC}
  586. Function fpc_WideStr_Compare(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE']; compilerproc;
  587. {
  588. Compares 2 WideStrings;
  589. The result is
  590. <0 if S1<S2
  591. 0 if S1=S2
  592. >0 if S1>S2
  593. }
  594. Var
  595. MaxI,Temp : SizeInt;
  596. begin
  597. if pointer(S1)=pointer(S2) then
  598. begin
  599. fpc_WideStr_Compare:=0;
  600. exit;
  601. end;
  602. Maxi:=Length(S1);
  603. temp:=Length(S2);
  604. If MaxI>Temp then
  605. MaxI:=Temp;
  606. Temp:=CompareWord(S1[1],S2[1],MaxI);
  607. if temp=0 then
  608. temp:=Length(S1)-Length(S2);
  609. fpc_WideStr_Compare:=Temp;
  610. end;
  611. Function fpc_WideStr_Compare_Equal(const S1,S2 : WideString): SizeInt;[Public,Alias : 'FPC_WIDESTR_COMPARE_EQUAL']; compilerproc;
  612. {
  613. Compares 2 WideStrings for equality only;
  614. The result is
  615. 0 if S1=S2
  616. <>0 if S1<>S2
  617. }
  618. Var
  619. MaxI : SizeInt;
  620. begin
  621. if pointer(S1)=pointer(S2) then
  622. exit(0);
  623. Maxi:=Length(S1);
  624. If MaxI<>Length(S2) then
  625. exit(-1)
  626. else
  627. exit(CompareWord(S1[1],S2[1],MaxI));
  628. end;
  629. {$ifdef VER2_4}
  630. // obsolete but needed for bootstrapping with 2.4
  631. Procedure fpc_WideStr_CheckZero(p : pointer);[Public,Alias : 'FPC_WIDESTR_CHECKZERO']; compilerproc;
  632. begin
  633. if p=nil then
  634. HandleErrorFrame(201,get_frame);
  635. end;
  636. Procedure fpc_WideStr_CheckRange(len,index : SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc;
  637. begin
  638. if (index>len div 2) or (Index<1) then
  639. HandleErrorFrame(201,get_frame);
  640. end;
  641. {$else VER2_4}
  642. Procedure fpc_WideStr_CheckRange(p: Pointer; index: SizeInt);[Public,Alias : 'FPC_WIDESTR_RANGECHECK']; compilerproc;
  643. begin
  644. if (p=nil) or (index>PWideRec(p-WideFirstOff)^.len div 2) or (Index<1) then
  645. HandleErrorFrame(201,get_frame);
  646. end;
  647. {$endif VER2_4}
  648. Procedure fpc_WideStr_SetLength(Var S : WideString; l : SizeInt);[Public,Alias : 'FPC_WIDESTR_SETLENGTH']; compilerproc;
  649. {
  650. Sets The length of string S to L.
  651. Makes sure S is unique, and contains enough room.
  652. }
  653. Var
  654. Temp : Pointer;
  655. movelen: SizeInt;
  656. begin
  657. if (l>0) then
  658. begin
  659. if Pointer(S)=nil then
  660. begin
  661. { Need a complete new string...}
  662. Pointer(s):=NewWideString(l);
  663. end
  664. { windows doesn't support reallocing widestrings, this code
  665. is anyways subject to be removed because widestrings shouldn't be
  666. ref. counted anymore (FK) }
  667. else
  668. if
  669. {$ifdef MSWINDOWS}
  670. not winwidestringalloc and
  671. {$endif MSWINDOWS}
  672. True
  673. then
  674. begin
  675. Dec(Pointer(S),WideFirstOff);
  676. if SizeUInt(L*sizeof(WideChar)+WideRecLen)>MemSize(Pointer(S)) then
  677. reallocmem(pointer(S), L*sizeof(WideChar)+WideRecLen);
  678. Inc(Pointer(S), WideFirstOff);
  679. end
  680. else
  681. begin
  682. { Reallocation is needed... }
  683. Temp:=Pointer(NewWideString(L));
  684. if Length(S)>0 then
  685. begin
  686. if l < succ(length(s)) then
  687. movelen := l
  688. { also move terminating null }
  689. else
  690. movelen := succ(length(s));
  691. Move(Pointer(S)^,Temp^,movelen * Sizeof(WideChar));
  692. end;
  693. fpc_widestr_decr_ref(Pointer(S));
  694. Pointer(S):=Temp;
  695. end;
  696. { Force nil termination in case it gets shorter }
  697. PWord(Pointer(S)+l*sizeof(WideChar))^:=0;
  698. {$ifdef MSWINDOWS}
  699. if not winwidestringalloc then
  700. {$endif MSWINDOWS}
  701. PWideRec(Pointer(S)-WideFirstOff)^.Len:=l*sizeof(WideChar);
  702. end
  703. else
  704. begin
  705. { Length=0 }
  706. if Pointer(S)<>nil then
  707. fpc_widestr_decr_ref (Pointer(S));
  708. Pointer(S):=Nil;
  709. end;
  710. end;
  711. {*****************************************************************************
  712. Public functions, In interface.
  713. *****************************************************************************}
  714. Function fpc_widestr_Unique(Var S : Pointer): Pointer; [Public,Alias : 'FPC_WIDESTR_UNIQUE']; compilerproc;
  715. begin
  716. pointer(result) := pointer(s);
  717. end;
  718. Function Fpc_WideStr_Copy (Const S : WideString; Index,Size : SizeInt) : WideString;compilerproc;
  719. var
  720. ResultAddress : Pointer;
  721. begin
  722. ResultAddress:=Nil;
  723. dec(index);
  724. if Index < 0 then
  725. Index := 0;
  726. { Check Size. Accounts for Zero-length S, the double check is needed because
  727. Size can be maxint and will get <0 when adding index }
  728. if (Size>Length(S)) or
  729. (Index+Size>Length(S)) then
  730. Size:=Length(S)-Index;
  731. If Size>0 then
  732. begin
  733. If Index<0 Then
  734. Index:=0;
  735. ResultAddress:=Pointer(NewWideString (Size));
  736. if ResultAddress<>Nil then
  737. begin
  738. Move (PWideChar(S)[Index],ResultAddress^,Size*sizeof(WideChar));
  739. PWideRec(ResultAddress-WideFirstOff)^.Len:=Size*sizeof(WideChar);
  740. PWideChar(ResultAddress+Size*sizeof(WideChar))^:=#0;
  741. end;
  742. end;
  743. fpc_widestr_decr_ref(Pointer(fpc_widestr_copy));
  744. Pointer(fpc_widestr_Copy):=ResultAddress;
  745. end;
  746. Function Pos (Const Substr : WideString; Const Source : WideString) : SizeInt;
  747. var
  748. i,MaxLen : SizeInt;
  749. pc : pwidechar;
  750. begin
  751. Pos:=0;
  752. if Length(SubStr)>0 then
  753. begin
  754. MaxLen:=Length(source)-Length(SubStr);
  755. i:=0;
  756. pc:=@source[1];
  757. while (i<=MaxLen) do
  758. begin
  759. inc(i);
  760. if (SubStr[1]=pc^) and
  761. (CompareWord(Substr[1],pc^,Length(SubStr))=0) then
  762. begin
  763. Pos:=i;
  764. exit;
  765. end;
  766. inc(pc);
  767. end;
  768. end;
  769. end;
  770. { Faster version for a widechar alone }
  771. Function Pos (c : WideChar; Const s : WideString) : SizeInt;
  772. var
  773. i: SizeInt;
  774. pc : pwidechar;
  775. begin
  776. pc:=@s[1];
  777. for i:=1 to length(s) do
  778. begin
  779. if pc^=c then
  780. begin
  781. pos:=i;
  782. exit;
  783. end;
  784. inc(pc);
  785. end;
  786. pos:=0;
  787. end;
  788. Function Pos (c : WideChar; Const s : RawByteString) : SizeInt;
  789. begin
  790. result:=Pos(c,WideString(s));
  791. end;
  792. Function Pos (c : RawByteString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  793. begin
  794. result:=Pos(WideString(c),s);
  795. end;
  796. Function Pos (c : ShortString; Const s : WideString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  797. begin
  798. result:=Pos(WideString(c),s);
  799. end;
  800. Function Pos (c : WideString; Const s : RawByteString) : SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  801. begin
  802. result:=Pos(c,WideString(s));
  803. end;
  804. { Faster version for a char alone. Must be implemented because }
  805. { pos(c: char; const s: shortstring) also exists, so otherwise }
  806. { using pos(char,pchar) will always call the shortstring version }
  807. { (exact match for first argument), also with $h+ (JM) }
  808. Function Pos (c : Char; Const s : WideString) : SizeInt;
  809. var
  810. i: SizeInt;
  811. wc : widechar;
  812. pc : pwidechar;
  813. begin
  814. wc:=c;
  815. pc:=@s[1];
  816. for i:=1 to length(s) do
  817. begin
  818. if pc^=wc then
  819. begin
  820. pos:=i;
  821. exit;
  822. end;
  823. inc(pc);
  824. end;
  825. pos:=0;
  826. end;
  827. Procedure Delete (Var S : WideString; Index,Size: SizeInt);
  828. Var
  829. LS : SizeInt;
  830. begin
  831. LS:=Length(S);
  832. if (Index>LS) or (Index<=0) or (Size<=0) then
  833. exit;
  834. UniqueString (S);
  835. { (Size+Index) will overflow if Size=MaxInt. }
  836. if Size>LS-Index then
  837. Size:=LS-Index+1;
  838. if Size<=LS-Index then
  839. begin
  840. Dec(Index);
  841. Move(PWideChar(S)[Index+Size],PWideChar(S)[Index],(LS-Index-Size+1)*sizeof(WideChar));
  842. end;
  843. Setlength(s,LS-Size);
  844. end;
  845. Procedure Insert (Const Source : WideString; Var S : WideString; Index : SizeInt);
  846. var
  847. Temp : WideString;
  848. LS : SizeInt;
  849. begin
  850. If Length(Source)=0 then
  851. exit;
  852. if index <= 0 then
  853. index := 1;
  854. Ls:=Length(S);
  855. if index > LS then
  856. index := LS+1;
  857. Dec(Index);
  858. Pointer(Temp) := NewWideString(Length(Source)+LS);
  859. SetLength(Temp,Length(Source)+LS);
  860. If Index>0 then
  861. move (PWideChar(S)^,PWideChar(Temp)^,Index*sizeof(WideChar));
  862. Move (PWideChar(Source)^,PWideChar(Temp)[Index],Length(Source)*sizeof(WideChar));
  863. If (LS-Index)>0 then
  864. Move(PWideChar(S)[Index],PWideChar(temp)[Length(Source)+index],(LS-Index)*sizeof(WideChar));
  865. S:=Temp;
  866. end;
  867. function UpCase(const s : WideString) : WideString;
  868. begin
  869. result:=widestringmanager.UpperWideStringProc(s);
  870. end;
  871. Procedure SetString (Out S : WideString; Buf : PWideChar; Len : SizeInt);
  872. begin
  873. SetLength(S,Len);
  874. If (Buf<>Nil) and (Len>0) then
  875. Move (Buf[0],S[1],Len*sizeof(WideChar));
  876. end;
  877. Procedure SetString (Out S : WideString; Buf : PChar; Len : SizeInt);
  878. begin
  879. SetLength(S,Len);
  880. If (Buf<>Nil) and (Len>0) then
  881. widestringmanager.Ansi2WideMoveProc(Buf,DefaultSystemCodePage,S,Len);
  882. end;
  883. {$ifndef FPUNONE}
  884. Function fpc_Val_Real_WideStr(Const S : WideString; out Code : ValSInt): ValReal; [public, alias:'FPC_VAL_REAL_WIDESTR']; compilerproc;
  885. Var
  886. SS : String;
  887. begin
  888. fpc_Val_Real_WideStr := 0;
  889. if length(S) > 255 then
  890. code := 256
  891. else
  892. begin
  893. SS := S;
  894. Val(SS,fpc_Val_Real_WideStr,code);
  895. end;
  896. end;
  897. {$endif}
  898. function fpc_val_enum_widestr(str2ordindex:pointer;const s:widestring;out code:valsint):longint;compilerproc;
  899. var ss:shortstring;
  900. begin
  901. if length(s)>255 then
  902. code:=256
  903. else
  904. begin
  905. ss:=s;
  906. val(ss,fpc_val_enum_widestr,code);
  907. end;
  908. end;
  909. Function fpc_Val_Currency_WideStr(Const S : WideString; out Code : ValSInt): Currency; [public, alias:'FPC_VAL_CURRENCY_WIDESTR']; compilerproc;
  910. Var
  911. SS : String;
  912. begin
  913. if length(S) > 255 then
  914. begin
  915. fpc_Val_Currency_WideStr:=0;
  916. code := 256;
  917. end
  918. else
  919. begin
  920. SS := S;
  921. Val(SS,fpc_Val_Currency_WideStr,code);
  922. end;
  923. end;
  924. Function fpc_Val_UInt_WideStr (Const S : WideString; out Code : ValSInt): ValUInt; [public, alias:'FPC_VAL_UINT_WIDESTR']; compilerproc;
  925. Var
  926. SS : ShortString;
  927. begin
  928. fpc_Val_UInt_WideStr := 0;
  929. if length(S) > 255 then
  930. code := 256
  931. else
  932. begin
  933. SS := S;
  934. Val(SS,fpc_Val_UInt_WideStr,code);
  935. end;
  936. end;
  937. Function fpc_Val_SInt_WideStr (DestSize: SizeInt; Const S : WideString; out Code : ValSInt): ValSInt; [public, alias:'FPC_VAL_SINT_WIDESTR']; compilerproc;
  938. Var
  939. SS : ShortString;
  940. begin
  941. fpc_Val_SInt_WideStr:=0;
  942. if length(S)>255 then
  943. code:=256
  944. else
  945. begin
  946. SS := S;
  947. fpc_Val_SInt_WideStr := int_Val_SInt_ShortStr(DestSize,SS,Code);
  948. end;
  949. end;
  950. {$ifndef CPU64}
  951. Function fpc_Val_qword_WideStr (Const S : WideString; out Code : ValSInt): qword; [public, alias:'FPC_VAL_QWORD_WIDESTR']; compilerproc;
  952. Var
  953. SS : ShortString;
  954. begin
  955. fpc_Val_qword_WideStr:=0;
  956. if length(S)>255 then
  957. code:=256
  958. else
  959. begin
  960. SS := S;
  961. Val(SS,fpc_Val_qword_WideStr,Code);
  962. end;
  963. end;
  964. Function fpc_Val_int64_WideStr (Const S : WideString; out Code : ValSInt): Int64; [public, alias:'FPC_VAL_INT64_WIDESTR']; compilerproc;
  965. Var
  966. SS : ShortString;
  967. begin
  968. fpc_Val_int64_WideStr:=0;
  969. if length(S)>255 then
  970. code:=256
  971. else
  972. begin
  973. SS := S;
  974. Val(SS,fpc_Val_int64_WideStr,Code);
  975. end;
  976. end;
  977. {$endif CPU64}
  978. {$ifndef FPUNONE}
  979. procedure fpc_WideStr_Float(d : ValReal;len,fr,rt : SizeInt;out s : WideString);compilerproc;
  980. var
  981. ss : shortstring;
  982. begin
  983. str_real(len,fr,d,treal_type(rt),ss);
  984. s:=ss;
  985. end;
  986. {$endif}
  987. procedure fpc_widestr_enum(ordinal,len:sizeint;typinfo,ord2strindex:pointer;out s:widestring);compilerproc;
  988. var ss:shortstring;
  989. begin
  990. fpc_shortstr_enum(ordinal,len,typinfo,ord2strindex,ss);
  991. s:=ss;
  992. end;
  993. procedure fpc_widestr_bool(b : boolean;len:sizeint;out s:widestring);compilerproc;
  994. var ss:shortstring;
  995. begin
  996. fpc_shortstr_bool(b,len,ss);
  997. s:=ss;
  998. end;
  999. {$ifdef FPC_HAS_STR_CURRENCY}
  1000. procedure fpc_WideStr_Currency(c : Currency;len,fr : SizeInt;out s : WideString);compilerproc;
  1001. var
  1002. ss : shortstring;
  1003. begin
  1004. str(c:len:fr,ss);
  1005. s:=ss;
  1006. end;
  1007. {$endif FPC_HAS_STR_CURRENCY}
  1008. Procedure fpc_WideStr_SInt(v : ValSint; Len : SizeInt; out S : WideString);compilerproc;
  1009. Var
  1010. SS : ShortString;
  1011. begin
  1012. Str (v:Len,SS);
  1013. S:=SS;
  1014. end;
  1015. Procedure fpc_WideStr_UInt(v : ValUInt;Len : SizeInt; out S : WideString);compilerproc;
  1016. Var
  1017. SS : ShortString;
  1018. begin
  1019. str(v:Len,SS);
  1020. S:=SS;
  1021. end;
  1022. {$ifndef CPU64}
  1023. Procedure fpc_WideStr_Int64(v : Int64; Len : SizeInt; out S : WideString);compilerproc;
  1024. Var
  1025. SS : ShortString;
  1026. begin
  1027. Str (v:Len,SS);
  1028. S:=SS;
  1029. end;
  1030. Procedure fpc_WideStr_Qword(v : Qword;Len : SizeInt; out S : WideString);compilerproc;
  1031. Var
  1032. SS : ShortString;
  1033. begin
  1034. str(v:Len,SS);
  1035. S:=SS;
  1036. end;
  1037. {$endif CPU64}
  1038. { converts an utf-16 code point or surrogate pair to utf-32 }
  1039. function utf16toutf32(const S: WideString; const index: SizeInt; out len: longint): UCS4Char; [public, alias: 'FPC_WIDETOUTF32'];
  1040. var
  1041. w: widechar;
  1042. begin
  1043. { UTF-16 points in the range #$0-#$D7FF and #$E000-#$FFFF }
  1044. { are the same in UTF-32 }
  1045. w:=s[index];
  1046. if (w<=#$d7ff) or
  1047. (w>=#$e000) then
  1048. begin
  1049. result:=UCS4Char(w);
  1050. len:=1;
  1051. end
  1052. { valid surrogate pair? }
  1053. else if (w<=#$dbff) and
  1054. { w>=#$d7ff check not needed, checked above }
  1055. (index<length(s)) and
  1056. (s[index+1]>=#$dc00) and
  1057. (s[index+1]<=#$dfff) then
  1058. { convert the surrogate pair to UTF-32 }
  1059. begin
  1060. result:=(UCS4Char(w)-$d800) shl 10 + (UCS4Char(s[index+1])-$dc00) + $10000;
  1061. len:=2;
  1062. end
  1063. else
  1064. { invalid surrogate -> do nothing }
  1065. begin
  1066. result:=UCS4Char(w);
  1067. len:=1;
  1068. end;
  1069. end;
  1070. function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1071. begin
  1072. if assigned(Source) then
  1073. Result:=UnicodeToUtf8(Dest,MaxBytes,Source,IndexWord(Source^,-1,0))
  1074. else
  1075. Result:=0;
  1076. end;
  1077. function UnicodeToUtf8(Dest: PChar; MaxDestBytes: SizeUInt; Source: PWideChar; SourceChars: SizeUInt): SizeUInt;
  1078. var
  1079. i,j : SizeUInt;
  1080. w : word;
  1081. lw : longword;
  1082. len : longint;
  1083. begin
  1084. result:=0;
  1085. if source=nil then
  1086. exit;
  1087. i:=0;
  1088. j:=0;
  1089. if assigned(Dest) then
  1090. begin
  1091. while (i<SourceChars) and (j<MaxDestBytes) do
  1092. begin
  1093. w:=word(Source[i]);
  1094. case w of
  1095. 0..$7f:
  1096. begin
  1097. Dest[j]:=char(w);
  1098. inc(j);
  1099. end;
  1100. $80..$7ff:
  1101. begin
  1102. if j+1>=MaxDestBytes then
  1103. break;
  1104. Dest[j]:=char($c0 or (w shr 6));
  1105. Dest[j+1]:=char($80 or (w and $3f));
  1106. inc(j,2);
  1107. end;
  1108. $800..$d7ff,$e000..$ffff:
  1109. begin
  1110. if j+2>=MaxDestBytes then
  1111. break;
  1112. Dest[j]:=char($e0 or (w shr 12));
  1113. Dest[j+1]:=char($80 or ((w shr 6) and $3f));
  1114. Dest[j+2]:=char($80 or (w and $3f));
  1115. inc(j,3);
  1116. end;
  1117. $d800..$dbff:
  1118. {High Surrogates}
  1119. begin
  1120. if j+3>=MaxDestBytes then
  1121. break;
  1122. if (i<sourcechars-1) and
  1123. (word(Source[i+1]) >= $dc00) and
  1124. (word(Source[i+1]) <= $dfff) then
  1125. begin
  1126. lw:=longword(utf16toutf32(Source[i] + Source[i+1], 1, len));
  1127. Dest[j]:=char($f0 or (lw shr 18));
  1128. Dest[j+1]:=char($80 or ((lw shr 12) and $3f));
  1129. Dest[j+2]:=char($80 or ((lw shr 6) and $3f));
  1130. Dest[j+3]:=char($80 or (lw and $3f));
  1131. inc(j,4);
  1132. inc(i);
  1133. end;
  1134. end;
  1135. end;
  1136. inc(i);
  1137. end;
  1138. if j>SizeUInt(MaxDestBytes-1) then
  1139. j:=MaxDestBytes-1;
  1140. Dest[j]:=#0;
  1141. end
  1142. else
  1143. begin
  1144. while i<SourceChars do
  1145. begin
  1146. case word(Source[i]) of
  1147. $0..$7f:
  1148. inc(j);
  1149. $80..$7ff:
  1150. inc(j,2);
  1151. $800..$d7ff,$e000..$ffff:
  1152. inc(j,3);
  1153. $d800..$dbff:
  1154. begin
  1155. if (i<sourcechars-1) and
  1156. (word(Source[i+1]) >= $dc00) and
  1157. (word(Source[i+1]) <= $dfff) then
  1158. begin
  1159. inc(j,4);
  1160. inc(i);
  1161. end;
  1162. end;
  1163. end;
  1164. inc(i);
  1165. end;
  1166. end;
  1167. result:=j+1;
  1168. end;
  1169. function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: SizeInt): SizeInt;{$ifdef SYSTEMINLINE}inline;{$endif}
  1170. begin
  1171. if assigned(Source) then
  1172. Result:=Utf8ToUnicode(Dest,MaxChars,Source,strlen(Source))
  1173. else
  1174. Result:=0;
  1175. end;
  1176. function UTF8ToUnicode(Dest: PWideChar; MaxDestChars: SizeUInt; Source: PChar; SourceBytes: SizeUInt): SizeUInt;
  1177. const
  1178. UNICODE_INVALID=63;
  1179. var
  1180. InputUTF8: SizeUInt;
  1181. IBYTE: BYTE;
  1182. OutputUnicode: SizeUInt;
  1183. PRECHAR: SizeUInt;
  1184. TempBYTE: BYTE;
  1185. CharLen: SizeUint;
  1186. LookAhead: SizeUInt;
  1187. UC: SizeUInt;
  1188. begin
  1189. if not assigned(Source) then
  1190. begin
  1191. result:=0;
  1192. exit;
  1193. end;
  1194. result:=SizeUInt(-1);
  1195. InputUTF8:=0;
  1196. OutputUnicode:=0;
  1197. PreChar:=0;
  1198. if Assigned(Dest) Then
  1199. begin
  1200. while (OutputUnicode<MaxDestChars) and (InputUTF8<SourceBytes) do
  1201. begin
  1202. IBYTE:=byte(Source[InputUTF8]);
  1203. if (IBYTE and $80) = 0 then
  1204. begin
  1205. //One character US-ASCII, convert it to unicode
  1206. if IBYTE = 10 then
  1207. begin
  1208. If (PreChar<>13) and FALSE then
  1209. begin
  1210. //Expand to crlf, conform UTF-8.
  1211. //This procedure will break the memory alocation by
  1212. //FPC for the widestring, so never use it. Condition never true due the "and FALSE".
  1213. if OutputUnicode+1<MaxDestChars then
  1214. begin
  1215. Dest[OutputUnicode]:=WideChar(13);
  1216. inc(OutputUnicode);
  1217. Dest[OutputUnicode]:=WideChar(10);
  1218. inc(OutputUnicode);
  1219. PreChar:=10;
  1220. end
  1221. else
  1222. begin
  1223. Dest[OutputUnicode]:=WideChar(13);
  1224. inc(OutputUnicode);
  1225. end;
  1226. end
  1227. else
  1228. begin
  1229. Dest[OutputUnicode]:=WideChar(IBYTE);
  1230. inc(OutputUnicode);
  1231. PreChar:=IBYTE;
  1232. end;
  1233. end
  1234. else
  1235. begin
  1236. Dest[OutputUnicode]:=WideChar(IBYTE);
  1237. inc(OutputUnicode);
  1238. PreChar:=IBYTE;
  1239. end;
  1240. inc(InputUTF8);
  1241. end
  1242. else
  1243. begin
  1244. TempByte:=IBYTE;
  1245. CharLen:=0;
  1246. while (TempBYTE and $80)<>0 do
  1247. begin
  1248. TempBYTE:=(TempBYTE shl 1) and $FE;
  1249. inc(CharLen);
  1250. end;
  1251. //Test for the "CharLen" conforms UTF-8 string
  1252. //This means the 10xxxxxx pattern.
  1253. if SizeUInt(InputUTF8+CharLen-1)>SourceBytes then
  1254. begin
  1255. //Insuficient chars in string to decode
  1256. //UTF-8 array. Fallback to single char.
  1257. CharLen:= 1;
  1258. end;
  1259. for LookAhead := 1 to CharLen-1 do
  1260. begin
  1261. if ((byte(Source[InputUTF8+LookAhead]) and $80)<>$80) or
  1262. ((byte(Source[InputUTF8+LookAhead]) and $40)<>$00) then
  1263. begin
  1264. //Invalid UTF-8 sequence, fallback.
  1265. CharLen:= LookAhead;
  1266. break;
  1267. end;
  1268. end;
  1269. UC:=$FFFF;
  1270. case CharLen of
  1271. 1: begin
  1272. //Not valid UTF-8 sequence
  1273. UC:=UNICODE_INVALID;
  1274. end;
  1275. 2: begin
  1276. //Two bytes UTF, convert it
  1277. UC:=(byte(Source[InputUTF8]) and $1F) shl 6;
  1278. UC:=UC or (byte(Source[InputUTF8+1]) and $3F);
  1279. if UC <= $7F then
  1280. begin
  1281. //Invalid UTF sequence.
  1282. UC:=UNICODE_INVALID;
  1283. end;
  1284. end;
  1285. 3: begin
  1286. //Three bytes, convert it to unicode
  1287. UC:= (byte(Source[InputUTF8]) and $0F) shl 12;
  1288. UC:= UC or ((byte(Source[InputUTF8+1]) and $3F) shl 6);
  1289. UC:= UC or ((byte(Source[InputUTF8+2]) and $3F));
  1290. if (UC <= $7FF) or (UC >= $FFFE) or ((UC >= $D800) and (UC <= $DFFF)) then
  1291. begin
  1292. //Invalid UTF-8 sequence
  1293. UC:= UNICODE_INVALID;
  1294. End;
  1295. end;
  1296. 4: begin
  1297. //Four bytes, convert it to two unicode characters
  1298. UC:= (byte(Source[InputUTF8]) and $07) shl 18;
  1299. UC:= UC or ((byte(Source[InputUTF8+1]) and $3F) shl 12);
  1300. UC:= UC or ((byte(Source[InputUTF8+2]) and $3F) shl 6);
  1301. UC:= UC or ((byte(Source[InputUTF8+3]) and $3F));
  1302. if (UC < $10000) or (UC > $10FFFF) then
  1303. begin
  1304. UC:= UNICODE_INVALID;
  1305. end
  1306. else
  1307. begin
  1308. { only store pair if room }
  1309. dec(UC,$10000);
  1310. if (OutputUnicode<MaxDestChars-1) then
  1311. begin
  1312. Dest[OutputUnicode]:=WideChar(UC shr 10 + $D800);
  1313. inc(OutputUnicode);
  1314. UC:=(UC and $3ff) + $DC00;
  1315. end
  1316. else
  1317. begin
  1318. InputUTF8:= InputUTF8 + CharLen;
  1319. { don't store anything }
  1320. CharLen:=0;
  1321. end;
  1322. end;
  1323. end;
  1324. 5,6,7: begin
  1325. //Invalid UTF8 to unicode conversion,
  1326. //mask it as invalid UNICODE too.
  1327. UC:=UNICODE_INVALID;
  1328. end;
  1329. end;
  1330. if CharLen > 0 then
  1331. begin
  1332. PreChar:=UC;
  1333. Dest[OutputUnicode]:=WideChar(UC);
  1334. inc(OutputUnicode);
  1335. end;
  1336. InputUTF8:= InputUTF8 + CharLen;
  1337. end;
  1338. end;
  1339. Result:=OutputUnicode+1;
  1340. end
  1341. else
  1342. begin
  1343. while (InputUTF8<SourceBytes) do
  1344. begin
  1345. IBYTE:=byte(Source[InputUTF8]);
  1346. if (IBYTE and $80) = 0 then
  1347. begin
  1348. //One character US-ASCII, convert it to unicode
  1349. if IBYTE = 10 then
  1350. begin
  1351. if (PreChar<>13) and FALSE then
  1352. begin
  1353. //Expand to crlf, conform UTF-8.
  1354. //This procedure will break the memory alocation by
  1355. //FPC for the widestring, so never use it. Condition never true due the "and FALSE".
  1356. inc(OutputUnicode,2);
  1357. PreChar:=10;
  1358. end
  1359. else
  1360. begin
  1361. inc(OutputUnicode);
  1362. PreChar:=IBYTE;
  1363. end;
  1364. end
  1365. else
  1366. begin
  1367. inc(OutputUnicode);
  1368. PreChar:=IBYTE;
  1369. end;
  1370. inc(InputUTF8);
  1371. end
  1372. else
  1373. begin
  1374. TempByte:=IBYTE;
  1375. CharLen:=0;
  1376. while (TempBYTE and $80)<>0 do
  1377. begin
  1378. TempBYTE:=(TempBYTE shl 1) and $FE;
  1379. inc(CharLen);
  1380. end;
  1381. //Test for the "CharLen" conforms UTF-8 string
  1382. //This means the 10xxxxxx pattern.
  1383. if SizeUInt(InputUTF8+CharLen-1)>SourceBytes then
  1384. begin
  1385. //Insuficient chars in string to decode
  1386. //UTF-8 array. Fallback to single char.
  1387. CharLen:= 1;
  1388. end;
  1389. for LookAhead := 1 to CharLen-1 do
  1390. begin
  1391. if ((byte(Source[InputUTF8+LookAhead]) and $80)<>$80) or
  1392. ((byte(Source[InputUTF8+LookAhead]) and $40)<>$00) then
  1393. begin
  1394. //Invalid UTF-8 sequence, fallback.
  1395. CharLen:= LookAhead;
  1396. break;
  1397. end;
  1398. end;
  1399. UC:=$FFFF;
  1400. case CharLen of
  1401. 1: begin
  1402. //Not valid UTF-8 sequence
  1403. UC:=UNICODE_INVALID;
  1404. end;
  1405. 2: begin
  1406. //Two bytes UTF, convert it
  1407. UC:=(byte(Source[InputUTF8]) and $1F) shl 6;
  1408. UC:=UC or (byte(Source[InputUTF8+1]) and $3F);
  1409. if UC <= $7F then
  1410. begin
  1411. //Invalid UTF sequence.
  1412. UC:=UNICODE_INVALID;
  1413. end;
  1414. end;
  1415. 3: begin
  1416. //Three bytes, convert it to unicode
  1417. UC:= (byte(Source[InputUTF8]) and $0F) shl 12;
  1418. UC:= UC or ((byte(Source[InputUTF8+1]) and $3F) shl 6);
  1419. UC:= UC or ((byte(Source[InputUTF8+2]) and $3F));
  1420. If (UC <= $7FF) or (UC >= $FFFE) or ((UC >= $D800) and (UC <= $DFFF)) then
  1421. begin
  1422. //Invalid UTF-8 sequence
  1423. UC:= UNICODE_INVALID;
  1424. end;
  1425. end;
  1426. 4: begin
  1427. //Four bytes, convert it to two unicode characters
  1428. UC:= (byte(Source[InputUTF8]) and $07) shl 18;
  1429. UC:= UC or ((byte(Source[InputUTF8+1]) and $3F) shl 12);
  1430. UC:= UC or ((byte(Source[InputUTF8+2]) and $3F) shl 6);
  1431. UC:= UC or ((byte(Source[InputUTF8+3]) and $3F));
  1432. if (UC < $10000) or (UC > $10FFFF) then
  1433. UC:= UNICODE_INVALID
  1434. else
  1435. { extra character character }
  1436. inc(OutputUnicode);
  1437. end;
  1438. 5,6,7: begin
  1439. //Invalid UTF8 to unicode conversion,
  1440. //mask it as invalid UNICODE too.
  1441. UC:=UNICODE_INVALID;
  1442. end;
  1443. end;
  1444. if CharLen > 0 then
  1445. begin
  1446. PreChar:=UC;
  1447. inc(OutputUnicode);
  1448. end;
  1449. InputUTF8:= InputUTF8 + CharLen;
  1450. end;
  1451. end;
  1452. Result:=OutputUnicode+1;
  1453. end;
  1454. end;
  1455. function UTF8Encode(const s : WideString) : RawByteString;
  1456. var
  1457. i : SizeInt;
  1458. hs : UTF8String;
  1459. begin
  1460. result:='';
  1461. if s='' then
  1462. exit;
  1463. SetLength(hs,length(s)*3);
  1464. i:=UnicodeToUtf8(pchar(hs),length(hs)+1,PWideChar(s),length(s));
  1465. if i>0 then
  1466. begin
  1467. SetLength(hs,i-1);
  1468. result:=hs;
  1469. end;
  1470. end;
  1471. const
  1472. SNoWidestrings = 'This binary has no widestrings support compiled in.';
  1473. SRecompileWithWidestrings = 'Recompile the application with a widestrings-manager in the program uses clause.';
  1474. procedure unimplementedwidestring;
  1475. begin
  1476. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  1477. If IsConsole then
  1478. begin
  1479. Writeln(StdErr,SNoWidestrings);
  1480. Writeln(StdErr,SRecompileWithWidestrings);
  1481. end;
  1482. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  1483. HandleErrorFrame(233,get_frame);
  1484. end;
  1485. {$warnings off}
  1486. function GenericWideCase(const s : WideString) : WideString;
  1487. begin
  1488. unimplementedwidestring;
  1489. end;
  1490. function CompareWideString(const s1, s2 : WideString) : PtrInt;
  1491. begin
  1492. unimplementedwidestring;
  1493. end;
  1494. function CompareTextWideString(const s1, s2 : WideString): PtrInt;
  1495. begin
  1496. unimplementedwidestring;
  1497. end;
  1498. {$warnings on}
  1499. function DefaultCharLengthPChar(const Str: PChar): PtrInt;forward;
  1500. function DefaultCodePointLength(const Str: PChar; MaxLookAead: PtrInt): Ptrint;forward;
  1501. procedure initwidestringmanager;
  1502. begin
  1503. fillchar(widestringmanager,sizeof(widestringmanager),0);
  1504. {$ifndef HAS_WIDESTRINGMANAGER}
  1505. widestringmanager.Wide2AnsiMoveProc:=@DefaultWide2AnsiMove;
  1506. widestringmanager.Ansi2WideMoveProc:=@DefaultAnsi2WideMove;
  1507. widestringmanager.UpperWideStringProc:=@GenericWideCase;
  1508. widestringmanager.LowerWideStringProc:=@GenericWideCase;
  1509. {$endif HAS_WIDESTRINGMANAGER}
  1510. widestringmanager.CompareWideStringProc:=@CompareWideString;
  1511. widestringmanager.CompareTextWideStringProc:=@CompareTextWideString;
  1512. widestringmanager.CharLengthPCharProc:=@DefaultCharLengthPChar;
  1513. widestringmanager.CodePointLengthProc:=@DefaultCodePointLength;
  1514. end;