| 1 | 
 | 
|---|
| 2 | {*****************************************************************************}
 | 
|---|
| 3 | {                                                                             }
 | 
|---|
| 4 | {    Tnt Delphi Unicode Controls                                              }
 | 
|---|
| 5 | {      http://www.tntware.com/delphicontrols/unicode/                         }
 | 
|---|
| 6 | {        Version: 2.3.0                                                       }
 | 
|---|
| 7 | {                                                                             }
 | 
|---|
| 8 | {    Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com)       }
 | 
|---|
| 9 | {                                                                             }
 | 
|---|
| 10 | {*****************************************************************************}
 | 
|---|
| 11 | 
 | 
|---|
| 12 | unit TntSystem;
 | 
|---|
| 13 | 
 | 
|---|
| 14 | {$INCLUDE TntCompilers.inc}
 | 
|---|
| 15 | 
 | 
|---|
| 16 | {*****************************************************************************}
 | 
|---|
| 17 | {  Special thanks go to Francisco Leong for originating the design for        }
 | 
|---|
| 18 | {    WideString-enabled resourcestrings.                                      }
 | 
|---|
| 19 | {*****************************************************************************}
 | 
|---|
| 20 | 
 | 
|---|
| 21 | interface
 | 
|---|
| 22 | 
 | 
|---|
| 23 | uses
 | 
|---|
| 24 |   Windows;
 | 
|---|
| 25 | 
 | 
|---|
| 26 | // These functions should not be used by Delphi code since conversions are implicit.
 | 
|---|
| 27 | {TNT-WARN WideCharToString}
 | 
|---|
| 28 | {TNT-WARN WideCharLenToString}
 | 
|---|
| 29 | {TNT-WARN WideCharToStrVar}
 | 
|---|
| 30 | {TNT-WARN WideCharLenToStrVar}
 | 
|---|
| 31 | {TNT-WARN StringToWideChar}
 | 
|---|
| 32 | 
 | 
|---|
| 33 | // ................ ANSI TYPES ................
 | 
|---|
| 34 | {TNT-WARN Char}
 | 
|---|
| 35 | {TNT-WARN PChar}
 | 
|---|
| 36 | {TNT-WARN String}
 | 
|---|
| 37 | 
 | 
|---|
| 38 | {TNT-WARN CP_ACP} // <-- use DefaultSystemCodePage
 | 
|---|
| 39 | function DefaultSystemCodePage: Cardinal; // implicitly used when converting AnsiString <--> WideString.
 | 
|---|
| 40 | 
 | 
|---|
| 41 | var
 | 
|---|
| 42 |   WideCustomLoadResString: function(ResStringRec: PResStringRec; var Value: WideString): Boolean;
 | 
|---|
| 43 | 
 | 
|---|
| 44 | {TNT-WARN LoadResString}
 | 
|---|
| 45 | function WideLoadResString(ResStringRec: PResStringRec): WideString;
 | 
|---|
| 46 | {TNT-WARN ParamCount}
 | 
|---|
| 47 | function WideParamCount: Integer;
 | 
|---|
| 48 | {TNT-WARN ParamStr}
 | 
|---|
| 49 | function WideParamStr(Index: Integer): WideString;
 | 
|---|
| 50 | 
 | 
|---|
| 51 | // ......... introduced .........
 | 
|---|
| 52 | 
 | 
|---|
| 53 | const
 | 
|---|
| 54 |   { Each Unicode stream should begin with the code U+FEFF,  }
 | 
|---|
| 55 |   {   which the standard defines as the *byte order mark*.  }
 | 
|---|
| 56 |   UNICODE_BOM = WideChar($FEFF);
 | 
|---|
| 57 |   UNICODE_BOM_SWAPPED = WideChar($FFFE);
 | 
