You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
5.6 KiB

  1. unit utsUtils;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, utsTypes;
  6. function tsStrAlloc(aSize: Cardinal): PWideChar;
  7. function tsStrNew(const aText: PWideChar): PWideChar;
  8. procedure tsStrDispose(const aText: PWideChar);
  9. function tsStrLength(aText: PWideChar): Cardinal;
  10. function tsStrCopy(aDst, aSrc: PWideChar): PWideChar;
  11. function tsAnsiToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar; const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  12. function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer;
  13. function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer;
  14. function tsAnsiSBCDToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar; const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  15. implementation
  16. uses
  17. utsCodePages;
  18. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  19. function tsStrAlloc(aSize: Cardinal): PWideChar;
  20. begin
  21. aSize := (aSize + 1) shl 1;
  22. GetMem(result, aSize);
  23. FillChar(result^, aSize, 0);
  24. end;
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. function tsStrNew(const aText: PWideChar): PWideChar;
  27. begin
  28. result := tsStrAlloc(tsStrLength(aText));
  29. tsStrCopy(result, aText);
  30. end;
  31. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  32. procedure tsStrDispose(const aText: PWideChar);
  33. begin
  34. FreeMem(aText);
  35. end;
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. function tsStrLength(aText: PWideChar): Cardinal;
  38. begin
  39. result := 0;
  40. if Assigned(aText) then
  41. while (ord(aText^) <> 0) do begin
  42. inc(result);
  43. inc(aText);
  44. end;
  45. end;
  46. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. function tsStrCopy(aDst, aSrc: PWideChar): PWideChar;
  48. begin
  49. result := aDst;
  50. if Assigned(aDst) and Assigned(aSrc) then
  51. while ord(aSrc^) <> 0 do begin
  52. aDst^ := aSrc^;
  53. inc(aDst);
  54. inc(aSrc);
  55. end;
  56. end;
  57. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. function tsAnsiToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar;
  59. const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  60. begin
  61. result := 0;
  62. case aCodePage of
  63. tsUTF8:
  64. result := tsUTF8ToWide(aDst, aSize, aSrc, aDefaultChar);
  65. tsISO_8859_1:
  66. result := tsISO_8859_1ToWide(aDst, aSize, aSrc);
  67. else
  68. result := tsAnsiSBCDToWide(aDst, aSize, aSrc, aCodePage, aDefaultChar);
  69. end;
  70. end;
  71. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. function tsISO_8859_1ToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar): Integer;
  73. begin
  74. result := 0;
  75. if Assigned(aDst) and Assigned(aSrc) then
  76. while (ord(aSrc^) <> 0) and (result < aSize) do begin
  77. aDst^ := WideChar(aSrc^);
  78. inc(aDst);
  79. inc(aSrc);
  80. inc(result);
  81. end;
  82. end;
  83. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  84. function tsUTF8ToWide(aDst: PWideChar; const aSize: Integer; const aSrc: PAnsiChar; const aDefaultChar: WideChar): Integer;
  85. procedure AddToDest(aCharCode: UInt64);
  86. begin
  87. if (aCharCode > $FFFF) then
  88. aCharCode := ord(aDefaultChar);
  89. PWord(aDst)^ := aCharCode;
  90. inc(aDst);
  91. result := result + 1;
  92. end;
  93. const
  94. STATE_STARTBYTE = 0;
  95. STATE_FOLLOWBYTE = 1;
  96. var
  97. cc: QWord;
  98. len, state, c: Integer;
  99. p: PByte;
  100. tmp: Byte;
  101. begin
  102. result := 0;
  103. if not Assigned(aDst) or not Assigned(aSrc) or (aSize <= 0) then
  104. exit;
  105. p := PByte(aSrc);
  106. len := Length(aSrc);
  107. state := STATE_STARTBYTE;
  108. while (len > 0) do begin
  109. case state of
  110. STATE_STARTBYTE: begin
  111. if (p^ and %10000000 = 0) then begin
  112. AddToDest(p^);
  113. end else if (p^ and %01000000 > 0) then begin
  114. tmp := p^;
  115. c := 0;
  116. while (tmp and %10000000) > 0 do begin
  117. inc(c);
  118. tmp := tmp shl 1;
  119. end;
  120. cc := p^ and ((1 shl (7 - c)) - 1);
  121. state := STATE_FOLLOWBYTE;
  122. c := c - 1;
  123. end;
  124. end;
  125. STATE_FOLLOWBYTE: begin
  126. if ((p^ and %11000000) = %10000000) then begin
  127. cc := (cc shl 6) or (p^ and %00111111);
  128. c := c - 1;
  129. if (c = 0) then begin
  130. AddToDest(cc);
  131. state := STATE_STARTBYTE;
  132. end;
  133. end else
  134. state := STATE_STARTBYTE;
  135. end;
  136. end;
  137. if (result >= aSize) then
  138. exit;
  139. inc(p);
  140. end;
  141. end;
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. function tsAnsiSBCDToWide(aDst: PWideChar; const aSize: Integer; aSrc: PAnsiChar;
  144. const aCodePage: TtsCodePage; const aDefaultChar: WideChar): Integer;
  145. var
  146. tmp: WideChar;
  147. cp: PtsCodePageValues;
  148. begin
  149. result := 0;
  150. cp := ANSI_TO_WIDE_CODE_PAGE_LUT[aCodePage];
  151. if not Assigned(aDst) or
  152. not Assigned(aSrc) or
  153. not Assigned(cp) or
  154. (aSize < 0) then exit;
  155. while (Ord(aSrc^) <> 0) and (result < aSize) do begin
  156. tmp := WideChar(cp^[aSrc^]);
  157. if (ord(tmp) = 0) then begin
  158. if (ord(aDefaultChar) <> 0) then begin
  159. aDst^ := aDefaultChar;
  160. inc(aDst);
  161. end;
  162. end else begin
  163. aDst^ := tmp;
  164. inc(aDst);
  165. end;
  166. inc(aSrc);
  167. end;
  168. end;
  169. end.