Sometimes stream data requires conversion before an application can use it: you might have a stream over a file of EBCDIC characters which you would prefer to handle as their ASCII equivalents, or you might need to encrypt or decrypt file data.
Wrapper streams provide a mechanism for working with streams which require such conversion. Wrapper streams hold on to an underlying stream, delegating to it most streams operations. The wrapper stream carries out appropriate processing in its own implementations of the streaming protocol.
The Streams module includes a base class called <wrapper-stream> upon which other wrapping streams can be implemented.
A subclass of <wrapper-stream> can "pass on" functions such as read-element and write-element by simply delegating these operations to the inner stream, as shown below:
define method read-element (ws :: <io-wrapper-stream>,
#key on-end-of-stream)
=> (element)
read-element(ws.inner-stream,
on-end-of-stream: on-end-of-stream)
end method;
define method write-element (ws :: <io-wrapper-stream>, element)
=> ()
write-element(ws.inner-stream, element)
end method;
Assuming that <io-wrapper-stream> delegates all other operations to its inner stream, the following would suffice to implement a 16-bit Unicode character stream wrapping an 8-bit character stream.
define class <unicode-stream> (<io-wrapper-stream>) end class;
define method read-element (s :: <unicode-stream>,
#key on-end-of-stream)
=> (ch :: <unicode-character>)
with-stream-locked (s)
let first-char = read-element(s.inner-stream,
on-end-of-stream);
let second-char = read-element(s.inner-stream,
on-end-of-stream)
end;
convert-byte-pair-to-unicode(first-char, second-char)
end method;
define method write-element (s :: <unicode-stream>,
c :: <character>)
=> ()
let (first-char, second-char) =
convert-unicode-to-byte-pair(c);
with-stream-locked (s)
write-element(s.inner-stream, first-char);
write-element(s.inner-stream, second-char)
end;
c
end method;
define method stream-position (s :: <unicode-stream>)
=> p :: <integer>;
truncate/(stream-position(s.inner-stream), 2)
end method;
define method stream-position-setter (p :: <integer>,
s :: <unicode-stream>);
stream-position(s.inner-stream) := p * 2
end method;