blob: 56823312656e81512253435ebf2e2fa91248fde1 [file] [log] [blame]
Jens Geyerd5436f52014-10-03 19:50:38 +02001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19
20unit Thrift.Stream;
21
Jens Geyer9f7f11e2016-04-14 21:37:11 +020022{$I Thrift.Defines.inc}
Nick4f5229e2016-04-14 16:43:22 +030023
Jens Geyerd5436f52014-10-03 19:50:38 +020024interface
25
26uses
27 Classes,
28 SysUtils,
29 SysConst,
30 RTLConsts,
Jens Geyer9f7f11e2016-04-14 21:37:11 +020031 {$IFDEF OLD_UNIT_NAMES}
32 ActiveX,
Nick4f5229e2016-04-14 16:43:22 +030033 {$ELSE}
Jens Geyer9f7f11e2016-04-14 21:37:11 +020034 Winapi.ActiveX,
35 {$ENDIF}
Nick4f5229e2016-04-14 16:43:22 +030036 Thrift.Utils;
Jens Geyerd5436f52014-10-03 19:50:38 +020037
38type
Jens Geyerd5436f52014-10-03 19:50:38 +020039 IThriftStream = interface
Jens Geyer5a781c22025-02-04 23:35:55 +010040 ['{67801A9F-3B85-41CF-9025-D18AC6849B58}']
Jens Geyer17c3ad92017-09-05 20:31:27 +020041 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload;
42 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); overload;
43 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload;
44 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload;
Jens Geyerd5436f52014-10-03 19:50:38 +020045 procedure Open;
46 procedure Close;
47 procedure Flush;
48 function IsOpen: Boolean;
49 function ToArray: TBytes;
Jens Geyer5a781c22025-02-04 23:35:55 +010050 function CanSeek : Boolean;
Jens Geyer41f47af2019-11-09 23:24:52 +010051 function Size : Int64;
52 function Position : Int64;
53 end;
54
55
56 TThriftStreamImpl = class abstract( TInterfacedObject, IThriftStream)
Jens Geyerfad7fd32019-11-09 23:24:52 +010057 strict private
Jens Geyer17c3ad92017-09-05 20:31:27 +020058 procedure CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer); overload;
Jens Geyerfad7fd32019-11-09 23:24:52 +010059 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010060 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020061 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload; inline;
62 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); overload; virtual;
63 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload; inline;
64 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +020065 procedure Open; virtual; abstract;
66 procedure Close; virtual; abstract;
67 procedure Flush; virtual; abstract;
68 function IsOpen: Boolean; virtual; abstract;
69 function ToArray: TBytes; virtual; abstract;
Jens Geyer5a781c22025-02-04 23:35:55 +010070 function CanSeek : Boolean; virtual;
Jens Geyera019cda2019-11-09 23:24:52 +010071 function Size : Int64; virtual;
72 function Position : Int64; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +020073 end;
74
Jens Geyera019cda2019-11-09 23:24:52 +010075 TThriftStreamAdapterDelphi = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +010076 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +020077 FStream : TStream;
78 FOwnsStream : Boolean;
Jens Geyerfad7fd32019-11-09 23:24:52 +010079 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010080 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020081 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
82 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +020083 procedure Open; override;
84 procedure Close; override;
85 procedure Flush; override;
86 function IsOpen: Boolean; override;
87 function ToArray: TBytes; override;
Jens Geyer5a781c22025-02-04 23:35:55 +010088 function CanSeek : Boolean; override;
Jens Geyera019cda2019-11-09 23:24:52 +010089 function Size : Int64; override;
90 function Position : Int64; override;
Jens Geyerd5436f52014-10-03 19:50:38 +020091 public
Jens Geyer41f47af2019-11-09 23:24:52 +010092 constructor Create( const aStream: TStream; aOwnsStream : Boolean);
Jens Geyerd5436f52014-10-03 19:50:38 +020093 destructor Destroy; override;
94 end;
95
Jens Geyera019cda2019-11-09 23:24:52 +010096 TThriftStreamAdapterCOM = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +010097 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +020098 FStream : IStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +010099 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +0100100 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +0200101 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
102 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200103 procedure Open; override;
104 procedure Close; override;
105 procedure Flush; override;
106 function IsOpen: Boolean; override;
107 function ToArray: TBytes; override;
Jens Geyer5a781c22025-02-04 23:35:55 +0100108 function CanSeek : Boolean; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100109 function Size : Int64; override;
110 function Position : Int64; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200111 public
Jens Geyer41f47af2019-11-09 23:24:52 +0100112 constructor Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200113 end;
114
Jens Geyerf726ae32021-06-04 11:17:26 +0200115
116 TThriftMemoryStream = class(TMemoryStream)
117 strict protected
118 FInitialCapacity : NativeInt;
119 public
120 constructor Create( const aInitialCapacity : NativeInt = 4096);
121
122 // reimplemented
123 procedure Clear;
124
125 // make it publicly visible
126 property Capacity;
127 end;
128
129
130
Jens Geyerd5436f52014-10-03 19:50:38 +0200131implementation
132
Jens Geyer41f47af2019-11-09 23:24:52 +0100133uses Thrift.Transport;
134
Jens Geyerf726ae32021-06-04 11:17:26 +0200135
136{ TThriftMemoryStream }
137
138constructor TThriftMemoryStream.Create( const aInitialCapacity : NativeInt);
139begin
140 inherited Create;
141 FInitialCapacity := aInitialCapacity;
142 Clear;
143end;
144
145
146procedure TThriftMemoryStream.Clear;
147// reimplemented to keep initial capacity
148begin
149 Position := 0;
150 Size := 0;
151
152 // primary goal: minimize costly reallocations (performance!)
153 // secondary goal: prevent costly ressource over-allocations
154 if (FInitialCapacity >= 1024*1024) // if we are talking about MB
155 or ((Capacity div 2) > FInitialCapacity) // or the allocated buffer is really large
156 or (Capacity < FInitialCapacity) // or we are actually below the limit
157 then Capacity := FInitialCapacity;
158end;
159
160
Jens Geyerd5436f52014-10-03 19:50:38 +0200161{ TThriftStreamAdapterCOM }
162
163procedure TThriftStreamAdapterCOM.Close;
164begin
165 FStream := nil;
166end;
167
Jens Geyer41f47af2019-11-09 23:24:52 +0100168constructor TThriftStreamAdapterCOM.Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200169begin
170 inherited Create;
Jens Geyer41f47af2019-11-09 23:24:52 +0100171 FStream := aStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200172end;
173
174procedure TThriftStreamAdapterCOM.Flush;
175begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200176 if IsOpen then begin
177 if FStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200178 FStream.Commit( STGC_DEFAULT );
179 end;
180 end;
181end;
182
Jens Geyer5a781c22025-02-04 23:35:55 +0100183function TThriftStreamAdapterCOM.CanSeek : Boolean;
184var statstg: TStatStg;
185begin
186 result := IsOpen and Succeeded( FStream.Stat( statstg, STATFLAG_NONAME));
187end;
188
Jens Geyer41f47af2019-11-09 23:24:52 +0100189function TThriftStreamAdapterCOM.Size : Int64;
190var statstg: TStatStg;
191begin
192 FillChar( statstg, SizeOf( statstg), 0);
193 if IsOpen
194 and Succeeded( FStream.Stat( statstg, STATFLAG_NONAME ))
195 then result := statstg.cbSize
196 else result := 0;
197end;
198
199function TThriftStreamAdapterCOM.Position : Int64;
200var newpos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
201begin
202 if SUCCEEDED( FStream.Seek( 0, STREAM_SEEK_CUR, newpos))
203 then result := Int64(newpos)
204 else raise TTransportExceptionEndOfFile.Create('Seek() error');
205end;
206
Jens Geyerd5436f52014-10-03 19:50:38 +0200207function TThriftStreamAdapterCOM.IsOpen: Boolean;
208begin
209 Result := FStream <> nil;
210end;
211
212procedure TThriftStreamAdapterCOM.Open;
213begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200214 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200215end;
216
Jens Geyer17c3ad92017-09-05 20:31:27 +0200217function TThriftStreamAdapterCOM.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100218var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200219begin
220 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200221
222 if count >= buflen-offset
223 then count := buflen-offset;
224
Jens Geyerd5436f52014-10-03 19:50:38 +0200225 Result := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200226 if FStream <> nil then begin
227 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100228 pTmp := pBuf;
229 Inc( pTmp, offset);
230 FStream.Read( pTmp, count, @Result);
Jens Geyerd5436f52014-10-03 19:50:38 +0200231 end;
232 end;
233end;
234
235function TThriftStreamAdapterCOM.ToArray: TBytes;
236var
Jens Geyer41f47af2019-11-09 23:24:52 +0100237 len : Int64;
Nick4f5229e2016-04-14 16:43:22 +0300238 NewPos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
Jens Geyerd5436f52014-10-03 19:50:38 +0200239 cbRead : Integer;
240begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100241 len := Self.Size;
Jens Geyerd5436f52014-10-03 19:50:38 +0200242 SetLength( Result, len );
243
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200244 if len > 0 then begin
245 if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200246 FStream.Read( @Result[0], len, @cbRead);
247 end;
248 end;
249end;
250
Jens Geyer17c3ad92017-09-05 20:31:27 +0200251procedure TThriftStreamAdapterCOM.Write( const pBuf: Pointer; offset: Integer; count: Integer);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200252var nWritten : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100253 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200254begin
255 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200256 if IsOpen then begin
257 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100258 pTmp := pBuf;
259 Inc( pTmp, offset);
260 FStream.Write( pTmp, count, @nWritten);
Jens Geyerd5436f52014-10-03 19:50:38 +0200261 end;
262 end;
263end;
264
265{ TThriftStreamImpl }
266
Jens Geyer17c3ad92017-09-05 20:31:27 +0200267procedure TThriftStreamImpl.CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200268begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200269 if count > 0 then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200270 if (offset < 0) or ( offset >= buflen) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200271 raise ERangeError.Create( SBitsIndexError );
272 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200273 if count > buflen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200274 raise ERangeError.Create( SBitsIndexError );
275 end;
276 end;
277end;
278
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200279function TThriftStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200280begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200281 if Length(buffer) > 0
282 then Result := Read( @buffer[0], Length(buffer), offset, count)
283 else Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200284end;
285
286function TThriftStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
287begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200288 Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200289 CheckSizeAndOffset( pBuf, buflen, offset, count );
Jens Geyerd5436f52014-10-03 19:50:38 +0200290end;
291
292procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);
293begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200294 if Length(buffer) > 0
295 then Write( @buffer[0], offset, count);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200296end;
297
298procedure TThriftStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
299begin
300 CheckSizeAndOffset( pBuf, offset+count, offset, count);
Jens Geyerd5436f52014-10-03 19:50:38 +0200301end;
302
Jens Geyer5a781c22025-02-04 23:35:55 +0100303function TThriftStreamImpl.CanSeek : Boolean;
304begin
305 result := FALSE; // TRUE indicates Size and Position are implemented
306end;
307
Jens Geyera019cda2019-11-09 23:24:52 +0100308function TThriftStreamImpl.Size : Int64;
309begin
310 ASSERT(FALSE);
311 raise ENotImplemented.Create(ClassName+'.Size');
312end;
313
314function TThriftStreamImpl.Position : Int64;
315begin
316 ASSERT(FALSE);
317 raise ENotImplemented.Create(ClassName+'.Position');
318end;
319
320
Jens Geyerd5436f52014-10-03 19:50:38 +0200321{ TThriftStreamAdapterDelphi }
322
Jens Geyer41f47af2019-11-09 23:24:52 +0100323constructor TThriftStreamAdapterDelphi.Create( const aStream: TStream; aOwnsStream: Boolean);
324begin
325 inherited Create;
326 FStream := aStream;
327 FOwnsStream := aOwnsStream;
328end;
329
330destructor TThriftStreamAdapterDelphi.Destroy;
331begin
332 if FOwnsStream
333 then Close;
334
335 inherited;
336end;
337
Jens Geyerd5436f52014-10-03 19:50:38 +0200338procedure TThriftStreamAdapterDelphi.Close;
339begin
340 FStream.Free;
341 FStream := nil;
342 FOwnsStream := False;
343end;
344
Jens Geyerd5436f52014-10-03 19:50:38 +0200345procedure TThriftStreamAdapterDelphi.Flush;
346begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200347 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200348end;
349
Jens Geyer5a781c22025-02-04 23:35:55 +0100350function TThriftStreamAdapterDelphi.CanSeek : Boolean;
351begin
352 try
353 result := IsOpen and (FStream.Size >= 0); // throws if not implemented
354 except
355 result := FALSE; // seek not implemented
356 end;
357end;
358
Jens Geyer41f47af2019-11-09 23:24:52 +0100359function TThriftStreamAdapterDelphi.Size : Int64;
360begin
361 result := FStream.Size;
362end;
363
364function TThriftStreamAdapterDelphi.Position : Int64;
365begin
366 result := FStream.Position;
367end;
368
Jens Geyerd5436f52014-10-03 19:50:38 +0200369function TThriftStreamAdapterDelphi.IsOpen: Boolean;
370begin
371 Result := FStream <> nil;
372end;
373
374procedure TThriftStreamAdapterDelphi.Open;
375begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200376 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200377end;
378
Jens Geyer17c3ad92017-09-05 20:31:27 +0200379function TThriftStreamAdapterDelphi.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100380var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200381begin
382 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200383
384 if count >= buflen-offset
385 then count := buflen-offset;
386
Jens Geyer5089b0a2018-02-01 22:37:18 +0100387 if count > 0 then begin
388 pTmp := pBuf;
389 Inc( pTmp, offset);
390 Result := FStream.Read( pTmp^, count)
391 end
Jens Geyer17c3ad92017-09-05 20:31:27 +0200392 else Result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200393end;
394
395function TThriftStreamAdapterDelphi.ToArray: TBytes;
396var
397 OrgPos : Integer;
398 len : Integer;
399begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100400 if FStream <> nil
401 then len := FStream.Size
402 else len := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200403
404 SetLength( Result, len );
405
406 if len > 0 then
407 begin
408 OrgPos := FStream.Position;
409 try
410 FStream.Position := 0;
411 FStream.ReadBuffer( Pointer(@Result[0])^, len );
412 finally
413 FStream.Position := OrgPos;
414 end;
415 end
416end;
417
Jens Geyer17c3ad92017-09-05 20:31:27 +0200418procedure TThriftStreamAdapterDelphi.Write(const pBuf : Pointer; offset, count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +0100419var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200420begin
421 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200422 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100423 pTmp := pBuf;
424 Inc( pTmp, offset);
425 FStream.Write( pTmp^, count)
Jens Geyerd5436f52014-10-03 19:50:38 +0200426 end;
427end;
428
429end.