Advanced Tools Module User’s Guide : PART II Advanced Tools Module Packages : Chapter 4 Using Streams : Examples : Creating and Using Chains of Streaming Elements
Creating and Using Chains of Streaming Elements
A chain of streaming elements is the composition of a single terminal streaming element with one or more filtered stream elements. The terminal streaming element is constructed first and then passed to a filtered stream constructor, which in turn can be passed to another filtered stream constructor. Each streaming element is responsible for a particular task and is independent of the task performed by other streaming elements. The filtered stream elements are not aware of the real type of the streaming element that is used internally. They are linked to it by a handle instance.
Output Example
The first example shows how to create and use a chain of streaming elements. It creates a Unicode character output stream that encodes UTF-16 characters using the UCS Transformation Format 8-bit form (UTF-8). The UTF-8 Unicode stream is connected to a buffered binary output stream that sends the transformed bytes to a file:
The class RWUCharToUTF8ByteOutputStreamImp converts the UTF-16 characters to the UCS Transformation Format 8-bit form (UTF-8).
The class RWBufferedByteOutputStreamImp is connected to class RWByteToStreambufOutputStreamImp to provide the buffered byte output stream.
Figure 13 is a representation of the chain of streaming elements used in this example.
Figure 13 – Streaming elements—output stream
The complete example is located in directory ...\examples\stream in the file UnicodeCharacterFilteredWrite.cpp. Only part of the code is presented below.
 
RWUChar array[17]= {0x0F00, 0x0F13, 0x0F0A, 0x0F3B, 0x0F8A, 0x0F68,
0x0F35, 0x0F61, 0x0F43, 0x0F39, 0x0F7F, 0x0F1E,
0x0F86, 0x0FA4, 0x0F91, 0x0F88, 0x0F0F}; // 1
 
// initialize the array of UTF-16 character
 
filebuf fbuf; // 2
fbuf.open("UnicodeCharacterFilteredWrite.dat", ios::out |
ios::binary);
 
RWByteOutputStream binOutputStream =
RWByteToStreambufOutputStreamImp::make(fbuf); // 3
 
RWByteOutputStream bufferedBinOutputStream=
RWBufferedByteOutputStreamImp::make(binOutputStream,1024); // 4
 
RWUCharOutputStream UTF8OutputStream=
RWUCharToUTF8ByteOutputStreamImp::make(bufferedBinOutputStream);// 5
 
try {
RWSize i;
for(i=0; i<17; i++)
UTF8OutputStream << array[i]; // 6
 
for(i=0; i<17; i++)
UTF8OutputStream.write(array[i]); // 7
 
UTF8OutputStream.write(array,17); // 8
}
catch(const RWIncompleteStreamOperation& e) { // 9
cout << e.why() << endl;
cout << e.elementsProcessed() << endl;
}
catch(const RWExternalStreamException& e) {
cout << e.why() << endl;
}
//1 Stores UTF-16 characters using type RWUChar, which is a typedef for unsigned short. In this example, 17 UTF-16 characters, which are part of the Tibetan Unicode character set, are stored.
//2 Creates an iostreams file buffer, and opens it in output mode. If the code is compiled on a PC platform, the file buffer needs to be opened in binary mode by specifying the flag ios::binary. If you built the Advanced Tools Module with the Standard iostreams library, you need to qualify filebuf and other iostreams elements with std::, or you need to include using declarations. The complete example code makes use of macros defined by the Essential Tools Module in order to support both the classic and Standard iostreams.
//3 Creates a concrete instance of class RWByteToStreambufOutputStreamImp. The class is created by calling its static member function make(), which creates an instance of self and returns it as a binary output stream handle. In this example, the make() function takes a reference to an iostreams streambuf object that is used as the sink of bytes.
//4 Creates a concrete instance of class RWBufferedByteOutputStreamImp. The class is created by calling one of its static member functions make(), which creates an instance of self and returns it as a binary output stream handle. Several static make() functions are available to construct an instance of class RWBufferedByteOutputStreamImp. All take a handle to the next streaming element, which must be of type RWByteOutputStream. The static make() function in this example takes a second parameter that specifies the size of the buffer to be allocated.
//5 Creates a concrete instance of class RWUCharToUTF8ByteOutputStreamImp. The class is created by calling its static member function make(), which creates an instance of self and returns it as a UTF-16 output stream handle. The make() function takes a handle to the next streaming element, which must be of type RWByteOutputStream. It is used as a sink for the bytes generated when converting UTF-16 characters to the UTF-8 form.
//6 Inserts single UTF-16 characters into the stream. Insertion operations can be cascaded as in the following example which inserts the array’s first three UTF-16 characters into the stream, and then the manipulator rwFlush triggers the stream flushing.
 
