c++-gtk-utils: gstreams

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

Classes | Typedefs
gstreams

#include <c++-gtk-utils/gstream.h> More...

## Classes
class | Cgu::basic_gstreambuf< charT, Traits >
| C++ stream buffer for GIO streams. More...
class | Cgu::basic_gostream< charT, Traits >
| C++ output stream for GIO streams. More...
class | Cgu::basic_gistream< charT, Traits >
| C++ input stream for GIO streams. More...
class | Cgu::basic_giostream< charT, Traits >
| C++ input-output stream for GIO streams. More...

## Typedefs
typedef basic_gstreambuf< char > | Cgu::gstreambuf
| C++ stream buffer for GIO streams for char type. More...
typedef basic_gistream< char > | Cgu::gistream
| C++ input stream for GIO streams for char type. More...
typedef basic_gostream< char > | Cgu::gostream
| C++ output stream for GIO streams for char type. More...
typedef basic_giostream< char > | Cgu::giostream
| C++ input/output stream for GIO streams for char type. More...
typedef basic_gstreambuf< wchar_t > | Cgu::wgstreambuf
| C++ stream buffer for GIO streams for wchar_t type. More...
typedef basic_gistream< wchar_t > | Cgu::wgistream
| C++ input stream for GIO streams for wchar_t type. More...
typedef basic_gostream< wchar_t > | Cgu::wgostream
| C++ output stream for GIO streams for wchar_t type. More...
typedef basic_giostream< wchar_t > | Cgu::wgiostream
| C++ input/output stream for GIO streams for wchar_t type. More...
typedef basic_gstreambuf< char16_t > | Cgu::u16gstreambuf
| C++ stream buffer for GIO streams for char16_t type. More...
typedef basic_gistream< char16_t > | Cgu::u16gistream
| C++ input stream for GIO streams for char16_t type. More...
typedef basic_gostream< char16_t > | Cgu::u16gostream
| C++ output stream for GIO streams for char16_t type. More...
typedef basic_giostream< char16_t > | Cgu::u16giostream
| C++ input/output stream for GIO streams for char16_t type. More...
typedef basic_gstreambuf< char32_t > | Cgu::u32gstreambuf
| C++ stream buffer for GIO streams for char32_t type. More...
typedef basic_gistream< char32_t > | Cgu::u32gistream
| C++ input stream for GIO streams for char32_t type. More...
typedef basic_gostream< char32_t > | Cgu::u32gostream
| C++ output stream for GIO streams for char32_t type. More...
typedef basic_giostream< char32_t > | Cgu::u32giostream
| C++ input/output stream for GIO streams for char32_t type. More...

## Detailed Description

#include <c++-gtk-utils/gstream.h>

The c++-gtk-utils library contains C++ classes providing a streambuffer and stream objects interfacing with GIO streams.

Normally 'true' would be passed as the second (manage) argument of the gostream/gistream/giostream constructors or of the attach() methods, so that the destructors of these classes close the GIO streams concerned, which helps exception safety (the attach() method will also close any previous GIO stream). If this behaviour is not wanted, pass 'false' instead to that argument. The same applies to the wide stream classes.

C++ stream objects are not suitable for asynchronous input and output. On sockets and pipes or other special devices, they may block on a read or write until the read or write request has been satisfied. In circumstances where asynchronous input and output is wanted, it will be necessary to start a new thread in which to carry out the input and output operations (which is what GIO does behind the scenes on its asynchronous operations) or use the GIO interfaces directly.

Here are some examples of use:

