wstrings.inc 43 KB

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