Statistics
| Branch: | Tag: | Revision:

root / UStreamHelper.pas

History | View | Annotate | Download (17.1 kB)

1 0:95bd93c28625 aksdb
(*
2 0:95bd93c28625 aksdb
 * CDDL HEADER START
3 0:95bd93c28625 aksdb
 *
4 0:95bd93c28625 aksdb
 * The contents of this file are subject to the terms of the
5 0:95bd93c28625 aksdb
 * Common Development and Distribution License, Version 1.0 only
6 0:95bd93c28625 aksdb
 * (the "License").  You may not use this file except in compliance
7 0:95bd93c28625 aksdb
 * with the License.
8 0:95bd93c28625 aksdb
 *
9 0:95bd93c28625 aksdb
 * You can obtain a copy of the license at
10 0:95bd93c28625 aksdb
 * http://www.opensource.org/licenses/cddl1.php.
11 0:95bd93c28625 aksdb
 * See the License for the specific language governing permissions
12 0:95bd93c28625 aksdb
 * and limitations under the License.
13 0:95bd93c28625 aksdb
 *
14 0:95bd93c28625 aksdb
 * When distributing Covered Code, include this CDDL HEADER in each
15 0:95bd93c28625 aksdb
 * file and include the License file at
16 0:95bd93c28625 aksdb
 * http://www.opensource.org/licenses/cddl1.php.  If applicable,
17 0:95bd93c28625 aksdb
 * add the following below this CDDL HEADER, with the fields enclosed
18 0:95bd93c28625 aksdb
 * by brackets "[]" replaced with your own identifying * information:
19 0:95bd93c28625 aksdb
 *      Portions Copyright [yyyy] [name of copyright owner]
20 0:95bd93c28625 aksdb
 *
21 0:95bd93c28625 aksdb
 * CDDL HEADER END
22 0:95bd93c28625 aksdb
 *
23 0:95bd93c28625 aksdb
 *
24 0:95bd93c28625 aksdb
 *      Portions Copyright 2007 Andreas Schneider
25 0:95bd93c28625 aksdb
 *)
26 0:95bd93c28625 aksdb
27 0:95bd93c28625 aksdb
{@abstract(This unit contains procedures and classes to help with stream handling.
28 0:95bd93c28625 aksdb
It can be used to ease copying of streams and to assist in writing and reading
29 0:95bd93c28625 aksdb
specialized types to/from streams.)
30 0:95bd93c28625 aksdb
31 0:95bd93c28625 aksdb
@bold(Warning!!!)@br
32 0:95bd93c28625 aksdb
Due to a problem with generics in FPC 2.2.0 I introduced @link(TStreamType) as
33 0:95bd93c28625 aksdb
workaround to reference the actual type of stream used inside the
34 0:95bd93c28625 aksdb
@link(TStreamWrapper).
35 0:95bd93c28625 aksdb
36 0:95bd93c28625 aksdb
@author(Andreas Schneider <aksdb@gmx.de>)
37 0:95bd93c28625 aksdb
@created(2007-07-08)
38 0:95bd93c28625 aksdb
@lastmod(2007-11-14)}
39 0:95bd93c28625 aksdb
unit UStreamHelper;
40 0:95bd93c28625 aksdb
41 0:95bd93c28625 aksdb
{$mode objfpc}{$H+}
42 0:95bd93c28625 aksdb
43 0:95bd93c28625 aksdb
interface
44 0:95bd93c28625 aksdb
45 0:95bd93c28625 aksdb
uses
46 3:38a8c6979797 aksdb
  Classes, RtlConsts, SysUtils;
47 0:95bd93c28625 aksdb
48 0:95bd93c28625 aksdb
type
49 0:95bd93c28625 aksdb
  {@name is the stub for the method which will handle the OnProgress callbacks.
50 0:95bd93c28625 aksdb
  @param(ATotal Specifies the complete size of the operation.)
51 0:95bd93c28625 aksdb
  @param(ACurrent Specifies the current position during the operation.)}
52 0:95bd93c28625 aksdb
  TOnProgressEvent = procedure(ATotal, ACurrent: Cardinal) of object;
53 0:95bd93c28625 aksdb
54 0:95bd93c28625 aksdb
  { TFifoStream }
55 0:95bd93c28625 aksdb
56 0:95bd93c28625 aksdb
  {@abstract(The @name contains special handling for queuing and dequeing. It is
57 0:95bd93c28625 aksdb
  meant to be used as a network queue.)}
58 0:95bd93c28625 aksdb
  TFifoStream = class(TStream)
59 0:95bd93c28625 aksdb
    destructor Destroy; override;
60 0:95bd93c28625 aksdb
  protected
61 0:95bd93c28625 aksdb
    FMemory: Pointer;
62 0:95bd93c28625 aksdb
    FSize, FRealSize, FPosition, FLockOffset: Longint;
63 0:95bd93c28625 aksdb
    FCapacity: Longint;