// open file for input, another for output, and make the
// output file a gzipped copy of the input (gzipping a
// file doesn't get much easier than this)
Cgu::gistream input;
Cgu::gostream output;
Cgu::GobjHandle<GFile> file_in(g_file_new_for_path("filename"));
GFileInputStream* is = g_file_read(file_in, 0, 0);
if (is)
input.attach(Cgu::GobjHandle<GInputStream>(G_INPUT_STREAM(is)), // takes ownership of 'is'
true);
else {
std::cerr << "Can't open file 'filename'" << std::endl;
return;
}
Cgu::GobjHandle<GFile> file_out(g_file_new_for_path("filename.gz"));
GFileOutputStream* os = g_file_replace(file_out, 0, false,
G_FILE_CREATE_REPLACE_DESTINATION,
0, 0);
if (os) {
output.attach(Cgu::GobjHandle<GOutputStream>(G_OUTPUT_STREAM(os)), // takes ownership of 'os'
true,
Cgu::GobjHandle<GConverter>(
G_CONVERTER(g_zlib_compressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1)))
);
}
else {
std::cerr << "Can't create file 'filename.gz'" << std::endl;
return;
}
// this does the copying, and is shorthand for creating your own buffer
// and calling std::istream::read() and std::ostream::write() on it
output << input.rdbuf();
--------------------------------------------------------------------
// establish a TCP socket on localhost, listen for connections on port
// 1200 and receive whitespace-separated words for processing
using Cgu::GobjHandle;
GobjHandle<GInetAddress> i(g_inet_address_new_loopback(G_SOCKET_FAMILY_IPV4));
GobjHandle<GSocketAddress> a(g_inet_socket_address_new(i, 1200));
GobjHandle<GSocketListener> l(g_socket_listener_new());
gboolean success = g_socket_listener_add_address(l,
a,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_TCP,
0, 0, 0);
if (!success) {
std::cerr << "Can't bind socket on localhost" << std::endl;
return;
}
GSocketConnection* c = g_socket_listener_accept(l, 0, 0, 0);
if (!c) {
std::cerr << "Can't listen on localhost" << std::endl;
return;
}
Cgu::giostream sock_strm(GobjHandle<GIOStream>(G_IO_STREAM(c)), true); // takes ownership of c
sock_strm.set_output_buffered(false);
std::cout << "Connection accepted" << std::endl;
std::string str;
while (sock_strm >> str) {
[ ... do something with the word in str ... ]
// acknowledge the client
sock_strm << "ACK\n";
}
--------------------------------------------------------------------
// read line delimited text from a pipe until it is closed by the
// writer: assume 'fd' is the read file descriptor of the pipe
// (in real life you would probably want to use a Cgu::fdistream
// object in this usage and bypass GIO)
Cgu::gistream istrm(Cgu::GobjHandle<GInputStream>(g_unix_input_stream_new(fd, true)), true);
if (!istrm.get_gio_stream().get()) {
std::cerr << "Can't create gio file-descriptor input stream" << std::endl;
return;
}
std::string line;
while (std::getline(istrm, line)) {
[ ... do something with the read text ... ]
}

Note
  1. Users cannot (except by derivation) use the virtual protected methods of the streambuffer classes, including xsgetn() and xsputn(). Instead, if they want direct access to the streambuffer other than through the gostream/gistream/giostream methods (or their wide stream equivalents), they should use the public forwarding functions provided by std::streambuf base class.
  2. These streambuffers and stream objects are not copiable.
  3. The base glib requirement for the c++-gtk-utils library is glib >= 2.10.0, but the gstreams component will only be available if glib >= 2.16.0 is installed.

## Buffering

The classes implement buffering on input streams and (unless output buffering is switched off) on output streams. They implement the buffering internally and do not use GBufferedInputStream and GBufferedOutputStream. This has a number of efficiency advantages and also retains random access, on devices that support it, for buffered streams (GBufferedInputStream and GBufferedOutputStream do not do so). So far as concerns random access on GIOStream objects, which are opened for both read and write, see giostream and random access

The streambuf class provides a block read and write in xsgetn() and xsputn(), which will be called by the read() and write() methods (and some other output operators) inherited by gistream, gostream and giostream (and their wide stream equivalents) from std::basic_istream and std::basic_ostream. They operate (after appropriately vacating and resetting the buffers) by doing a block read and write directly to and from the target, and are very efficient for large block reads (those significantly exceeding the buffer size). If users want all reads and writes to go through the buffers, by using std::basic_streambuf<>::xsputn() and std::basic_streambuf<>::xsgetn() then the symbol CGU_GSTREAM_USE_STD_N_READ_WRITE can be defined. (libstdc++-3 provides efficient inbuilt versions of these std::basic_streambuf functions for block reads not significantly larger than the buffer size, provided output buffering has not been turned off by the set_output_buffered() method of these classes.)

Note however that if CGU_GSTREAM_USE_STD_N_READ_WRITE is to be defined, it is best to do this by textually amending the installed gstream.h header file rather than by defining the symbol in user code before that file is included. This will ensure that all source files in a program which include the gstream.h header are guaranteed to see the same definitions so that the C++ standard's one-definition-rule is complied with.