|---|
| 58 |   UTF8_BOM = AnsiString(#$EF#$BB#$BF);
 | 
|---|
| 59 | 
 | 
|---|
| 60 | function WideStringToUTF8(const S: WideString): AnsiString;
 | 
|---|
| 61 | function UTF8ToWideString(const S: AnsiString): WideString;
 | 
|---|
| 62 | 
 | 
|---|
| 63 | function WideStringToUTF7(const W: WideString): AnsiString;
 | 
|---|
| 64 | function UTF7ToWideString(const S: AnsiString): WideString;
 | 
|---|
| 65 | 
 | 
|---|
| 66 | function StringToWideStringEx(const S: AnsiString; CodePage: Cardinal): WideString;
 | 
|---|
| 67 | function WideStringToStringEx(const WS: WideString; CodePage: Cardinal): AnsiString;
 | 
|---|
| 68 | 
 | 
|---|
| 69 | function UCS2ToWideString(const Value: AnsiString): WideString;
 | 
|---|
| 70 | function WideStringToUCS2(const Value: WideString): AnsiString;
 | 
|---|
| 71 | 
 | 
|---|
| 72 | function CharSetToCodePage(ciCharset: UINT): Cardinal;
 | 
|---|
| 73 | function LCIDToCodePage(ALcid: LCID): Cardinal;
 | 
|---|
| 74 | function KeyboardCodePage: Cardinal;
 | 
|---|
| 75 | function KeyUnicode(CharCode: Word): WideChar;
 | 
|---|
| 76 | 
 | 
|---|
| 77 | procedure StrSwapByteOrder(Str: PWideChar);
 | 
|---|
| 78 | 
 | 
|---|
| 79 | type
 | 
|---|
| 80 |   TTntSystemUpdate =
 | 
|---|
| 81 |     (tsWideResourceStrings
 | 
|---|
| 82 |      {$IFNDEF COMPILER_9_UP}, tsFixImplicitCodePage, tsFixWideStrConcat, tsFixWideFormat {$ENDIF}
 | 
|---|
| 83 |     );
 | 
|---|
| 84 |   TTntSystemUpdateSet = set of TTntSystemUpdate;
 | 
|---|
| 85 | 
 | 
|---|
| 86 | const
 | 
|---|
| 87 |   AllTntSystemUpdates = [Low(TTntSystemUpdate)..High(TTntSystemUpdate)];
 | 
|---|
| 88 | 
 | 
|---|
| 89 | procedure InstallTntSystemUpdates(Updates: TTntSystemUpdateSet = AllTntSystemUpdates);
 | 
|---|
| 90 | 
 | 
|---|
| 91 | implementation
 | 
|---|
| 92 | 
 | 
|---|
| 93 | uses
 | 
|---|
| 94 |   SysUtils, Variants, TntWindows, TntSysUtils;
 | 
|---|
| 95 | 
 | 
|---|
| 96 | var
 | 
|---|
| 97 |   GDefaultSystemCodePage: Cardinal;
 | 
|---|
| 98 | 
 | 
|---|
| 99 | function DefaultSystemCodePage: Cardinal;
 | 
|---|
| 100 | begin
 | 
|---|
| 101 |   Result := GDefaultSystemCodePage;
 | 
|---|
| 102 | end;
 | 
|---|
| 103 | 
 | 
|---|
| 104 | var
 | 
|---|
| 105 |   IsDebugging: Boolean;
 | 
|---|
| 106 | 
 | 
|---|
| 107 | function WideLoadResString(ResStringRec: PResStringRec): WideString;
 | 
|---|
| 108 | const
 | 
|---|
| 109 |   MAX_RES_STRING_SIZE = 4097; { MSDN documents this as the maximum size of a string in table. }
 | 
|---|
| 110 | var
 | 
|---|
| 111 |   Buffer: array [0..MAX_RES_STRING_SIZE] of WideChar; { Buffer leaves room for null terminator. }
 | 
|---|
| 112 |   PCustom: PAnsiChar;
 | 
|---|
| 113 | begin
 | 
|---|
| 114 |   if Assigned(WideCustomLoadResString) and WideCustomLoadResString(ResStringRec, Result) then
 | 
|---|
| 115 |     exit; { a custom resourcestring has been loaded. }
 | 
|---|
| 116 | 
 | 
|---|
| 117 |   if ResStringRec = nil then
 | 
|---|
| 118 |     Result := ''
 | 
|---|
| 119 |   else if ResStringRec.Identifier < 64*1024 then
 | 
|---|
| 120 |     SetString(Result, Buffer,
 | 
|---|
| 121 |       Tnt_LoadStringW(FindResourceHInstance(ResStringRec.Module^),
 | 
|---|
| 122 |         ResStringRec.Identifier, Buffer, MAX_RES_STRING_SIZE))
 | 
|---|
| 123 |   else begin
 | 
|---|
| 124 |     // custom string pointer
 | 
|---|
| 125 |     PCustom := PAnsiChar(ResStringRec.Identifier); { I would like to use PWideChar, but this would break legacy code. }
 | 
|---|
| 126 |     if  (StrLen{TNT-ALLOW StrLen}(PCustom) > Cardinal(Length(UTF8_BOM)))
 | 
|---|
| 127 |     and CompareMem(PCustom, PAnsiChar(UTF8_BOM), Length(UTF8_BOM)) then
 | 
|---|
| 128 |       // detected UTF8
 | 
|---|
| 129 |       Result := UTF8ToWideString(PAnsiChar(PCustom + Length(UTF8_BOM)))
 | 
|---|
| 130 |     else
 | 
|---|
| 131 |       // normal
 | 
|---|
| 132 |       Result := PCustom;
 | 
|---|
| 133 |   end;
 | 
|---|
| 134 | end;
 | 
|---|
| 135 | 
 | 
|---|
| 136 | function WideGetParamStr(P: PWideChar; var Param: WideString): PWideChar;
 | 
|---|
| 137 | var
 | 
|---|
| 138 |   i, Len: Integer;
 | 
|---|
| 139 |   Start, S, Q: PWideChar;
 | 
|---|
| 140 | begin
 | 
|---|
| 141 |   while True do
 | 
|---|
| 142 |   begin
 | 
|---|
| 143 |     while (P[0] <> #0) and (P[0] <= ' ') do
 | 
|---|
| 144 |       Inc(P);
 | 
|---|
| 145 |     if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
 | 
|---|
| 146 |   end;
 | 
|---|
| 147 |   Len := 0;
 | 
|---|
| 148 |   Start := P;
 | 
|---|
| 149 |   while P[0] > ' ' do
 | 
|---|
| 150 |   begin
 | 
|---|
| 151 |     if P[0] = '"' then
 | 
|---|
| 152 |     begin
 | 
|---|
| 153 |       Inc(P);
 | 
|---|
| 154 |       while (P[0] <> #0) and (P[0] <> '"') do
 | 
|---|
| 155 |       begin
 | 
|---|
| 156 |         Q := P + 1;
 | 
|---|
| 157 |         Inc(Len, Q - P);
 | 
|---|
| 158 |         P := Q;
 | 
|---|
| 159 |       end;
 | 
|---|
| 160 |       if P[0] <> #0 then
 | 
|---|
| 161 |         Inc(P);
 | 
|---|
| 162 |     end
 | 
|---|
| 163 |     else
 | 
|---|
| 164 |     begin
 | 
|---|
| 165 |       Q := P + 1;
 | 
|---|
| 166 |       Inc(Len, Q - P);
 | 
|---|
| 167 |       P := Q;
 | 
|---|
| 168 |     end;
 | 
|---|
| 169 |   end;
 | 
|---|
| 170 | 
 | 
|---|
| 171 |   SetLength(Param, Len);
 | 
|---|
| 172 | 
 | 
|---|
| 173 |   P := Start;
 | 
|---|
| 174 |   S := PWideChar(Param);
 | 
|---|
| 175 |   i := 0;
 | 
|---|
| 176 |   while P[0] > ' ' do
 | 
|---|
| 177 |   begin
 | 
|---|
| 178 |     if P[0] = '"' then
 | 
|---|
| 179 |     begin
 | 
|---|
| 180 |       Inc(P);
 | 
|---|
| 181 |       while (P[0] <> #0) and (P[0] <> '"') do
 | 
|---|
| 182 |       begin
 | 
|---|
| 183 |         Q := P + 1;
 | 
|---|
| 184 |         while P < Q do
 | 
|---|
| 185 |         begin
 | 
|---|
| 186 |           S[i] := P^;
 | 
|---|
| 187 |           Inc(P);
 | 
|---|
| 188 |           Inc(i);
 | 
|---|
| 189 |         end;
 | 
|---|
| 190 |       end;
 | 
|---|
| 191 |       if P[0] <> #0 then Inc(P);
 | 
|---|
| 192 |     end
 | 
|---|
| 193 |     else
 | 
|---|
| 194 |     begin
 | 
|---|
| 195 |       Q := P + 1;
 | 
|---|
| 196 |       while P < Q do
 | 
|---|
| 197 |       begin
 | 
|---|
| 198 |         S[i] := P^;
 | 
|---|
| 199 |         Inc(P);
 | 
|---|
| 200 |         Inc(i);
 | 
|---|
| 201 |       end;
 | 
|---|
| 202 |     end;
 | 
|---|
| 203 |   end;
 | 
|---|
| 204 | 
 | 
|---|
| 205 |   Result := P;
 | 
|---|
| 206 | end;
 | 
|---|
| 207 | 
 | 
|---|
| 208 | function WideParamCount: Integer;
 | 
|---|
| 209 | var
 | 
|---|
| 210 |   P: PWideChar;
 | 
|---|
| 211 |   S: WideString;
 | 
|---|
| 212 | begin
 | 
|---|
| 213 |   P := WideGetParamStr(GetCommandLineW, S);
 | 
|---|
| 214 |   Result := 0;
 | 
|---|
| 215 |   while True do
 | 
|---|
| 216 |   begin
 | 
|---|
| 217 |     P := WideGetParamStr(P, S);
 | 
|---|
| 218 |     if S = '' then Break;
 | 
|---|
| 219 |     Inc(Result);
 | 
|---|
| 220 |   end;
 | 
|---|
| 221 | end;
 | 
|---|
| 222 | 
 | 
|---|
| 223 | function WideParamStr(Index: Integer): WideString;
 | 
|---|
| 224 | var
 | 
|---|
| 225 |   P: PWideChar;
 | 
|---|
| 226 | begin
 | 
|---|
| 227 |   if Index = 0 then
 | 
|---|
| 228 |     Result := WideGetModuleFileName(0)
 | 
|---|
| 229 |   else
 | 
|---|
| 230 |   begin
 | 
|---|
| 231 |     P := GetCommandLineW;
 | 
|---|
| 232 |     while True do
 | 
|---|
| 233 |     begin
 | 
|---|
| 234 |       P := WideGetParamStr(P, Result);
 | 
|---|
| 235 |       if (Index = 0) or (Result = '') then Break;
 | 
|---|
| 236 |       Dec(Index);
 | 
|---|
| 237 |     end;
 | 
|---|
| 238 |   end;
 | 
|---|
| 239 | end;
 | 
|---|
| 240 | 
 | 
|---|
| 241 | function WideStringToUTF8(const S: WideString): AnsiString;
 | 
|---|
| 242 | begin
 | 
|---|
| 243 |   Result := UTF8Encode(S);
 | 
|---|
| 244 | end;
 | 
|---|
| 245 | 
 | 
|---|
| 246 | function UTF8ToWideString(const S: AnsiString): WideString;
 | 
|---|
| 247 | begin
 | 
|---|
| 248 |   Result := UTF8Decode(S);
 | 
|---|
| 249 | end;
 | 
|---|
| 250 | 
 | 
|---|
| 251 |   { ======================================================================= }
 | 
|---|
| 252 |   { Original File:   ConvertUTF7.c                                          }
 | 
|---|
| 253 |   { Author: David B. Goldsmith                                              }
 | 
|---|
| 254 |   { Copyright (C) 1994, 1996 Taligent, Inc. All rights reserved.            }
 | 
|---|
| 255 |   {                                                                         }
 | 
|---|
| 256 |   { This code is copyrighted. Under the copyright laws, this code may not   }
 | 
|---|
| 257 |   { be copied, in whole or part, without prior written consent of Taligent. }
 | 
|---|
| 258 |   {                                                                         }
 | 
|---|
| 259 |   { Taligent grants the right to use this code as long as this ENTIRE       }
 | 
|---|
| 260 |   { copyright notice is reproduced in the code.  The code is provided       }
 | 
|---|
| 261 |   { AS-IS, AND TALIGENT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR         }
 | 
|---|
| 262 |   { IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED WARRANTIES OF            }
 | 
|---|
| 263 |   { MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT      }
 | 
|---|
| 264 |   { WILL TALIGENT BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING,          }
 | 
|---|
| 265 |   { WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS      }
 | 
|---|
| 266 |   { INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY          }
 | 
|---|
| 267 |   { LOSS) ARISING OUT OF THE USE OR INABILITY TO USE THIS CODE, EVEN        }
 | 
|---|
| 268 |   { IF TALIGENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.        }
 | 
|---|
| 269 |   { BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF         }
 | 
|---|
| 270 |   { LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE            }
 | 
|---|
| 271 |   { LIMITATION MAY NOT APPLY TO YOU.                                        }
 | 
|---|
| 272 |   {                                                                         }
 | 
|---|
| 273 |   { RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the        }
 | 
|---|
| 274 |   { government is subject to restrictions as set forth in subparagraph      }
 | 
|---|
| 275 |   { (c)(l)(ii) of the Rights in Technical Data and Computer Software        }
 | 
|---|
| 276 |   { clause at DFARS 252.227-7013 and FAR 52.227-19.                         }
 | 
|---|
| 277 |   {                                                                         }
 | 
|---|
| 278 |   { This code may be protected by one or more U.S. and International        }
 | 
|---|
| 279 |   { Patents.                                                                }
 | 
|---|
| 280 |   {                                                                         }
 | 
|---|
| 281 |   { TRADEMARKS: Taligent and the Taligent Design Mark are registered        }
 | 
|---|
| 282 |   { trademarks of Taligent, Inc.                                            }
 | 
|---|
| 283 |   { ======================================================================= }
 | 
|---|
| 284 | 
 | 
|---|
| 285 | type UCS2 = Word;
 | 
|---|
| 286 | 
 | 
|---|
| 287 | const
 | 
|---|
| 288 |   _base64: AnsiString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
 | 
|---|
| 289 |   _direct: AnsiString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789''(),-./:?';
 | 
|---|
| 290 |   _optional: AnsiString = '!"#$%&*;<=>@[]^_`{|}';
 | 
|---|
| 291 |   _spaces: AnsiString = #9#13#10#32;
 | 
|---|
| 292 | 
 | 
|---|
| 293 | var
 | 
|---|
| 294 |   base64: PAnsiChar;
 | 
|---|
| 295 |   invbase64: array[0..127] of SmallInt;
 | 
|---|
| 296 |   direct: PAnsiChar;
 | 
|---|
| 297 |   optional: PAnsiChar;
 | 
|---|
| 298 |   spaces: PAnsiChar;
 | 
|---|
| 299 |   mustshiftsafe: array[0..127] of AnsiChar;
 | 
|---|
| 300 |   mustshiftopt: array[0..127] of AnsiChar;
 | 
|---|
| 301 | 
 | 
|---|
| 302 | var
 | 
|---|
| 303 |   needtables: Boolean = True;
 | 
|---|
| 304 | 
 | 
|---|
| 305 | procedure Initialize_UTF7_Data;
 | 
|---|
| 306 | begin
 | 
|---|
| 307 |   base64 := PAnsiChar(_base64);
 | 
|---|
| 308 |   direct := PAnsiChar(_direct);
 | 
|---|
| 309 |   optional := PAnsiChar(_optional);
 | 
|---|
| 310 |   spaces := PAnsiChar(_spaces);
 | 
|---|
| 311 | end;
 | 
|---|
| 312 | 
 | 
|---|
| 313 | procedure tabinit;
 | 
|---|
| 314 | var
 | 
|---|
| 315 |   i: Integer;
 | 
|---|
| 316 |   limit: Integer;
 | 
|---|
| 317 | begin
 | 
|---|
| 318 |   i := 0;
 | 
|---|
| 319 |   while (i < 128) do
 | 
|---|
| 320 |   begin
 | 
|---|
| 321 |     mustshiftopt[i] := #1;
 | 
|---|
| 322 |     mustshiftsafe[i] := #1;
 | 
|---|
| 323 |     invbase64[i] := -1;
 | 
|---|
| 324 |     Inc(i);
 | 
|---|
| 325 |   end { For };
 | 
|---|
| 326 |   limit := Length(_Direct);
 | 
|---|
| 327 |   i := 0;
 | 
|---|
| 328 |   while (i < limit) do
 | 
|---|
| 329 |   begin
 | 
|---|
| 330 |     mustshiftopt[Integer(direct[i])] := #0;
 | 
|---|
| 331 |     mustshiftsafe[Integer(direct[i])] := #0;
 | 
|---|
| 332 |     Inc(i);
 | 
|---|
| 333 |   end { For };
 | 
|---|
| 334 |   limit := Length(_Spaces);
 | 
|---|
| 335 |   i := 0;
 | 
|---|
| 336 |   while (i < limit) do
 | 
|---|
| 337 |   begin
 | 
|---|
| 338 |     mustshiftopt[Integer(spaces[i])] := #0;
 | 
|---|
| 339 |     mustshiftsafe[Integer(spaces[i])] := #0;
 | 
|---|
| 340 |     Inc(i);
 | 
|---|
| 341 |   end { For };
 | 
|---|
| 342 |   limit := Length(_Optional);
 | 
|---|
| 343 |   i := 0;
 | 
|---|
| 344 |   while (i < limit) do
 | 
|---|
| 345 |   begin
 | 
|---|
| 346 |     mustshiftopt[Integer(optional[i])] := #0;
 | 
|---|
| 347 |     Inc(i);
 | 
|---|
| 348 |   end { For };
 | 
|---|
| 349 |   limit := Length(_Base64);
 | 
|---|
| 350 |   i := 0;
 | 
|---|
| 351 |   while (i < limit) do
 | 
|---|
| 352 |   begin
 | 
|---|
| 353 |     invbase64[Integer(base64[i])] := i;
 | 
|---|
| 354 |     Inc(i);
 | 
|---|
| 355 |   end { For };
 | 
|---|
| 356 |   needtables := False;
 | 
|---|
| 357 | end; { tabinit }
 | 
|---|
| 358 | 
 | 
|---|
| 359 | function WRITE_N_BITS(x: UCS2; n: Integer; var BITbuffer: Cardinal; var bufferbits: Integer): Integer;
 | 
|---|
| 360 | begin
 | 
|---|
| 361 |   BITbuffer := BITbuffer or (x and (not (-1 shl n))) shl (32 - n - bufferbits);
 | 
|---|
| 362 |   bufferbits := bufferbits + n;
 | 
|---|
| 363 |   Result := bufferbits;
 | 
|---|
| 364 | end; { WRITE_N_BITS }
 | 
|---|
| 365 | 
 | 
|---|
| 366 | function READ_N_BITS(n: Integer; var BITbuffer: Cardinal; var bufferbits: Integer): UCS2;
 | 
|---|
| 367 | var
 | 
|---|
| 368 |   buffertemp: Cardinal;
 | 
|---|
| 369 | begin
 | 
|---|
| 370 |   buffertemp := BITbuffer shr (32 - n);
 | 
|---|
| 371 |   BITbuffer := BITbuffer shl n;
 | 
|---|
| 372 |   bufferbits := bufferbits - n;
 | 
|---|
| 373 |   Result := UCS2(buffertemp);
 | 
|---|
| 374 | end; { READ_N_BITS }
 | 
|---|
| 375 | 
 | 
|---|
| 376 | function ConvertUCS2toUTF7(var sourceStart: PWideChar; sourceEnd: PWideChar;
 | 
|---|
| 377 |   var targetStart: PAnsiChar; targetEnd: PAnsiChar; optional: Boolean;
 | 
|---|
| 378 |     verbose: Boolean): Integer;
 | 
|---|
| 379 | var
 | 
|---|
| 380 |   r: UCS2;
 | 
|---|
| 381 |   target: PAnsiChar;
 | 
|---|
| 382 |   source: PWideChar;
 | 
|---|
| 383 |   BITbuffer: Cardinal;
 | 
|---|
| 384 |   bufferbits: Integer;
 | 
|---|
| 385 |   shifted: Boolean;
 | 
|---|
| 386 |   needshift: Boolean;
 | 
|---|
| 387 |   done: Boolean;
 | 
|---|
| 388 |   mustshift: PAnsiChar;
 | 
|---|
| 389 | begin
 | 
|---|
| 390 |   Initialize_UTF7_Data;
 | 
|---|
| 391 |   Result := 0;
 | 
|---|
| 392 |   BITbuffer := 0;
 | 
|---|
| 393 |   bufferbits := 0;
 | 
|---|
| 394 |   shifted := False;
 | 
|---|
| 395 |   source := sourceStart;
 | 
|---|
| 396 |   target := targetStart;
 | 
|---|
| 397 |   r := 0;
 | 
|---|
| 398 |   if needtables then
 | 
|---|
| 399 |     tabinit;
 | 
|---|
| 400 |   if optional then
 | 
|---|
| 401 |     mustshift := @mustshiftopt[0]
 | 
|---|
| 402 |   else
 | 
|---|
| 403 |     mustshift := @mustshiftsafe[0];
 | 
|---|
| 404 |   repeat
 | 
|---|
| 405 |     done := source >= sourceEnd;
 | 
|---|
| 406 |     if not Done then
 | 
|---|
| 407 |     begin
 | 
|---|
| 408 |       r := Word(source^);
 | 
|---|
| 409 |       Inc(Source);
 | 
|---|
| 410 |     end { If };
 | 
|---|
| 411 |     needshift := (not done) and ((r > $7F) or (mustshift[r] <> #0));
 | 
|---|
| 412 |     if needshift and (not shifted) then
 | 
|---|
| 413 |     begin
 | 
|---|
| 414 |       if (Target >= TargetEnd) then
 | 
|---|
| 415 |       begin
 | 
|---|
| 416 |         Result := 2;
 | 
|---|
| 417 |         break;
 | 
|---|
| 418 |       end { If };
 | 
|---|
| 419 |       target^ := '+';
 | 
|---|
| 420 |       Inc(target);
 | 
|---|
| 421 |       { Special case handling of the SHIFT_IN character }
 | 
|---|
| 422 |       if (r = UCS2('+')) then
 | 
|---|
| 423 |       begin
 | 
|---|
| 424 |         if (target >= targetEnd) then
 | 
|---|
| 425 |         begin
 | 
|---|
| 426 |           Result := 2;
 | 
|---|
| 427 |           break;
 | 
|---|
| 428 |         end;
 | 
|---|
| 429 |         target^ := '-';
 | 
|---|
| 430 |         Inc(target);
 | 
|---|
| 431 |       end
 | 
|---|
| 432 |       else
 | 
|---|
| 433 |         shifted := True;
 | 
|---|
| 434 |     end { If };
 | 
|---|
| 435 |     if shifted then
 | 
|---|
| 436 |     begin
 | 
|---|
| 437 |       { Either write the character to the bit buffer, or pad }
 | 
|---|
| 438 |       { the bit buffer out to a full base64 character. }
 | 
|---|
| 439 |       { }
 | 
|---|
| 440 |       if needshift then
 | 
|---|
| 441 |         WRITE_N_BITS(r, 16, BITbuffer, bufferbits)
 | 
|---|
| 442 |       else
 | 
|---|
| 443 |         WRITE_N_BITS(0, (6 - (bufferbits mod 6)) mod 6, BITbuffer,
 | 
|---|
| 444 |           bufferbits);
 | 
|---|
| 445 |       { Flush out as many full base64 characters as possible }
 | 
|---|
| 446 |       { from the bit buffer. }
 | 
|---|
| 447 |       { }
 | 
|---|
| 448 |       while (target < targetEnd) and (bufferbits >= 6) do
 | 
|---|
| 449 |       begin
 | 
|---|
| 450 |         Target^ := base64[READ_N_BITS(6, BITbuffer, bufferbits)];
 | 
|---|
| 451 |         Inc(Target);
 | 
|---|
| 452 |       end { While };
 | 
|---|
| 453 |       if (bufferbits >= 6) then
 | 
|---|
| 454 |       begin
 | 
|---|
| 455 |         if (target >= targetEnd) then
 | 
|---|
| 456 |         begin
 | 
|---|
| 457 |           Result := 2;
 | 
|---|
| 458 |           break;
 | 
|---|
| 459 |         end { If };
 | 
|---|
| 460 |       end { If };
 | 
|---|
| 461 |       if (not needshift) then
 | 
|---|
| 462 |       begin
 | 
|---|
| 463 |         { Write the explicit shift out character if }
 | 
|---|
| 464 |         { 1) The caller has requested we always do it, or }
 | 
|---|
| 465 |         { 2) The directly encoded character is in the }
 | 
|---|
| 466 |         { base64 set, or }
 | 
|---|
| 467 |         { 3) The directly encoded character is SHIFT_OUT. }
 | 
|---|
| 468 |         { }
 | 
|---|
| 469 |         if verbose or ((not done) and ((invbase64[r] >= 0) or (r =
 | 
|---|
| 470 |           Integer('-')))) then
 | 
|---|
| 471 |         begin
 | 
|---|
| 472 |           if (target >= targetEnd) then
 | 
|---|
| 473 |           begin
 | 
|---|
| 474 |             Result := 2;
 | 
|---|
| 475 |             Break;
 | 
|---|
| 476 |           end { If };
 | 
|---|
| 477 |           Target^ := '-';
 | 
|---|
| 478 |           Inc(Target);
 | 
|---|
| 479 |         end { If };
 | 
|---|
| 480 |         shifted := False;
 | 
|---|
| 481 |       end { If };
 | 
|---|
| 482 |       { The character can be directly encoded as ASCII. }
 | 
|---|
| 483 |     end { If };
 | 
|---|
| 484 |     if (not needshift) and (not done) then
 | 
|---|
| 485 |     begin
 | 
|---|
| 486 |       if (target >= targetEnd) then
 | 
|---|
| 487 |       begin
 | 
|---|
| 488 |         Result := 2;
 | 
|---|
| 489 |         break;
 | 
|---|
| 490 |       end { If };
 | 
|---|
| 491 |       Target^ := AnsiChar(r);
 | 
|---|
| 492 |       Inc(Target);
 | 
|---|
| 493 |     end { If };
 | 
|---|
| 494 |   until (done);
 | 
|---|
| 495 |   sourceStart := source;
 | 
|---|
| 496 |   targetStart := target;
 | 
|---|
| 497 | end; { ConvertUCS2toUTF7 }
 | 
|---|
| 498 | 
 | 
|---|
| 499 | function ConvertUTF7toUCS2(var sourceStart: PAnsiChar; sourceEnd: PAnsiChar;
 | 
|---|
| 500 |   var targetStart: PWideChar; targetEnd: PWideChar): Integer;
 | 
|---|
| 501 | var
 | 
|---|
| 502 |   target: PWideChar { Register };
 | 
|---|
| 503 |   source: PAnsiChar { Register };
 | 
|---|
| 504 |   BITbuffer: Cardinal { & "Address Of" Used };
 | 
|---|
| 505 |   bufferbits: Integer { & "Address Of" Used };
 | 
|---|
| 506 |   shifted: Boolean { Used In Boolean Context };
 | 
|---|
| 507 |   first: Boolean { Used In Boolean Context };
 | 
|---|
| 508 |   wroteone: Boolean;
 | 
|---|
| 509 |   base64EOF: Boolean;
 | 
|---|
| 510 |   base64value: Integer;
 | 
|---|
| 511 |   done: Boolean;
 | 
|---|
| 512 |   c: UCS2;
 | 
|---|
| 513 |   prevc: UCS2;
 | 
|---|
| 514 |   junk: UCS2 { Used In Boolean Context };
 | 
|---|
| 515 | begin
 | 
|---|
| 516 |   Initialize_UTF7_Data;
 | 
|---|
| 517 |   Result := 0;
 | 
|---|
| 518 |   BITbuffer := 0;
 | 
|---|
| 519 |   bufferbits := 0;
 | 
|---|
| 520 |   shifted := False;
 | 
|---|
| 521 |   first := False;
 | 
|---|
| 522 |   wroteone := False;
 | 
|---|
| 523 |   source := sourceStart;
 | 
|---|
| 524 |   target := targetStart;
 | 
|---|
| 525 |   c := 0;
 | 
|---|
| 526 |   if needtables then
 | 
|---|
| 527 |     tabinit;
 | 
|---|
| 528 |   repeat
 | 
|---|
| 529 |     { read an ASCII character c }
 | 
|---|
| 530 |     done := Source >= SourceEnd;
 | 
|---|
| 531 |     if (not done) then
 | 
|---|
| 532 |     begin
 | 
|---|
| 533 |       c := Word(Source^);
 | 
|---|
| 534 |       Inc(Source);
 | 
|---|
| 535 |     end { If };
 | 
|---|
| 536 |     if shifted then
 | 
|---|
| 537 |     begin
 | 
|---|
| 538 |       { We're done with a base64 string if we hit EOF, it's not a valid }
 | 
|---|
| 539 |       { ASCII character, or it's not in the base64 set. }
 | 
|---|
| 540 |       { }
 | 
|---|
| 541 |       base64value := invbase64[c];
 | 
|---|
| 542 |       base64EOF := (done or (c > $7F)) or (base64value < 0);
 | 
|---|
| 543 |       if base64EOF then
 | 
|---|
| 544 |       begin
 | 
|---|
| 545 |         shifted := False;
 | 
|---|
| 546 |         { If the character causing us to drop out was SHIFT_IN or }
 | 
|---|
| 547 |         { SHIFT_OUT, it may be a special escape for SHIFT_IN. The }
 | 
|---|
| 548 |         { test for SHIFT_IN is not necessary, but allows an alternate }
 | 
|---|
| 549 |         { form of UTF-7 where SHIFT_IN is escaped by SHIFT_IN. This }
 | 
|---|
| 550 |         { only works for some values of SHIFT_IN. }
 | 
|---|
| 551 |         { }
 | 
|---|
| 552 |         if ((not done) and ((c = Integer('+')) or (c = Integer('-')))) then
 | 
|---|
| 553 |         begin
 | 
|---|
| 554 |           { get another character c }
 | 
|---|
| 555 |           prevc := c;
 | 
|---|
| 556 |           Done := Source >= SourceEnd;
 | 
|---|
| 557 |           if (not Done) then
 | 
|---|
| 558 |           begin
 | 
|---|
| 559 |             c := Word(Source^);
 | 
|---|
| 560 |             Inc(Source);
 | 
|---|
| 561 |             { If no base64 characters were encountered, and the }
 | 
|---|
| 562 |             { character terminating the shift sequence was }
 | 
|---|
| 563 |             { SHIFT_OUT, then it's a special escape for SHIFT_IN. }
 | 
|---|
| 564 |             { }
 | 
|---|
| 565 |           end;
 | 
|---|
| 566 |           if first and (prevc = Integer('-')) then
 | 
|---|
| 567 |           begin
 | 
|---|
| 568 |             { write SHIFT_IN unicode }
 | 
|---|
| 569 |             if (target >= targetEnd) then
 | 
|---|
| 570 |             begin
 | 
|---|
| 571 |               Result := 2;
 | 
|---|
| 572 |               break;
 | 
|---|
| 573 |             end { If };
 | 
|---|
| 574 |             Target^ := WideChar('+');
 | 
|---|
| 575 |             Inc(Target);
 | 
|---|
| 576 |           end
 | 
|---|
| 577 |           else
 | 
|---|
| 578 |           begin
 | 
|---|
| 579 |             if (not wroteone) then
 | 
|---|
| 580 |             begin
 | 
|---|
| 581 |               Result := 1;
 | 
|---|
| 582 |             end { If };
 | 
|---|
| 583 |           end { Else };
 | 
|---|
| 584 |           ;
 | 
|---|
| 585 |         end { If }
 | 
|---|
| 586 |         else
 | 
|---|
| 587 |         begin
 | 
|---|
| 588 |           if (not wroteone) then
 | 
|---|
| 589 |           begin
 | 
|---|
| 590 |             Result := 1;
 | 
|---|
| 591 |           end { If };
 | 
|---|
| 592 |         end { Else };
 | 
|---|
| 593 |       end { If }
 | 
|---|
| 594 |       else
 | 
|---|
| 595 |       begin
 | 
|---|
| 596 |         { Add another 6 bits of base64 to the bit buffer. }
 | 
|---|
| 597 |         WRITE_N_BITS(base64value, 6, BITbuffer,
 | 
|---|
| 598 |           bufferbits);
 | 
|---|
| 599 |         first := False;
 | 
|---|
| 600 |       end { Else };
 | 
|---|
| 601 |       { Extract as many full 16 bit characters as possible from the }
 | 
|---|
| 602 |       { bit buffer. }
 | 
|---|
| 603 |       { }
 | 
|---|
| 604 |       while (bufferbits >= 16) and (target < targetEnd) do
 | 
|---|
| 605 |       begin
 | 
|---|
| 606 |         { write a unicode }
 | 
|---|
| 607 |         Target^ := WideChar(READ_N_BITS(16, BITbuffer, bufferbits));
 | 
|---|
| 608 |         Inc(Target);
 | 
|---|
| 609 |         wroteone := True;
 | 
|---|
| 610 |       end { While };
 | 
|---|
| 611 |       if (bufferbits >= 16) then
 | 
|---|
| 612 |       begin
 | 
|---|
| 613 |         if (target >= targetEnd) then
 | 
|---|
| 614 |         begin
 | 
|---|
| 615 |           Result := 2;
 | 
|---|
| 616 |           Break;
 | 
|---|
| 617 |         end;
 | 
|---|
| 618 |       end { If };
 | 
|---|
| 619 |       if (base64EOF) then
 | 
|---|
| 620 |       begin
 | 
|---|
| 621 |         junk := READ_N_BITS(bufferbits, BITbuffer, bufferbits);
 | 
|---|
| 622 |         if (junk <> 0) then
 | 
|---|
| 623 |         begin
 | 
|---|
| 624 |           Result := 1;
 | 
|---|
| 625 |         end { If };
 | 
|---|
| 626 |       end { If };
 | 
|---|
| 627 |     end { If };
 | 
|---|
| 628 |     if (not shifted) and (not done) then
 | 
|---|
| 629 |     begin
 | 
|---|
| 630 |       if (c = Integer('+')) then
 | 
|---|
| 631 |       begin
 | 
|---|
| 632 |         shifted := True;
 | 
|---|
| 633 |         first := True;
 | 
|---|
| 634 |         wroteone := False;
 | 
|---|
| 635 |       end { If }
 | 
|---|
| 636 |       else
 | 
|---|
| 637 |       begin
 | 
|---|
| 638 |         { It must be a directly encoded character. }
 | 
|---|
| 639 |         if (c > $7F) then
 | 
|---|
| 640 |         begin
 | 
|---|
| 641 |           Result := 1;
 | 
|---|
| 642 |         end { If };
 | 
|---|
| 643 |         if (target >= targetEnd) then
 | 
|---|
| 644 |         begin
 | 
|---|
| 645 |           Result := 2;
 | 
|---|
| 646 |           break;
 | 
|---|
| 647 |         end { If };
 | 
|---|
| 648 |         Target^ := WideChar(c);
 | 
|---|
| 649 |         Inc(Target);
 | 
|---|
| 650 |       end { Else };
 | 
|---|
| 651 |     end { If };
 | 
|---|
| 652 |   until (done);
 | 
|---|
| 653 |   sourceStart := source;
 | 
|---|
| 654 |   targetStart := target;
 | 
|---|
| 655 | end; { ConvertUTF7toUCS2 }
 | 
|---|
| 656 | 
 | 
|---|
| 657 |   {*****************************************************************************}
 | 
|---|
| 658 |   { Thanks to Francisco Leong for providing the Pascal conversion of            }
 | 
|---|
| 659 |   {   ConvertUTF7.c (by David B. Goldsmith)                                     }
 | 
|---|
| 660 |   {*****************************************************************************}
 | 
|---|
| 661 | 
 | 
|---|
| 662 | resourcestring
 | 
|---|
| 663 |   SBufferOverflow = 'Buffer overflow';
 | 
|---|
| 664 |   SInvalidUTF7 = 'Invalid UTF7';
 | 
|---|
| 665 | 
 | 
|---|
| 666 | function WideStringToUTF7(const W: WideString): AnsiString;
 | 
|---|
| 667 | var
 | 
|---|
| 668 |   SourceStart, SourceEnd: PWideChar;
 | 
|---|
| 669 |   TargetStart, TargetEnd: PAnsiChar;
 | 
|---|
| 670 | begin
 | 
|---|
| 671 |   if W = '' then
 | 
|---|
| 672 |     Result := ''
 | 
|---|
| 673 |   else
 | 
|---|
| 674 |   begin
 | 
|---|
| 675 |     SetLength(Result, Length(W) * 7); // Assume worst case
 | 
|---|
| 676 |     SourceStart := PWideChar(@W[1]);
 | 
|---|
| 677 |     SourceEnd := PWideChar(@W[Length(W)]) + 1;
 | 
|---|
| 678 |     TargetStart := PAnsiChar(@Result[1]);
 | 
|---|
| 679 |     TargetEnd := PAnsiChar(@Result[Length(Result)]) + 1;
 | 
|---|
| 680 |     if ConvertUCS2toUTF7(SourceStart, SourceEnd, TargetStart,
 | 
|---|
| 681 |       TargetEnd, True, False) <> 0
 | 
|---|
| 682 |     then
 | 
|---|
| 683 |       raise ETntInternalError.Create(SBufferOverflow);
 | 
|---|
| 684 |     SetLength(Result, TargetStart - PAnsiChar(@Result[1]));
 | 
|---|
| 685 |   end;
 | 
|---|
| 686 | end;
 | 
|---|
| 687 | 
 | 
|---|
| 688 | function UTF7ToWideString(const S: AnsiString): WideString;
 | 
|---|
| 689 | var
 | 
|---|
| 690 |   SourceStart, SourceEnd: PAnsiChar;
 | 
|---|
| 691 |   TargetStart, TargetEnd: PWideChar;
 | 
|---|
| 692 | begin
 | 
|---|
| 693 |   if (S = '') then
 | 
|---|
| 694 |     Result := ''
 | 
|---|
| 695 |   else
 | 
|---|
| 696 |   begin
 | 
|---|
| 697 |     SetLength(Result, Length(S)); // Assume Worst case
 | 
|---|
| 698 |     SourceStart := PAnsiChar(@S[1]);
 | 
|---|
| 699 |     SourceEnd := PAnsiChar(@S[Length(S)]) + 1;
 | 
|---|
| 700 |     TargetStart := PWideChar(@Result[1]);
 | 
|---|
| 701 |     TargetEnd := PWideChar(@Result[Length(Result)]) + 1;
 | 
|---|
| 702 |     case ConvertUTF7toUCS2(SourceStart, SourceEnd, TargetStart,
 | 
|---|
| 703 |       TargetEnd) of
 | 
|---|
| 704 |       1: raise ETntGeneralError.Create(SInvalidUTF7);
 | 
|---|
| 705 |       2: raise ETntInternalError.Create(SBufferOverflow);
 | 
|---|
| 706 |     end;
 | 
|---|
| 707 |     SetLength(Result, TargetStart - PWideChar(@Result[1]));
 | 
|---|
| 708 |   end;
 | 
|---|
| 709 | end;
 | 
|---|
| 710 | 
 | 
|---|
| 711 | function StringToWideStringEx(const S: AnsiString; CodePage: Cardinal): WideString;
 | 
|---|
| 712 | var
 | 
|---|
| 713 |   InputLength,
 | 
|---|
| 714 |   OutputLength: Integer;
 | 
|---|
| 715 | begin
 | 
|---|
| 716 |   if CodePage = CP_UTF7 then
 | 
|---|
| 717 |     Result := UTF7ToWideString(S) // CP_UTF7 not supported on Windows 95
 | 
|---|
| 718 |   else if CodePage = CP_UTF8 then
 | 
|---|
| 719 |     Result := UTF8ToWideString(S) // CP_UTF8 not supported on Windows 95
 | 
|---|
| 720 |   else begin
 | 
|---|
| 721 |     InputLength := Length(S);
 | 
|---|
| 722 |     OutputLength := MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, nil, 0);
 | 
|---|
| 723 |     SetLength(Result, OutputLength);
 | 
|---|
| 724 |     MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, PWideChar(Result), OutputLength);
 | 
|---|
| 725 |   end;
 | 
|---|
| 726 | end;
 | 
|---|
| 727 | 
 | 
|---|
| 728 | function WideStringToStringEx(const WS: WideString; CodePage: Cardinal): AnsiString;
 | 
|---|
| 729 | var
 | 
|---|
| 730 |   InputLength,
 | 
|---|
| 731 |   OutputLength: Integer;
 | 
|---|
| 732 | begin
 | 
|---|
| 733 |   if CodePage = CP_UTF7 then
 | 
|---|
| 734 |     Result := WideStringToUTF7(WS) // CP_UTF7 not supported on Windows 95
 | 
|---|
| 735 |   else if CodePage = CP_UTF8 then
 | 
|---|
| 736 |     Result := WideStringToUTF8(WS) // CP_UTF8 not supported on Windows 95
 | 
|---|
| 737 |   else begin
 | 
|---|
| 738 |     InputLength := Length(WS);
 | 
|---|
| 739 |     OutputLength := WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, nil, 0, nil, nil);
 | 
|---|
| 740 |     SetLength(Result, OutputLength);
 | 
|---|
| 741 |     WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, PAnsiChar(Result), OutputLength, nil, nil);
 | 