64 0:95bd93c28625 aksdb
    procedure SetCapacity(ANewCapacity: Longint);
65 0:95bd93c28625 aksdb
    procedure SetPointer(APtr: Pointer; ASize: Longint);
66 0:95bd93c28625 aksdb
    function GetOptimalCapacity(ANewCapacity: Longint): Longint;
67 0:95bd93c28625 aksdb
    function Realloc(var NewCapacity: Longint): Pointer; virtual;
68 0:95bd93c28625 aksdb
    property Capacity: Longint read FCapacity write SetCapacity;
69 0:95bd93c28625 aksdb
  public
70 0:95bd93c28625 aksdb
    function GetSize: Int64; override;
71 0:95bd93c28625 aksdb
    function Read(var Buffer; ACount: Longint): Longint; override;
72 0:95bd93c28625 aksdb
    function Write(const Buffer; ACount: Longint): Longint; override;
73 0:95bd93c28625 aksdb
    function Seek(AOffset: Longint; AOrigin: Word): Longint; override;
74 0:95bd93c28625 aksdb
    procedure LoadFromStream(AStream: TStream);
75 0:95bd93c28625 aksdb
    procedure SaveToStream(AStream: TStream);
76 0:95bd93c28625 aksdb
    procedure LoadFromFile(const FileName: string);
77 0:95bd93c28625 aksdb
    procedure SaveToFile(const FileName: string);
78 0:95bd93c28625 aksdb
    procedure SetSize(ANewSize: Longint); override;
79 0:95bd93c28625 aksdb
    procedure Clear;
80 0:95bd93c28625 aksdb
    procedure Dequeue(ACount: Longint);                                         //<Removes a specified number of bytes from the queue. @param(ACount The number of bytes to remove from the queue.)
81 0:95bd93c28625 aksdb
    procedure Enqueue(const Buffer; ACount: Longint);                           //<Adds a specified number of bytes from a given buffer to the end of the queue. @param(Buffer The buffer containing the data to enqueue.) @param(ACount The number of bytes to enqueue from the buffer.)
82 0:95bd93c28625 aksdb
    procedure Lock(AOffset, ASize: Longint);                                    //<Restricts the visible area of the stream. @param(AOffset is the starting position of the area.) @param(ASize The size of the area.)
83 0:95bd93c28625 aksdb
    procedure Unlock;                                                           //<Removes the restrictions from the stream and resets the visible area to the original size.
84 0:95bd93c28625 aksdb
    property Memory: Pointer read FMemory;
85 0:95bd93c28625 aksdb
  end;
86 0:95bd93c28625 aksdb
87 0:95bd93c28625 aksdb
88 0:95bd93c28625 aksdb
  { TStreamWrapper }
89 0:95bd93c28625 aksdb
90 0:95bd93c28625 aksdb
  {The @name is just a placeholder for the type used in the
91 0:95bd93c28625 aksdb
  @link(TStreamWrapper). It is currently in place to work around a problem with
92 0:95bd93c28625 aksdb
  generics in fpc 2.2.0}
93 0:95bd93c28625 aksdb
  TStreamType = TFifoStream;
94 0:95bd93c28625 aksdb
  //generic TStreamWrapper<TStreamType> = class(TObject{, IStream})
95 0:95bd93c28625 aksdb
  {@abstract(@name implements @link(IStream) and offers a bunch of functions to
96 0:95bd93c28625 aksdb
  ease reading and writing special types (like @link(Integer)s or @link(String)s.))}
97 3:38a8c6979797 aksdb
  TStreamWrapper = class(TObject)
98 0:95bd93c28625 aksdb
    constructor Create(AStream: TStreamType; AOwnsStream: Boolean = True);      //<Creates a new instance of @classname. @param(AStream The underlying stream to perform the actual operations on.) @param(AOwnsStream Defines wheather to free the stream on destruction of @classname or not. Defaults to @false.)
99 0:95bd93c28625 aksdb
    destructor Destroy; override;                                               //<Is called when the current instance of @classname is destroyed. If it owns the underlying stream it is destroyed aswell.
100 0:95bd93c28625 aksdb
  protected
101 0:95bd93c28625 aksdb
    FStream: TStream;
102 0:95bd93c28625 aksdb
    FOwnsStream: Boolean;
103 0:95bd93c28625 aksdb
    function GetStream: TStreamType;
104 0:95bd93c28625 aksdb
    procedure SetStream(AStream: TStreamType);
105 0:95bd93c28625 aksdb
  public
106 0:95bd93c28625 aksdb
    property Raw: TStreamType read GetStream write SetStream;                   //<Provides raw access to the underlying stream. Useful for manipulation of the stream position and other class specific calls.
107 0:95bd93c28625 aksdb
108 0:95bd93c28625 aksdb
    function ReadBoolean: Boolean;                                              //<Implementation of @link(IStream.ReadBoolean).
109 0:95bd93c28625 aksdb
    function ReadByte: Byte;                                                    //<Implementation of @link(IStream.ReadByte).
