2
0

fpwidestring.pp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. unit fpwidestring;
  2. {$mode objfpc}
  3. interface
  4. uses
  5. unicodedata;
  6. {$i rtldefs.inc}
  7. function SetActiveCollation(const AName : UnicodeString) : Boolean;
  8. function SetActiveCollation(const ACollation : PUCA_DataBook) : Boolean;
  9. function GetActiveCollation() : PUCA_DataBook;
  10. var
  11. DefaultCollationName : UnicodeString = '';
  12. implementation
  13. uses
  14. {$ifdef MSWINDOWS}
  15. Windows,
  16. {$endif MSWINDOWS}
  17. {$ifdef Unix}
  18. unixcp,
  19. {$endif}
  20. charset;
  21. procedure fpc_rangeerror; [external name 'FPC_RANGEERROR'];
  22. {$ifdef MSWINDOWS}
  23. function GetACP:UINT; external 'kernel32' name 'GetACP';
  24. {$endif MSWINDOWS}
  25. const
  26. IgnoreInvalidSequenceFlag = True;
  27. var
  28. OldManager : TUnicodeStringManager;
  29. {$ifdef FPC_HAS_FEATURE_THREADING}
  30. ThreadVar
  31. {$else FPC_HAS_FEATURE_THREADING}
  32. Var
  33. {$endif FPC_HAS_FEATURE_THREADING}
  34. current_DefaultSystemCodePage : TSystemCodePage;
  35. current_Map : punicodemap;
  36. current_Collation : record
  37. DataPtr : PUCA_DataBook;
  38. Data : TUCA_DataBook;
  39. end;
  40. function SetActiveCollation(const ACollation : PUCA_DataBook) : Boolean;
  41. begin
  42. Result := (ACollation <> nil);
  43. if Result then begin
  44. current_Collation.Data := ACollation^;
  45. current_Collation.DataPtr := @current_Collation.Data;
  46. end;
  47. end;
  48. function SetActiveCollation(const AName : UnicodeString) : Boolean;
  49. var
  50. c : PUCA_DataBook;
  51. begin
  52. c:=FindCollation(AName);
  53. Result := (c <> nil);
  54. if Result then
  55. Result := SetActiveCollation(c);
  56. end;
  57. function GetActiveCollation() : PUCA_DataBook;
  58. begin
  59. Result := current_Collation.DataPtr;
  60. end;
  61. {procedure error_CpNotFound(ACodePage:TSystemCodePage);
  62. begin
  63. System.error(reCodesetConversion);
  64. end;}
  65. procedure InitThread;
  66. var
  67. c : PUCA_DataBook;
  68. begin
  69. current_DefaultSystemCodePage:=DefaultSystemCodePage;
  70. current_Map:=getmap(current_DefaultSystemCodePage);
  71. c:=nil;
  72. if (DefaultCollationName<>'') then
  73. c:=FindCollation(DefaultCollationName);
  74. if (c=nil) and (GetCollationCount()>0) then
  75. c:=FindCollation(0);
  76. if (c<>nil) then
  77. SetActiveCollation(c);
  78. end;
  79. procedure FiniThread;
  80. begin
  81. current_Map:=nil;
  82. end;
  83. function FindMap(const cp: TSystemCodePage): punicodemap;inline;
  84. begin
  85. if (cp=DefaultSystemCodePage) then
  86. begin
  87. { update current_Map in case the DefaultSystemCodePage has been changed }
  88. if (current_DefaultSystemCodePage<>DefaultSystemCodePage) or not Assigned(current_Map) then
  89. begin
  90. FiniThread;
  91. InitThread;
  92. end;
  93. Result:=current_Map;
  94. end
  95. else
  96. Result:=getmap(cp);
  97. end;
  98. { return value:
  99. -1 if incomplete or invalid code point
  100. 0 if NULL character,
  101. > 0 if that's the length in bytes of the code point }
  102. function UTF8CodePointLength(const Str: PAnsiChar; MaxLookAead: PtrInt): Ptrint;
  103. {... taken from ustrings.inc}
  104. var
  105. p: PByte;
  106. TempBYTE: Byte;
  107. CharLen: SizeUint;
  108. LookAhead: SizeUInt;
  109. UC: SizeUInt;
  110. begin
  111. if (Str=nil) then
  112. exit(0);
  113. p:=PByte(Str);
  114. if (p^=0) then
  115. exit(0);
  116. p:=PByte(Str);
  117. if (p^ and $80) = 0 then //One character US-ASCII,
  118. exit(1);
  119. TempByte:=p^;
  120. CharLen:=0;
  121. while (TempByte and $80)<>0 do
  122. begin
  123. TempByte:=(TempByte shl 1) and $FE;
  124. Inc(CharLen);
  125. end;
  126. //Test for the "CharLen" conforms UTF-8 string
  127. //This means the 10xxxxxx pattern.
  128. if SizeUInt(CharLen-1)>MaxLookAead then //Insuficient chars in string to decode UTF-8 array
  129. exit(-1);
  130. for LookAhead := 1 to CharLen-1 do
  131. begin
  132. if ((p[LookAhead] and $80)<>$80) or
  133. ((p[LookAhead] and $40)<>$00)
  134. then
  135. begin
  136. //Invalid UTF-8 sequence, fallback.
  137. exit(-1);
  138. end;
  139. end;
  140. Result:=CharLen;
  141. case CharLen of
  142. 1: begin
  143. //Not valid UTF-8 sequence
  144. Result:=-1;
  145. end;
  146. 2: begin
  147. //Two bytes UTF, convert it
  148. UC:=(p^ and $1F) shl 6;
  149. UC:=UC or (p[1] and $3F);
  150. if UC <= $7F then
  151. begin
  152. //Invalid UTF sequence.
  153. Result:=-1;
  154. end;
  155. end;
  156. 3: begin
  157. //Three bytes, convert it to unicode
  158. UC:= (p^ and $0F) shl 12;
  159. UC:= UC or ((p[1] and $3F) shl 6);
  160. UC:= UC or ((p[2] and $3F));
  161. if (UC <= $7FF) or (UC >= $FFFE) or ((UC >= $D800) and (UC <= $DFFF)) then
  162. begin
  163. //Invalid UTF-8 sequence
  164. Result:=-1;
  165. End;
  166. end;
  167. 4: begin
  168. //Four bytes, convert it to two unicode characters
  169. UC:= (p^ and $07) shl 18;
  170. UC:= UC or ((p[1] and $3F) shl 12);
  171. UC:= UC or ((p[2] and $3F) shl 6);
  172. UC:= UC or ((p[3] and $3F));
  173. if (UC < $10000) or (UC > $10FFFF) then
  174. begin
  175. Result:=-1;
  176. end
  177. end;
  178. 5,6,7: begin
  179. //Invalid UTF8 to unicode conversion,
  180. //mask it as invalid UNICODE too.
  181. Result:=-1;
  182. end;
  183. end;
  184. end;
  185. { return value:
  186. -1 if incomplete or invalid code point
  187. 0 if NULL character,
  188. > 0 if that's the length in bytes of the code point }
  189. function CodePointLength(const Str: PAnsiChar; MaxLookAead: PtrInt): PtrInt;
  190. var
  191. p : PByte;
  192. begin
  193. if (current_DefaultSystemCodePage=CP_UTF8) then
  194. exit(UTF8CodePointLength(Str,MaxLookAead));
  195. if (Str=nil) then
  196. exit(0);
  197. p:=PByte(Str);
  198. if (p^=0) then
  199. exit(0);
  200. if (current_Map=nil) then
  201. exit(1);
  202. if (p^>current_Map^.lastchar) then
  203. exit(-1);
  204. case current_Map^.map[p^].flag of
  205. umf_undefined : Result:=-1;
  206. umf_leadbyte :
  207. begin
  208. if (MaxLookAead>0) then
  209. Result:=2
  210. else
  211. Result:=-1;
  212. end;
  213. else
  214. Result:=1;
  215. end;
  216. end;
  217. procedure Unicode2AnsiMove(source:punicodechar;var dest:RawByteString;cp : TSystemCodePage;len:SizeInt);
  218. var
  219. locSource : punicodechar;
  220. locMap : punicodemap;
  221. destBuffer : PAnsiChar;
  222. destLen,actualLen, i : SizeInt;
  223. blockLen : SizeInt;
  224. begin
  225. if (len=0) then
  226. begin
  227. SetLength(dest,0);
  228. exit;
  229. end;
  230. if (cp=CP_UTF8) then
  231. begin
  232. destLen:=UnicodeToUtf8(nil,High(SizeUInt),source,len);
  233. SetLength(dest,destLen-1);
  234. UnicodeToUtf8(@dest[1],destLen,source,len);
  235. SetCodePage(dest,cp,False);
  236. exit;
  237. end;
  238. if (cp=CP_UTF16) then
  239. begin
  240. destLen:=len*SizeOf(UnicodeChar);
  241. SetLength(dest,destLen);
  242. Move(source^,dest[1],destLen);
  243. SetCodePage(dest,cp,False);
  244. exit;
  245. end;
  246. locMap:=FindMap(cp);
  247. if (locMap=nil) then
  248. begin
  249. DefaultUnicode2AnsiMove(source,dest,DefaultSystemCodePage,len);
  250. exit;
  251. end;
  252. destLen:=3*len;
  253. SetLength(dest,destLen);
  254. destBuffer:=@dest[1];
  255. actualLen:=0;
  256. locSource:=source;
  257. for i:=1 to len do
  258. begin
  259. blockLen:=getascii(tunicodechar(locSource^),locMap,destBuffer,(destLen-actualLen));
  260. if (blockLen<0) then
  261. begin
  262. destLen:=destLen + 3*(1+len-i);
  263. SetLength(dest,destLen);
  264. destBuffer:=@dest[1];
  265. blockLen:=getascii(tunicodechar(locSource^),locMap,destBuffer,(destLen-actualLen));
  266. end;
  267. Inc(destBuffer,blockLen);
  268. actualLen:=actualLen+blockLen;
  269. Inc(locSource);
  270. end;
  271. if (actualLen<>Length(dest)) then
  272. SetLength(dest,actualLen);
  273. if (Length(dest)>0) then
  274. SetCodePage(dest,cp,False);
  275. end;
  276. procedure Ansi2UnicodeMove(source:PAnsiChar; cp:TSystemCodePage; var dest:UnicodeString; len:SizeInt);
  277. var
  278. locMap : punicodemap;
  279. destLen : SizeUInt;
  280. begin
  281. if (len<=0) then
  282. begin
  283. SetLength(dest,0);
  284. exit;
  285. end;
  286. if (cp=CP_UTF8) then
  287. begin
  288. destLen:=Utf8ToUnicode(nil,high(SizeUint),source,len);
  289. if destLen > 0 then
  290. SetLength(dest,destLen-1)
  291. else
  292. SetLength(dest,0);
  293. Utf8ToUnicode(@dest[1],destLen,source,len);
  294. exit;
  295. end;
  296. if (cp=CP_UTF16) then
  297. begin
  298. //what if (len mod 2) > 0 ?
  299. destLen:=len div SizeOf(UnicodeChar);
  300. SetLength(dest,destLen);
  301. Move(source^,dest[1],(destLen*SizeOf(UnicodeChar)));
  302. exit;
  303. end;
  304. locMap:=FindMap(cp);
  305. if (locMap=nil) then
  306. begin
  307. DefaultAnsi2UnicodeMove(source,DefaultSystemCodePage,dest,len);
  308. exit;
  309. end;
  310. destLen:=getunicode(source,len,locMap,nil);
  311. SetLength(dest,destLen);
  312. getunicode(source,len,locMap,tunicodestring(@dest[1]));
  313. end;
  314. {$ifdef MSWINDOWS}
  315. procedure Ansi2WideMove(source:PAnsiChar; cp:TSystemCodePage; var dest:WideString; len:SizeInt);
  316. var
  317. locMap : punicodemap;
  318. destLen : SizeInt;
  319. begin
  320. if (len<=0) then
  321. begin
  322. SetLength(dest,0);
  323. exit;
  324. end;
  325. locMap:=FindMap(cp);
  326. if (locMap=nil) then
  327. begin
  328. DefaultAnsi2WideMove(source,DefaultSystemCodePage,dest,len);
  329. exit;
  330. end;
  331. destLen:=getunicode(source,len,locMap,nil);
  332. SetLength(dest,destLen);
  333. getunicode(source,len,locMap,tunicodestring(@dest[1]));
  334. end;
  335. {$endif MSWINDOWS}
  336. function UpperUnicodeString(const S: UnicodeString): UnicodeString;
  337. begin
  338. if (UnicodeToUpper(S,IgnoreInvalidSequenceFlag,Result) <> 0) then
  339. system.error(reRangeError);
  340. end;
  341. function UpperWideString(const S: WideString): WideString;
  342. var
  343. u : UnicodeString;
  344. begin
  345. u:=s;
  346. Result:=UpperUnicodeString(u);
  347. end;
  348. function LowerUnicodeString(const S: UnicodeString): UnicodeString;
  349. begin
  350. if (UnicodeToLower(S,IgnoreInvalidSequenceFlag,Result) <> 0) then
  351. system.error(reRangeError);
  352. end;
  353. function LowerWideString(const S: WideString): WideString;
  354. var
  355. u : UnicodeString;
  356. begin
  357. u:=s;
  358. Result:=LowerUnicodeString(u);
  359. end;
  360. function CompareUnicodeStringUCA(p1,p2:PUnicodeChar; l1,l2:PtrInt) : PtrInt;inline;
  361. begin
  362. Result := IncrementalCompareString(p1,l1,p2,l2,current_Collation.DataPtr);
  363. end;
  364. function CompareUnicodeString(p1,p2:PUnicodeChar; l1,l2:PtrInt) : PtrInt;inline;
  365. begin
  366. if (Pointer(p1)=Pointer(p2)) then
  367. exit(0);
  368. if (l1=0) then
  369. exit(-l2);
  370. if (l2=0) then
  371. exit(l1);
  372. Result := CompareUnicodeStringUCA(p1,p2,l1,l2);
  373. end;
  374. type
  375. TChangedPropsRecord = record
  376. ComparisonStrength : Byte;
  377. end;
  378. const
  379. SECONDARY_STRENGTH_LEVEL = 2;
  380. function CompareUnicodeString(const s1, s2 : UnicodeString;Options : TCompareOptions) : PtrInt;
  381. function DoCompare() : PtrInt;
  382. var
  383. changedProps : TChangedPropsRecord;
  384. begin
  385. changedProps.ComparisonStrength := current_Collation.Data.ComparisonStrength;
  386. try
  387. if (coIgnoreCase in Options) then
  388. current_Collation.Data.ComparisonStrength := SECONDARY_STRENGTH_LEVEL;
  389. Result:=CompareUnicodeString(
  390. PUnicodeChar(Pointer(s1)),
  391. PUnicodeChar(Pointer(s2)),
  392. Length(s1),Length(s2)
  393. );
  394. finally
  395. current_Collation.Data.ComparisonStrength := changedProps.ComparisonStrength;
  396. end;
  397. end;
  398. begin
  399. if (current_Collation.DataPtr=nil) then
  400. exit(OldManager.CompareUnicodeStringProc(s1,s2,Options));
  401. if (Options=[]) then begin
  402. exit(
  403. CompareUnicodeString(
  404. PUnicodeChar(Pointer(s1)),
  405. PUnicodeChar(Pointer(s2)),
  406. Length(s1),Length(s2)
  407. )
  408. );
  409. end;
  410. Result:=DoCompare();
  411. end;
  412. function CompareWideString(const s1, s2 : WideString; Options : TCompareOptions) : PtrInt;
  413. function DoCompare() : PtrInt;
  414. var
  415. changedProps : TChangedPropsRecord;
  416. begin
  417. changedProps.ComparisonStrength := current_Collation.Data.ComparisonStrength;
  418. try
  419. if (coIgnoreCase in Options) then
  420. current_Collation.Data.ComparisonStrength := SECONDARY_STRENGTH_LEVEL;
  421. Result:=CompareUnicodeString(
  422. PUnicodeChar(Pointer(s1)),
  423. PUnicodeChar(Pointer(s2)),
  424. Length(s1),Length(s2)
  425. );
  426. finally
  427. current_Collation.Data.ComparisonStrength := changedProps.ComparisonStrength;
  428. end;
  429. end;
  430. begin
  431. if (current_Collation.DataPtr=nil) then
  432. exit(OldManager.CompareUnicodeStringProc(s1,s2,Options));
  433. if (Options=[]) then begin
  434. exit(
  435. CompareUnicodeString(
  436. PUnicodeChar(Pointer(s1)),
  437. PUnicodeChar(Pointer(s2)),
  438. Length(s1),Length(s2)
  439. )
  440. );
  441. end;
  442. Result:=DoCompare();
  443. end;
  444. function CompareTextUnicodeString(const s1, s2 : UnicodeString) : PtrInt;
  445. begin
  446. Result:=CompareUnicodeString(s1,s2,[coIgnoreCase]);
  447. end;
  448. function CompareTextWideString(const s1, s2 : WideString) : PtrInt;
  449. begin
  450. Result:=CompareWideString(s1,s2,[coIgnoreCase]);
  451. end;
  452. procedure EnsureAnsiLen(var S: AnsiString; const len: SizeInt); inline;
  453. begin
  454. if (len>length(s)) then
  455. if (length(s) < 10*256) then
  456. setlength(s,length(s)+10)
  457. else
  458. setlength(s,length(s)+length(s) shr 8);
  459. end;
  460. procedure ConcatCharToAnsiStr(const c: AnsiChar; var S: AnsiString; var index: SizeInt);
  461. begin
  462. EnsureAnsiLen(s,index);
  463. pansichar(@s[index])^:=c;
  464. inc(index);
  465. end;
  466. function UpperAnsiString(const s : ansistring) : ansistring;
  467. var
  468. p : PAnsiChar;
  469. i,resindex : SizeInt;
  470. mblen : SizeInt;
  471. us,usl : UnicodeString;
  472. locMap : punicodemap;
  473. ulen,slen : SizeUint;
  474. k,aalen,ai : SizeInt;
  475. aa : array[0..8] of AnsiChar;
  476. begin
  477. if (Length(s)=0) then
  478. exit('');
  479. if (DefaultSystemCodePage=CP_UTF8) then
  480. begin
  481. //convert to UnicodeString,uppercase,convert back to utf8
  482. ulen:=Utf8ToUnicode(nil,high(SizeUint),@s[1],Length(s));
  483. if ulen>0 then
  484. SetLength(us,ulen-1);
  485. Utf8ToUnicode(@us[1],ulen,@s[1],Length(s));
  486. us:=UpperUnicodeString(us);
  487. ulen:=Length(us);
  488. slen:=UnicodeToUtf8(nil,high(SizeUInt),@us[1],ulen);
  489. SetLength(Result,slen);
  490. UnicodeToUtf8(@Result[1],slen,@us[1],ulen);
  491. exit;
  492. end;
  493. locMap:=FindMap(DefaultSystemCodePage);
  494. if (locMap=nil) then
  495. exit(System.UpCase(s));
  496. SetLength(us,2);
  497. p:=@s[1];
  498. slen:=length(s);
  499. SetLength(result,slen+10);
  500. i:=1;
  501. resindex:=1;
  502. while (i<=slen) do
  503. begin
  504. mblen:=CodePointLength(p,slen-i);
  505. if (mblen<=0) then
  506. begin
  507. ConcatCharToAnsiStr(p^,result,resindex);
  508. mblen:=1;
  509. end
  510. else
  511. begin
  512. SetLength(us,2);
  513. ulen:=getunicode(p,mblen,locMap,@us[1]);
  514. if (Length(us)<>ulen) then
  515. SetLength(us,ulen);
  516. usl:=UpperUnicodeString(us);
  517. for k:=1 to Length(usl) do
  518. begin
  519. aalen:=getascii(tunicodechar(us[k]),locMap,@aa[Low(aa)],Length(aa));
  520. for ai:=0 to aalen-1 do
  521. ConcatCharToAnsiStr(aa[ai],result,resindex);
  522. end;
  523. end;
  524. Inc(p,mblen);
  525. end;
  526. SetLength(result,resindex-1);
  527. end;
  528. function LowerAnsiString(const s : ansistring) : ansistring;
  529. var
  530. p : PAnsiChar;
  531. i,resindex : SizeInt;
  532. mblen : SizeInt;
  533. us,usl : UnicodeString;
  534. locMap : punicodemap;
  535. k,aalen,ai : SizeInt;
  536. slen, ulen : SizeUInt;
  537. aa : array[0..8] of AnsiChar;
  538. begin
  539. if (Length(s)=0) then
  540. exit('');
  541. if (DefaultSystemCodePage=CP_UTF8) then
  542. begin
  543. //convert to UnicodeString,lowercase,convert back to utf8
  544. ulen:=Utf8ToUnicode(nil,high(SizeUInt),@s[1],Length(s));
  545. if ulen>0 then
  546. SetLength(us,ulen-1);
  547. Utf8ToUnicode(@us[1],ulen,@s[1],Length(s));
  548. us:=LowerUnicodeString(us);
  549. ulen:=Length(us);
  550. slen:=UnicodeToUtf8(nil,high(SizeUInt),@us[1],ulen);
  551. SetLength(Result,slen);
  552. UnicodeToUtf8(@Result[1],slen,@us[1],ulen);
  553. exit;
  554. end;
  555. locMap:=FindMap(DefaultSystemCodePage);
  556. if (locMap=nil) then
  557. exit(System.LowerCase(s));
  558. SetLength(us,2);
  559. p:=@s[1];
  560. slen:=length(s);
  561. SetLength(result,slen+10);
  562. i:=1;
  563. resindex:=1;
  564. while (i<=slen) do
  565. begin
  566. mblen:=CodePointLength(p,slen-i);
  567. if (mblen<=0) then
  568. begin
  569. ConcatCharToAnsiStr(p^,result,resindex);
  570. mblen:=1;
  571. end
  572. else
  573. begin
  574. SetLength(us,2);
  575. ulen:=getunicode(p,mblen,locMap,@us[1]);
  576. if (Length(us)<>ulen) then
  577. SetLength(us,ulen);
  578. usl:=LowerUnicodeString(us);
  579. for k:=1 to Length(usl) do
  580. begin
  581. aalen:=getascii(tunicodechar(us[k]),locMap,@aa[Low(aa)],Length(aa));
  582. for ai:=0 to aalen-1 do
  583. ConcatCharToAnsiStr(aa[ai],result,resindex);
  584. end;
  585. end;
  586. Inc(p,mblen);
  587. end;
  588. SetLength(result,resindex-1);
  589. end;
  590. procedure ansi2pchar(const s: ansistring; const orgp: pansichar; out p: pansichar);
  591. var
  592. newlen: sizeint;
  593. begin
  594. newlen:=length(s);
  595. if newlen>strlen(orgp) then
  596. fpc_rangeerror;
  597. p:=orgp;
  598. if (newlen>0) then
  599. move(s[1],p[0],newlen);
  600. p[newlen]:=#0;
  601. end;
  602. function AnsiStrLower(Str: PAnsiChar): PAnsiChar;
  603. var
  604. temp: ansistring;
  605. begin
  606. temp:=LowerAnsiString(str);
  607. ansi2pchar(temp,str,result);
  608. end;
  609. function AnsiStrUpper(Str: PAnsiChar): PAnsiChar;
  610. var
  611. temp: ansistring;
  612. begin
  613. temp:=UpperAnsiString(str);
  614. ansi2pchar(temp,str,result);
  615. end;
  616. function CharLengthPChar(const Str: PAnsiChar): PtrInt;
  617. var
  618. len:PtrInt;
  619. nextlen: ptrint;
  620. s: PAnsiChar;
  621. begin
  622. Result:=0;
  623. if (Str=nil) or (Byte(Str^)=0) then
  624. exit;
  625. s:=str;
  626. len:=strlen(s);
  627. repeat
  628. nextlen:=CodePointLength(s,len);
  629. { skip invalid/incomplete sequences }
  630. if (nextlen<0) then
  631. nextlen:=1;
  632. Inc(result,nextlen);
  633. Inc(s,nextlen);
  634. Dec(len,nextlen);
  635. until (nextlen=0);
  636. end;
  637. function InternalCompareStrAnsiString(
  638. const S1, S2 : PAnsiChar;
  639. const Len1, Len2 : PtrUInt
  640. ) : PtrInt;inline;
  641. var
  642. a, b : UnicodeString;
  643. begin
  644. a := '';
  645. Ansi2UnicodeMove(S1,DefaultSystemCodePage,a,Len1);
  646. b := '';
  647. Ansi2UnicodeMove(S2,DefaultSystemCodePage,b,Len2);
  648. Result := CompareUnicodeString(a,b,[]);
  649. end;
  650. function StrLCompAnsiString(S1, S2: PAnsiChar; MaxLen: PtrUInt): PtrInt;
  651. begin
  652. if (current_Collation.DataPtr=nil) then
  653. exit(OldManager.StrLCompAnsiStringProc(s1,s2,MaxLen));
  654. if (MaxLen=0) then
  655. exit(0);
  656. Result := InternalCompareStrAnsiString(S1,S2,MaxLen,MaxLen);
  657. end;
  658. function CompareStrAnsiString(const S1, S2: ansistring): PtrInt;
  659. var
  660. l1, l2 : PtrInt;
  661. begin
  662. if (current_Collation.DataPtr=nil) then
  663. exit(OldManager.CompareStrAnsiStringProc(s1,s2));
  664. if (Pointer(S1)=Pointer(S2)) then
  665. exit(0);
  666. l1:=Length(S1);
  667. l2:=Length(S2);
  668. if (l1=0) or (l2=0) then
  669. exit(l1-l2);
  670. Result := InternalCompareStrAnsiString(@S1[1],@S2[1],l1,l2);
  671. end;
  672. function CompareTextAnsiString(const S1, S2: ansistring): PtrInt;
  673. var
  674. a,b : ansistring;
  675. begin
  676. a:=UpperAnsistring(s1);
  677. b:=UpperAnsistring(s2);
  678. Result:=CompareStrAnsiString(a,b);
  679. end;
  680. function StrCompAnsiString(S1, S2: PChar): PtrInt;
  681. var
  682. l1,l2 : PtrInt;
  683. begin
  684. if (current_Collation.DataPtr=nil) then
  685. exit(OldManager.StrCompAnsiStringProc(s1,s2));
  686. l1:=strlen(S1);
  687. l2:=strlen(S2);
  688. Result := InternalCompareStrAnsiString(S1,S2,l1,l2);
  689. end;
  690. function StrLICompAnsiString(S1, S2: PChar; MaxLen: PtrUInt): PtrInt;
  691. var
  692. a, b: ansistring;
  693. begin
  694. if (MaxLen=0) then
  695. exit(0);
  696. SetLength(a,MaxLen);
  697. Move(s1^,a[1],MaxLen);
  698. SetLength(b,MaxLen);
  699. Move(s2^,b[1],MaxLen);
  700. Result:=CompareTextAnsiString(a,b);
  701. end;
  702. function StrICompAnsiString(S1, S2: PChar): PtrInt;
  703. begin
  704. Result:=CompareTextAnsiString(ansistring(s1),ansistring(s2));
  705. end;
  706. function StrLowerAnsiString(Str: PChar): PChar;
  707. var
  708. temp: ansistring;
  709. begin
  710. temp:=LowerAnsiString(str);
  711. ansi2pchar(temp,str,result);
  712. end;
  713. function StrUpperAnsiString(Str: PChar): PChar;
  714. var
  715. temp: ansistring;
  716. begin
  717. temp:=UpperAnsiString(str);
  718. ansi2pchar(temp,str,result);
  719. end;
  720. //------------------------------------------------------------------------------
  721. procedure SetPascalWideStringManager();
  722. var
  723. locWideStringManager : TUnicodeStringManager;
  724. begin
  725. OldManager := widestringmanager;
  726. locWideStringManager:=widestringmanager;
  727. With locWideStringManager do
  728. begin
  729. Wide2AnsiMoveProc:=@Unicode2AnsiMove;
  730. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  731. Ansi2WideMoveProc:=@Ansi2WideMove;
  732. UpperWideStringProc:=@UpperWideString;
  733. LowerWideStringProc:=@LowerWideString;
  734. CompareWideStringProc:=@CompareWideString;
  735. {$else FPC_WIDESTRING_EQUAL_UNICODESTRING}
  736. Ansi2WideMoveProc:=@Ansi2UnicodeMove;
  737. UpperWideStringProc:=@UpperUnicodeString;
  738. LowerWideStringProc:=@LowerUnicodeString;
  739. CompareWideStringProc:=@CompareUnicodeString;
  740. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  741. CharLengthPCharProc:=@CharLengthPChar;
  742. CodePointLengthProc:=@CodePointLength;
  743. UpperAnsiStringProc:=@UpperAnsiString;
  744. LowerAnsiStringProc:=@LowerAnsiString;
  745. CompareStrAnsiStringProc:=@CompareStrAnsiString;
  746. CompareTextAnsiStringProc:=@CompareTextAnsiString;
  747. StrCompAnsiStringProc:=@StrCompAnsiString;
  748. StrICompAnsiStringProc:=@StrICompAnsiString;
  749. StrLCompAnsiStringProc:=@StrLCompAnsiString;
  750. StrLICompAnsiStringProc:=@StrLICompAnsiString;
  751. StrLowerAnsiStringProc:=@StrLowerAnsiString;
  752. StrUpperAnsiStringProc:=@StrUpperAnsiString;
  753. ThreadInitProc:=@InitThread;
  754. ThreadFiniProc:=@FiniThread;
  755. { Unicode }
  756. Unicode2AnsiMoveProc:=@Unicode2AnsiMove;
  757. Ansi2UnicodeMoveProc:=@Ansi2UnicodeMove;
  758. UpperUnicodeStringProc:=@UpperUnicodeString;
  759. LowerUnicodeStringProc:=@LowerUnicodeString;
  760. CompareUnicodeStringProc:=@CompareUnicodeString;
  761. end;
  762. SetUnicodeStringManager(locWideStringManager);
  763. DefaultUnicodeCodePage:=CP_UTF16;
  764. {$ifdef MSWINDOWS}
  765. DefaultSystemCodePage:=GetACP();
  766. {$ELSE MSWINDOWS}
  767. {$ifdef UNIX}
  768. DefaultSystemCodePage:=GetSystemCodepage;
  769. if (DefaultSystemCodePage = CP_NONE) then
  770. DefaultSystemCodePage:=CP_UTF8;
  771. {$ifdef FPCRTL_FILESYSTEM_UTF8}
  772. DefaultFileSystemCodePage:=CP_UTF8;
  773. {$else}
  774. DefaultFileSystemCodePage:=DefaultSystemCodepage;
  775. {$endif}
  776. DefaultRTLFileSystemCodePage:=DefaultFileSystemCodePage;
  777. {$ELSE UNIX}
  778. if Assigned (WideStringManager.GetStandardCodePageProc) then
  779. DefaultSystemCodePage := WideStringManager.GetStandardCodePageProc (scpAnsi)
  780. else
  781. DefaultSystemCodePage := CP_NONE;
  782. DefaultFileSystemCodePage := DefaultSystemCodePage;
  783. DefaultRTLFileSystemCodePage := DefaultSystemCodePage;
  784. {$endif UNIX}
  785. {$endif MSWINDOWS}
  786. end;
  787. initialization
  788. current_Collation.DataPtr := nil;
  789. SetPascalWideStringManager();
  790. InitThread();
  791. finalization
  792. FiniThread();
  793. end.