wstrings.inc 32 KB

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