110 0:95bd93c28625 aksdb
    function ReadCardinal: Cardinal;                                            //<Implementation of @link(IStream.ReadCardinal).
111 0:95bd93c28625 aksdb
    function ReadInteger: Integer;                                              //<Implementation of @link(IStream.ReadInteger).
112 0:95bd93c28625 aksdb
    function ReadInt64: Int64;                                                  //<Implementation of @link(IStream.ReadInt64).
113 0:95bd93c28625 aksdb
    function ReadSmallInt: SmallInt;                                            //<Implementation of @link(IStream.ReadSmallInt).
114 0:95bd93c28625 aksdb
    function ReadWord: Word;                                                    //<Implementation of @link(IStream.ReadWord).
115 0:95bd93c28625 aksdb
    function ReadString: string;                                                //<Implementation of @link(IStream.ReadString).
116 0:95bd93c28625 aksdb
    function ReadStringFixed(ALength: Integer): string;                         //<Implementation of @link(IStream.ReadStringFixed).
117 0:95bd93c28625 aksdb
    procedure WriteBoolean(AValue: Boolean);                                    //<Implementation of @link(IStream.WriteBoolean).
118 0:95bd93c28625 aksdb
    procedure WriteByte(AValue: Byte);                                          //<Implementation of @link(IStream.WriteByte).
119 0:95bd93c28625 aksdb
    procedure WriteCardinal(AValue: Cardinal);                                  //<Implementation of @link(IStream.WriteCardinal).
120 0:95bd93c28625 aksdb
    procedure WriteInteger(AValue: Integer);                                    //<Implementation of @link(IStream.WriteInteger).
121 0:95bd93c28625 aksdb
    procedure WriteInt64(AValue: Int64);                                        //<Implementation of @link(IStream.WriteInt64).
122 0:95bd93c28625 aksdb
    procedure WriteSmallInt(AValue: SmallInt);                                  //<Implementation of @link(IStream.WriteSmallInt).
123 0:95bd93c28625 aksdb
    procedure WriteWord(AValue: Word);                                          //<Implementation of @link(IStream.WriteWord).
124 0:95bd93c28625 aksdb
    procedure WriteString(AValue: string);                                      //<Implementation of @link(IStream.WriteString).
125 0:95bd93c28625 aksdb
    procedure WriteStringFixed(AValue: string; ALength: Integer);               //<Implementation of @link(IStream.WriteStringFixed).
126 0:95bd93c28625 aksdb
127 0:95bd93c28625 aksdb
    function Read(ABuffer: PByte; ACount: Cardinal): Cardinal;                  //<Implementation of @link(IStream.Read).
128 0:95bd93c28625 aksdb
    function Write(ABuffer: PByte; ACount: Cardinal): Cardinal;                 //<Implementation of @link(IStream.Write).
129 0:95bd93c28625 aksdb
130 0:95bd93c28625 aksdb
    procedure Skip(ACount: Cardinal);                                           //<Implementation of @link(IStream.Skip).
131 0:95bd93c28625 aksdb
  end;
132 0:95bd93c28625 aksdb
133 0:95bd93c28625 aksdb
{@name is used to have a progress (see @link(TOnProgressEvent)) for a copy
134 0:95bd93c28625 aksdb
action of the content of one stream into another. This is especially useful
135 0:95bd93c28625 aksdb
for writing and reading to @link(TFileStream).
136 0:95bd93c28625 aksdb
@param(ASource The stream from which the content is copied.)
137 0:95bd93c28625 aksdb
@param(ATarget The stream to which the content is copied.)
138 0:95bd93c28625 aksdb
@param(ACount Specifies the amount to copy. 0 means, that the whole stream is processed.)
139 0:95bd93c28625 aksdb
@param(AOnProgress The callback for the @link(TOnProgressEvent). Defaults to @nil.)
140 0:95bd93c28625 aksdb
@returns(The amount of bytes copied.)}
141 0:95bd93c28625 aksdb
function StreamCopy(ASource, ATarget: TStream; ACount: Int64; AOnProgress: TOnProgressEvent = nil): Int64;
142 0:95bd93c28625 aksdb
143 0:95bd93c28625 aksdb
implementation
144 0:95bd93c28625 aksdb
145 0:95bd93c28625 aksdb
function StreamCopy(ASource, ATarget: TStream; ACount: Int64; AOnProgress: TOnProgressEvent = nil): Int64;
146 0:95bd93c28625 aksdb
var
147 0:95bd93c28625 aksdb
  i, targetSize: Int64;
148 0:95bd93c28625 aksdb
  buffer: array[0..4095] of byte;
149 0:95bd93c28625 aksdb
begin
150 0:95bd93c28625 aksdb
  Result := 0;
151 0:95bd93c28625 aksdb
  if (ACount = 0) then
152 0:95bd93c28625 aksdb
  begin
153 0:95bd93c28625 aksdb
    //This WILL fail for non-seekable streams...