UTF8OutputStream << array[0] << array[1] << array[2] << rwFlush;
//7 Inserts single UTF-16 characters into the stream.
//8 Inserts an array of UTF-16 characters into the stream.
//9 Catches exceptions potentially thrown by the stream. The Streams package defines two exception classes: RWExternalStreamException and RWIncompleteStreamOperation.
Class RWExternalStreamException returns an error message and an error code. Class RWIncompleteStreamOperation inherits from class RWExternalStreamException and is thrown when an operation partially succeeds. In the above example, writing an array of UTF-16 characters might fail after writing some of the characters. An instance of class RWIncompleteStreamOperation can be queried for the number of elements successfully written. For more information on exceptions, see “Error Handling.”
Input Example
The next example implements the previous example’s corresponding input operation. It creates a UTF-16 character input stream that decodes UTF-16 characters using the UTF-8 form. The UTF-8 Unicode stream is connected to a buffered binary input stream that gets bytes from the file created in the previous example. The class RWUCharFromUTF8ByteInputStreamImp converts the bytes into UTF-16 characters. The class RWBufferedByteInputStreamImp is connected to class RWByteFromStreambufInputStreamImp to provide the buffered byte input stream.
Figure 14 is a representation of the chain of streaming elements used in this example.
Figure 14 – Streaming elements—input stream
The complete example is located in directory ...\examples\stream in the file UnicodeCharacterFilteredRead.cpp. Only part of the code is presented below.
 
filebuf fbuf; // 1
fbuf.open("UnicodeCharacterFilteredWrite.dat", ios::in |
ios::binary);
RWByteInputStream binInputStream =
RWByteFromStreambufInputStreamImp::make(fbuf); // 2
 
RWByteInputStream bufferedBinInputStream=
RWBufferedByteInputStreamImp::make(binInputStream,1024); // 3
 
RWUCharInputStream UTF8InputStream=
RWUCharFromUTF8ByteInputStreamImp::make(bufferedBinInputStream);// 4
 
try {
RWSize i;
RWUChar theUChar; // 5
 
for(i=0; i<17; i++) {
UTF8InputStream >> theUChar; // 6
// do something with the UTF-16 character read
}
 
for(i=0; i<17; i++) {
theUChar= UTF8InputStream.read(); // 7
// do something with the value read
}
 
RWUChar array[17];
RWSize read_= UTF8InputStream.read(array,17); // 8
cout << "The number of Unicode character(s) read is: "
<< read_ << endl;
// do something with the array of UTF-16 characters
 
RWUChar until_= 0x0F7F;
 
read_= UTF8InputStream.readUntil(array,17,until_); // 9
if(UTF8InputStream.isGood()) //10
cout << "The operation succeeded\n";
cout << "The number of Unicode character(s) stored is: "
<< read_ << endl;
// do something with the array of UTF-16 character(s)
 
if (UTF8InputStream.isGood()) //10
cout << "The stream is in a valid state" << endl;
else
cout << "The stream is in error state" << endl;
 
if(UTF8InputStream.isEof()) //11
cout << "There is no more data available for reading"
<< endl;
else {
while(!UTF8InputStream.isEof()) //11
theUChar= UTF8InputStream.read();
// do something with the UTF-16 Character
} //end else
} // end try
catch(const RWExternalStreamException& e) { //12
cout << e.why() << endl;
}
//1 Creates an iostreams file buffer, and opens it in input mode. If the code is compiled on a PC platform, the file buffer needs to be opened in binary mode by specifying the flag ios::binary. If you built the Advanced Tools Module with the Standard iostreams library, you need to qualify filebuf and other iostreams elements with std::, or you need to include using declarations. The complete code makes use of macros defined by the Essential Tools Module in order to support both the classic and Standard iostreams.
//2 Creates a concrete instance of class RWByteFromStreambufInputStreamImp. The class is created by calling its static member function make(), which creates an instance of self and returns it as a binary input stream handle. In this example the make() function takes a reference to an iostreams streambuf object that is used as the source of bytes.
//3 Creates a concrete instance of class RWBufferedByteInputStreamImp. The class is created by calling one of its static member functions make(), which creates an instance of self and returns it as a binary input stream handle. Several static make() functions are available to construct an instance of class RWBufferedByteInputStreamImp. All take a handle to the next streaming element, which must be of type RWByteInputStream. The static make() function used in this example takes a second parameter that specifies the size of the buffer to be allocated.
//4 Creates a concrete instance of class RWUCharFromUTF8ByteInputStreamImp. The class is created by calling its static member function make(), which creates an instance of self and returns it as a UTF-16 input stream handle. The make() function takes a handle to the next streaming element, which must be of type RWByteInputStream. It is used as the source of bytes.
//5 Declares a single UTF-16 character variable. RWUChar is a typedef for unsigned short and is used by the Streams package to represent UTF-16 characters.
//6 Extracts single UTF-16 characters from the stream. Extraction operations can be cascaded as in the following example which extracts three UTF-16 characters from the stream. If the stream cannot provide enough UTF-16 characters, then a RWExternalStreamException is thrown.
 
RWUChar value1, value2, value3;
UTF8InputStream >> value1 >> value2 >> value3;
//7 Extracts single UTF-16 characters from the stream.
//8 Reads an array of UTF-16 characters from the stream. The number of actual characters extracted is returned, and if this number differs from the number requested, then the input stream member function isFail() returns true.
//9 Read UTF-16 characters from the stream until a certain value is read or a maximum number of characters is read. If the UTF-16 character value requested is read, it is removed from the stream, but not inserted in the result array. The readUntil function returns the number of elements inserted in the result array. If the function fails to read the requested UTF-16 character value, then the input stream member function isFail() returns true.
//10 Checks the stream status.
//11 Checks for more UTF-16 characters in the stream.
//12 Catches exceptions potentially thrown by the stream. Class RWExternalStreamException is the base class for all exceptions thrown by the Streams package. It returns an error message and an error code. For more information on exceptions, see “Error Handling.”