One possible case for defining that symbol is where the user wants to use the tie() method of gistream or giostream (inherited from std::basic_ios) to procure flushing of an output stream before extraction from an input stream is made by gistream::read() or giostream::read() (and likewise their wide stream equivalents). Such flushing might not occur where a call to read() is made unless CGU_GSTREAM_USE_STD_N_READ_WRITE is defined, because an implementation is permitted to defer such flushing until underflow() occurs, and the block read by read(), as forwarded to xsgetn(), will never invoke underflow() if that symbol is not defined. (Having said that, any basic_istream implementation which does defer output flushing until underflow() is called makes tie() unusable anyway for a number of purposes, because the time of flushing would become dependent on whether a read request can be satisfied by what is already in the buffers.)

4 characters are stored and available for putback. However, if the symbol CGU_GSTREAM_USE_STD_N_READ_WRITE is not defined, then a call to gstreambuf::xsgetn() via gistream::read() or giostream::read() (or their wide stream equivalents) with a request for less than 4 characters will result in less than 4 characters available for putback (if these block read methods obtain some characters but less than 4, only the number of characters obtained by them is guaranteed to be available for putback).

## giostream and random access

For GIO objects which implement GSeekable (which are GFileIOStream, GFileInputStream, GFileOutputStream, GMemoryInputStream and GMemoryOutputStream), the classes in this c++-gtk-utils library implement the tellg(), tellp(), seekg() and seekp() random access methods.

The presence of buffering does not impede this where a stream is only opened for reading or only opened for writing. However, it presents complications if the giostream class or its wide stream equivalents are to be used with a GFIleIOStream object (GFileIOStream objects are opened for both read and write). Because the classes employ buffering of input, and optional buffering of output, the logical file position (the file position expected by the user from the reads and writes she has made) will usually differ from the actual file position seen by the underlying operating system. The gstreambuf class provided by this library implements intelligent tying between input and output streams for GFileIOStream objects which means that if output has been made unbuffered by a call to set_output_buffered(false) and no converter has been attached, all reads and writes onto the file system from the same giostream object (or its wide stream equivalents) will be made at the expected logical position.