154 0:95bd93c28625 aksdb
    ASource.Position := 0;
155 0:95bd93c28625 aksdb
    ACount := ASource.Size;
156 0:95bd93c28625 aksdb
  end;
157 0:95bd93c28625 aksdb
  targetSize := ACount;
158 0:95bd93c28625 aksdb
  while ACount > 0 do
159 0:95bd93c28625 aksdb
  begin
160 0:95bd93c28625 aksdb
    if (ACount > SizeOf(buffer)) then
161 0:95bd93c28625 aksdb
      i := SizeOf(Buffer)
162 0:95bd93c28625 aksdb
    else
163 0:95bd93c28625 aksdb
      i := ACount;
164 0:95bd93c28625 aksdb
    i := ASource.Read(buffer, i);
165 0:95bd93c28625 aksdb
    i := ATarget.Write(buffer, i);
166 0:95bd93c28625 aksdb
    if i = 0 then break;
167 0:95bd93c28625 aksdb
    Dec(ACount, i);
168 0:95bd93c28625 aksdb
    Inc(Result, i);
169 0:95bd93c28625 aksdb
    if Assigned(AOnProgress) then
170 0:95bd93c28625 aksdb
      AOnProgress(targetSize, Result);
171 0:95bd93c28625 aksdb
  end;
172 0:95bd93c28625 aksdb
end;
173 0:95bd93c28625 aksdb
174 0:95bd93c28625 aksdb
{ TFifoStream }
175 0:95bd93c28625 aksdb
176 0:95bd93c28625 aksdb
const TMSGrow = 4096; { Use 4k blocks. }
177 0:95bd93c28625 aksdb
178 0:95bd93c28625 aksdb
destructor TFifoStream.Destroy;
179 0:95bd93c28625 aksdb
begin
180 0:95bd93c28625 aksdb
  Clear;
181 0:95bd93c28625 aksdb
  inherited Destroy;
182 0:95bd93c28625 aksdb
end;
183 0:95bd93c28625 aksdb
184 0:95bd93c28625 aksdb
procedure TFifoStream.SetCapacity(ANewCapacity: Longint);
185 0:95bd93c28625 aksdb
begin
186 0:95bd93c28625 aksdb
  SetPointer(Realloc(ANewCapacity), FSize);
187 0:95bd93c28625 aksdb
  FCapacity := ANewCapacity;
188 0:95bd93c28625 aksdb
end;
189 0:95bd93c28625 aksdb
190 0:95bd93c28625 aksdb
procedure TFifoStream.SetPointer(APtr: Pointer; ASize: Longint);
191 0:95bd93c28625 aksdb
begin
192 0:95bd93c28625 aksdb
  FMemory := APtr;
193 0:95bd93c28625 aksdb
  FSize := ASize;
194 0:95bd93c28625 aksdb
end;
195 0:95bd93c28625 aksdb
196 0:95bd93c28625 aksdb
function TFifoStream.GetOptimalCapacity(ANewCapacity: Longint): Longint;
197 0:95bd93c28625 aksdb
begin
198 0:95bd93c28625 aksdb
  Result := ANewCapacity;
199 0:95bd93c28625 aksdb
  if Result <= 0 then
200 0:95bd93c28625 aksdb
    Result := 0
201 0:95bd93c28625 aksdb
  else
202 0:95bd93c28625 aksdb
  begin
203 0:95bd93c28625 aksdb
    // if growing, grow at least a quarter
204 0:95bd93c28625 aksdb
    if (Result > FCapacity) and (Result < (5 * FCapacity) div 4) then
205 0:95bd93c28625 aksdb
      Result := (5 * FCapacity) div 4;
206 0:95bd93c28625 aksdb
    // round off to block size.
207 0:95bd93c28625 aksdb
    Result := (Result + (TMSGrow-1)) and not (TMSGROW-1);
208 0:95bd93c28625 aksdb
  end;
209 0:95bd93c28625 aksdb
end;
210 0:95bd93c28625 aksdb
211 0:95bd93c28625 aksdb
function TFifoStream.Realloc(var NewCapacity: Longint): Pointer;
212 0:95bd93c28625 aksdb
begin
213 0:95bd93c28625 aksdb
  NewCapacity := GetOptimalCapacity(NewCapacity);
214 0:95bd93c28625 aksdb
  // Only now check !
215 0:95bd93c28625 aksdb
  if NewCapacity = FCapacity then
216 0:95bd93c28625 aksdb
    Result := FMemory
217 0:95bd93c28625 aksdb
  else
218 0:95bd93c28625 aksdb
  begin
219 0:95bd93c28625 aksdb
    Result := ReAllocMem(FMemory, NewCapacity);
220 0:95bd93c28625 aksdb
    if (Result = nil) and (NewCapacity > 0) then
221 0:95bd93c28625 aksdb
      raise EStreamError.Create(SMemoryStreamError);
222 0:95bd93c28625 aksdb
  end;
