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.
|
---|