blob: 0f4e723e85b1483e0ce25b0c15162e061a5e0ff5 [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 Geyer41f47af2019-11-09 23:24:52 +010040 ['{DBE61E28-2A77-42DB-A5A3-3CCB8A2D09FA}']
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 Geyer41f47af2019-11-09 23:24:52 +010045 procedure CheckReadBytesAvailable( const value : Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +020046 procedure Open;
47 procedure Close;
48 procedure Flush;
49 function IsOpen: Boolean;
50 function ToArray: TBytes;
51 end;
52
Jens Geyer41f47af2019-11-09 23:24:52 +010053
54 IThriftStream2 = interface( IThriftStream)
55 ['{1F55D9FE-F617-4B80-B8CA-4A300D8E33F6}']
56 function Size : Int64;
57 function Position : Int64;
58 end;
59
60
61 TThriftStreamImpl = class abstract( TInterfacedObject, IThriftStream)
Jens Geyerfad7fd32019-11-09 23:24:52 +010062 strict private
Jens Geyer17c3ad92017-09-05 20:31:27 +020063 procedure CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer); overload;
Jens Geyerfad7fd32019-11-09 23:24:52 +010064 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010065 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020066 procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload; inline;
67 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); overload; virtual;
68 function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload; inline;
69 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload; virtual;
Jens Geyer41f47af2019-11-09 23:24:52 +010070 procedure CheckReadBytesAvailable( const value : Integer); virtual; abstract;
Jens Geyerd5436f52014-10-03 19:50:38 +020071 procedure Open; virtual; abstract;
72 procedure Close; virtual; abstract;
73 procedure Flush; virtual; abstract;
74 function IsOpen: Boolean; virtual; abstract;
75 function ToArray: TBytes; virtual; abstract;
76 end;
77
Jens Geyer41f47af2019-11-09 23:24:52 +010078 TThriftStreamAdapterDelphi = class( TThriftStreamImpl, IThriftStream2)
Jens Geyerfad7fd32019-11-09 23:24:52 +010079 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +020080 FStream : TStream;
81 FOwnsStream : Boolean;
Jens Geyerfad7fd32019-11-09 23:24:52 +010082 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +010083 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +020084 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
85 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyer41f47af2019-11-09 23:24:52 +010086 procedure CheckReadBytesAvailable( const value : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +020087 procedure Open; override;
88 procedure Close; override;
89 procedure Flush; override;
90 function IsOpen: Boolean; override;
91 function ToArray: TBytes; override;
Jens Geyer41f47af2019-11-09 23:24:52 +010092
93 // IThriftStream2
94 function Size : Int64;
95 function Position : Int64;
Jens Geyerd5436f52014-10-03 19:50:38 +020096 public
Jens Geyer41f47af2019-11-09 23:24:52 +010097 constructor Create( const aStream: TStream; aOwnsStream : Boolean);
Jens Geyerd5436f52014-10-03 19:50:38 +020098 destructor Destroy; override;
99 end;
100
Jens Geyer41f47af2019-11-09 23:24:52 +0100101 TThriftStreamAdapterCOM = class( TThriftStreamImpl, IThriftStream2)
Jens Geyerfad7fd32019-11-09 23:24:52 +0100102 strict private
Jens Geyerd5436f52014-10-03 19:50:38 +0200103 FStream : IStream;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100104 strict protected
Jens Geyer41f47af2019-11-09 23:24:52 +0100105 // IThriftStream
Jens Geyer17c3ad92017-09-05 20:31:27 +0200106 procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
107 function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
Jens Geyer41f47af2019-11-09 23:24:52 +0100108 procedure CheckReadBytesAvailable( const value : Integer); override;
Jens Geyerd5436f52014-10-03 19:50:38 +0200109 procedure Open; override;
110 procedure Close; override;
111 procedure Flush; override;
112 function IsOpen: Boolean; override;
113 function ToArray: TBytes; override;
Jens Geyer41f47af2019-11-09 23:24:52 +0100114
115 // IThriftStream2
116 function Size : Int64;
117 function Position : Int64;
Jens Geyerd5436f52014-10-03 19:50:38 +0200118 public
Jens Geyer41f47af2019-11-09 23:24:52 +0100119 constructor Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200120 end;
121
122implementation
123
Jens Geyer41f47af2019-11-09 23:24:52 +0100124uses Thrift.Transport;
125
Jens Geyerd5436f52014-10-03 19:50:38 +0200126{ TThriftStreamAdapterCOM }
127
128procedure TThriftStreamAdapterCOM.Close;
129begin
130 FStream := nil;
131end;
132
Jens Geyer41f47af2019-11-09 23:24:52 +0100133constructor TThriftStreamAdapterCOM.Create( const aStream: IStream);
Jens Geyerd5436f52014-10-03 19:50:38 +0200134begin
135 inherited Create;
Jens Geyer41f47af2019-11-09 23:24:52 +0100136 FStream := aStream;
Jens Geyerd5436f52014-10-03 19:50:38 +0200137end;
138
139procedure TThriftStreamAdapterCOM.Flush;
140begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200141 if IsOpen then begin
142 if FStream <> nil then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200143 FStream.Commit( STGC_DEFAULT );
144 end;
145 end;
146end;
147
Jens Geyer41f47af2019-11-09 23:24:52 +0100148function TThriftStreamAdapterCOM.Size : Int64;
149var statstg: TStatStg;
150begin
151 FillChar( statstg, SizeOf( statstg), 0);
152 if IsOpen
153 and Succeeded( FStream.Stat( statstg, STATFLAG_NONAME ))
154 then result := statstg.cbSize
155 else result := 0;
156end;
157
158function TThriftStreamAdapterCOM.Position : Int64;
159var newpos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
160begin
161 if SUCCEEDED( FStream.Seek( 0, STREAM_SEEK_CUR, newpos))
162 then result := Int64(newpos)
163 else raise TTransportExceptionEndOfFile.Create('Seek() error');
164end;
165
Jens Geyerd5436f52014-10-03 19:50:38 +0200166function TThriftStreamAdapterCOM.IsOpen: Boolean;
167begin
168 Result := FStream <> nil;
169end;
170
171procedure TThriftStreamAdapterCOM.Open;
172begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200173 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200174end;
175
Jens Geyer17c3ad92017-09-05 20:31:27 +0200176function TThriftStreamAdapterCOM.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100177var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200178begin
179 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200180
181 if count >= buflen-offset
182 then count := buflen-offset;
183
Jens Geyerd5436f52014-10-03 19:50:38 +0200184 Result := 0;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200185 if FStream <> nil then begin
186 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100187 pTmp := pBuf;
188 Inc( pTmp, offset);
189 FStream.Read( pTmp, count, @Result);
Jens Geyerd5436f52014-10-03 19:50:38 +0200190 end;
191 end;
192end;
193
Jens Geyer41f47af2019-11-09 23:24:52 +0100194procedure TThriftStreamAdapterCOM.CheckReadBytesAvailable( const value : Integer);
195var nRemaining : Int64;
196begin
197 nRemaining := Self.Size - Self.Position;
198 if nRemaining < value
199 then raise TTransportExceptionEndOfFile.Create('Not enough input data');
200end;
201
Jens Geyerd5436f52014-10-03 19:50:38 +0200202function TThriftStreamAdapterCOM.ToArray: TBytes;
203var
Jens Geyer41f47af2019-11-09 23:24:52 +0100204 len : Int64;
Nick4f5229e2016-04-14 16:43:22 +0300205 NewPos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64 {$IFEND};
Jens Geyerd5436f52014-10-03 19:50:38 +0200206 cbRead : Integer;
207begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100208 len := Self.Size;
Jens Geyerd5436f52014-10-03 19:50:38 +0200209 SetLength( Result, len );
210
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200211 if len > 0 then begin
212 if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200213 FStream.Read( @Result[0], len, @cbRead);
214 end;
215 end;
216end;
217
Jens Geyer17c3ad92017-09-05 20:31:27 +0200218procedure TThriftStreamAdapterCOM.Write( const pBuf: Pointer; offset: Integer; count: Integer);
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200219var nWritten : Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100220 pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200221begin
222 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200223 if IsOpen then begin
224 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100225 pTmp := pBuf;
226 Inc( pTmp, offset);
227 FStream.Write( pTmp, count, @nWritten);
Jens Geyerd5436f52014-10-03 19:50:38 +0200228 end;
229 end;
230end;
231
232{ TThriftStreamImpl }
233
Jens Geyer17c3ad92017-09-05 20:31:27 +0200234procedure TThriftStreamImpl.CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);
Jens Geyerd5436f52014-10-03 19:50:38 +0200235begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200236 if count > 0 then begin
Jens Geyer17c3ad92017-09-05 20:31:27 +0200237 if (offset < 0) or ( offset >= buflen) then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200238 raise ERangeError.Create( SBitsIndexError );
239 end;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200240 if count > buflen then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200241 raise ERangeError.Create( SBitsIndexError );
242 end;
243 end;
244end;
245
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200246function TThriftStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
Jens Geyerd5436f52014-10-03 19:50:38 +0200247begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200248 if Length(buffer) > 0
249 then Result := Read( @buffer[0], Length(buffer), offset, count)
250 else Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200251end;
252
253function TThriftStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
254begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200255 Result := 0;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200256 CheckSizeAndOffset( pBuf, buflen, offset, count );
Jens Geyerd5436f52014-10-03 19:50:38 +0200257end;
258
259procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);
260begin
Jens Geyera76e6c72017-09-08 21:03:30 +0200261 if Length(buffer) > 0
262 then Write( @buffer[0], offset, count);
Jens Geyer17c3ad92017-09-05 20:31:27 +0200263end;
264
265procedure TThriftStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
266begin
267 CheckSizeAndOffset( pBuf, offset+count, offset, count);
Jens Geyerd5436f52014-10-03 19:50:38 +0200268end;
269
270{ TThriftStreamAdapterDelphi }
271
Jens Geyer41f47af2019-11-09 23:24:52 +0100272constructor TThriftStreamAdapterDelphi.Create( const aStream: TStream; aOwnsStream: Boolean);
273begin
274 inherited Create;
275 FStream := aStream;
276 FOwnsStream := aOwnsStream;
277end;
278
279destructor TThriftStreamAdapterDelphi.Destroy;
280begin
281 if FOwnsStream
282 then Close;
283
284 inherited;
285end;
286
Jens Geyerd5436f52014-10-03 19:50:38 +0200287procedure TThriftStreamAdapterDelphi.Close;
288begin
289 FStream.Free;
290 FStream := nil;
291 FOwnsStream := False;
292end;
293
Jens Geyerd5436f52014-10-03 19:50:38 +0200294procedure TThriftStreamAdapterDelphi.Flush;
295begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200296 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200297end;
298
Jens Geyer41f47af2019-11-09 23:24:52 +0100299function TThriftStreamAdapterDelphi.Size : Int64;
300begin
301 result := FStream.Size;
302end;
303
304function TThriftStreamAdapterDelphi.Position : Int64;
305begin
306 result := FStream.Position;
307end;
308
Jens Geyerd5436f52014-10-03 19:50:38 +0200309function TThriftStreamAdapterDelphi.IsOpen: Boolean;
310begin
311 Result := FStream <> nil;
312end;
313
314procedure TThriftStreamAdapterDelphi.Open;
315begin
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200316 // nothing to do
Jens Geyerd5436f52014-10-03 19:50:38 +0200317end;
318
Jens Geyer17c3ad92017-09-05 20:31:27 +0200319function TThriftStreamAdapterDelphi.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
Jens Geyer5089b0a2018-02-01 22:37:18 +0100320var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200321begin
322 inherited;
Jens Geyer17c3ad92017-09-05 20:31:27 +0200323
324 if count >= buflen-offset
325 then count := buflen-offset;
326
Jens Geyer5089b0a2018-02-01 22:37:18 +0100327 if count > 0 then begin
328 pTmp := pBuf;
329 Inc( pTmp, offset);
330 Result := FStream.Read( pTmp^, count)
331 end
Jens Geyer17c3ad92017-09-05 20:31:27 +0200332 else Result := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200333end;
334
Jens Geyer41f47af2019-11-09 23:24:52 +0100335procedure TThriftStreamAdapterDelphi.CheckReadBytesAvailable( const value : Integer);
336var nRemaining : Int64;
337begin
338 nRemaining := FStream.Size - FStream.Position;
339 if nRemaining < value then raise TTransportExceptionEndOfFile.Create('Not enough input data');
340end;
341
Jens Geyerd5436f52014-10-03 19:50:38 +0200342function TThriftStreamAdapterDelphi.ToArray: TBytes;
343var
344 OrgPos : Integer;
345 len : Integer;
346begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100347 if FStream <> nil
348 then len := FStream.Size
349 else len := 0;
Jens Geyerd5436f52014-10-03 19:50:38 +0200350
351 SetLength( Result, len );
352
353 if len > 0 then
354 begin
355 OrgPos := FStream.Position;
356 try
357 FStream.Position := 0;
358 FStream.ReadBuffer( Pointer(@Result[0])^, len );
359 finally
360 FStream.Position := OrgPos;
361 end;
362 end
363end;
364
Jens Geyer17c3ad92017-09-05 20:31:27 +0200365procedure TThriftStreamAdapterDelphi.Write(const pBuf : Pointer; offset, count: Integer);
Jens Geyer5089b0a2018-02-01 22:37:18 +0100366var pTmp : PByte;
Jens Geyerd5436f52014-10-03 19:50:38 +0200367begin
368 inherited;
Jens Geyer9f7f11e2016-04-14 21:37:11 +0200369 if count > 0 then begin
Jens Geyer5089b0a2018-02-01 22:37:18 +0100370 pTmp := pBuf;
371 Inc( pTmp, offset);
372 FStream.Write( pTmp^, count)
Jens Geyerd5436f52014-10-03 19:50:38 +0200373 end;
374end;
375
376end.