223 0:95bd93c28625 aksdb
end;
224 0:95bd93c28625 aksdb
225 0:95bd93c28625 aksdb
function TFifoStream.GetSize: Int64;
226 0:95bd93c28625 aksdb
begin
227 0:95bd93c28625 aksdb
  Result := FSize;
228 0:95bd93c28625 aksdb
end;
229 0:95bd93c28625 aksdb
230 0:95bd93c28625 aksdb
function TFifoStream.Read(var Buffer; ACount: Longint): Longint;
231 0:95bd93c28625 aksdb
begin
232 0:95bd93c28625 aksdb
  Result := 0;
233 0:95bd93c28625 aksdb
  If (FSize > 0) and (FPosition - FLockOffset < FSize) then
234 0:95bd93c28625 aksdb
  begin
235 0:95bd93c28625 aksdb
    Result := FSize - (FPosition - FLockOffset);
236 0:95bd93c28625 aksdb
    if Result > ACount then Result := ACount;
237 0:95bd93c28625 aksdb
    Move((FMemory + FPosition)^, Buffer, Result);
238 0:95bd93c28625 aksdb
    FPosition := FPosition + Result;
239 0:95bd93c28625 aksdb
  end;
240 0:95bd93c28625 aksdb
end;
241 0:95bd93c28625 aksdb
242 0:95bd93c28625 aksdb
function TFifoStream.Write(const Buffer; ACount: Longint): Longint;
243 0:95bd93c28625 aksdb
var
244 0:95bd93c28625 aksdb
  NewPos: Longint;
245 0:95bd93c28625 aksdb
begin
246 0:95bd93c28625 aksdb
  Unlock;
247 0:95bd93c28625 aksdb
  if ACount = 0 then
248 0:95bd93c28625 aksdb
    Exit(0);
249 0:95bd93c28625 aksdb
  NewPos := FPosition + ACount;
250 0:95bd93c28625 aksdb
  if NewPos > FSize then
251 0:95bd93c28625 aksdb
  begin
252 0:95bd93c28625 aksdb
    if NewPos > FCapacity then
253 0:95bd93c28625 aksdb
      SetCapacity(NewPos);
254 0:95bd93c28625 aksdb
    FSize := NewPos;
255 0:95bd93c28625 aksdb
  end;
256 0:95bd93c28625 aksdb
  System.Move(Buffer, (FMemory + FPosition)^, ACount);
257 0:95bd93c28625 aksdb
  FPosition := NewPos;
258 0:95bd93c28625 aksdb
  Result := ACount;
259 0:95bd93c28625 aksdb
end;
260 0:95bd93c28625 aksdb
261 0:95bd93c28625 aksdb
function TFifoStream.Seek(AOffset: Longint; AOrigin: Word): Longint;
262 0:95bd93c28625 aksdb
begin
263 0:95bd93c28625 aksdb
  case AOrigin of
264 0:95bd93c28625 aksdb
    soFromBeginning : FPosition := AOffset + FLockOffset;
265 0:95bd93c28625 aksdb
    soFromEnd       : FPosition := FSize + AOffset + FLockOffset;
266 0:95bd93c28625 aksdb
    soFromCurrent   : FPosition := FPosition + AOffset;
267 0:95bd93c28625 aksdb
  end;
268 0:95bd93c28625 aksdb
  Result := FPosition - FLockOffset;
269 0:95bd93c28625 aksdb
end;
270 0:95bd93c28625 aksdb
271 0:95bd93c28625 aksdb
procedure TFifoStream.LoadFromStream(AStream: TStream);
272 0:95bd93c28625 aksdb
begin
273 0:95bd93c28625 aksdb
  Unlock;
274 0:95bd93c28625 aksdb
  AStream.Position := 0;
275 0:95bd93c28625 aksdb
  SetSize(AStream.Size);
276 0:95bd93c28625 aksdb
  If FSize > 0 then AStream.ReadBuffer(FMemory^,FSize);
277 0:95bd93c28625 aksdb
end;
278 0:95bd93c28625 aksdb
279 0:95bd93c28625 aksdb
procedure TFifoStream.SaveToStream(AStream: TStream);
280 0:95bd93c28625 aksdb
begin
281 0:95bd93c28625 aksdb
  if FSize > 0 then AStream.WriteBuffer((FMemory + FLockOffset)^, FSize);
282 0:95bd93c28625 aksdb
end;
283 0:95bd93c28625 aksdb
284 0:95bd93c28625 aksdb
procedure TFifoStream.LoadFromFile(const FileName: string);
285 0:95bd93c28625 aksdb
var
286 0:95bd93c28625 aksdb
  S: TFileStream;
287 0:95bd93c28625 aksdb
begin
288 0:95bd93c28625 aksdb
  S := TFileStream.Create(FileName, fmOpenRead);
289 0:95bd93c28625 aksdb
  try
290 0:95bd93c28625 aksdb
    LoadFromStream(S);
