2 {*****************************************************************************}
4 { Tnt Delphi Unicode Controls }
5 { http://www.tntware.com/delphicontrols/unicode/ }
8 { Copyright (c) 2002-2007, Troy Wolbrink (troy.wolbrink@tntware.com) }
10 {*****************************************************************************}
14 {$INCLUDE TntCompilers.inc}
18 { TODO: Consider: TTntRegIniFile, TTntMemIniFile (consider if UTF8 fits into this solution). }
20 {***********************************************}
21 { WideChar-streaming implemented by Maël Hörz }
22 {***********************************************}
25 Classes
, SysUtils
, Windows
, TntSysUtils
,
26 {$IFNDEF COMPILER_10_UP}
36 EWideFileStreamError
= class(WideException
)
37 constructor Create(ResStringRec
: PResStringRec
; const FileName
: WideString
);
39 EWideFCreateError
= class(EWideFileStreamError
);
40 EWideFOpenError
= class(EWideFileStreamError
);
42 // ......... introduced .........
44 TTntStreamCharSet
= (csAnsi
, csUnicode
, csUnicodeSwapped
, csUtf8
);
46 function AutoDetectCharacterSet(Stream
: TStream
): TTntStreamCharSet
;
48 //---------------------------------------------------------------------------------------------
50 //---------------------------------------------------------------------------------------------
52 {TNT-WARN ExtractStrings}
54 {TNT-WARN TStringStream} // TODO: Implement a TWideStringStream
56 // A potential implementation of TWideStringStream can be found at:
57 // http://kdsxml.cvs.sourceforge.net/kdsxml/Global/KDSClasses.pas?revision=1.10&view=markup
59 procedure TntPersistent_AfterInherited_DefineProperties(Filer
: TFiler
; Instance
: TPersistent
);
62 {TNT-WARN TFileStream}
63 TTntFileStream
= class(THandleStream
)
65 constructor Create(const FileName
: WideString
; Mode
: Word);
66 destructor Destroy
; override;
69 {TNT-WARN TMemoryStream}
70 TTntMemoryStream
= class(TMemoryStream
{TNT-ALLOW TMemoryStream})
72 procedure LoadFromFile(const FileName
: WideString
);
73 procedure SaveToFile(const FileName
: WideString
);
76 {TNT-WARN TResourceStream}
77 TTntResourceStream
= class(TCustomMemoryStream
)
81 procedure Initialize(Instance
: THandle
; Name
, ResType
: PWideChar
);
83 constructor Create(Instance
: THandle
; const ResName
: WideString
; ResType
: PWideChar
);
84 constructor CreateFromID(Instance
: THandle
; ResID
: Word; ResType
: PWideChar
);
85 destructor Destroy
; override;
86 function Write(const Buffer
; Count
: Longint): Longint; override;
87 procedure SaveToFile(const FileName
: WideString
);
92 {TNT-WARN TAnsiStrings}
93 TAnsiStrings
{TNT-ALLOW TAnsiStrings} = class(TStrings
{TNT-ALLOW TStrings})
95 procedure LoadFromFile(const FileName
: WideString
); reintroduce
;
96 procedure SaveToFile(const FileName
: WideString
); reintroduce
;
97 procedure LoadFromFileEx(const FileName
: WideString
; CodePage
: Cardinal);
98 procedure SaveToFileEx(const FileName
: WideString
; CodePage
: Cardinal);
99 procedure LoadFromStreamEx(Stream
: TStream
; CodePage
: Cardinal); virtual; abstract;
100 procedure SaveToStreamEx(Stream
: TStream
; CodePage
: Cardinal); virtual; abstract;
103 TAnsiStringsForWideStringsAdapter
= class(TAnsiStrings
{TNT-ALLOW TAnsiStrings})
105 FWideStrings
: TTntStrings
;
106 FAdapterCodePage
: Cardinal;
108 function Get(Index
: Integer): AnsiString
; override;
109 procedure Put(Index
: Integer; const S
: AnsiString
); override;
110 function GetCount
: Integer; override;
111 function GetObject(Index
: Integer): TObject
; override;
112 procedure PutObject(Index
: Integer; AObject
: TObject
); override;
113 procedure SetUpdateState(Updating
: Boolean); override;
114 function AdapterCodePage
: Cardinal; dynamic;
116 constructor Create(AWideStrings
: TTntStrings
; _AdapterCodePage
: Cardinal = 0);
117 procedure Clear
; override;
118 procedure Delete(Index
: Integer); override;
119 procedure Insert(Index
: Integer; const S
: AnsiString
); override;
120 procedure LoadFromStreamEx(Stream
: TStream
; CodePage
: Cardinal); override;
121 procedure SaveToStreamEx(Stream
: TStream
; CodePage
: Cardinal); override;
125 TTntStrings
= class(TWideStrings
)
127 FLastFileCharSet
: TTntStreamCharSet
;
128 FAnsiStrings
: TAnsiStrings
{TNT-ALLOW TAnsiStrings};
129 procedure SetAnsiStrings(const Value
: TAnsiStrings
{TNT-ALLOW TAnsiStrings});
130 procedure ReadData(Reader
: TReader
);
131 procedure ReadDataUTF7(Reader
: TReader
);
132 procedure ReadDataUTF8(Reader
: TReader
);
133 procedure WriteDataUTF7(Writer
: TWriter
);
135 procedure DefineProperties(Filer
: TFiler
); override;
138 destructor Destroy
; override;
140 procedure LoadFromFile(const FileName
: WideString
); override;
141 procedure LoadFromStream(Stream
: TStream
); override;
142 procedure LoadFromStream_BOM(Stream
: TStream
; WithBOM
: Boolean); virtual;
144 procedure SaveToFile(const FileName
: WideString
); override;
145 procedure SaveToStream(Stream
: TStream
); override;
146 procedure SaveToStream_BOM(Stream
: TStream
; WithBOM
: Boolean); virtual;
148 property LastFileCharSet
: TTntStreamCharSet read FLastFileCharSet
;
150 property AnsiStrings
: TAnsiStrings
{TNT-ALLOW TAnsiStrings} read FAnsiStrings write SetAnsiStrings stored
False;
153 { TTntStringList class }
155 TTntStringList
= class;
156 TWideStringListSortCompare
= function(List
: TTntStringList
; Index1
, Index2
: Integer): Integer;
158 {TNT-WARN TStringList}
159 TTntStringList
= class(TTntStrings
)
162 FList
: PWideStringItemList
;
166 FDuplicates
: TDuplicates
;
167 FCaseSensitive
: Boolean;
168 FOnChange
: TNotifyEvent
;
169 FOnChanging
: TNotifyEvent
;
170 procedure ExchangeItems(Index1
, Index2
: Integer);
172 procedure QuickSort(L
, R
: Integer; SCompare
: TWideStringListSortCompare
);
173 procedure SetSorted(Value
: Boolean);
174 procedure SetCaseSensitive(const Value
: Boolean);
176 procedure Changed
; virtual;
177 procedure Changing
; virtual;
178 function Get(Index
: Integer): WideString
; override;
179 function GetCapacity
: Integer; override;
180 function GetCount
: Integer; override;
181 function GetObject(Index
: Integer): TObject
; override;
182 procedure Put(Index
: Integer; const S
: WideString
); override;
183 procedure PutObject(Index
: Integer; AObject
: TObject
); override;
184 procedure SetCapacity(NewCapacity
: Integer); override;
185 procedure SetUpdateState(Updating
: Boolean); override;
186 function CompareStrings(const S1
, S2
: WideString
): Integer; override;
187 procedure InsertItem(Index
: Integer; const S
: WideString
; AObject
: TObject
); virtual;
189 destructor Destroy
; override;
190 function Add(const S
: WideString
): Integer; override;
191 function AddObject(const S
: WideString
; AObject
: TObject
): Integer; override;
192 procedure Clear
; override;
193 procedure Delete(Index
: Integer); override;
194 procedure Exchange(Index1
, Index2
: Integer); override;
195 function Find(const S
: WideString
; var Index
: Integer): Boolean; virtual;
196 function IndexOf(const S
: WideString
): Integer; override;
197 function IndexOfName(const Name
: WideString
): Integer; override;
198 procedure Insert(Index
: Integer; const S
: WideString
); override;
199 procedure InsertObject(Index
: Integer; const S
: WideString
;
200 AObject
: TObject
); override;
201 procedure Sort
; virtual;
202 procedure CustomSort(Compare
: TWideStringListSortCompare
); virtual;
203 property Duplicates
: TDuplicates read FDuplicates write FDuplicates
;
204 property Sorted
: Boolean read FSorted write SetSorted
;
205 property CaseSensitive
: Boolean read FCaseSensitive write SetCaseSensitive
;
206 property OnChange
: TNotifyEvent read FOnChange write FOnChange
;
207 property OnChanging
: TNotifyEvent read FOnChanging write FOnChanging
;
210 // ......... introduced .........
212 TListTargetCompare
= function (Item
, Target
: Pointer): Integer;
214 function FindSortedListByTarget(List
: TList
; TargetCompare
: TListTargetCompare
;
215 Target
: Pointer; var Index
: Integer): Boolean;
217 function ClassIsRegistered(const clsid
: TCLSID
): Boolean;
220 RuntimeUTFStreaming
: Boolean;
223 TBufferedAnsiString
= class(TObject
)
225 FStringBuffer
: AnsiString
;
226 LastWriteIndex
: Integer;
229 procedure AddChar(const wc
: AnsiChar
);
230 procedure AddString(const s
: AnsiString
);
231 procedure AddBuffer(Buff
: PAnsiChar
; Chars
: Integer);
232 function Value
: AnsiString
;
233 function BuffPtr
: PAnsiChar
;
236 TBufferedWideString
= class(TObject
)
238 FStringBuffer
: WideString
;
239 LastWriteIndex
: Integer;
242 procedure AddChar(const wc
: WideChar
);
243 procedure AddString(const s
: WideString
);
244 procedure AddBuffer(Buff
: PWideChar
; Chars
: Integer);
245 function Value
: WideString
;
246 function BuffPtr
: PWideChar
;
249 TBufferedStreamReader
= class(TStream
)
252 FStreamSize
: Integer;
253 FBuffer
: array of Byte;
254 FBufferSize
: Integer;
255 FBufferStartPosition
: Integer;
256 FVirtualPosition
: Integer;
257 procedure UpdateBufferFromPosition(StartPos
: Integer);
259 constructor Create(Stream
: TStream
; BufferSize
: Integer = 1024);
260 function Read(var Buffer
; Count
: Longint): Longint; override;
261 function Write(const Buffer
; Count
: Longint): Longint; override;
262 function Seek(Offset
: Longint; Origin
: Word): Longint; override;
265 // "synced" wide string
266 type TSetAnsiStrEvent
= procedure(const Value
: AnsiString
) of object;
267 function GetSyncedWideString(var WideStr
: WideString
; const AnsiStr
: AnsiString
): WideString
;
268 procedure SetSyncedWideString(const Value
: WideString
; var WideStr
: WideString
;
269 const AnsiStr
: AnsiString
; SetAnsiStr
: TSetAnsiStrEvent
);
272 TWideComponentHelper
= class(TComponent
)
274 FComponent
: TComponent
;
276 procedure Notification(AComponent
: TComponent
; Operation
: TOperation
); override;
278 constructor Create(AOwner
: TComponent
); override;
279 constructor CreateHelper(AOwner
: TComponent
; ComponentHelperList
: TComponentList
);
282 function FindWideComponentHelper(ComponentHelperList
: TComponentList
; Component
: TComponent
): TWideComponentHelper
;
287 RTLConsts
, ComObj
, Math
,
288 Registry
, TypInfo
, TntSystem
;
290 { EWideFileStreamError }
292 constructor EWideFileStreamError
.Create(ResStringRec
: PResStringRec
;
293 const FileName
: WideString
);
295 inherited CreateResFmt(ResStringRec
, [WideExpandFileName(FileName
),
296 WideSysErrorMessage(GetLastError
)]);
301 //===========================================================================
302 // The Delphi 5 Classes.pas never supported the streaming of WideStrings.
303 // The Delphi 6 Classes.pas supports WideString streaming. But it's too bad that
304 // the Delphi 6 IDE doesn't use the updated Classes.pas. Switching between Form/Text
305 // mode corrupts extended characters in WideStrings even under Delphi 6.
306 // Delphi 7 seems to finally get right. But let's keep the UTF7 support at design time
307 // to enable sharing source code with previous versions of Delphi.
309 // The purpose of this solution is to store WideString properties which contain
310 // non-ASCII chars in the form of UTF7 under the old property name + '_UTF7'.
312 // Special thanks go to Francisco Leong for helping to develop this solution.
315 { TTntWideStringPropertyFiler }
317 TTntWideStringPropertyFiler
= class
319 FInstance
: TPersistent
;
320 FPropInfo
: PPropInfo
;
321 procedure ReadDataUTF8(Reader
: TReader
);
322 procedure ReadDataUTF7(Reader
: TReader
);
323 procedure WriteDataUTF7(Writer
: TWriter
);
325 procedure DefineProperties(Filer
: TFiler
; Instance
: TPersistent
; PropName
: AnsiString
);
328 function ReaderNeedsUtfHelp(Reader
: TReader
): Boolean;
330 if Reader
.Owner
= nil then
331 Result
:= False { designtime - visual form inheritance ancestor }
332 else if csDesigning
in Reader
.Owner
.ComponentState
then
333 {$IFDEF COMPILER_7_UP}
334 Result
:= False { Delphi 7+: designtime - doesn't need UTF help. }
336 Result
:= True { Delphi 6: designtime - always needs UTF help. }
339 Result
:= RuntimeUTFStreaming
; { runtime }
342 procedure TTntWideStringPropertyFiler
.ReadDataUTF8(Reader
: TReader
);
344 if ReaderNeedsUtfHelp(Reader
) then
345 SetWideStrProp(FInstance
, FPropInfo
, UTF8ToWideString(Reader
.ReadString
))
347 Reader
.ReadString
; { do nothing with Result }
350 procedure TTntWideStringPropertyFiler
.ReadDataUTF7(Reader
: TReader
);
352 if ReaderNeedsUtfHelp(Reader
) then
353 SetWideStrProp(FInstance
, FPropInfo
, UTF7ToWideString(Reader
.ReadString
))
355 Reader
.ReadString
; { do nothing with Result }
358 procedure TTntWideStringPropertyFiler
.WriteDataUTF7(Writer
: TWriter
);
360 Writer
.WriteString(WideStringToUTF7(GetWideStrProp(FInstance
, FPropInfo
)));
363 procedure TTntWideStringPropertyFiler
.DefineProperties(Filer
: TFiler
; Instance
: TPersistent
;
364 PropName
: AnsiString
);
366 {$IFNDEF COMPILER_7_UP}
367 function HasData
: Boolean;
369 CurrPropValue
: WideString
;
372 Result
:= IsStoredProp(Instance
, FPropInfo
);
374 and (Filer
.Ancestor
<> nil)
375 and (GetPropInfo(Filer
.Ancestor
, PropName
, [tkWString
]) <> nil) then
377 // must be different than ancestor
378 CurrPropValue
:= GetWideStrProp(Instance
, FPropInfo
);
379 Result
:= CurrPropValue
<> GetWideStrProp(Filer
.Ancestor
, GetPropInfo(Filer
.Ancestor
, PropName
));
382 // must be non-blank and different than UTF8 (implies all ASCII <= 127)
383 CurrPropValue
:= GetWideStrProp(Instance
, FPropInfo
);
384 Result
:= (CurrPropValue
<> '') and (WideStringToUTF8(CurrPropValue
) <> CurrPropValue
);
390 FInstance
:= Instance
;
391 FPropInfo
:= GetPropInfo(Instance
, PropName
, [tkWString
]);
392 if FPropInfo
<> nil then begin
393 // must be published (and of type WideString)
394 Filer
.DefineProperty(PropName
+ 'W', ReadDataUTF8
, nil, False);
395 {$IFDEF COMPILER_7_UP}
396 Filer
.DefineProperty(PropName
+ '_UTF7', ReadDataUTF7
, WriteDataUTF7
, False);
398 Filer
.DefineProperty(PropName
+ '_UTF7', ReadDataUTF7
, WriteDataUTF7
, HasData
);
405 { TTntWideCharPropertyFiler }
407 TTntWideCharPropertyFiler
= class
409 FInstance
: TPersistent
;
410 FPropInfo
: PPropInfo
;
411 {$IFNDEF COMPILER_9_UP}
413 procedure GetLookupInfo(var Ancestor
: TPersistent
;
414 var Root
, LookupRoot
, RootAncestor
: TComponent
);
416 procedure ReadData_W(Reader
: TReader
);
417 procedure ReadDataUTF7(Reader
: TReader
);
418 procedure WriteData_W(Writer
: TWriter
);
419 function ReadChar(Reader
: TReader
): WideChar
;
421 procedure DefineProperties(Filer
: TFiler
; Instance
: TPersistent
; PropName
: AnsiString
);
424 {$IFNDEF COMPILER_9_UP}
426 TGetLookupInfoEvent
= procedure(var Ancestor
: TPersistent
;
427 var Root
, LookupRoot
, RootAncestor
: TComponent
) of object;
429 function AncestorIsValid(Ancestor
: TPersistent
; Root
, RootAncestor
: TComponent
): Boolean;
431 Result
:= (Ancestor
<> nil) and (RootAncestor
<> nil) and
432 Root
.InheritsFrom(RootAncestor
.ClassType
);
435 function IsDefaultOrdPropertyValue(Instance
: TObject
; PropInfo
: PPropInfo
;
436 OnGetLookupInfo
: TGetLookupInfoEvent
): Boolean;
438 Ancestor
: TPersistent
;
439 LookupRoot
: TComponent
;
440 RootAncestor
: TComponent
;
442 AncestorValid
: Boolean;
451 if Assigned(OnGetLookupInfo
) then
452 OnGetLookupInfo(Ancestor
, Root
, LookupRoot
, RootAncestor
);
454 AncestorValid
:= AncestorIsValid(Ancestor
, Root
, RootAncestor
);
457 if (PropInfo
^.GetProc
<> nil) and (PropInfo
^.SetProc
<> nil) then
459 Value
:= GetOrdProp(Instance
, PropInfo
);
460 if AncestorValid
then
461 Result
:= Value
= GetOrdProp(Ancestor
, PropInfo
)
464 Default
:= PPropInfo(PropInfo
)^.Default
;
465 Result
:= (Default
<> LongInt($80000000)) and (Value
= Default
);
470 procedure TTntWideCharPropertyFiler
.GetLookupInfo(var Ancestor
: TPersistent
;
471 var Root
, LookupRoot
, RootAncestor
: TComponent
);
473 Ancestor
:= FWriter
.Ancestor
;
474 Root
:= FWriter
.Root
;
475 LookupRoot
:= FWriter
.LookupRoot
;
476 RootAncestor
:= FWriter
.RootAncestor
;
480 function TTntWideCharPropertyFiler
.ReadChar(Reader
: TReader
): WideChar
;
484 case Reader
.NextValue
of
486 Temp
:= Reader
.ReadWideString
;
488 Temp
:= Reader
.ReadString
;
490 raise EReadError
.Create(SInvalidPropertyValue
);
493 if Length(Temp
) > 1 then
494 raise EReadError
.Create(SInvalidPropertyValue
);
498 procedure TTntWideCharPropertyFiler
.ReadData_W(Reader
: TReader
);
500 SetOrdProp(FInstance
, FPropInfo
, Ord(ReadChar(Reader
)));
503 procedure TTntWideCharPropertyFiler
.ReadDataUTF7(Reader
: TReader
);
507 S
:= UTF7ToWideString(Reader
.ReadString
);
509 SetOrdProp(FInstance
, FPropInfo
, 0)
511 SetOrdProp(FInstance
, FPropInfo
, Ord(S
[1]))
514 type TAccessWriter
= class(TWriter
);
516 procedure TTntWideCharPropertyFiler
.WriteData_W(Writer
: TWriter
);
521 Temp
:= WideChar(GetOrdProp(FInstance
, FPropInfo
));
523 TAccessWriter(Writer
).WriteValue(vaWString
);
525 Writer
.Write(L
, SizeOf(Integer));
526 Writer
.Write(Pointer(@Temp
[1])^, L
* 2);
529 procedure TTntWideCharPropertyFiler
.DefineProperties(Filer
: TFiler
;
530 Instance
: TPersistent
; PropName
: AnsiString
);
532 {$IFNDEF COMPILER_9_UP}
533 function HasData
: Boolean;
535 CurrPropValue
: Integer;
538 Result
:= IsStoredProp(Instance
, FPropInfo
);
539 if Result
and (Filer
.Ancestor
<> nil) and
540 (GetPropInfo(Filer
.Ancestor
, PropName
, [tkWChar
]) <> nil) then
542 // must be different than ancestor
543 CurrPropValue
:= GetOrdProp(Instance
, FPropInfo
);
544 Result
:= CurrPropValue
<> GetOrdProp(Filer
.Ancestor
, GetPropInfo(Filer
.Ancestor
, PropName
));
546 if Result
and (Filer
is TWriter
) then
548 FWriter
:= TWriter(Filer
);
549 Result
:= not IsDefaultOrdPropertyValue(Instance
, FPropInfo
, GetLookupInfo
);
555 FInstance
:= Instance
;
556 FPropInfo
:= GetPropInfo(Instance
, PropName
, [tkWChar
]);
557 if FPropInfo
<> nil then
559 // must be published (and of type WideChar)
560 {$IFDEF COMPILER_9_UP}
561 Filer
.DefineProperty(PropName
+ 'W', ReadData_W
, WriteData_W
, False);
563 Filer
.DefineProperty(PropName
+ 'W', ReadData_W
, WriteData_W
, HasData
);
565 Filer
.DefineProperty(PropName
+ '_UTF7', ReadDataUTF7
, nil, False);
571 procedure TntPersistent_AfterInherited_DefineProperties(Filer
: TFiler
; Instance
: TPersistent
);
576 WideStringFiler
: TTntWideStringPropertyFiler
;
577 WideCharFiler
: TTntWideCharPropertyFiler
;
579 Count
:= GetTypeData(Instance
.ClassInfo
)^.PropCount
;
582 WideStringFiler
:= TTntWideStringPropertyFiler
.Create
;
584 WideCharFiler
:= TTntWideCharPropertyFiler
.Create
;
586 GetMem(PropList
, Count
* SizeOf(Pointer));
588 GetPropInfos(Instance
.ClassInfo
, PropList
);
589 for I
:= 0 to Count
- 1 do
591 PropInfo
:= PropList
^[I
];
592 if (PropInfo
= nil) then
594 if (PropInfo
.PropType
^.Kind
= tkWString
) then
595 WideStringFiler
.DefineProperties(Filer
, Instance
, PropInfo
.Name
)
596 else if (PropInfo
.PropType
^.Kind
= tkWChar
) then
597 WideCharFiler
.DefineProperties(Filer
, Instance
, PropInfo
.Name
)
600 FreeMem(PropList
, Count
* SizeOf(Pointer));
606 WideStringFiler
.Free
;
613 constructor TTntFileStream
.Create(const FileName
: WideString
; Mode
: Word);
615 CreateHandle
: Integer;
617 ErrorMessage
: WideString
;
620 if Mode
= fmCreate
then
622 CreateHandle
:= WideFileCreate(FileName
);
623 if CreateHandle
< 0 then begin
625 ErrorMessage
:= WideSysErrorMessage(GetLastError
);
626 raise EWideFCreateError
.CreateFmt(SFCreateErrorEx
, [WideExpandFileName(FileName
), ErrorMessage
]);
628 raise EWideFCreateError
.CreateFmt(SFCreateError
, [WideExpandFileName(FileName
)]);
634 CreateHandle
:= WideFileOpen(FileName
, Mode
);
635 if CreateHandle
< 0 then begin
637 ErrorMessage
:= WideSysErrorMessage(GetLastError
);
638 raise EWideFOpenError
.CreateFmt(SFOpenErrorEx
, [WideExpandFileName(FileName
), ErrorMessage
]);
640 raise EWideFOpenError
.CreateFmt(SFOpenError
, [WideExpandFileName(FileName
)]);
644 inherited Create(CreateHandle
);
647 destructor TTntFileStream
.Destroy
;
649 if Handle
>= 0 then FileClose(Handle
);
654 procedure TTntMemoryStream
.LoadFromFile(const FileName
: WideString
);
658 Stream
:= TTntFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
660 LoadFromStream(Stream
);
666 procedure TTntMemoryStream
.SaveToFile(const FileName
: WideString
);
670 Stream
:= TTntFileStream
.Create(FileName
, fmCreate
);
672 SaveToStream(Stream
);
678 { TTntResourceStream }
680 constructor TTntResourceStream
.Create(Instance
: THandle
; const ResName
: WideString
;
684 Initialize(Instance
, PWideChar(ResName
), ResType
);
687 constructor TTntResourceStream
.CreateFromID(Instance
: THandle
; ResID
: Word;
691 Initialize(Instance
, PWideChar(ResID
), ResType
);
694 procedure TTntResourceStream
.Initialize(Instance
: THandle
; Name
, ResType
: PWideChar
);
698 raise EResNotFound
.CreateFmt(SResNotFound
, [Name
]);
702 HResInfo
:= FindResourceW(Instance
, Name
, ResType
);
703 if HResInfo
= 0 then Error
;
704 HGlobal
:= LoadResource(Instance
, HResInfo
);
705 if HGlobal
= 0 then Error
;
706 SetPointer(LockResource(HGlobal
), SizeOfResource(Instance
, HResInfo
));
709 destructor TTntResourceStream
.Destroy
;
711 UnlockResource(HGlobal
);
712 FreeResource(HGlobal
); { Technically this is not necessary (MS KB #193678) }
716 function TTntResourceStream
.Write(const Buffer
; Count
: Longint): Longint;
718 raise EStreamError
.CreateRes(PResStringRec(@SCantWriteResourceStreamError
));
721 procedure TTntResourceStream
.SaveToFile(const FileName
: WideString
);
725 Stream
:= TTntFileStream
.Create(FileName
, fmCreate
);
727 SaveToStream(Stream
);
735 procedure TAnsiStrings
{TNT-ALLOW TAnsiStrings}.LoadFromFile(const FileName
: WideString
);
739 Stream
:= TTntFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
741 LoadFromStream(Stream
);
747 procedure TAnsiStrings
{TNT-ALLOW TAnsiStrings}.SaveToFile(const FileName
: WideString
);
751 Stream
:= TTntFileStream
.Create(FileName
, fmCreate
);
753 SaveToStream(Stream
);
759 procedure TAnsiStrings
{TNT-ALLOW TAnsiStrings}.LoadFromFileEx(const FileName
: WideString
; CodePage
: Cardinal);
763 Stream
:= TTntFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
765 LoadFromStreamEx(Stream
, CodePage
);
771 procedure TAnsiStrings
{TNT-ALLOW TAnsiStrings}.SaveToFileEx(const FileName
: WideString
; CodePage
: Cardinal);
775 Stream
:= TTntFileStream
.Create(FileName
, fmCreate
);
777 if (CodePage
= CP_UTF8
) then
778 Stream
.WriteBuffer(PAnsiChar(UTF8_BOM
)^, Length(UTF8_BOM
));
779 SaveToStreamEx(Stream
, CodePage
);
785 { TAnsiStringsForWideStringsAdapter }
787 constructor TAnsiStringsForWideStringsAdapter
.Create(AWideStrings
: TTntStrings
; _AdapterCodePage
: Cardinal);
790 FWideStrings
:= AWideStrings
;
791 FAdapterCodePage
:= _AdapterCodePage
;
794 function TAnsiStringsForWideStringsAdapter
.AdapterCodePage
: Cardinal;
796 if FAdapterCodePage
= 0 then
797 Result
:= TntSystem
.DefaultSystemCodePage
799 Result
:= FAdapterCodePage
;
802 procedure TAnsiStringsForWideStringsAdapter
.Clear
;
807 procedure TAnsiStringsForWideStringsAdapter
.Delete(Index
: Integer);
809 FWideStrings
.Delete(Index
);
812 function TAnsiStringsForWideStringsAdapter
.Get(Index
: Integer): AnsiString
;
814 Result
:= WideStringToStringEx(FWideStrings
.Get(Index
), AdapterCodePage
);
817 procedure TAnsiStringsForWideStringsAdapter
.Put(Index
: Integer; const S
: AnsiString
);
819 FWideStrings
.Put(Index
, StringToWideStringEx(S
, AdapterCodePage
));
822 function TAnsiStringsForWideStringsAdapter
.GetCount
: Integer;
824 Result
:= FWideStrings
.GetCount
;
827 procedure TAnsiStringsForWideStringsAdapter
.Insert(Index
: Integer; const S
: AnsiString
);
829 FWideStrings
.Insert(Index
, StringToWideStringEx(S
, AdapterCodePage
));
832 function TAnsiStringsForWideStringsAdapter
.GetObject(Index
: Integer): TObject
;
834 Result
:= FWideStrings
.GetObject(Index
);
837 procedure TAnsiStringsForWideStringsAdapter
.PutObject(Index
: Integer; AObject
: TObject
);
839 FWideStrings
.PutObject(Index
, AObject
);
842 procedure TAnsiStringsForWideStringsAdapter
.SetUpdateState(Updating
: Boolean);
844 FWideStrings
.SetUpdateState(Updating
);
847 procedure TAnsiStringsForWideStringsAdapter
.LoadFromStreamEx(Stream
: TStream
; CodePage
: Cardinal);
854 Size
:= Stream
.Size
- Stream
.Position
;
855 SetString(S
, nil, Size
);
856 Stream
.Read(Pointer(S
)^, Size
);
857 FWideStrings
.SetTextStr(StringToWideStringEx(S
, CodePage
));
863 procedure TAnsiStringsForWideStringsAdapter
.SaveToStreamEx(Stream
: TStream
; CodePage
: Cardinal);
867 S
:= WideStringToStringEx(FWideStrings
.GetTextStr
, CodePage
);
868 Stream
.WriteBuffer(Pointer(S
)^, Length(S
));
873 constructor TTntStrings
.Create
;
876 FAnsiStrings
:= TAnsiStringsForWideStringsAdapter
.Create(Self
);
877 FLastFileCharSet
:= csUnicode
;
880 destructor TTntStrings
.Destroy
;
882 FreeAndNil(FAnsiStrings
);
886 procedure TTntStrings
.SetAnsiStrings(const Value
: TAnsiStrings
{TNT-ALLOW TAnsiStrings});
888 FAnsiStrings
.Assign(Value
);
891 procedure TTntStrings
.DefineProperties(Filer
: TFiler
);
893 {$IFNDEF COMPILER_7_UP}
894 function DoWrite
: Boolean;
896 if Filer
.Ancestor
<> nil then
899 if Filer
.Ancestor
is TWideStrings
then
900 Result
:= not Equals(TWideStrings(Filer
.Ancestor
))
902 else Result
:= Count
> 0;
905 function DoWriteAsUTF7
: Boolean;
910 for i
:= 0 to Count
- 1 do begin
911 if (Strings
[i
] <> '') and (WideStringToUTF8(Strings
[i
]) <> Strings
[i
]) then begin
913 break
; { found a string with non-ASCII chars (> 127) }
920 inherited DefineProperties(Filer
); { Handles main 'Strings' property.' }
921 Filer
.DefineProperty('WideStrings', ReadData
, nil, False);
922 Filer
.DefineProperty('WideStringsW', ReadDataUTF8
, nil, False);
923 {$IFDEF COMPILER_7_UP}
924 Filer
.DefineProperty('WideStrings_UTF7', ReadDataUTF7
, WriteDataUTF7
, False);
926 Filer
.DefineProperty('WideStrings_UTF7', ReadDataUTF7
, WriteDataUTF7
, DoWrite
and DoWriteAsUTF7
);
930 procedure TTntStrings
.LoadFromFile(const FileName
: WideString
);
934 Stream
:= TTntFileStream
.Create(FileName
, fmOpenRead
or fmShareDenyWrite
);
936 FLastFileCharSet
:= AutoDetectCharacterSet(Stream
);
937 Stream
.Position
:= 0;
938 LoadFromStream(Stream
);
944 procedure TTntStrings
.LoadFromStream(Stream
: TStream
);
946 LoadFromStream_BOM(Stream
, True);
949 procedure TTntStrings
.LoadFromStream_BOM(Stream
: TStream
; WithBOM
: Boolean);
952 StreamCharSet
: TTntStreamCharSet
;
959 StreamCharSet
:= AutoDetectCharacterSet(Stream
)
961 StreamCharSet
:= csUnicode
;
962 DataLeft
:= Stream
.Size
- Stream
.Position
;
963 if (StreamCharSet
in [csUnicode
, csUnicodeSwapped
]) then
965 // BOM indicates Unicode text stream
966 if DataLeft
< SizeOf(WideChar
) then
969 SetLength(SW
, DataLeft
div SizeOf(WideChar
));
970 Stream
.Read(PWideChar(SW
)^, DataLeft
);
971 if StreamCharSet
= csUnicodeSwapped
then
972 StrSwapByteOrder(PWideChar(SW
));
976 else if StreamCharSet
= csUtf8
then
978 // BOM indicates UTF-8 text stream
979 SetLength(SA
, DataLeft
div SizeOf(AnsiChar
));
980 Stream
.Read(PAnsiChar(SA
)^, DataLeft
);
981 SetTextStr(UTF8ToWideString(SA
));
985 // without byte order mark it is assumed that we are loading ANSI text
986 SetLength(SA
, DataLeft
div SizeOf(AnsiChar
));
987 Stream
.Read(PAnsiChar(SA
)^, DataLeft
);
995 procedure TTntStrings
.ReadData(Reader
: TReader
);
997 if Reader
.NextValue
in [vaString
, vaLString
] then
998 SetTextStr(Reader
.ReadString
) {JCL compatiblity}
999 else if Reader
.NextValue
= vaWString
then
1000 SetTextStr(Reader
.ReadWideString
) {JCL compatiblity}
1005 Reader
.ReadListBegin
;
1006 while not Reader
.EndOfList
do
1007 if Reader
.NextValue
in [vaString
, vaLString
] then
1008 Add(Reader
.ReadString
) {TStrings compatiblity}
1010 Add(Reader
.ReadWideString
);
1018 procedure TTntStrings
.ReadDataUTF7(Reader
: TReader
);
1020 Reader
.ReadListBegin
;
1021 if ReaderNeedsUtfHelp(Reader
) then
1026 while not Reader
.EndOfList
do
1027 Add(UTF7ToWideString(Reader
.ReadString
))
1032 while not Reader
.EndOfList
do
1033 Reader
.ReadString
; { do nothing with Result }
1038 procedure TTntStrings
.ReadDataUTF8(Reader
: TReader
);
1040 Reader
.ReadListBegin
;
1041 if ReaderNeedsUtfHelp(Reader
)
1042 or (Count
= 0){ Legacy support where 'WideStrings' was never written in lieu of WideStringsW }
1047 while not Reader
.EndOfList
do
1048 Add(UTF8ToWideString(Reader
.ReadString
))
1053 while not Reader
.EndOfList
do
1054 Reader
.ReadString
; { do nothing with Result }
1059 procedure TTntStrings
.SaveToFile(const FileName
: WideString
);
1063 Stream
:= TTntFileStream
.Create(FileName
, fmCreate
);
1065 SaveToStream(Stream
);
1071 procedure TTntStrings
.SaveToStream(Stream
: TStream
);
1073 SaveToStream_BOM(Stream
, True);
1076 procedure TTntStrings
.SaveToStream_BOM(Stream
: TStream
; WithBOM
: Boolean);
1077 // Saves the currently loaded text into the given stream.
1078 // WithBOM determines whether to write a byte order mark or not.
1083 if WithBOM
then begin
1085 Stream
.WriteBuffer(BOM
, SizeOf(WideChar
));
1088 Stream
.WriteBuffer(PWideChar(SW
)^, Length(SW
) * SizeOf(WideChar
));
1091 procedure TTntStrings
.WriteDataUTF7(Writer
: TWriter
);
1095 Writer
.WriteListBegin
;
1096 for I
:= 0 to Count
-1 do
1097 Writer
.WriteString(WideStringToUTF7(Get(I
)));
1098 Writer
.WriteListEnd
;
1103 destructor TTntStringList
.Destroy
;
1108 if FCount
<> 0 then Finalize(FList
^[0], FCount
);
1113 function TTntStringList
.Add(const S
: WideString
): Integer;
1115 Result
:= AddObject(S
, nil);
1118 function TTntStringList
.AddObject(const S
: WideString
; AObject
: TObject
): Integer;
1123 if Find(S
, Result
) then
1126 dupError
: Error(PResStringRec(@SDuplicateString
), 0);
1128 InsertItem(Result
, S
, AObject
);
1131 procedure TTntStringList
.Changed
;
1133 if (not FUpdating
) and Assigned(FOnChange
) then
1137 procedure TTntStringList
.Changing
;
1139 if (not FUpdating
) and Assigned(FOnChanging
) then
1143 procedure TTntStringList
.Clear
;
1148 Finalize(FList
^[0], FCount
);
1155 procedure TTntStringList
.Delete(Index
: Integer);
1157 if (Index
< 0) or (Index
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1159 Finalize(FList
^[Index
]);
1161 if Index
< FCount
then
1162 System
.Move(FList
^[Index
+ 1], FList
^[Index
],
1163 (FCount
- Index
) * SizeOf(TWideStringItem
));
1167 procedure TTntStringList
.Exchange(Index1
, Index2
: Integer);
1169 if (Index1
< 0) or (Index1
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index1
);
1170 if (Index2
< 0) or (Index2
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index2
);
1172 ExchangeItems(Index1
, Index2
);
1176 procedure TTntStringList
.ExchangeItems(Index1
, Index2
: Integer);
1179 Item1
, Item2
: PWideStringItem
;
1181 Item1
:= @FList
^[Index1
];
1182 Item2
:= @FList
^[Index2
];
1183 Temp
:= Integer(Item1
^.FString
);
1184 Integer(Item1
^.FString
) := Integer(Item2
^.FString
);
1185 Integer(Item2
^.FString
) := Temp
;
1186 Temp
:= Integer(Item1
^.FObject
);
1187 Integer(Item1
^.FObject
) := Integer(Item2
^.FObject
);
1188 Integer(Item2
^.FObject
) := Temp
;
1191 function TTntStringList
.Find(const S
: WideString
; var Index
: Integer): Boolean;
1193 L
, H
, I
, C
: Integer;
1201 C
:= CompareStrings(FList
^[I
].FString
, S
);
1202 if C
< 0 then L
:= I
+ 1 else
1208 if Duplicates
<> dupAccept
then L
:= I
;
1215 function TTntStringList
.Get(Index
: Integer): WideString
;
1217 if (Index
< 0) or (Index
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1218 Result
:= FList
^[Index
].FString
;
1221 function TTntStringList
.GetCapacity
: Integer;
1223 Result
:= FCapacity
;
1226 function TTntStringList
.GetCount
: Integer;
1231 function TTntStringList
.GetObject(Index
: Integer): TObject
;
1233 if (Index
< 0) or (Index
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1234 Result
:= FList
^[Index
].FObject
;
1237 procedure TTntStringList
.Grow
;
1241 if FCapacity
> 64 then Delta
:= FCapacity
div 4 else
1242 if FCapacity
> 8 then Delta
:= 16 else
1244 SetCapacity(FCapacity
+ Delta
);
1247 function TTntStringList
.IndexOf(const S
: WideString
): Integer;
1249 if not Sorted
then Result
:= inherited IndexOf(S
) else
1250 if not Find(S
, Result
) then Result
:= -1;
1253 function TTntStringList
.IndexOfName(const Name
: WideString
): Integer;
1255 NameKey
: WideString
;
1258 Result
:= inherited IndexOfName(Name
)
1260 // use sort to find index more quickly
1261 NameKey
:= Name
+ NameValueSeparator
;
1262 Find(NameKey
, Result
);
1263 if (Result
< 0) or (Result
> Count
- 1) then
1265 else if CompareStrings(NameKey
, Copy(Strings
[Result
], 1, Length(NameKey
))) <> 0 then
1270 procedure TTntStringList
.Insert(Index
: Integer; const S
: WideString
);
1272 InsertObject(Index
, S
, nil);
1275 procedure TTntStringList
.InsertObject(Index
: Integer; const S
: WideString
;
1278 if Sorted
then Error(PResStringRec(@SSortedListError
), 0);
1279 if (Index
< 0) or (Index
> FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1280 InsertItem(Index
, S
, AObject
);
1283 procedure TTntStringList
.InsertItem(Index
: Integer; const S
: WideString
; AObject
: TObject
);
1286 if FCount
= FCapacity
then Grow
;
1287 if Index
< FCount
then
1288 System
.Move(FList
^[Index
], FList
^[Index
+ 1],
1289 (FCount
- Index
) * SizeOf(TWideStringItem
));
1290 with FList
^[Index
] do
1292 Pointer(FString
) := nil;
1300 procedure TTntStringList
.Put(Index
: Integer; const S
: WideString
);
1302 if Sorted
then Error(PResStringRec(@SSortedListError
), 0);
1303 if (Index
< 0) or (Index
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1305 FList
^[Index
].FString
:= S
;
1309 procedure TTntStringList
.PutObject(Index
: Integer; AObject
: TObject
);
1311 if (Index
< 0) or (Index
>= FCount
) then Error(PResStringRec(@SListIndexError
), Index
);
1313 FList
^[Index
].FObject
:= AObject
;
1317 procedure TTntStringList
.QuickSort(L
, R
: Integer; SCompare
: TWideStringListSortCompare
);
1326 while SCompare(Self
, I
, P
) < 0 do Inc(I
);
1327 while SCompare(Self
, J
, P
) > 0 do Dec(J
);
1330 ExchangeItems(I
, J
);
1339 if L
< J
then QuickSort(L
, J
, SCompare
);
1344 procedure TTntStringList
.SetCapacity(NewCapacity
: Integer);
1346 ReallocMem(FList
, NewCapacity
* SizeOf(TWideStringItem
));
1347 FCapacity
:= NewCapacity
;
1350 procedure TTntStringList
.SetSorted(Value
: Boolean);
1352 if FSorted
<> Value
then
1359 procedure TTntStringList
.SetUpdateState(Updating
: Boolean);
1361 FUpdating
:= Updating
;
1362 if Updating
then Changing
else Changed
;
1365 function WideStringListCompareStrings(List
: TTntStringList
; Index1
, Index2
: Integer): Integer;
1367 Result
:= List
.CompareStrings(List
.FList
^[Index1
].FString
,
1368 List
.FList
^[Index2
].FString
);
1371 procedure TTntStringList
.Sort
;
1373 CustomSort(WideStringListCompareStrings
);
1376 procedure TTntStringList
.CustomSort(Compare
: TWideStringListSortCompare
);
1378 if not Sorted
and (FCount
> 1) then
1381 QuickSort(0, FCount
- 1, Compare
);
1386 function TTntStringList
.CompareStrings(const S1
, S2
: WideString
): Integer;
1388 if CaseSensitive
then
1389 Result
:= WideCompareStr(S1
, S2
)
1391 Result
:= WideCompareText(S1
, S2
);
1394 procedure TTntStringList
.SetCaseSensitive(const Value
: Boolean);
1396 if Value
<> FCaseSensitive
then
1398 FCaseSensitive
:= Value
;
1399 if Sorted
then Sort
;
1403 //------------------------- TntClasses introduced procs ----------------------------------
1405 function AutoDetectCharacterSet(Stream
: TStream
): TTntStreamCharSet
;
1407 ByteOrderMark
: WideChar
;
1409 Utf8Test
: array[0..2] of AnsiChar
;
1412 ByteOrderMark
:= #0;
1413 if (Stream
.Size
- Stream
.Position
) >= SizeOf(ByteOrderMark
) then begin
1414 BytesRead
:= Stream
.Read(ByteOrderMark
, SizeOf(ByteOrderMark
));
1415 if (ByteOrderMark
<> UNICODE_BOM
) and (ByteOrderMark
<> UNICODE_BOM_SWAPPED
) then begin
1416 ByteOrderMark
:= #0;
1417 Stream
.Seek(-BytesRead
, soFromCurrent
);
1418 if (Stream
.Size
- Stream
.Position
) >= Length(Utf8Test
) * SizeOf(AnsiChar
) then begin
1419 BytesRead
:= Stream
.Read(Utf8Test
[0], Length(Utf8Test
) * SizeOf(AnsiChar
));
1420 if Utf8Test
<> UTF8_BOM
then
1421 Stream
.Seek(-BytesRead
, soFromCurrent
);
1425 // Test Byte Order Mark
1426 if ByteOrderMark
= UNICODE_BOM
then
1428 else if ByteOrderMark
= UNICODE_BOM_SWAPPED
then
1429 Result
:= csUnicodeSwapped
1430 else if Utf8Test
= UTF8_BOM
then
1436 function FindSortedListByTarget(List
: TList
; TargetCompare
: TListTargetCompare
;
1437 Target
: Pointer; var Index
: Integer): Boolean;
1439 L
, H
, I
, C
: Integer;
1443 H
:= List
.Count
- 1;
1447 C
:= TargetCompare(List
[i
], Target
);
1448 if C
< 0 then L
:= I
+ 1 else
1461 function ClassIsRegistered(const clsid
: TCLSID
): Boolean;
1465 Key
, Filename
: WideString
;
1467 // First, check to see if there is a ProgID. This will tell if the
1468 // control is registered on the machine. No ProgID, control won't run
1469 Result
:= ProgIDFromCLSID(clsid
, OleStr
) = S_OK
;
1470 if not Result
then Exit
; //Bail as soon as anything goes wrong.
1472 // Next, make sure that the file is actually there by rooting it out
1474 Key
:= WideFormat('\SOFTWARE\Classes\CLSID\%s', [GUIDToString(clsid
)]);
1475 Reg
:= TRegIniFile
.Create
;
1477 Reg
.RootKey
:= HKEY_LOCAL_MACHINE
;
1478 Result
:= Reg
.OpenKeyReadOnly(Key
);
1479 if not Result
then Exit
; // Bail as soon as anything goes wrong.
1481 FileName
:= Reg
.ReadString('InProcServer32', '', EmptyStr
);
1482 if (Filename
= EmptyStr
) then // try another key for the file name
1484 FileName
:= Reg
.ReadString('InProcServer', '', EmptyStr
);
1486 Result
:= Filename
<> EmptyStr
;
1487 if not Result
then Exit
;
1488 Result
:= WideFileExists(Filename
);
1494 { TBufferedAnsiString }
1496 procedure TBufferedAnsiString
.Clear
;
1498 LastWriteIndex
:= 0;
1499 if Length(FStringBuffer
) > 0 then
1500 FillChar(FStringBuffer
[1], Length(FStringBuffer
) * SizeOf(AnsiChar
), 0);
1503 procedure TBufferedAnsiString
.AddChar(const wc
: AnsiChar
);
1506 MAX_GROW_SIZE
= 256;
1510 Inc(LastWriteIndex
);
1511 if LastWriteIndex
> Length(FStringBuffer
) then begin
1512 GrowSize
:= Max(MIN_GROW_SIZE
, Length(FStringBuffer
));
1513 GrowSize
:= Min(GrowSize
, MAX_GROW_SIZE
);
1514 SetLength(FStringBuffer
, Length(FStringBuffer
) + GrowSize
);
1515 FillChar(FStringBuffer
[LastWriteIndex
], GrowSize
* SizeOf(AnsiChar
), 0);
1517 FStringBuffer
[LastWriteIndex
] := wc
;
1520 procedure TBufferedAnsiString
.AddString(const s
: AnsiString
);
1527 if LenS
> 0 then begin
1528 Inc(LastWriteIndex
);
1529 if LastWriteIndex
+ LenS
- 1 > Length(FStringBuffer
) then begin
1530 // determine optimum new allocation size
1531 BlockSize
:= Length(FStringBuffer
) div 2;
1532 if BlockSize
< 8 then
1534 AllocSize
:= ((LenS
div BlockSize
) + 1) * BlockSize
;
1536 SetLength(FStringBuffer
, Length(FStringBuffer
) + AllocSize
);
1537 FillChar(FStringBuffer
[Length(FStringBuffer
) - AllocSize
+ 1], AllocSize
* SizeOf(AnsiChar
), 0);
1539 CopyMemory(@FStringBuffer
[LastWriteIndex
], @s
[1], LenS
* SizeOf(AnsiChar
));
1540 Inc(LastWriteIndex
, LenS
- 1);
1544 procedure TBufferedAnsiString
.AddBuffer(Buff
: PAnsiChar
; Chars
: Integer);
1548 for i
:= 1 to Chars
do begin
1556 function TBufferedAnsiString
.Value
: AnsiString
;
1558 Result
:= PAnsiChar(FStringBuffer
);
1561 function TBufferedAnsiString
.BuffPtr
: PAnsiChar
;
1563 Result
:= PAnsiChar(FStringBuffer
);
1566 { TBufferedWideString }
1568 procedure TBufferedWideString
.Clear
;
1570 LastWriteIndex
:= 0;
1571 if Length(FStringBuffer
) > 0 then
1572 FillChar(FStringBuffer
[1], Length(FStringBuffer
) * SizeOf(WideChar
), 0);
1575 procedure TBufferedWideString
.AddChar(const wc
: WideChar
);
1578 MAX_GROW_SIZE
= 256;
1582 Inc(LastWriteIndex
);
1583 if LastWriteIndex
> Length(FStringBuffer
) then begin
1584 GrowSize
:= Max(MIN_GROW_SIZE
, Length(FStringBuffer
));
1585 GrowSize
:= Min(GrowSize
, MAX_GROW_SIZE
);
1586 SetLength(FStringBuffer
, Length(FStringBuffer
) + GrowSize
);
1587 FillChar(FStringBuffer
[LastWriteIndex
], GrowSize
* SizeOf(WideChar
), 0);
1589 FStringBuffer
[LastWriteIndex
] := wc
;
1592 procedure TBufferedWideString
.AddString(const s
: WideString
);
1596 for i
:= 1 to Length(s
) do
1600 procedure TBufferedWideString
.AddBuffer(Buff
: PWideChar
; Chars
: Integer);
1604 for i
:= 1 to Chars
do begin
1612 function TBufferedWideString
.Value
: WideString
;
1614 Result
:= PWideChar(FStringBuffer
);
1617 function TBufferedWideString
.BuffPtr
: PWideChar
;
1619 Result
:= PWideChar(FStringBuffer
);
1622 { TBufferedStreamReader }
1624 constructor TBufferedStreamReader
.Create(Stream
: TStream
; BufferSize
: Integer = 1024);
1628 FStreamSize
:= Stream
.Size
;
1630 FBufferSize
:= BufferSize
;
1631 SetLength(FBuffer
, BufferSize
);
1632 FBufferStartPosition
:= -FBufferSize
; { out of any useful range }
1633 // init virtual position
1634 FVirtualPosition
:= 0;
1637 function TBufferedStreamReader
.Seek(Offset
: Integer; Origin
: Word): Longint;
1640 soFromBeginning
: FVirtualPosition
:= Offset
;
1641 soFromCurrent
: Inc(FVirtualPosition
, Offset
);
1642 soFromEnd
: FVirtualPosition
:= FStreamSize
+ Offset
;
1644 Result
:= FVirtualPosition
;
1647 procedure TBufferedStreamReader
.UpdateBufferFromPosition(StartPos
: Integer);
1650 FStream
.Position
:= StartPos
;
1651 FStream
.Read(FBuffer
[0], FBufferSize
);
1652 FBufferStartPosition
:= StartPos
;
1654 FBufferStartPosition
:= -FBufferSize
; { out of any useful range }
1659 function TBufferedStreamReader
.Read(var Buffer
; Count
: Integer): Longint;
1662 FirstBufferRead
: Integer;
1663 StreamDirectRead
: Integer;
1666 if (FVirtualPosition
>= 0) and (Count
>= 0) then
1668 Result
:= FStreamSize
- FVirtualPosition
;
1671 if Result
> Count
then
1675 BytesLeft
:= Result
;
1677 // try to read what is left in buffer
1678 FirstBufferRead
:= FBufferStartPosition
+ FBufferSize
- FVirtualPosition
;
1679 if (FirstBufferRead
< 0) or (FirstBufferRead
> FBufferSize
) then
1680 FirstBufferRead
:= 0;
1681 FirstBufferRead
:= Min(FirstBufferRead
, Result
);
1682 if FirstBufferRead
> 0 then begin
1683 Move(FBuffer
[FVirtualPosition
- FBufferStartPosition
], Buf
[0], FirstBufferRead
);
1684 Dec(BytesLeft
, FirstBufferRead
);
1687 if BytesLeft
> 0 then begin
1688 // The first read in buffer was not enough
1689 StreamDirectRead
:= (BytesLeft
div FBufferSize
) * FBufferSize
;
1690 FStream
.Position
:= FVirtualPosition
+ FirstBufferRead
;
1691 FStream
.Read(Buf
[FirstBufferRead
], StreamDirectRead
);
1692 Dec(BytesLeft
, StreamDirectRead
);
1694 if BytesLeft
> 0 then begin
1695 // update buffer, and read what is left
1696 UpdateBufferFromPosition(FStream
.Position
);
1697 Move(FBuffer
[0], Buf
[FirstBufferRead
+ StreamDirectRead
], BytesLeft
);
1701 Inc(FVirtualPosition
, Result
);
1708 function TBufferedStreamReader
.Write(const Buffer
; Count
: Integer): Longint;
1710 raise ETntInternalError
.Create('Internal Error: class can not write.');
1714 //-------- synced wide string -----------------
1716 function GetSyncedWideString(var WideStr
: WideString
; const AnsiStr
: AnsiString
): WideString
;
1718 if AnsiString(WideStr
) <> (AnsiStr
) then begin
1719 WideStr
:= AnsiStr
; {AnsiStr changed. Keep WideStr in sync.}
1724 procedure SetSyncedWideString(const Value
: WideString
; var WideStr
: WideString
;
1725 const AnsiStr
: AnsiString
; SetAnsiStr
: TSetAnsiStrEvent
);
1727 if Value
<> GetSyncedWideString(WideStr
, AnsiStr
) then
1729 if (not WideSameStr(Value
, AnsiString(Value
))) {unicode chars lost in conversion}
1730 and (AnsiStr
= AnsiString(Value
)) {AnsiStr is not going to change}
1732 SetAnsiStr(''); {force the change}
1739 { TWideComponentHelper }
1741 function CompareComponentHelperToTarget(Item
, Target
: Pointer): Integer;
1743 if Integer(TWideComponentHelper(Item
).FComponent
) < Integer(Target
) then
1745 else if Integer(TWideComponentHelper(Item
).FComponent
) > Integer(Target
) then
1751 function FindWideComponentHelperIndex(ComponentHelperList
: TComponentList
; Component
: TComponent
; var Index
: Integer): Boolean;
1753 // find Component in sorted wide caption list (list is sorted by TWideComponentHelper.FComponent)
1754 Result
:= FindSortedListByTarget(ComponentHelperList
, CompareComponentHelperToTarget
, Component
, Index
);
1757 constructor TWideComponentHelper
.Create(AOwner
: TComponent
);
1759 raise ETntInternalError
.Create('TNT Internal Error: TWideComponentHelper.Create should never be encountered.');
1762 constructor TWideComponentHelper
.CreateHelper(AOwner
: TComponent
; ComponentHelperList
: TComponentList
);
1766 // don't use direct ownership for memory management
1767 inherited Create(nil);
1768 FComponent
:= AOwner
;
1769 FComponent
.FreeNotification(Self
);
1771 // insert into list according to sort
1772 FindWideComponentHelperIndex(ComponentHelperList
, FComponent
, Index
);
1773 ComponentHelperList
.Insert(Index
, Self
);
1776 procedure TWideComponentHelper
.Notification(AComponent
: TComponent
; Operation
: TOperation
);
1779 if (AComponent
= FComponent
) and (Operation
= opRemove
) then begin
1785 function FindWideComponentHelper(ComponentHelperList
: TComponentList
; Component
: TComponent
): TWideComponentHelper
;
1789 if FindWideComponentHelperIndex(ComponentHelperList
, Component
, Index
) then begin
1790 Result
:= TWideComponentHelper(ComponentHelperList
[Index
]);
1791 Assert(Result
.FComponent
= Component
, 'TNT Internal Error: FindWideComponentHelperIndex failed.');
1797 RuntimeUTFStreaming
:= False; { Delphi 6 and higher don't need UTF help at runtime. }