This cannot be done by the gstreambuf class where the output stream is set as buffered (the default). In that case, if the last operation on a giostream object 'strm' (or its wide stream equivalents) was a read, before the first write operation thereafter is made on it, the user should call strm.seekg(strm.tellg()) or strm.seekp(strm.tellp()) (the two have the same effect), in order to synchronise the logical and actual file positions, or if the user does not want to maintain the current logical file position, make some other call to seekg() or seekp() which does not comprise only seekg(0, std::ios_base::cur) or seekp(0, std::ios_base::cur). Many std::basic_iostream implementations, as inherited by Cgu::giostream, will synchronise positions automatically on seekable streams via their sentry objects in order to provide support for buffered random access on their std::basic_fstream class (gcc's libstdc++ library does this, for example), making these steps unnecessary, but following these steps will provide maximum portability.

If a GFileIOStream object attached to a giostream object (or its wide stream equivalents) is not seekable (that is, can_seek() returns false), say because an input or output converter has been attached or the filesystem is a network file system, no random access may be attempted. In particular, the tellg(), tellp(), seekg() and seekp() methods will not work (they will return pos_type(off_type(-1))). Furthermore, if a giostream object (or its wide stream equivalents) which manages a GFileIOStream object (as opposed to a socket) has a converter attached or is not seekable for some other reason, then after a read has been made no further write may be made using the same GFileIOStream object, so the use of converters with giostream objects and their wide stream equivalents should generally be restricted to use with sockets (GSocketConnection objects) only. Where converters are used with files on a filesystem, it is best to use the gostream and gistream classes (or their wide stream equivalents), and to close one stream before opening the other where they address the same file.

None of these restrictions applies to GSocketConnection objects obtained by a call to g_socket_listener_accept() or g_socket_client_connect(), or obtained in some other way, as these do not maintain file pointers. They can be attached to a giostream object or its wide stream equivalents, with or without a converter, without any special precautions being taken, other than the normal step of calling giostream::flush() (or using the std::flush manipulator) to flush the output buffer to the socket if the user needs to know that that has happened (or setting output buffering off with the set_output_buffered() method). In summary, on a socket, a read does not automatically flush the output buffer: it is for the user to do that.

## Wide streams and endianness

This library provides typedef'ed instances of the template classes for wchar_t, char16_t and char32_t characters (but see below under "other wide stream issues" for more about the char16_t and char32_t typedefs). Unless a converter is attached (for, say, UTF-32LE to UTF-32BE, or vice versa), with these wide character classes wide characters are written out in the native endian format of the writing machine. Whether or not a converter from one endianness to another is attached, special steps need to be taken if the text which is sent for output might be read by machines of unknown endianness.

No such special steps are required where the wide character classes are used with temporary files, pipes, fifos, unix domain sockets and network sockets on localhost, because in those cases they will be read by the same machine that writes; but they are required where sockets communicate with other computers over a network or when writing to files which may be distributed to and read by other computers with different endianness.

Where wide characters are to be exported to other machines, one useful approach is to convert to and from UTF-8 using the conversion functions in the Cgu::Utf8 namespace, and to use gostream/gistream/giostream with the converted text, or to attach a converter for UTF-8, generated by GIO's g_charset_converter_new(), directly to a wgostream, wgistream or wgiostream object.

Instead of converting exported text to UTF-8, another approach is to use a byte order marker (BOM) as the first character of the wide stream output. UCS permits a BOM character to be inserted, comprising static_cast<wchar_t>(0xfeff), static_cast<char16_t>(0xfeff) or static_cast<char32_t>(0xfeff), at the beginning of the output to the wide character stream. At the receiving end, this will appear as 0xfffe (UTF-16) or 0xfffe0000 (UTF-32) to a big endian machine with 8 bit char type if the text is little endian, or to a little endian machine with big endian text, so signaling a need to undertake byte swapping of text read from the stream. Another alternative is to label the physical medium conveying the file as UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE, as the case may be, in which case a BOM character should not be prepended.

Where it is established by either means that the input stream requires byte swapping, the wide character input stream and wide character input streambuffer classes have a set_byteswap() member function which should be called on opening the input stream as soon as it has been established that byte swapping is required. Once this function has been called with an argument of 'true', all further calls to stream functions which provide characters will provide those characters with the correct native endianness. Calling set_byteswap() on the narrow stream gistream, giostream and gstreambuf objects has no effect (byte order is irrelevant to narrow streams).

Here is an example of such use in a case where sizeof(wchar_t) is 4:

using Cgu::GobjHandle;
Cgu::wgistream input;
GobjHandle<GFile> file_in(g_file_new_for_path("filename"));
GFileInputStream* is = g_file_read(file_in, 0, 0);
if (is)
input.attach(GobjHandle<GInputStream>(G_INPUT_STREAM(is)), true); // takes ownership of 'is'
else {
std::cerr << "Can't open file 'filename'"
<< std::endl;
return;
}
wchar_t item;
input.get(item);
if (!input) {
std::cerr << "File 'filename' is empty" << std::endl;
return;
}
if (item == static_cast<wchar_t>(0xfffe0000))
input.set_byteswap(true);
else if (item != static_cast<wchar_t>(0xfeff)) {
// calling set_byteswap() will manipulate the buffers, so
// either call putback() before we call set_byteswap(), or
// call unget() instead
input.putback(item);
// the first character is not a BOM character so assume big endian
// format, and byte swap if the local machine is little endian
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
input.set_byteswap(true);
#endif
}
[ ... do something with the input file ... ]

## Other wide stream issues

basic_gstreambuf objects can be instantiated for any integer type which has an appropriate traits class provided for it which has the copy(), eof(), eq_int_type(), move(), not_eof() and to_int_type() static member functions. The integer type could in fact have any size, but the set_byteswap() methods for basic_gistream, basic_giostream and basic_gstreambuf will only have an effect if its size is either 2 or 4. Typedef'ed instances of the basic_gstreambuf class are provided by the library for characters of type wchar_t, char16_t and char32_t.

basic_gostream, basic_gistream and basic_giostream objects can be instantiated for the wchar_t type, and there are wgostream. wgistream and wgiostream typedefs for these.

In addition there are u16gistream, u16gostream, u16giostream, u32gistream, u32gostream and u32giostream typedefs for the corresponding char16_t and char32_t types. However these stream typedefs for char16_t and char32_t are more problematic, because to invoke them it is necessary for ctype (and other) facets to be provided for them. gcc's libstdc++ and clang's libc++ do not supply these (they only supply them for the wchar_t type): it would therefore for the user to provide them herself.

## gtkmm users

gtkmm/giomm does not provide C++ streams for GIO objects: instead, it provides a literal function-for-function wrapping. However, giomm users can use the stream classes provided by this library by converting the relevant Glib::RefPtr object to a Cgu::GobjHandle object. This can be done as follows:

// Glib::RefPtr<Gio::InputStream> to Cgu::GobjHandle<GInputStream>
inline
Cgu::GobjHandle<GInputStream> giomm_input_convert(const Glib::RefPtr<Gio::InputStream>& in) {
return Cgu::GobjHandle<GInputStream>(static_cast<GInputStream*>(g_object_ref(in.operator->()->gobj())));
}
// Glib::RefPtr<Gio::OutputStream> to Cgu::GobjHandle<GOutputStream>
inline
Cgu::GobjHandle<GOutputStream> giomm_output_convert(const Glib::RefPtr<Gio::OutputStream>& out) {
return Cgu::GobjHandle<GOutputStream>(static_cast<GOutputStream*>(g_object_ref(out.operator->()->gobj())));
}
// Glib::RefPtr<Gio::IOStream> to Cgu::GobjHandle<GIOStream>
inline
Cgu::GobjHandle<GIOStream> giomm_io_convert(const Glib::RefPtr<Gio::IOStream>& io) {
return Cgu::GobjHandle<GIOStream>(static_cast<GIOStream*>(g_object_ref(io.operator->()->gobj())));
}
// example printing a text file to stdout with file opened with giomm
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path("filename");
Glib::RefPtr<Gio::InputStream> is = file->read();
Cgu::gistream filein(giomm_input_convert(is), true);
std::string line;
while (std::getline(filein, line)) {
std::cout << line << '\n';
}

## Typedef Documentation

## ◆ giostream

Cgu::giostream

C++ input/output stream for GIO streams for char type.

## ◆ gistream

Cgu::gistream

C++ input stream for GIO streams for char type.

## ◆ gostream

Cgu::gostream

C++ output stream for GIO streams for char type.

## ◆ gstreambuf

Cgu::gstreambuf

C++ stream buffer for GIO streams for char type.

## ◆ u16giostream

Cgu::u16giostream

C++ input/output stream for GIO streams for char16_t type.

## ◆ u16gistream

Cgu::u16gistream

C++ input stream for GIO streams for char16_t type.

## ◆ u16gostream

Cgu::u16gostream

C++ output stream for GIO streams for char16_t type.

## ◆ u16gstreambuf

Cgu::u16gstreambuf

C++ stream buffer for GIO streams for char16_t type.

## ◆ u32giostream

Cgu::u32giostream

C++ input/output stream for GIO streams for char32_t type.

## ◆ u32gistream

Cgu::u32gistream

C++ input stream for GIO streams for char32_t type.

## ◆ u32gostream

Cgu::u32gostream

C++ output stream for GIO streams for char32_t type.

## ◆ u32gstreambuf

Cgu::u32gstreambuf

C++ stream buffer for GIO streams for char32_t type.

## ◆ wgiostream

Cgu::wgiostream

C++ input/output stream for GIO streams for wchar_t type.

## ◆ wgistream

Cgu::wgistream

C++ input stream for GIO streams for wchar_t type.

## ◆ wgostream

Cgu::wgostream

C++ output stream for GIO streams for wchar_t type.

## ◆ wgstreambuf

Cgu::wgstreambuf

C++ stream buffer for GIO streams for wchar_t type.

Cgu::basic_gostream
C++ output stream for GIO streams.
Definition: gstream.h:1369
Cgu::GobjHandle
This is a handle for managing the reference count of GObjects.
Definition: gobj_handle.h:148
Cgu::basic_gistream
C++ input stream for GIO streams.
Definition: gstream.h:1652
Cgu::basic_gistream::set_byteswap
void set_byteswap(bool swap)
Definition: gstream.h:1872
Cgu::basic_gistream::attach
void attach(const GobjHandle< GInputStream > &stream, bool manage, const GobjHandle< GConverter > &converter=GobjHandle< GConverter >())
Definition: gstream.h:1806
Cgu::basic_giostream
C++ input-output stream for GIO streams.
Definition: gstream.h:1928
Cgu::basic_gostream::attach
void attach(const GobjHandle< GOutputStream > &stream, bool manage, const GobjHandle< GConverter > &converter=GobjHandle< GConverter >())
Definition: gstream.h:1525