291 0:95bd93c28625 aksdb
  finally
292 0:95bd93c28625 aksdb
    S.free;
293 0:95bd93c28625 aksdb
  end;
294 0:95bd93c28625 aksdb
end;
295 0:95bd93c28625 aksdb
296 0:95bd93c28625 aksdb
procedure TFifoStream.SaveToFile(const FileName: string);
297 0:95bd93c28625 aksdb
var
298 0:95bd93c28625 aksdb
  S: TFileStream;
299 0:95bd93c28625 aksdb
begin
300 0:95bd93c28625 aksdb
  S := TFileStream.Create(FileName, fmCreate);
301 0:95bd93c28625 aksdb
  try
302 0:95bd93c28625 aksdb
    SaveToStream(S);
303 0:95bd93c28625 aksdb
  finally
304 0:95bd93c28625 aksdb
    S.free;
305 0:95bd93c28625 aksdb
  end;
306 0:95bd93c28625 aksdb
end;
307 0:95bd93c28625 aksdb
308 0:95bd93c28625 aksdb
procedure TFifoStream.SetSize(ANewSize: Longint);
309 0:95bd93c28625 aksdb
begin
310 0:95bd93c28625 aksdb
  Unlock;
311 0:95bd93c28625 aksdb
  SetCapacity(ANewSize);
312 0:95bd93c28625 aksdb
  FSize := ANewSize;
313 0:95bd93c28625 aksdb
  if FPosition > FSize then
314 0:95bd93c28625 aksdb
    FPosition := FSize;
315 0:95bd93c28625 aksdb
end;
316 0:95bd93c28625 aksdb
317 0:95bd93c28625 aksdb
procedure TFifoStream.Clear;
318 0:95bd93c28625 aksdb
begin
319 0:95bd93c28625 aksdb
  FSize := 0;
320 0:95bd93c28625 aksdb
  FRealSize := 0;
321 0:95bd93c28625 aksdb
  FPosition := 0;
322 0:95bd93c28625 aksdb
  FLockOffset := 0;
323 0:95bd93c28625 aksdb
  SetCapacity(0);
324 0:95bd93c28625 aksdb
end;
325 0:95bd93c28625 aksdb
326 0:95bd93c28625 aksdb
procedure TFifoStream.Dequeue(ACount: Longint);
327 0:95bd93c28625 aksdb
var
328 0:95bd93c28625 aksdb
  newCapacity, newSize: Longint;
329 0:95bd93c28625 aksdb
  queue, newMemory: Pointer;
330 0:95bd93c28625 aksdb
begin
331 0:95bd93c28625 aksdb
  Unlock;
332 0:95bd93c28625 aksdb
  if ACount >= FSize then
333 0:95bd93c28625 aksdb
  begin
334 0:95bd93c28625 aksdb
    Size := 0;
335 0:95bd93c28625 aksdb
    Exit;
336 0:95bd93c28625 aksdb
  end;
337 0:95bd93c28625 aksdb
338 0:95bd93c28625 aksdb
  queue := FMemory + ACount;
339 0:95bd93c28625 aksdb
  newSize := FSize - ACount;
340 0:95bd93c28625 aksdb
341 0:95bd93c28625 aksdb
  newCapacity := GetOptimalCapacity(newSize);
342 0:95bd93c28625 aksdb
  if newCapacity <> FCapacity then
343 0:95bd93c28625 aksdb
  begin
344 0:95bd93c28625 aksdb
    newMemory := GetMem(newCapacity);
345 0:95bd93c28625 aksdb
    System.Move(queue^, newMemory^, newSize);
346 0:95bd93c28625 aksdb
    if (newMemory = nil) and (newCapacity > 0) then
347 0:95bd93c28625 aksdb
      raise EStreamError.Create(SMemoryStreamError);
348 0:95bd93c28625 aksdb
    FreeMem(FMemory);
349 0:95bd93c28625 aksdb
    FMemory := newMemory;
350 0:95bd93c28625 aksdb
    FCapacity := newCapacity;
351 0:95bd93c28625 aksdb
  end else
352 0:95bd93c28625 aksdb
    System.Move(queue^, FMemory^, newSize);
353 0:95bd93c28625 aksdb
354 0:95bd93c28625 aksdb
  FSize := newSize;
355 0:95bd93c28625 aksdb
  if FPosition > ACount then
356 0:95bd93c28625 aksdb
    Dec(FPosition, ACount)
357 0:95bd93c28625 aksdb
  else
358 0:95bd93c28625 aksdb
    FPosition := 0;
359 0:95bd93c28625 aksdb
end;
360 0:95bd93c28625 aksdb
361 0:95bd93c28625 aksdb
procedure TFifoStream.Enqueue(const Buffer; ACount: Longint);
362 0:95bd93c28625 aksdb
var
363 0:95bd93c28625 aksdb
  oldPos: Int64;
364 0:95bd93c28625 aksdb
begin
365 0:95bd93c28625 aksdb
  Unlock;
