Skip to content

Commit 050adee

Browse files
committed
Add Streams.Wrapper unit & tests to DUnitX tests
1 parent 3656a90 commit 050adee

File tree

4 files changed

+732
-1
lines changed

4 files changed

+732
-1
lines changed

cupola/src/CSLE.Streams.Wrapper.pas

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
{
2+
This Source Code Form is subject to the terms of the Mozilla Public License,
3+
v. 2.0. If a copy of the MPL was not distributed with this file, You can
4+
obtain one at http://mozilla.org/MPL/2.0/
5+
6+
Copyright (C) 2000-2024, Peter Johnson (http://delphidabbler.com).
7+
8+
Defines the TStreamWrapper class. This is a base class for descendant classes
9+
that "wrap" a TStream class to provide some form of filter or additional
10+
functionality. The wrapped TStream is used to do physical i/o. TStreamWrapper
11+
simply replicates the facilities in the wrapped stream - it is for descendant
12+
classes to add functionality.
13+
14+
NOTE:
15+
This unit based on original code from https://github.com/ddablib/streams
16+
}
17+
18+
unit CSLE.Streams.Wrapper;
19+
20+
interface
21+
22+
uses
23+
// Delphi
24+
System.SysUtils,
25+
System.Classes;
26+
27+
type
28+
/// <summary>Base class for descendant classes that "wrap" a TStream class to
29+
/// provide some form of filter or additional functionality. The wrapped
30+
/// TStream is used to do physical i/o. This base class simply replicates the
31+
/// facilities in the wrapped stream - it is for descendant classes to add
32+
/// functionality.</summary>
33+
/// <remarks>Wrapping a TStream rather than adding functionality by extending
34+
/// the class means that the functionality provided by the wrapper class can
35+
/// be applied to any TStream descendant.</remarks>
36+
TStreamWrapper = class(TStream)
37+
strict private
38+
var
39+
/// <summary>Reference to wrapped stream.</summary>
40+
fBaseStream: TStream;
41+
/// <summary>Records whether wrapped stream is to be freed when this
42+
/// object is destroyed.</summary>
43+
fCloseStream: Boolean;
44+
strict protected
45+
46+
/// <summary>Sets the size of the wrapped stream.</summary>
47+
/// <param name="NewSize">[in] New size of stream.</param>
48+
/// <remarks>
49+
/// <para>If the wrapped stream does not support the <c>SetSize</c>
50+
/// operation then the stream's size is not changed.</para>
51+
/// <para>See also the overloaded version that takes a 64 bit size.</para>
52+
/// </remarks>
53+
procedure SetSize(NewSize: Int32); override; deprecated;
54+
55+
/// <summary>Sets the size of the wrapped stream.</summary>
56+
/// <param name="NewSize">[in] New size of stream.</param>
57+
/// <remarks>
58+
/// <para>If the wrapped stream does not support the <c>SetSize</c>
59+
/// operation then the stream's size is not changed.</para>
60+
/// <para>If the wrapped stream does not support 64 bit <c>SetSize</c> then
61+
/// <c>NewSize</c> is truncated to 32 bits.</para>
62+
/// <para>See also the overloaded version that takes a 32 bit size.</para>
63+
/// </remarks>
64+
procedure SetSize(const NewSize: Int64); override;
65+
66+
public
67+
68+
/// <summary>Object constructor. Creates a <c>TStream</c> descendant object
69+
/// that wraps another stream and optionally takes ownership of it.
70+
/// </summary>
71+
/// <param name="Stream">[in] Stream to be wrapped.</param>
72+
/// <param name="CloseStream">[in] Flag that indicates whether
73+
/// <c>Stream</c> is to be freed when this object is be destroyed
74+
/// (<c>True</c>) or whether caller retains responsibility for freeing
75+
/// <c>Stream</c> (<c>False</c>).</param>
76+
constructor Create(const Stream: TStream;
77+
const CloseStream: Boolean = False); virtual;
78+
79+
/// <summary>Tears down object. Frees wrapped stream iff <c>CloseStream</c>
80+
/// parameter of constructor was <c>True</c></summary>
81+
destructor Destroy; override;
82+
83+
/// <summary>Reads data from wrapped stream into a buffer.</summary>
84+
/// <param name="Buffer">[in/out] Buffer that receives data read from
85+
/// stream. Must have size of at least <c>Count</c> bytes.</param>
86+
/// <param name="Count">[in] Number of bytes to be read.</param>
87+
/// <returns>Number of bytes actually read.</returns>
88+
/// <remarks>If return value is less than <c>Count</c> then end of stream
89+
/// has been reached.</remarks>
90+
function Read(var Buffer; Count: Int32): Int32; override;
91+
92+
/// <summary>Reads data from wrapped stream into a byte array.</summary>
93+
/// <param name="Buffer">[in] Array of bytes that receives data read from
94+
/// stream. Must have size of at least <c>Count</c> elements.</param>
95+
/// <param name="Count">[in] Number of bytes to be read.</param>
96+
/// <returns>Number of bytes actually read.</returns>
97+
/// <remarks>If return value is less than <c>Count</c> then end of stream
98+
/// has been reached.</remarks>
99+
function Read64(Buffer: TBytes; Offset, Count: Int64): Int64; override;
100+
101+
/// <summary>Writes data from a buffer to wrapped stream.</summary>
102+
/// <param name="Buffer">[in] Buffer containg date to be written. Must
103+
/// contain at least <c>Count</c> bytes of data.</param>
104+
/// <param name="Count">[in] Number of bytes of data to be written.</param>
105+
/// <returns>Number of bytes actually written.</returns>
106+
/// <remarks>If the return value is less than <c>Count</c> then the stream
107+
/// is full and not all the data could be written.</remarks>
108+
function Write(const Buffer; Count: Int32): Int32; override;
109+
110+
/// <summary>Writes data from a byte array to wrapped stream.</summary>
111+
/// <param name="Buffer">[in] Array of bytes containing data to be written.
112+
/// Must have at least <c>Count</c> bytes elements.</param>
113+
/// <param name="Count">[in] Number of bytes of data to be written.</param>
114+
/// <returns>Number of bytes actually written.</returns>
115+
/// <remarks>If the return value is less than <c>Count</c> then the stream
116+
/// is full and not all the data could be written.</remarks>
117+
function Write64(const Buffer: TBytes; Offset, Count: Int64): Int64;
118+
override;
119+
120+
/// <summary>Sets the underlying stream's position.</summary>
121+
/// <param name="Offset">[in] New stream position relative to position
122+
/// defined by <c>Offset</c>.</param>
123+
/// <param name="Origin">[in] Specifies origin that <c>Offset</c> relates
124+
/// to. For details of values see documentation of <c>TStream.Seek</c>.
125+
/// </param>
126+
/// <returns>New stream position (value of <c>Position</c> property).
127+
/// </returns>
128+
/// <remarks>
129+
/// <para>If the wrapped stream does not support changing the stream
130+
/// position an exception will be raised.</para>
131+
/// <para>See also the overloaded version that takes a 64 bit size.</para>
132+
/// </remarks>
133+
function Seek(Offset: Int32; Origin: UInt16): Int32; override;
134+
135+
/// <summary>Sets the underlying stream's position.</summary>
136+
/// <param name="Offset">[in] New stream position relative to position
137+
/// defined by <c>Offset</c>.</param>
138+
/// <param name="Origin">[in] Specifies origin that <c>Offset</c> relates
139+
/// to. For details of values see documentation of <c>TSeekOrigin</c>.
140+
/// </param>
141+
/// <returns>New stream position (value of <c>Position</c> property).
142+
/// </returns>
143+
/// <remarks>
144+
/// <para>If the wrapped stream does not support changing the stream
145+
/// position an exception will be raised.</para>
146+
/// <para>If the wrapped stream does not support 64 bit <c>Seek</c> then
147+
/// the 32 bit version will be called instead and <c>Offset</c> may be
148+
/// truncated.</para>
149+
/// <para>See also the overloaded version that takes a 32 bit size.</para>
150+
/// </remarks>
151+
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
152+
153+
/// <summary>Reference to the wrapped stream object.</summary>
154+
/// <remarks>Enables caller and sub-classes to access the wrapped stream.
155+
/// </remarks>
156+
property BaseStream: TStream read fBaseStream;
157+
end;
158+
159+
implementation
160+
161+
{ TStreamWrapper }
162+
163+
constructor TStreamWrapper.Create(const Stream: TStream;
164+
const CloseStream: Boolean);
165+
begin
166+
inherited Create;
167+
fBaseStream := Stream;
168+
fCloseStream := CloseStream;
169+
end;
170+
171+
destructor TStreamWrapper.Destroy;
172+
begin
173+
if fCloseStream then
174+
fBaseStream.Free;
175+
inherited Destroy;
176+
end;
177+
178+
function TStreamWrapper.Read(var Buffer; Count: Int32): Int32;
179+
begin
180+
Result := fBaseStream.Read(Buffer, Count);
181+
end;
182+
183+
function TStreamWrapper.Read64(Buffer: TBytes; Offset, Count: Int64): Int64;
184+
begin
185+
Result := fBaseStream.Read64(Buffer, Offset, Count);
186+
end;
187+
188+
function TStreamWrapper.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
189+
begin
190+
Result := fBaseStream.Seek(Offset, Origin);
191+
end;
192+
193+
function TStreamWrapper.Seek(Offset: Int32; Origin: UInt16): Int32;
194+
begin
195+
Result := fBaseStream.Seek(Offset, Origin);
196+
end;
197+
198+
procedure TStreamWrapper.SetSize(const NewSize: Int64);
199+
begin
200+
fBaseStream.Size := NewSize;
201+
end;
202+
203+
procedure TStreamWrapper.SetSize(NewSize: Int32);
204+
begin
205+
// according to comments in TStream.SetSize if we implement 64 bit version of
206+
// SetSize, our 32 bit implementation must call it
207+
SetSize(Int64(NewSize));
208+
end;
209+
210+
function TStreamWrapper.Write(const Buffer; Count: Int32): Int32;
211+
begin
212+
Result := fBaseStream.Write(Buffer, Count);
213+
end;
214+
215+
function TStreamWrapper.Write64(const Buffer: TBytes; Offset,
216+
Count: Int64): Int64;
217+
begin
218+
Result := fBaseStream.Write64(Buffer, Offset, Count);
219+
end;
220+
221+
end.
222+

cupola/tests/CodeSnip.Cupola.Tests.dpr

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ uses
1818
Test.Utils.Dates in 'Test.Utils.Dates.pas',
1919
CSLE.Utils.Dates in '..\src\CSLE.Utils.Dates.pas',
2020
Test.TextData in 'Test.TextData.pas',
21-
CSLE.TextData in '..\src\CSLE.TextData.pas';
21+
CSLE.TextData in '..\src\CSLE.TextData.pas',
22+
CSLE.Streams.Wrapper in '..\src\CSLE.Streams.Wrapper.pas',
23+
Test.Streams.Wrapper in 'Test.Streams.Wrapper.pas';
2224

2325
{$IFNDEF TESTINSIGHT}
2426
var

cupola/tests/CodeSnip.Cupola.Tests.dproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
<DCCReference Include="..\src\CSLE.Utils.Dates.pas"/>
7676
<DCCReference Include="Test.TextData.pas"/>
7777
<DCCReference Include="..\src\CSLE.TextData.pas"/>
78+
<DCCReference Include="..\src\CSLE.Streams.Wrapper.pas"/>
79+
<DCCReference Include="Test.Streams.Wrapper.pas"/>
7880
<BuildConfiguration Include="Base">
7981
<Key>Base</Key>
8082
</BuildConfiguration>

0 commit comments

Comments
 (0)