1 (*
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 
20 unit Thrift.Stream;
21 
22 {$I Thrift.Defines.inc}
23 
24 interface
25 
26 uses
27   Classes,
28   SysUtils,
29   SysConst,
30   RTLConsts,
31   {$IFDEF OLD_UNIT_NAMES}
32   ActiveX,
33   {$ELSE}
34   Winapi.ActiveX,
35   {$ENDIF}
36   Thrift.Utils;
37 
38 type
39   IThriftStream = interface
40     ['{3A61A8A6-3639-4B91-A260-EFCA23944F3A}']
41     procedure Write( const buffer: TBytes; offset: Integer; count: Integer);  overload;
42     procedure Write( const pBuf : Pointer; offset: Integer; count: Integer);  overload;
Readnull43     function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer;  overload;
Readnull44     function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;  overload;
45     procedure Open;
46     procedure Close;
47     procedure Flush;
IsOpennull48     function IsOpen: Boolean;
ToArraynull49     function ToArray: TBytes;
Sizenull50     function Size : Int64;
Positionnull51     function Position : Int64;
52   end;
53 
54 
55   TThriftStreamImpl = class abstract( TInterfacedObject, IThriftStream)
56   strict private
57     procedure CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);  overload;
58   strict protected
59     // IThriftStream
60     procedure Write( const buffer: TBytes; offset: Integer; count: Integer); overload; inline;
61     procedure Write( const pBuf : Pointer; offset: Integer; count: Integer);  overload; virtual;
Readnull62     function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; overload; inline;
Readnull63     function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; overload; virtual;
64     procedure Open; virtual; abstract;
65     procedure Close; virtual; abstract;
66     procedure Flush; virtual; abstract;
IsOpennull67     function IsOpen: Boolean; virtual; abstract;
ToArraynull68     function ToArray: TBytes; virtual; abstract;
Sizenull69     function Size : Int64; virtual;
Positionnull70     function Position : Int64;  virtual;
71   end;
72 
73   TThriftStreamAdapterDelphi = class( TThriftStreamImpl)
74   strict private
75     FStream : TStream;
76     FOwnsStream : Boolean;
77   strict protected
78     // IThriftStream
79     procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
Readnull80     function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
81     procedure Open; override;
82     procedure Close; override;
83     procedure Flush; override;
IsOpennull84     function IsOpen: Boolean; override;
ToArraynull85     function ToArray: TBytes; override;
Sizenull86     function Size : Int64; override;
Positionnull87     function Position : Int64;  override;
88   public
89     constructor Create( const aStream: TStream; aOwnsStream : Boolean);
90     destructor Destroy; override;
91   end;
92 
93   TThriftStreamAdapterCOM = class( TThriftStreamImpl)
94   strict private
95     FStream : IStream;
96   strict protected
97     // IThriftStream
98     procedure Write( const pBuf : Pointer; offset: Integer; count: Integer); override;
Readnull99     function Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer; override;
100     procedure Open; override;
101     procedure Close; override;
102     procedure Flush; override;
IsOpennull103     function IsOpen: Boolean; override;
ToArraynull104     function ToArray: TBytes; override;
Sizenull105     function Size : Int64; override;
Positionnull106     function Position : Int64;  override;
107   public
108     constructor Create( const aStream: IStream);
109   end;
110 
111 implementation
112 
113 uses Thrift.Transport;
114 
115 { TThriftStreamAdapterCOM }
116 
117 procedure TThriftStreamAdapterCOM.Close;
118 begin
119   FStream := nil;
120 end;
121 
122 constructor TThriftStreamAdapterCOM.Create( const aStream: IStream);
123 begin
124   inherited Create;
125   FStream := aStream;
126 end;
127 
128 procedure TThriftStreamAdapterCOM.Flush;
129 begin
130   if IsOpen then begin
131     if FStream <> nil then begin
132       FStream.Commit( STGC_DEFAULT );
133     end;
134   end;
135 end;
136 
Sizenull137 function TThriftStreamAdapterCOM.Size : Int64;
138 var statstg: TStatStg;
139 begin
140   FillChar( statstg, SizeOf( statstg), 0);
141   if  IsOpen
142   and Succeeded( FStream.Stat( statstg, STATFLAG_NONAME ))
143   then result := statstg.cbSize
144   else result := 0;
145 end;
146 
TThriftStreamAdapterCOM.Positionnull147 function TThriftStreamAdapterCOM.Position : Int64;
148 var newpos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64  {$IFEND};
149 begin
150   if SUCCEEDED( FStream.Seek( 0, STREAM_SEEK_CUR, newpos))
151   then result := Int64(newpos)
152   else raise TTransportExceptionEndOfFile.Create('Seek() error');
153 end;
154 
TThriftStreamAdapterCOM.IsOpennull155 function TThriftStreamAdapterCOM.IsOpen: Boolean;
156 begin
157   Result := FStream <> nil;
158 end;
159 
160 procedure TThriftStreamAdapterCOM.Open;
161 begin
162   // nothing to do
163 end;
164 
Readnull165 function TThriftStreamAdapterCOM.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
166 var pTmp : PByte;
167 begin
168   inherited;
169 
170   if count >= buflen-offset
171   then count := buflen-offset;
172 
173   Result := 0;
174   if FStream <> nil then begin
175     if count > 0 then begin
176       pTmp := pBuf;
177       Inc( pTmp, offset);
178       FStream.Read( pTmp, count, @Result);
179     end;
180   end;
181 end;
182 
ToArraynull183 function TThriftStreamAdapterCOM.ToArray: TBytes;
184 var
185   len : Int64;
186   NewPos : {$IF CompilerVersion >= 29.0} UInt64 {$ELSE} Int64  {$IFEND};
187   cbRead : Integer;
188 begin
189   len := Self.Size;
190   SetLength( Result, len );
191 
192   if len > 0 then begin
193     if Succeeded( FStream.Seek( 0, STREAM_SEEK_SET, NewPos) ) then begin
194       FStream.Read( @Result[0], len, @cbRead);
195     end;
196   end;
197 end;
198 
199 procedure TThriftStreamAdapterCOM.Write( const pBuf: Pointer; offset: Integer; count: Integer);
200 var nWritten : Integer;
201     pTmp : PByte;
202 begin
203   inherited;
204   if IsOpen then begin
205     if count > 0 then begin
206       pTmp := pBuf;
207       Inc( pTmp, offset);
208       FStream.Write( pTmp, count, @nWritten);
209     end;
210   end;
211 end;
212 
213 { TThriftStreamImpl }
214 
215 procedure TThriftStreamImpl.CheckSizeAndOffset( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer);
216 begin
217   if count > 0 then begin
218     if (offset < 0) or ( offset >= buflen) then begin
219       raise ERangeError.Create( SBitsIndexError );
220     end;
221     if count > buflen then begin
222       raise ERangeError.Create( SBitsIndexError );
223     end;
224   end;
225 end;
226 
Readnull227 function TThriftStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
228 begin
229   if Length(buffer) > 0
230   then Result := Read( @buffer[0], Length(buffer), offset, count)
231   else Result := 0;
232 end;
233 
Readnull234 function TThriftStreamImpl.Read( const pBuf : Pointer; const buflen : Integer; offset: Integer; count: Integer): Integer;
235 begin
236   Result := 0;
237   CheckSizeAndOffset( pBuf, buflen, offset, count );
238 end;
239 
240 procedure TThriftStreamImpl.Write(const buffer: TBytes; offset, count: Integer);
241 begin
242   if Length(buffer) > 0
243   then Write( @buffer[0], offset, count);
244 end;
245 
246 procedure TThriftStreamImpl.Write( const pBuf : Pointer; offset: Integer; count: Integer);
247 begin
248   CheckSizeAndOffset( pBuf, offset+count, offset, count);
249 end;
250 
Sizenull251 function TThriftStreamImpl.Size : Int64;
252 begin
253   ASSERT(FALSE);
254   raise ENotImplemented.Create(ClassName+'.Size');
255 end;
256 
Positionnull257 function TThriftStreamImpl.Position : Int64;
258 begin
259   ASSERT(FALSE);
260   raise ENotImplemented.Create(ClassName+'.Position');
261 end;
262 
263 
264 { TThriftStreamAdapterDelphi }
265 
266 constructor TThriftStreamAdapterDelphi.Create( const aStream: TStream; aOwnsStream: Boolean);
267 begin
268   inherited Create;
269   FStream := aStream;
270   FOwnsStream := aOwnsStream;
271 end;
272 
273 destructor TThriftStreamAdapterDelphi.Destroy;
274 begin
275   if FOwnsStream
276   then Close;
277 
278   inherited;
279 end;
280 
281 procedure TThriftStreamAdapterDelphi.Close;
282 begin
283   FStream.Free;
284   FStream := nil;
285   FOwnsStream := False;
286 end;
287 
288 procedure TThriftStreamAdapterDelphi.Flush;
289 begin
290   // nothing to do
291 end;
292 
Sizenull293 function TThriftStreamAdapterDelphi.Size : Int64;
294 begin
295   result := FStream.Size;
296 end;
297 
TThriftStreamAdapterDelphi.Positionnull298 function TThriftStreamAdapterDelphi.Position : Int64;
299 begin
300   result := FStream.Position;
301 end;
302 
TThriftStreamAdapterDelphi.IsOpennull303 function TThriftStreamAdapterDelphi.IsOpen: Boolean;
304 begin
305   Result := FStream <> nil;
306 end;
307 
308 procedure TThriftStreamAdapterDelphi.Open;
309 begin
310   // nothing to do
311 end;
312 
Readnull313 function TThriftStreamAdapterDelphi.Read(const pBuf : Pointer; const buflen : Integer; offset, count: Integer): Integer;
314 var pTmp : PByte;
315 begin
316   inherited;
317 
318   if count >= buflen-offset
319   then count := buflen-offset;
320 
321   if count > 0 then begin
322     pTmp := pBuf;
323     Inc( pTmp, offset);
324     Result := FStream.Read( pTmp^, count)
325   end
326   else Result := 0;
327 end;
328 
ToArraynull329 function TThriftStreamAdapterDelphi.ToArray: TBytes;
330 var
331   OrgPos : Integer;
332   len : Integer;
333 begin
334   if FStream <> nil
335   then len := FStream.Size
336   else len := 0;
337 
338   SetLength( Result, len );
339 
340   if len > 0 then
341   begin
342     OrgPos := FStream.Position;
343     try
344       FStream.Position := 0;
345       FStream.ReadBuffer( Pointer(@Result[0])^, len );
346     finally
347       FStream.Position := OrgPos;
348     end;
349   end
350 end;
351 
352 procedure TThriftStreamAdapterDelphi.Write(const pBuf : Pointer; offset, count: Integer);
353 var pTmp : PByte;
354 begin
355   inherited;
356   if count > 0 then begin
357     pTmp := pBuf;
358     Inc( pTmp, offset);
359     FStream.Write( pTmp^, count)
360   end;
361 end;
362 
363 end.
364