366 0:95bd93c28625 aksdb
  oldPos := FPosition;
367 0:95bd93c28625 aksdb
  FPosition := FSize;
368 0:95bd93c28625 aksdb
  Write(Buffer, ACount);
369 0:95bd93c28625 aksdb
  FPosition := oldPos;
370 0:95bd93c28625 aksdb
end;
371 0:95bd93c28625 aksdb
372 0:95bd93c28625 aksdb
procedure TFifoStream.Lock(AOffset, ASize: Longint);
373 0:95bd93c28625 aksdb
begin
374 0:95bd93c28625 aksdb
  if (FLockOffset <> 0) or (FRealSize <> 0) then Exit;
375 0:95bd93c28625 aksdb
  FLockOffset := AOffset;
376 0:95bd93c28625 aksdb
  FRealSize := FSize;
377 0:95bd93c28625 aksdb
  FSize := ASize;
378 0:95bd93c28625 aksdb
end;
379 0:95bd93c28625 aksdb
380 0:95bd93c28625 aksdb
procedure TFifoStream.Unlock;
381 0:95bd93c28625 aksdb
begin
382 0:95bd93c28625 aksdb
  if (FLockOffset = 0) and (FRealSize = 0) then Exit;
383 0:95bd93c28625 aksdb
  FLockOffset := 0;
384 0:95bd93c28625 aksdb
  FSize := FRealSize;
385 0:95bd93c28625 aksdb
  FRealSize := 0;
386 0:95bd93c28625 aksdb
end;
387 0:95bd93c28625 aksdb
388 0:95bd93c28625 aksdb
{ TStreamWrapper }
389 0:95bd93c28625 aksdb
390 0:95bd93c28625 aksdb
constructor TStreamWrapper.Create(AStream: TStreamType; AOwnsStream: Boolean);
391 0:95bd93c28625 aksdb
begin
392 0:95bd93c28625 aksdb
  inherited Create;
393 0:95bd93c28625 aksdb
  FStream := TStream(AStream);
394 0:95bd93c28625 aksdb
  FOwnsStream := AOwnsStream;
395 0:95bd93c28625 aksdb
end;
396 0:95bd93c28625 aksdb
397 0:95bd93c28625 aksdb
destructor TStreamWrapper.Destroy;
398 0:95bd93c28625 aksdb
begin
399 0:95bd93c28625 aksdb
  if FOwnsStream and Assigned(FStream) then FreeAndNil(FStream);
400 0:95bd93c28625 aksdb
  inherited Destroy;
401 0:95bd93c28625 aksdb
end;
402 0:95bd93c28625 aksdb
403 0:95bd93c28625 aksdb
function TStreamWrapper.GetStream: TStreamType;
404 0:95bd93c28625 aksdb
begin
405 0:95bd93c28625 aksdb
  Result := TStreamType(FStream);
406 0:95bd93c28625 aksdb
end;
407 0:95bd93c28625 aksdb
408 0:95bd93c28625 aksdb
procedure TStreamWrapper.SetStream(AStream: TStreamType);
409 0:95bd93c28625 aksdb
begin
410 0:95bd93c28625 aksdb
  FStream := TStream(AStream);
411 0:95bd93c28625 aksdb
end;
412 0:95bd93c28625 aksdb
413 0:95bd93c28625 aksdb
function TStreamWrapper.ReadBoolean: Boolean;
414 0:95bd93c28625 aksdb
begin
415 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(False);
416 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Boolean));
417 0:95bd93c28625 aksdb
end;
418 0:95bd93c28625 aksdb
419 0:95bd93c28625 aksdb
function TStreamWrapper.ReadByte: Byte;
420 0:95bd93c28625 aksdb
begin
421 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
422 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Byte));
423 0:95bd93c28625 aksdb
end;
424 0:95bd93c28625 aksdb
425 0:95bd93c28625 aksdb
function TStreamWrapper.ReadCardinal: Cardinal;
426 0:95bd93c28625 aksdb
begin
427 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
428 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Cardinal));
429 0:95bd93c28625 aksdb
end;
430 0:95bd93c28625 aksdb
431 0:95bd93c28625 aksdb
function TStreamWrapper.ReadInteger: Integer;
432 0:95bd93c28625 aksdb
begin
433 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
434 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Integer));
435 0:95bd93c28625 aksdb
end;
436 0:95bd93c28625 aksdb
437 0:95bd93c28625 aksdb
function TStreamWrapper.ReadInt64: Int64;
438 0:95bd93c28625 aksdb
begin
439 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
440 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Int64));
441 0:95bd93c28625 aksdb
end;
442 0:95bd93c28625 aksdb
443 0:95bd93c28625 aksdb
function TStreamWrapper.ReadSmallInt: SmallInt;
444 0:95bd93c28625 aksdb
begin
445 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
446 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(SmallInt));
447 0:95bd93c28625 aksdb
end;
448 0:95bd93c28625 aksdb
449 0:95bd93c28625 aksdb
function TStreamWrapper.ReadWord: Word;
450 0:95bd93c28625 aksdb
begin
451 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit(0);
452 0:95bd93c28625 aksdb
  FStream.Read(Result, SizeOf(Word));