|---|
| 742 |   end;
 | 
|---|
| 743 | end;
 | 
|---|
| 744 | 
 | 
|---|
| 745 | function UCS2ToWideString(const Value: AnsiString): WideString;
 | 
|---|
| 746 | begin
 | 
|---|
| 747 |   if Length(Value) = 0 then
 | 
|---|
| 748 |     Result := ''
 | 
|---|
| 749 |   else
 | 
|---|
| 750 |     SetString(Result, PWideChar(@Value[1]), Length(Value) div SizeOf(WideChar))
 | 
|---|
| 751 | end;
 | 
|---|
| 752 | 
 | 
|---|
| 753 | function WideStringToUCS2(const Value: WideString): AnsiString;
 | 
|---|
| 754 | begin
 | 
|---|
| 755 |   if Length(Value) = 0 then
 | 
|---|
| 756 |     Result := ''
 | 
|---|
| 757 |   else
 | 
|---|
| 758 |     SetString(Result, PAnsiChar(@Value[1]), Length(Value) * SizeOf(WideChar))
 | 
|---|
| 759 | end;
 | 
|---|
| 760 | 
 | 
|---|
| 761 | { Windows.pas doesn't declare TranslateCharsetInfo() correctly. }
 | 
|---|
| 762 | function TranslateCharsetInfo(lpSrc: PDWORD; var lpCs: TCharsetInfo; dwFlags: DWORD): BOOL; stdcall; external gdi32 name 'TranslateCharsetInfo';
 | 
|---|
| 763 | 
 | 
|---|
| 764 | function CharSetToCodePage(ciCharset: UINT): Cardinal;
 | 
|---|
| 765 | var
 | 
|---|
| 766 |   C: TCharsetInfo;
 | 
|---|
| 767 | begin
 | 
|---|
| 768 |   Win32Check(TranslateCharsetInfo(PDWORD(ciCharset), C, TCI_SRCCHARSET));
 | 
|---|
| 769 |   Result := C.ciACP
 | 
|---|
| 770 | end;
 | 
|---|
| 771 | 
 | 
|---|
| 772 | function LCIDToCodePage(ALcid: LCID): Cardinal;
 | 
|---|
| 773 | var
 | 
|---|
| 774 |   Buf: array[0..6] of AnsiChar;
 | 
|---|
| 775 | begin
 | 
|---|
| 776 |   GetLocaleInfo(ALcid, LOCALE_IDefaultAnsiCodePage, Buf, 6);
 | 
|---|
| 777 |   Result := StrToIntDef(Buf, GetACP);
 | 
|---|
| 778 | end;
 | 
|---|
| 779 | 
 | 
|---|
| 780 | function KeyboardCodePage: Cardinal;
 | 
|---|
| 781 | begin
 | 
|---|
| 782 |   Result := LCIDToCodePage(GetKeyboardLayout(0) and $FFFF);
 | 
|---|
| 783 | end;
 | 
|---|
| 784 | 
 | 
|---|
| 785 | function KeyUnicode(CharCode: Word): WideChar;
 | 
|---|
| 786 | var
 | 
|---|
| 787 |   AChar: AnsiChar;
 | 
|---|
| 788 | begin
 | 
|---|
| 789 |   // converts the given character (as it comes with a WM_CHAR message) into its
 | 
|---|
| 790 |   // corresponding Unicode character depending on the active keyboard layout
 | 
|---|
| 791 |   if CharCode <= Word(High(AnsiChar)) then begin
 | 
|---|
| 792 |     AChar := AnsiChar(CharCode);
 | 
|---|
| 793 |     MultiByteToWideChar(KeyboardCodePage, MB_USEGLYPHCHARS, @AChar, 1, @Result, 1);
 | 
|---|
| 794 |   end else
 | 
|---|
| 795 |     Result := WideChar(CharCode);
 | 
|---|
| 796 | end;
 | 
|---|
| 797 | 
 | 
|---|
| 798 | procedure StrSwapByteOrder(Str: PWideChar);
 | 
|---|
| 799 | var
 | 
|---|
| 800 |   P: PWord;
 | 
|---|
| 801 | begin
 | 
|---|
| 802 |   P := PWord(Str);
 | 
|---|
| 803 |   While (P^ <> 0) do begin
 | 
|---|
| 804 |     P^ := MakeWord(HiByte(P^), LoByte(P^));
 | 
|---|
| 805 |     Inc(P);
 | 
|---|
| 806 |   end;
 | 
|---|
| 807 | end;
 | 
|---|
| 808 | 
 | 
|---|
| 809 | //--------------------------------------------------------------------
 | 
|---|
| 810 | //                LoadResString()
 | 
|---|
| 811 | //
 | 
|---|
| 812 | //  This system function is used to retrieve a resourcestring and
 | 
|---|
| 813 | //   return the result as an AnsiString.  If we believe that the result
 | 
|---|
| 814 | //    is only a temporary value, and that it will be immediately
 | 
|---|
| 815 | //     assigned to a WideString or a Variant, then we will save the
 | 
|---|
| 816 | //      Unicode result as well as a reference to the original Ansi string.
 | 
|---|
| 817 | //       WStrFromPCharLen() or VarFromLStr() will return this saved
 | 
|---|
| 818 | //        Unicode string if it appears to receive the most recent result
 | 
|---|
| 819 | //         of LoadResString.
 | 
|---|
| 820 | //--------------------------------------------------------------------
 | 
|---|
| 821 | 
 | 
|---|
| 822 | 
 | 
|---|
| 823 |   //===========================================================================================
 | 
|---|
| 824 |   //
 | 
|---|
| 825 |   //    function CodeMatchesPatternForUnicode(...);
 | 
|---|
| 826 |   //
 | 
|---|
| 827 |   //    GIVEN:  SomeWideString := SSomeResString;  { WideString := resourcestring }
 | 
|---|
| 828 |   //
 | 
|---|
| 829 |   //    Delphi will compile this statement into the following:
 | 
|---|
| 830 |   //    -------------------------------------------------
 | 
|---|
| 831 |   //    TempAnsiString := LoadResString(@SSomeResString);
 | 
|---|
| 832 |   //      LINE 1:  lea edx,[SomeTempAnsiString]
 | 
|---|
| 833 |   //      LINE 2:  mov eax,[@SomeResString]
 | 
|---|
| 834 |   //      LINE 3:  call LoadResString
 | 
|---|
| 835 |   //
 | 
|---|
| 836 |   //    WStrFromLStr(SomeWideString, TempAnsiString);  { SomeWideString := TempAnsiString }
 | 
|---|
| 837 |   //      LINE 4:  mov edx,[SomeTempAnsiString]
 | 
|---|
| 838 |   //      LINE 5:  mov/lea eax [@SomeWideString]
 | 
|---|
| 839 |   //      LINE 6:  call @WStrFromLStr
 | 
|---|
| 840 |   //    -------------------------------------------------
 | 
|---|
| 841 |   //
 | 
|---|
| 842 |   //    The order in which the parameters are prepared for WStrFromLStr (ie LINE 4 & 5) is
 | 
|---|
| 843 |   //      reversed when assigning a non-temporary AnsiString to a WideString.
 | 
|---|
| 844 |   //
 | 
|---|
| 845 |   //    This code, for example, results in LINE 4 and LINE 5 being swapped.
 | 
|---|
| 846 |   //
 | 
|---|
| 847 |   //      SomeAnsiString := SSomeResString;
 | 
|---|
| 848 |   //      SomeWideString := SomeAnsiString;
 | 
|---|
| 849 |   //
 | 
|---|
| 850 |   //    Since we know the "signature" used by the compiler, we can detect this pattern.
 | 
|---|
| 851 |   //     If we believe it is only temporary, we can save the Unicode results for later
 | 
|---|
| 852 |   //      retrieval from WStrFromLStr.
 | 
|---|
| 853 |   //
 | 
|---|
| 854 |   //    One final note:  When assigning a resourcestring to a Variant, the same patterns exist.
 | 
|---|
| 855 |   //===========================================================================================
 | 
|---|
| 856 | 
 | 
|---|
| 857 | function CodeMatchesPatternForUnicode(PLine4: PAnsiChar): Boolean;
 | 
|---|
| 858 | const
 | 
|---|
| 859 |   SIZEOF_OPCODE = 1 {byte};
 | 
|---|
| 860 |   MOV_16_OPCODE = AnsiChar($8B); { we'll assume operand size is 16 bits }
 | 
|---|
| 861 |   MOV_32_OPCODE = AnsiChar($B8); { we'll assume operand size is 32 bits }
 | 
|---|
| 862 |   LEA_OPCODE    = AnsiChar($8D); { operand size can be 16 or 40 bits }
 | 
|---|
| 863 |   CALL_OPCODE   = AnsiChar($E8); { assumed operand size is 32 bits }
 | 
|---|
| 864 |   BREAK_OPCODE  = AnsiChar($CC); {in a breakpoint}
 | 
|---|
| 865 | var
 | 
|---|
| 866 |   PLine1: PAnsiChar;
 | 
|---|
| 867 |   PLine2: PAnsiChar;
 | 
|---|
| 868 |   PLine3: PAnsiChar;
 | 
|---|
| 869 |   DataSize: Integer; // bytes in first LEA operand
 | 
|---|
| 870 | begin
 | 
|---|
| 871 |   Result := False;
 | 
|---|
| 872 | 
 | 
|---|
| 873 |   PLine3 := PLine4 - SizeOf(CALL_OPCODE) - 4;
 | 
|---|
| 874 |   PLine2 := PLine3 - SizeOf(MOV_32_OPCODE) - 4;
 | 
|---|
| 875 | 
 | 
|---|
| 876 |   // figure PLine1 and operand size
 | 
|---|
| 877 |   DataSize := 2; { try 16 bit operand for line 1 }
 | 
|---|
| 878 |   PLine1 := PLine2 - DataSize - SizeOf(LEA_OPCODE);
 | 
|---|
| 879 |   if (PLine1^ <> LEA_OPCODE) and (not (IsDebugging and (PLine1^ = BREAK_OPCODE))) then
 | 
|---|
| 880 |   begin
 | 
|---|
| 881 |     DataSize := 5; { try 40 bit operand for line 1 }
 | 
|---|
| 882 |     PLine1 := PLine2 - DataSize - SizeOf(LEA_OPCODE);
 | 
|---|
| 883 |   end;
 | 
|---|
| 884 |   if (PLine1^ = LEA_OPCODE) or (IsDebugging and (PLine1^ = BREAK_OPCODE)) then
 | 
|---|
| 885 |   begin
 | 
|---|
| 886 |     if CompareMem(PLine1 + SIZEOF_OPCODE, PLine4 + SIZEOF_OPCODE, DataSize) then
 | 
|---|
| 887 |     begin
 | 
|---|
| 888 |       // After this check, it seems to match the WideString <- (temp) AnsiString pattern
 | 
|---|
| 889 |       Result := True; // It is probably OK. (The side effects of being wrong aren't very bad.)
 | 
|---|
| 890 |     end;
 | 
|---|
| 891 |   end;
 | 
|---|
| 892 | end;
 | 
|---|
| 893 | 
 | 
|---|
| 894 | threadvar
 | 
|---|
| 895 |   PLastResString: PAnsiChar;
 | 
|---|
| 896 |   LastResStringValue: AnsiString;
 | 
|---|
| 897 |   LastWideResString: WideString;
 | 
|---|
| 898 | 
 | 
|---|
| 899 | procedure FreeTntSystemThreadVars;
 | 
|---|
| 900 | begin
 | 
|---|
| 901 |   LastResStringValue := '';
 | 
|---|
| 902 |   LastWideResString := '';
 | 
|---|
| 903 | end;
 | 
|---|
| 904 | 
 | 
|---|
| 905 | procedure Custom_System_EndThread(ExitCode: Integer);
 | 
|---|
| 906 | begin
 | 
|---|
| 907 |   FreeTntSystemThreadVars;
 | 
|---|
| 908 |   {$IFDEF COMPILER_10_UP}
 | 
|---|
| 909 |   if Assigned(SystemThreadEndProc) then
 | 
|---|
| 910 |     SystemThreadEndProc(ExitCode);
 | 
|---|
| 911 |   {$ENDIF}
 | 
|---|
| 912 |   ExitThread(ExitCode);
 | 
|---|
| 913 | end;
 | 
|---|
| 914 | 
 | 
|---|
| 915 | function Custom_System_LoadResString(ResStringRec: PResStringRec): AnsiString;
 | 
|---|
| 916 | var
 | 
|---|
| 917 |   ReturnAddr: Pointer;
 | 
|---|
| 918 | begin
 | 
|---|
| 919 |   // get return address
 | 
|---|
| 920 |   asm
 | 
|---|
| 921 |     PUSH   ECX
 | 
|---|
| 922 |     MOV    ECX, [EBP + 4]
 | 
|---|
| 923 |     MOV    ReturnAddr, ECX
 | 
|---|
| 924 |     POP    ECX
 | 
|---|
| 925 |   end;
 | 
|---|
| 926 |   // check calling code pattern
 | 
|---|
| 927 |   if CodeMatchesPatternForUnicode(ReturnAddr) then begin
 | 
|---|
| 928 |     // result will probably be assigned to an intermediate AnsiString
 | 
|---|
| 929 |     //   on its way to either a WideString or Variant.
 | 
|---|
| 930 |     LastWideResString := WideLoadResString(ResStringRec);
 | 
|---|
| 931 |     Result := LastWideResString;
 | 
|---|
| 932 |     LastResStringValue := Result;
 | 
|---|
| 933 |     if Result = '' then
 | 
|---|
| 934 |       PLastResString := nil
 | 
|---|
| 935 |     else
 | 
|---|
| 936 |       PLastResString := PAnsiChar(Result);
 | 
|---|
| 937 |   end else begin
 | 
|---|
| 938 |     // result will probably be assigned to an actual AnsiString variable.
 | 
|---|
| 939 |     PLastResString := nil;
 | 
|---|
| 940 |     Result := WideLoadResString(ResStringRec);
 | 
|---|
| 941 |   end;
 | 
|---|
| 942 | end;
 | 
|---|
| 943 | 
 | 
|---|
| 944 | //--------------------------------------------------------------------
 | 
|---|
| 945 | //                WStrFromPCharLen()
 | 
|---|
| 946 | //
 | 
|---|
| 947 | //  This system function is used to assign an AnsiString to a WideString.
 | 
|---|
| 948 | //   It has been modified to assign Unicode results from LoadResString.
 | 
|---|
| 949 | //     Another purpose of this function is to specify the code page.
 | 
|---|
| 950 | //--------------------------------------------------------------------
 | 
|---|
| 951 | 
 | 
|---|
| 952 | procedure Custom_System_WStrFromPCharLen(var Dest: WideString; Source: PAnsiChar; Length: Integer);
 | 
|---|
| 953 | var
 | 
|---|
| 954 |   DestLen: Integer;
 | 
|---|
| 955 |   Buffer: array[0..2047] of WideChar;
 | 
|---|
| 956 |   Local_PLastResString: Pointer;
 | 
|---|
| 957 | begin
 | 
|---|
| 958 |   Local_PLastResString := PLastResString;
 | 
|---|
| 959 |   if  (Local_PLastResString <> nil)
 | 
|---|
| 960 |   and (Local_PLastResString = Source)
 | 
|---|
| 961 |   and (System.Length(LastResStringValue) = Length)
 | 
|---|
| 962 |   and (LastResStringValue = Source) then begin
 | 
|---|
| 963 |     // use last unicode resource string
 | 
|---|
| 964 |     PLastResString := nil; { clear for further use }
 | 
|---|
| 965 |     Dest := LastWideResString;
 | 
|---|
| 966 |   end else begin
 | 
|---|
| 967 |     if Local_PLastResString <> nil then
 | 
|---|
| 968 |       PLastResString := nil; { clear for further use }
 | 
|---|
| 969 |     if Length <= 0 then
 | 
|---|
| 970 |     begin
 | 
|---|
| 971 |       Dest := '';
 | 
|---|
| 972 |       Exit;
 | 
|---|
| 973 |     end;
 | 
|---|
| 974 |     if Length + 1 < High(Buffer) then
 | 
|---|
| 975 |     begin
 | 
|---|
| 976 |       DestLen := MultiByteToWideChar(DefaultSystemCodePage, 0, Source, Length, Buffer,
 | 
|---|
| 977 |         High(Buffer));
 | 
|---|
| 978 |       if DestLen > 0 then
 | 
|---|
| 979 |       begin
 | 
|---|
| 980 |         SetLength(Dest, DestLen);
 | 
|---|
| 981 |         Move(Pointer(@Buffer[0])^, Pointer(Dest)^, DestLen * SizeOf(WideChar));
 | 
|---|
| 982 |         Exit;
 | 
|---|
| 983 |       end;
 | 
|---|
| 984 |     end;
 | 
|---|
| 985 |     DestLen := (Length + 1);
 | 
|---|
| 986 |     SetLength(Dest, DestLen); // overallocate, trim later
 | 
|---|
| 987 |     DestLen := MultiByteToWideChar(DefaultSystemCodePage, 0, Source, Length, Pointer(Dest),
 | 
|---|
| 988 |       DestLen);
 | 
|---|
| 989 |     if DestLen < 0 then
 | 
|---|
| 990 |       DestLen := 0;
 | 
|---|
| 991 |     SetLength(Dest, DestLen);
 | 
|---|
| 992 |   end;
 | 
|---|
| 993 | end;
 | 
|---|
| 994 | 
 | 
|---|
| 995 | {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 996 | 
 | 
|---|
| 997 | //--------------------------------------------------------------------
 | 
|---|
| 998 | //                LStrFromPWCharLen()
 | 
|---|
| 999 | //
 | 
|---|
| 1000 | //  This system function is used to assign an WideString to an AnsiString.
 | 
|---|
| 1001 | //   It has not been modified from its original purpose other than to specify the code page.
 | 
|---|
| 1002 | //--------------------------------------------------------------------
 | 
|---|
| 1003 | 
 | 
|---|
| 1004 | procedure Custom_System_LStrFromPWCharLen(var Dest: AnsiString; Source: PWideChar; Length: Integer);
 | 
|---|
| 1005 | var
 | 
|---|
| 1006 |   DestLen: Integer;
 | 
|---|
| 1007 |   Buffer: array[0..4095] of AnsiChar;
 | 
|---|
| 1008 | begin
 | 
|---|
| 1009 |   if Length <= 0 then
 | 
|---|
| 1010 |   begin
 | 
|---|
| 1011 |     Dest := '';
 | 
|---|
| 1012 |     Exit;
 | 
|---|
| 1013 |   end;
 | 
|---|
| 1014 |   if Length + 1 < (High(Buffer) div sizeof(WideChar)) then
 | 
|---|
| 1015 |   begin
 | 
|---|
| 1016 |     DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Source,
 | 
|---|
| 1017 |       Length, Buffer, High(Buffer),
 | 
|---|
| 1018 |       nil, nil);
 | 
|---|
| 1019 |     if DestLen >= 0 then
 | 
|---|
| 1020 |     begin
 | 
|---|
| 1021 |       SetLength(Dest, DestLen);
 | 
|---|
| 1022 |       Move(Pointer(@Buffer[0])^, PAnsiChar(Dest)^, DestLen);
 | 
|---|
| 1023 |       Exit;
 | 
|---|
| 1024 |     end;
 | 
|---|
| 1025 |   end;
 | 
|---|
| 1026 | 
 | 
|---|
| 1027 |   DestLen := (Length + 1) * sizeof(WideChar);
 | 
|---|
| 1028 |   SetLength(Dest, DestLen); // overallocate, trim later
 | 
|---|
| 1029 |   DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Source, Length, Pointer(Dest), DestLen,
 | 
|---|
| 1030 |     nil, nil);
 | 
|---|
| 1031 |   if DestLen < 0 then
 | 
|---|
| 1032 |     DestLen := 0;
 | 
|---|
| 1033 |   SetLength(Dest, DestLen);
 | 
|---|
| 1034 | end;
 | 
|---|
| 1035 | 
 | 
|---|
| 1036 | //--------------------------------------------------------------------
 | 
|---|
| 1037 | //                WStrToString()
 | 
|---|
| 1038 | //
 | 
|---|
| 1039 | //  This system function is used to assign an WideString to an short string.
 | 
|---|
| 1040 | //   It has not been modified from its original purpose other than to specify the code page.
 | 
|---|
| 1041 | //--------------------------------------------------------------------
 | 
|---|
| 1042 | 
 | 
|---|
| 1043 | procedure Custom_System_WStrToString(Dest: PShortString; const Source: WideString; MaxLen: Integer);
 | 
|---|
| 1044 | var
 | 
|---|
| 1045 |   SourceLen, DestLen: Integer;
 | 
|---|
| 1046 |   Buffer: array[0..511] of AnsiChar;
 | 
|---|
| 1047 | begin
 | 
|---|
| 1048 |   if MaxLen > 255 then MaxLen := 255;
 | 
|---|
| 1049 |   SourceLen := Length(Source);
 | 
|---|
| 1050 |   if SourceLen >= MaxLen then SourceLen := MaxLen;
 | 
|---|
| 1051 |   if SourceLen = 0 then
 | 
|---|
| 1052 |     DestLen := 0
 | 
|---|
| 1053 |   else begin
 | 
|---|
| 1054 |     DestLen := WideCharToMultiByte(DefaultSystemCodePage, 0, Pointer(Source), SourceLen,
 | 
|---|
| 1055 |       Buffer, SizeOf(Buffer), nil, nil);
 | 
|---|
| 1056 |     if DestLen > MaxLen then DestLen := MaxLen;
 | 
|---|
| 1057 |   end;
 | 
|---|
| 1058 |   Dest^[0] := Chr(DestLen);
 | 
|---|
| 1059 |   if DestLen > 0 then Move(Buffer, Dest^[1], DestLen);
 | 
|---|
| 1060 | end;
 | 
|---|
| 1061 | 
 | 
|---|
| 1062 | {$ENDIF}
 | 
|---|
| 1063 | 
 | 
|---|
| 1064 | //--------------------------------------------------------------------
 | 
|---|
| 1065 | //                VarFromLStr()
 | 
|---|
| 1066 | //
 | 
|---|
| 1067 | //  This system function is used to assign an AnsiString to a Variant.
 | 
|---|
| 1068 | //   It has been modified to assign Unicode results from LoadResString.
 | 
|---|
| 1069 | //--------------------------------------------------------------------
 | 
|---|
| 1070 | 
 | 
|---|
| 1071 | procedure Custom_System_VarFromLStr(var V: TVarData; const Value: AnsiString);
 | 
|---|
| 1072 | const
 | 
|---|
| 1073 |   varDeepData = $BFE8;
 | 
|---|
| 1074 | var
 | 
|---|
| 1075 |   Local_PLastResString: Pointer;
 | 
|---|
| 1076 | begin
 | 
|---|
| 1077 |   if (V.VType and varDeepData) <> 0 then
 | 
|---|
| 1078 |     VarClear(PVariant(@V)^);
 | 
|---|
| 1079 | 
 | 
|---|
| 1080 |   Local_PLastResString := PLastResString;
 | 
|---|
| 1081 |   if  (Local_PLastResString <> nil)
 | 
|---|
| 1082 |   and (Local_PLastResString = PAnsiChar(Value))
 | 
|---|
| 1083 |   and (LastResStringValue = Value) then begin
 | 
|---|
| 1084 |     // use last unicode resource string
 | 
|---|
| 1085 |     PLastResString := nil; { clear for further use }
 | 
|---|
| 1086 |     V.VOleStr := nil;
 | 
|---|
| 1087 |     V.VType := varOleStr;
 | 
|---|
| 1088 |     WideString(Pointer(V.VOleStr)) := Copy(LastWideResString, 1, MaxInt);
 | 
|---|
| 1089 |   end else begin
 | 
|---|
| 1090 |     if Local_PLastResString <> nil then
 | 
|---|
| 1091 |       PLastResString := nil; { clear for further use }
 | 
|---|
| 1092 |     V.VString := nil;
 | 
|---|
| 1093 |     V.VType := varString;
 | 
|---|
| 1094 |     AnsiString(V.VString) := Value;
 | 
|---|
| 1095 |   end;
 | 
|---|
| 1096 | end;
 | 
|---|
| 1097 | 
 | 
|---|
| 1098 | {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1099 | 
 | 
|---|
| 1100 | //--------------------------------------------------------------------
 | 
|---|
| 1101 | //                WStrCat3()     A := B + C;
 | 
|---|
| 1102 | //
 | 
|---|
| 1103 | //  This system function is used to concatenate two strings into one result.
 | 
|---|
| 1104 | //    This function is added because A := '' + '' doesn't necessarily result in A = '';
 | 
|---|
| 1105 | //--------------------------------------------------------------------
 | 
|---|
| 1106 | 
 | 
|---|
| 1107 | procedure Custom_System_WStrCat3(var Dest: WideString; const Source1, Source2: WideString);
 | 
|---|
| 1108 | 
 | 
|---|
| 1109 |   function NewWideString(CharLength: Longint): Pointer;
 | 
|---|
| 1110 |   var
 | 
|---|
| 1111 |     _NewWideString: function(CharLength: Longint): Pointer;
 | 
|---|
| 1112 |   begin
 | 
|---|
| 1113 |     asm
 | 
|---|
| 1114 |       PUSH   ECX
 | 
|---|
| 1115 |       MOV    ECX, offset System.@NewWideString;
 | 
|---|
| 1116 |       MOV    _NewWideString, ECX
 | 
|---|
| 1117 |       POP    ECX
 | 
|---|
| 1118 |     end;
 | 
|---|
| 1119 |     Result := _NewWideString(CharLength);
 | 
|---|
| 1120 |   end;
 | 
|---|
| 1121 | 
 | 
|---|
| 1122 |   procedure WStrSet(var S: WideString; P: PWideChar);
 | 
|---|
| 1123 |   var
 | 
|---|
| 1124 |     Temp: Pointer;
 | 
|---|
| 1125 |   begin
 | 
|---|
| 1126 |     Temp := Pointer(InterlockedExchange(Integer(S), Integer(P)));
 | 
|---|
| 1127 |     if Temp <> nil then
 | 
|---|
| 1128 |       WideString(Temp) := '';
 | 
|---|
| 1129 |   end;
 | 
|---|
| 1130 | 
 | 
|---|
| 1131 | var
 | 
|---|
| 1132 |   Source1Len, Source2Len: Integer;
 | 
|---|
| 1133 |   NewStr: PWideChar;
 | 
|---|
| 1134 | begin
 | 
|---|
| 1135 |   Source1Len := Length(Source1);
 | 
|---|
| 1136 |   Source2Len := Length(Source2);
 | 
|---|
| 1137 |   if (Source1Len <> 0) or (Source2Len <> 0) then
 | 
|---|
| 1138 |   begin
 | 
|---|
| 1139 |     NewStr := NewWideString(Source1Len + Source2Len);
 | 
|---|
| 1140 |     Move(Pointer(Source1)^, Pointer(NewStr)^, Source1Len * sizeof(WideChar));
 | 
|---|
| 1141 |     Move(Pointer(Source2)^, NewStr[Source1Len], Source2Len * sizeof(WideChar));
 | 
|---|
| 1142 |     WStrSet(Dest, NewStr);
 | 
|---|
| 1143 |   end else
 | 
|---|
| 1144 |     Dest := '';
 | 
|---|
| 1145 | end;
 | 
|---|
| 1146 | 
 | 
|---|
| 1147 | {$ENDIF}
 | 
|---|
| 1148 | 
 | 
|---|
| 1149 | //--------------------------------------------------------------------
 | 
|---|
| 1150 | //                System proc replacements
 | 
|---|
| 1151 | //--------------------------------------------------------------------
 | 
|---|
| 1152 | 
 | 
|---|
| 1153 | type
 | 
|---|
| 1154 |   POverwrittenData = ^TOverwrittenData;
 | 
|---|
| 1155 |   TOverwrittenData = record
 | 
|---|
| 1156 |     Location: Pointer;
 | 
|---|
| 1157 |     OldCode: array[0..6] of Byte;
 | 
|---|
| 1158 |   end;
 | 
|---|
| 1159 | 
 | 
|---|
| 1160 | procedure OverwriteProcedure(OldProcedure, NewProcedure: pointer; Data: POverwrittenData = nil);
 | 
|---|
| 1161 | { OverwriteProcedure originally from Igor Siticov }
 | 
|---|
| 1162 | { Modified by Jacques Garcia Vazquez }
 | 
|---|
| 1163 | var
 | 
|---|
| 1164 |   x: PAnsiChar;
 | 
|---|
| 1165 |   y: integer;
 | 
|---|
| 1166 |   ov2, ov: cardinal;
 | 
|---|
| 1167 |   p: pointer;
 | 
|---|
| 1168 | begin
 | 
|---|
| 1169 |   if Assigned(Data) and (Data.Location <> nil) then
 | 
|---|
| 1170 |     exit; { procedure already overwritten }
 | 
|---|
| 1171 | 
 | 
|---|
| 1172 |   // need six bytes in place of 5
 | 
|---|
| 1173 |   x := PAnsiChar(OldProcedure);
 | 
|---|
| 1174 |   if not VirtualProtect(Pointer(x), 6, PAGE_EXECUTE_READWRITE, @ov) then
 | 
|---|
| 1175 |     RaiseLastOSError;
 | 
|---|
| 1176 | 
 | 
|---|
| 1177 |   // if a jump is present then a redirect is found
 | 
|---|
| 1178 |   // $FF25 = jmp dword ptr [xxx]
 | 
|---|
| 1179 |   // This redirect is normally present in bpl files, but not in exe files
 | 
|---|
| 1180 |   p := OldProcedure;
 | 
|---|
| 1181 | 
 | 
|---|
| 1182 |   if Word(p^) = $25FF then
 | 
|---|
| 1183 |   begin
 | 
|---|
| 1184 |     Inc(Integer(p), 2); // skip the jump
 | 
|---|
| 1185 |     // get the jump address p^ and dereference it p^^
 | 
|---|
| 1186 |     p := Pointer(Pointer(p^)^);
 | 
|---|
| 1187 | 
 | 
|---|
| 1188 |     // release the memory
 | 
|---|
| 1189 |     if not VirtualProtect(Pointer(x), 6, ov, @ov2) then
 | 
|---|
| 1190 |       RaiseLastOSError;
 | 
|---|
| 1191 | 
 | 
|---|
| 1192 |     // re protect the correct one
 | 
|---|
| 1193 |     x := PAnsiChar(p);
 | 
|---|
| 1194 |     if not VirtualProtect(Pointer(x), 6, PAGE_EXECUTE_READWRITE, @ov) then
 | 
|---|
| 1195 |       RaiseLastOSError;
 | 
|---|
| 1196 |   end;
 | 
|---|
| 1197 | 
 | 
|---|
| 1198 |   if Assigned(Data) then
 | 
|---|
| 1199 |   begin
 | 
|---|
| 1200 |     Move(x^, Data.OldCode, 6);
 | 
|---|
| 1201 |     { Assign Location last so that Location <> nil only if OldCode is properly initialized. }
 | 
|---|
| 1202 |     Data.Location := x;
 | 
|---|
| 1203 |   end;
 | 
|---|
| 1204 | 
 | 
|---|
| 1205 |   x[0] := AnsiChar($E9);
 | 
|---|
| 1206 |   y := integer(NewProcedure) - integer(p) - 5;
 | 
|---|
| 1207 |   x[1] := AnsiChar(y and 255);
 | 
|---|
| 1208 |   x[2] := AnsiChar((y shr 8) and 255);
 | 
|---|
| 1209 |   x[3] := AnsiChar((y shr 16) and 255);
 | 
|---|
| 1210 |   x[4] := AnsiChar((y shr 24) and 255);
 | 
|---|
| 1211 | 
 | 
|---|
| 1212 |   if not VirtualProtect(Pointer(x), 6, ov, @ov2) then
 | 
|---|
| 1213 |     RaiseLastOSError;
 | 
|---|
| 1214 | end;
 | 
|---|
| 1215 | 
 | 
|---|
| 1216 | procedure RestoreProcedure(OriginalProc: Pointer; Data: TOverwrittenData);
 | 
|---|
| 1217 | var
 | 
|---|
| 1218 |   ov, ov2: Cardinal;
 | 
|---|
| 1219 | begin
 | 
|---|
| 1220 |   if Data.Location <> nil then begin
 | 
|---|
| 1221 |     if not VirtualProtect(Data.Location, 6, PAGE_EXECUTE_READWRITE, @ov) then
 | 
|---|
| 1222 |       RaiseLastOSError;
 | 
|---|
| 1223 |     Move(Data.OldCode, Data.Location^, 6);
 | 
|---|
| 1224 |     if not VirtualProtect(Data.Location, 6, ov, @ov2) then
 | 
|---|
| 1225 |       RaiseLastOSError;
 | 
|---|
| 1226 |   end;
 | 
|---|
| 1227 | end;
 | 
|---|
| 1228 | 
 | 
|---|
| 1229 | function Addr_System_EndThread: Pointer;
 | 
|---|
| 1230 | begin
 | 
|---|
| 1231 |   Result := @System.EndThread;
 | 
|---|
| 1232 | end;
 | 
|---|
| 1233 | 
 | 
|---|
| 1234 | function Addr_System_LoadResString: Pointer;
 | 
|---|
| 1235 | begin
 | 
|---|
| 1236 |   Result := @System.LoadResString{TNT-ALLOW LoadResString};
 | 
|---|
| 1237 | end;
 | 
|---|
| 1238 | 
 | 
|---|
| 1239 | function Addr_System_WStrFromPCharLen: Pointer;
 | 
|---|
| 1240 | asm
 | 
|---|
| 1241 |   mov eax, offset System.@WStrFromPCharLen;
 | 
|---|
| 1242 | end;
 | 
|---|
| 1243 | 
 | 
|---|
| 1244 | {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1245 | function Addr_System_LStrFromPWCharLen: Pointer;
 | 
|---|
| 1246 | asm
 | 
|---|
| 1247 |   mov eax, offset System.@LStrFromPWCharLen;
 | 
|---|
| 1248 | end;
 | 
|---|
| 1249 | 
 | 
|---|
| 1250 | function Addr_System_WStrToString: Pointer;
 | 
|---|
| 1251 | asm
 | 
|---|
| 1252 |   mov eax, offset System.@WStrToString;
 | 
|---|
| 1253 | end;
 | 
|---|
| 1254 | {$ENDIF}
 | 
|---|
| 1255 | 
 | 
|---|
| 1256 | function Addr_System_VarFromLStr: Pointer;
 | 
|---|
| 1257 | asm
 | 
|---|
| 1258 |   mov eax, offset System.@VarFromLStr;
 | 
|---|
| 1259 | end;
 | 
|---|
| 1260 | 
 | 
|---|
| 1261 | function Addr_System_WStrCat3: Pointer;
 | 
|---|
| 1262 | asm
 | 
|---|
| 1263 |   mov eax, offset System.@WStrCat3;
 | 
|---|
| 1264 | end;
 | 
|---|
| 1265 | 
 | 
|---|
| 1266 | var
 | 
|---|
| 1267 |   System_EndThread_Code,
 | 
|---|
| 1268 |   System_LoadResString_Code,
 | 
|---|
| 1269 |   System_WStrFromPCharLen_Code,
 | 
|---|
| 1270 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1271 |   System_LStrFromPWCharLen_Code,
 | 
|---|
| 1272 |   System_WStrToString_Code,
 | 
|---|
| 1273 |   {$ENDIF}
 | 
|---|
| 1274 |   System_VarFromLStr_Code
 | 
|---|
| 1275 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1276 |   ,
 | 
|---|
| 1277 |   System_WStrCat3_Code,
 | 
|---|
| 1278 |   SysUtils_WideFmtStr_Code
 | 
|---|
| 1279 |   {$ENDIF}
 | 
|---|
| 1280 |   : TOverwrittenData;
 | 
|---|
| 1281 | 
 | 
|---|
| 1282 | procedure InstallEndThreadOverride;
 | 
|---|
| 1283 | begin
 | 
|---|
| 1284 |   OverwriteProcedure(Addr_System_EndThread,  @Custom_System_EndThread,  @System_EndThread_Code);
 | 
|---|
| 1285 | end;
 | 
|---|
| 1286 | 
 | 
|---|
| 1287 | procedure InstallStringConversionOverrides;
 | 
|---|
| 1288 | begin
 | 
|---|
| 1289 |   OverwriteProcedure(Addr_System_WStrFromPCharLen,  @Custom_System_WStrFromPCharLen,  @System_WStrFromPCharLen_Code);
 | 
|---|
| 1290 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1291 |   OverwriteProcedure(Addr_System_LStrFromPWCharLen, @Custom_System_LStrFromPWCharLen, @System_LStrFromPWCharLen_Code);
 | 
|---|
| 1292 |   OverwriteProcedure(Addr_System_WStrToString,      @Custom_System_WStrToString,      @System_WStrToString_Code);
 | 
|---|
| 1293 |   {$ENDIF}
 | 
|---|
| 1294 | end;
 | 
|---|
| 1295 | 
 | 
|---|
| 1296 | procedure InstallWideResourceStrings;
 | 
|---|
| 1297 | begin
 | 
|---|
| 1298 |   OverwriteProcedure(Addr_System_LoadResString,     @Custom_System_LoadResString,     @System_LoadResString_Code);
 | 
|---|
| 1299 |   OverwriteProcedure(Addr_System_VarFromLStr,       @Custom_System_VarFromLStr,       @System_VarFromLStr_Code);
 | 
|---|
| 1300 | end;
 | 
|---|
| 1301 | 
 | 
|---|
| 1302 | {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1303 | procedure InstallWideStringConcatenationFix;
 | 
|---|
| 1304 | begin
 | 
|---|
| 1305 |   OverwriteProcedure(Addr_System_WStrCat3,          @Custom_System_WStrCat3,          @System_WStrCat3_Code);
 | 
|---|
| 1306 | end;
 | 
|---|
| 1307 | 
 | 
|---|
| 1308 | procedure InstallWideFormatFixes;
 | 
|---|
| 1309 | begin
 | 
|---|
| 1310 |   OverwriteProcedure(@SysUtils.WideFmtStr, @TntSysUtils.Tnt_WideFmtStr, @SysUtils_WideFmtStr_Code);
 | 
|---|
| 1311 | end;
 | 
|---|
| 1312 | {$ENDIF}
 | 
|---|
| 1313 | 
 | 
|---|
| 1314 | procedure InstallTntSystemUpdates(Updates: TTntSystemUpdateSet = AllTntSystemUpdates);
 | 
|---|
| 1315 | begin
 | 
|---|
| 1316 |   InstallEndThreadOverride;
 | 
|---|
| 1317 |   if tsWideResourceStrings in Updates then begin
 | 
|---|
| 1318 |     InstallStringConversionOverrides;
 | 
|---|
| 1319 |     InstallWideResourceStrings;
 | 
|---|
| 1320 |   end;
 | 
|---|
| 1321 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1322 |     if tsFixImplicitCodePage in Updates then begin
 | 
|---|
| 1323 |       InstallStringConversionOverrides;
 | 
|---|
| 1324 |       { CP_ACP is the code page used by the non-Unicode Windows API. }
 | 
|---|
| 1325 |       GDefaultSystemCodePage := CP_ACP{TNT-ALLOW CP_ACP};
 | 
|---|
| 1326 |     end;
 | 
|---|
| 1327 |     if tsFixWideStrConcat in Updates then begin
 | 
|---|
| 1328 |       InstallWideStringConcatenationFix;
 | 
|---|
| 1329 |     end;
 | 
|---|
| 1330 |     if tsFixWideFormat in Updates then begin
 | 
|---|
| 1331 |       InstallWideFormatFixes;
 | 
|---|
| 1332 |     end;
 | 
|---|
| 1333 |   {$ENDIF}
 | 
|---|
| 1334 | end;
 | 
|---|
| 1335 | 
 | 
|---|
| 1336 | {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1337 | var
 | 
|---|
| 1338 |   StartupDefaultUserCodePage: Cardinal;
 | 
|---|
| 1339 | {$ENDIF}
 | 
|---|
| 1340 | 
 | 
|---|
| 1341 | procedure UninstallSystemOverrides;
 | 
|---|
| 1342 | begin
 | 
|---|
| 1343 |   RestoreProcedure(Addr_System_EndThread,  System_EndThread_Code);
 | 
|---|
| 1344 |   // String Conversion
 | 
|---|
| 1345 |   RestoreProcedure(Addr_System_WStrFromPCharLen,  System_WStrFromPCharLen_Code);
 | 
|---|
| 1346 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1347 |   RestoreProcedure(Addr_System_LStrFromPWCharLen, System_LStrFromPWCharLen_Code);
 | 
|---|
| 1348 |   RestoreProcedure(Addr_System_WStrToString,      System_WStrToString_Code);
 | 
|---|
| 1349 |   GDefaultSystemCodePage := StartupDefaultUserCodePage;
 | 
|---|
| 1350 |   {$ENDIF}
 | 
|---|
| 1351 |   // Wide resourcestring
 | 
|---|
| 1352 |   RestoreProcedure(Addr_System_LoadResString,     System_LoadResString_Code);
 | 
|---|
| 1353 |   RestoreProcedure(Addr_System_VarFromLStr,       System_VarFromLStr_Code);
 | 
|---|
| 1354 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1355 |   // WideString concat fix
 | 
|---|
| 1356 |   RestoreProcedure(Addr_System_WStrCat3,          System_WStrCat3_Code);
 | 
|---|
| 1357 |   // WideFormat fixes
 | 
|---|
| 1358 |   RestoreProcedure(@SysUtils.WideFmtStr, SysUtils_WideFmtStr_Code);
 | 
|---|
| 1359 |   {$ENDIF}
 | 
|---|
| 1360 | end;
 | 
|---|
| 1361 | 
 | 
|---|
| 1362 | initialization
 | 
|---|
| 1363 |   {$IFDEF COMPILER_9_UP}
 | 
|---|
| 1364 |   GDefaultSystemCodePage := GetACP;
 | 
|---|
| 1365 |   {$ELSE}
 | 
|---|
| 1366 |     {$IFDEF COMPILER_7_UP}
 | 
|---|
| 1367 |     if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion >= 5) then
 | 
|---|
| 1368 |       GDefaultSystemCodePage := CP_THREAD_ACP // Win 2K/XP/...
 | 
|---|
| 1369 |     else
 | 
|---|
| 1370 |       GDefaultSystemCodePage := LCIDToCodePage(GetThreadLocale); // Win NT4/95/98/ME
 | 
|---|
| 1371 |     {$ELSE}
 | 
|---|
| 1372 |     GDefaultSystemCodePage := CP_ACP{TNT-ALLOW CP_ACP};
 | 
|---|
| 1373 |     {$ENDIF}
 | 
|---|
| 1374 |   {$ENDIF}
 | 
|---|
| 1375 |   {$IFNDEF COMPILER_9_UP}
 | 
|---|
| 1376 |   StartupDefaultUserCodePage := DefaultSystemCodePage;
 | 
|---|
| 1377 |   {$ENDIF}
 | 
|---|
| 1378 |   IsDebugging := DebugHook > 0;
 | 
|---|
| 1379 | 
 | 
|---|
| 1380 | finalization
 | 
|---|
| 1381 |   UninstallSystemOverrides;
 | 
|---|
| 1382 |   FreeTntSystemThreadVars; { Make MemorySleuth happy. }
 | 
|---|
| 1383 | 
 | 
|---|
| 1384 | end.
 | 
|---|