blob: 6c1320d998ed5b9283c01ab0d50bf4a386fde9bd [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 Geyera019cda2019-11-09 23:24:52 +010040 ['{3A61A8A6-3639-4B91-A260-EFCA23944F3A}']
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 Geyer41f47af2019-11-09 23:24:52 +010050 function Size : Int64;
51 function Position : Int64;
52 end;
53
54
55 TThriftStreamImpl = class abstract( TInterfacedObject, IThriftStream)
Jens Geyerfad7fd32019-11-09 23:24:52 +010056 strict private
Jens Geyer17c3ad92017-09-05 20:31:27 +020057 procedure CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer); overload;
Jens Geyerfad7fd32019-11-09 23:24:52 +010058 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010059 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020060 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload; inline;
61 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); overload; virtual;
62 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload; inline;
63 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +020064 procedure Open; virtual; abstract;
65 procedure Close; virtual; abstract;
66 procedure Flush; virtual; abstract;
67 function IsOpen: Boolean; virtual; abstract;
68 function ToArray: TBytes; virtual; abstract;
Jens Geyera019cda2019-11-09 23:24:52 +010069 function Size : Int64; virtual;
70 function Position : Int64; virtual;
Jens Geyerd5436f52014-10-03 19:50:38 +020071 end;
72
Jens Geyera019cda2019-11-09 23:24:52 +010073 TThriftStreamAdapterDelphi = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +010074 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +020075 FStream : TStream;
76 FOwnsStream : Boolean;
Jens Geyerfad7fd32019-11-09 23:24:52 +010077 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010078 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020079 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
80 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +020081 procedure Open; override;
82 procedure Close; override;
83 procedure Flush; override;
84 function IsOpen: Boolean; override;
85 function ToArray: TBytes; override;
Jens Geyera019cda2019-11-09 23:24:52 +010086 function Size : Int64; override;
87 function Position : Int64; override;
Jens Geyerd5436f52014-10-03 19:50:38 +020088 public
Jens Geyer41f47af2019-11-09 23:24:52 +010089 constructor Create( const aStream: TStream; aOwnsStream : Boolean);
Jens Geyerd5436f52014-10-03 19:50:38 +020090 destructor Destroy; override;
91 end;
92
Jens Geyera019cda2019-11-09 23:24:52 +010093 TThriftStreamAdapterCOM = class( TThriftStreamImpl)
Jens Geyerfad7fd32019-11-09 23:24:52 +010094 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +020095 FStream : IStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +010096 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010097 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020098 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
99 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200100 procedure Open; override;
101 procedure Close; override;
102 procedure Flush; override;
103 function IsOpen: Boolean; override;
104 function ToArray: TBytes; override;
Jens Geyera019cda2019-11-09 23:24:52 +0100105 function Size : Int64; override;
106 function Position : Int64; override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200107 public
Jens Geyer41f47af2019-11-09 23:24:52 +0100108 constructor Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200109 end;
110
Jens Geyerf726ae32021-06-04 11:17:26 +0200111
112 TThriftMemoryStream = class(TMemoryStream)
113 strict protected
114 FInitialCapacity : NativeInt;
115 public
116 constructor Create( const aInitialCapacity : NativeInt = 4096);
117
118 // reimplemented
119 procedure Clear;
120
121 // make it publicly visible
122 property Capacity;
123 end;
124
125
126
Jens Geyerd5436f52014-10-03 19:50:38 +0200127implementation
128
Jens Geyer41f47af2019-11-09 23:24:52 +0100129uses Thrift.Transport;
130
Jens Geyerf726ae32021-06-04 11:17:26 +0200131
132{ TThriftMemoryStream }
133
134constructor TThriftMemoryStream.Create( const aInitialCapacity : NativeInt);
135begin
136 inherited Create;
137 FInitialCapacity := aInitialCapacity;
138 Clear;
139end;
140
141
142procedure TThriftMemoryStream.Clear;
143// reimplemented to keep initial capacity
144begin
145 Position := 0;
146 Size := 0;
147
148 // primary goal: minimize costly reallocations (performance!)
149 // secondary goal: prevent costly ressource over-allocations
150 if (FInitialCapacity >= 1024*1024) // if we are talking about MB
151 or ((Capacity div 2) > FInitialCapacity) // or the allocated buffer is really large
152 or (Capacity < FInitialCapacity) // or we are actually below the limit
153 then Capacity := FInitialCapacity;
154end;
155
156
Jens Geyerd5436f52014-10-03 19:50:38 +0200157{ TThriftStreamAdapterCOM }
158
159procedure TThriftStreamAdapterCOM.Close;
160begin
161 FStream := nil;
162end;
163
Jens Geyer41f47af2019-11-09 23:24:52 +0100164constructor TThriftStreamAdapterCOM.Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200165begin
166 inherited Create;
Jens Geyer41f47af2019-11-09 23:24:52 +0100167 FStream := aStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200168end;
169
170procedure TThriftStreamAdapterCOM.Flush;
171begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200172 if IsOpen then begin
173 if FStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200174 FStream.Commit( STGC_DEFAULT );
175 end;
176 end;
177end;
178
Jens Geyer41f47af2019-11-09 23:24:52 +0100179function TThriftStreamAdapterCOM.Size : Int64;
180var statstg: TStatStg;
181begin
182 FillChar( statstg, SizeOf( statstg), 0);
183 if IsOpen
184 and Succeeded( FStream.Stat( statstg, STATFLAG_NONAME ))
185 then result := statstg.cbSize
186 else result := 0;
187end;
188
189function TThriftStreamAdapterCOM.Position : Int64;
190var newpos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
191begin
192 if SUCCEEDED( FStream.Seek( 0, STREAM_SEEK_CUR, newpos))
193 then result := Int64(newpos)
194 else raise TTransportExceptionEndOfFile.Create('Seek() error');
195end;
196
Jens Geyerd5436f52014-10-03 19:50:38 +0200197function TThriftStreamAdapterCOM.IsOpen: Boolean;
198begin
199 Result := FStream <> nil;
200end;
201
202procedure TThriftStreamAdapterCOM.Open;
203begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200204 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200205end;
206
Jens Geyer17c3ad92017-09-05 20:31:27 +0200207function TThriftStreamAdapterCOM.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100208var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200209begin
210 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200211
212 if count >= buflen-offset
213 then count := buflen-offset;
214
Jens Geyerd5436f52014-10-03 19:50:38 +0200215 Result := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200216 if FStream <> nil then begin
217 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100218 pTmp := pBuf;
219 Inc( pTmp, offset);
220 FStream.Read( pTmp, count, @Result);
Jens Geyerd5436f52014-10-03 19:50:38 +0200221 end;
222 end;
223end;
224
225function TThriftStreamAdapterCOM.ToArray: TBytes;
226var
Jens Geyer41f47af2019-11-09 23:24:52 +0100227 len : Int64;
Nick4f5229e2016-04-14 16:43:22 +0300228 NewPos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
Jens Geyerd5436f52014-10-03 19:50:38 +0200229 cbRead : Integer;
230begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100231 len := Self.Size;
Jens Geyerd5436f52014-10-03 19:50:38 +0200232 SetLength( Result, len );
233
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200234 if len > 0 then begin
235 if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200236 FStream.Read( @Result[0], len, @cbRead);
237 end;
238 end;
239end;
240
Jens Geyer17c3ad92017-09-05 20:31:27 +0200241procedure TThriftStreamAdapterCOM.Write( const pBuf: Pointer; offset: Integer; count: Integer);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200242var nWritten : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100243 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200244begin
245 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200246 if IsOpen then begin
247 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100248 pTmp := pBuf;
249 Inc( pTmp, offset);
250 FStream.Write( pTmp, count, @nWritten);
Jens Geyerd5436f52014-10-03 19:50:38 +0200251 end;
252 end;
253end;
254
255{ TThriftStreamImpl }
256
Jens Geyer17c3ad92017-09-05 20:31:27 +0200257procedure TThriftStreamImpl.CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200258begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200259 if count > 0 then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200260 if (offset < 0) or ( offset >= buflen) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200261 raise ERangeError.Create( SBitsIndexError );
262 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200263 if count > buflen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200264 raise ERangeError.Create( SBitsIndexError );
265 end;
266 end;
267end;
268
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200269function TThriftStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200270begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200271 if Length(buffer) > 0
272 then Result := Read( @buffer[0], Length(buffer), offset, count)
273 else Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200274end;
275
276function TThriftStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
277begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200278 Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200279 CheckSizeAndOffset( pBuf, buflen, offset, count );
Jens Geyerd5436f52014-10-03 19:50:38 +0200280end;
281
282procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);
283begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200284 if Length(buffer) > 0
285 then Write( @buffer[0], offset, count);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200286end;
287
288procedure TThriftStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
289begin
290 CheckSizeAndOffset( pBuf, offset+count, offset, count);
Jens Geyerd5436f52014-10-03 19:50:38 +0200291end;
292
Jens Geyera019cda2019-11-09 23:24:52 +0100293function TThriftStreamImpl.Size : Int64;
294begin
295 ASSERT(FALSE);
296 raise ENotImplemented.Create(ClassName+'.Size');
297end;
298
299function TThriftStreamImpl.Position : Int64;
300begin
301 ASSERT(FALSE);
302 raise ENotImplemented.Create(ClassName+'.Position');
303end;
304
305
Jens Geyerd5436f52014-10-03 19:50:38 +0200306{ TThriftStreamAdapterDelphi }
307
Jens Geyer41f47af2019-11-09 23:24:52 +0100308constructor TThriftStreamAdapterDelphi.Create( const aStream: TStream; aOwnsStream: Boolean);
309begin
310 inherited Create;
311 FStream := aStream;
312 FOwnsStream := aOwnsStream;
313end;
314
315destructor TThriftStreamAdapterDelphi.Destroy;
316begin
317 if FOwnsStream
318 then Close;
319
320 inherited;
321end;
322
Jens Geyerd5436f52014-10-03 19:50:38 +0200323procedure TThriftStreamAdapterDelphi.Close;
324begin
325 FStream.Free;
326 FStream := nil;
327 FOwnsStream := False;
328end;
329
Jens Geyerd5436f52014-10-03 19:50:38 +0200330procedure TThriftStreamAdapterDelphi.Flush;
331begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200332 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200333end;
334
Jens Geyer41f47af2019-11-09 23:24:52 +0100335function TThriftStreamAdapterDelphi.Size : Int64;
336begin
337 result := FStream.Size;
338end;
339
340function TThriftStreamAdapterDelphi.Position : Int64;
341begin
342 result := FStream.Position;
343end;
344
Jens Geyerd5436f52014-10-03 19:50:38 +0200345function TThriftStreamAdapterDelphi.IsOpen: Boolean;
346begin
347 Result := FStream <> nil;
348end;
349
350procedure TThriftStreamAdapterDelphi.Open;
351begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200352 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200353end;
354
Jens Geyer17c3ad92017-09-05 20:31:27 +0200355function TThriftStreamAdapterDelphi.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100356var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200357begin
358 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200359
360 if count >= buflen-offset
361 then count := buflen-offset;
362
Jens Geyer5089b0a2018-02-01 22:37:18 +0100363 if count > 0 then begin
364 pTmp := pBuf;
365 Inc( pTmp, offset);
366 Result := FStream.Read( pTmp^, count)
367 end
Jens Geyer17c3ad92017-09-05 20:31:27 +0200368 else Result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200369end;
370
371function TThriftStreamAdapterDelphi.ToArray: TBytes;
372var
373 OrgPos : Integer;
374 len : Integer;
375begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100376 if FStream <> nil
377 then len := FStream.Size
378 else len := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200379
380 SetLength( Result, len );
381
382 if len > 0 then
383 begin
384 OrgPos := FStream.Position;
385 try
386 FStream.Position := 0;
387 FStream.ReadBuffer( Pointer(@Result[0])^, len );
388 finally
389 FStream.Position := OrgPos;
390 end;
391 end
392end;
393
Jens Geyer17c3ad92017-09-05 20:31:27 +0200394procedure TThriftStreamAdapterDelphi.Write(const pBuf : Pointer; offset, count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +0100395var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200396begin
397 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200398 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100399 pTmp := pBuf;
400 Inc( pTmp, offset);
401 FStream.Write( pTmp^, count)
Jens Geyerd5436f52014-10-03 19:50:38 +0200402 end;
403end;
404
405end.