453 0:95bd93c28625 aksdb
end;
454 0:95bd93c28625 aksdb
455 0:95bd93c28625 aksdb
function TStreamWrapper.ReadString: string;
456 0:95bd93c28625 aksdb
begin
457 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit('');
458 0:95bd93c28625 aksdb
  Result := ReadStringFixed(ReadInteger);
459 0:95bd93c28625 aksdb
end;
460 0:95bd93c28625 aksdb
461 0:95bd93c28625 aksdb
function TStreamWrapper.ReadStringFixed(ALength: Integer): string;
462 0:95bd93c28625 aksdb
begin
463 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit('');
464 0:95bd93c28625 aksdb
  SetLength(Result, ALength);
465 0:95bd93c28625 aksdb
  FStream.Read(PChar(Result)^, ALength);
466 0:95bd93c28625 aksdb
end;
467 0:95bd93c28625 aksdb
468 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteBoolean(AValue: Boolean);
469 0:95bd93c28625 aksdb
begin
470 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
471 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Boolean));
472 0:95bd93c28625 aksdb
end;
473 0:95bd93c28625 aksdb
474 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteByte(AValue: Byte);
475 0:95bd93c28625 aksdb
begin
476 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
477 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Byte));
478 0:95bd93c28625 aksdb
end;
479 0:95bd93c28625 aksdb
480 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteCardinal(AValue: Cardinal);
481 0:95bd93c28625 aksdb
begin
482 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
483 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Cardinal));
484 0:95bd93c28625 aksdb
end;
485 0:95bd93c28625 aksdb
486 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteInteger(AValue: Integer);
487 0:95bd93c28625 aksdb
begin
488 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
489 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Integer));
490 0:95bd93c28625 aksdb
end;
491 0:95bd93c28625 aksdb
492 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteInt64(AValue: Int64);
493 0:95bd93c28625 aksdb
begin
494 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
495 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Int64));
496 0:95bd93c28625 aksdb
end;
497 0:95bd93c28625 aksdb
498 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteSmallInt(AValue: SmallInt);
499 0:95bd93c28625 aksdb
begin
500 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
501 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(SmallInt));
502 0:95bd93c28625 aksdb
end;
503 0:95bd93c28625 aksdb
504 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteWord(AValue: Word);
505 0:95bd93c28625 aksdb
begin
506 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
507 0:95bd93c28625 aksdb
  FStream.Write(AValue, SizeOf(Word));
508 0:95bd93c28625 aksdb
end;
509 0:95bd93c28625 aksdb
510 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteString(AValue: string);
511 0:95bd93c28625 aksdb
var
512 0:95bd93c28625 aksdb
  stringLength: Integer;
513 0:95bd93c28625 aksdb
begin
514 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
515 0:95bd93c28625 aksdb
  stringLength := Length(AValue);
516 0:95bd93c28625 aksdb
  WriteInteger(stringLength);
517 0:95bd93c28625 aksdb
  WriteStringFixed(AValue, stringLength);
518 0:95bd93c28625 aksdb
end;
519 0:95bd93c28625 aksdb
520 0:95bd93c28625 aksdb
procedure TStreamWrapper.WriteStringFixed(AValue: string; ALength: Integer);
521 0:95bd93c28625 aksdb
begin
522 0:95bd93c28625 aksdb
  if not Assigned(FStream) then Exit;
523 0:95bd93c28625 aksdb
  FStream.Write(PChar(AValue)^, ALength);
524 0:95bd93c28625 aksdb
end;
525 0:95bd93c28625 aksdb
526 0:95bd93c28625 aksdb
function TStreamWrapper.Read(ABuffer: PByte; ACount: Cardinal): Cardinal;
527 0:95bd93c28625 aksdb
begin
528 0:95bd93c28625 aksdb
  Result := FStream.Read(ABuffer^, ACount);
529 0:95bd93c28625 aksdb
end;
530 0:95bd93c28625 aksdb
531 0:95bd93c28625 aksdb
function TStreamWrapper.Write(ABuffer: PByte; ACount: Cardinal): Cardinal;
532 0:95bd93c28625 aksdb
begin
533 0:95bd93c28625 aksdb
  Result := FStream.Write(ABuffer^, ACount);
534 0:95bd93c28625 aksdb
end;
535 0:95bd93c28625 aksdb
536 0:95bd93c28625 aksdb
procedure TStreamWrapper.Skip(ACount: Cardinal);
537 0:95bd93c28625 aksdb
begin
538 0:95bd93c28625 aksdb
  FStream.Seek(ACount, soFromCurrent);
539 0:95bd93c28625 aksdb
end;
540 0:95bd93c28625 aksdb
541 0:95bd93c28625 aksdb
end.