/* Copyright (C) 2010 to 2017 Chris Vine


The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License.  With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence.  This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).
*/

/**
 * @defgroup gstreams gstreams
 *
 * \#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:
 *
 * @code
 *   // 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 ... ]
 *   }
 * @endcode
 *
 *
 * @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.
 * @note 2. These streambuffers and stream objects are not copiable.
 * @note 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
 * @ref GioRandomAccessAnchor "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.)
 *
 * @b Note @b 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).
 *
 * @anchor GioRandomAccessAnchor
 * 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:
 *
 * @code
 *   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 ... ]
 * @endcode
 *
 * 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:
 *
 * @code
 *   // 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';
 *   }
 * @endcode
 */

#ifndef CGU_GSTREAM_H
#define CGU_GSTREAM_H

#include <glib.h>

#if defined(DOXYGEN_PARSING) || GLIB_CHECK_VERSION(2,16,0)

// see above for what this does
//#define CGU_GSTREAM_USE_STD_N_READ_WRITE 1

#include <istream>
#include <ostream>
#include <streambuf>
#include <algorithm>
#include <string>
#include <cstddef>

#include <glib.h>
#include <glib-object.h>
#include <gio/gio.h>

#include <c++-gtk-utils/gobj_handle.h>
#include <c++-gtk-utils/shared_handle.h>
#include <c++-gtk-utils/gerror_handle.h>
#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

/*
The following convenience typedefs appear at the end of this file:
typedef basic_gstreambuf<char> gstreambuf;
typedef basic_gistream<char> gistream;
typedef basic_gostream<char> gostream;
typedef basic_giostream<char> giostream;
typedef basic_gstreambuf<wchar_t> wgstreambuf;
typedef basic_gistream<wchar_t> wgistream;
typedef basic_gostream<wchar_t> wgostream;
typedef basic_giostream<wchar_t> wgiostream;
typedef basic_gstreambuf<char16_t> u16gstreambuf;
typedef basic_gistream<char16_t> u16gistream;
typedef basic_gostream<char16_t> u16gostream;
typedef basic_giostream<char16_t> u16giostream;
typedef basic_gstreambuf<char32_t> u32gstreambuf;
typedef basic_gistream<char32_t> u32gistream;
typedef basic_gostream<char32_t> u32gostream;
typedef basic_giostream<char32_t> u32giostream;
*/


/**
 * @headerfile gstream.h c++-gtk-utils/gstream.h
 * @brief C++ stream buffer for GIO streams
 * @sa gstreams
 * @ingroup gstreams
 *
 * This class provides a stream buffer for interfacing with GIO
 * streams.  It does the buffering for the basic_gostream,
 * basic_gistream and basic_giostream stream classes.
 */

template <class charT , class Traits = std::char_traits<charT> >
class basic_gstreambuf: public std::basic_streambuf<charT, Traits> {

public:
  typedef charT char_type;
  typedef Traits traits_type;
  typedef typename traits_type::int_type int_type;
  typedef typename traits_type::pos_type pos_type;
  typedef typename traits_type::off_type off_type;

private:
  GobjHandle<GInputStream> input_stream;
  GobjHandle<GOutputStream> output_stream;
  GobjHandle<GIOStream> io_stream;

  bool manage;
  bool byteswap;
  bool seek_mismatch;
  bool seekable;

  static const int output_buf_size = 1024;   // size of the data write buffer
  static const int putback_size = 4;         // size of read putback area
  static const int input_buf_size = 1024;    // size of the data read buffer

#if defined(CGU_USE_GLIB_MEMORY_SLICES_COMPAT) || defined(CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT)
  ScopedHandle<char_type*,
               GSliceFreeSize<(input_buf_size + putback_size) * sizeof(char_type)>> input_buffer;
  ScopedHandle<char_type*,
               GSliceFreeSize<output_buf_size * sizeof(char_type)>> output_buffer;
#else
  ScopedHandle<char_type*> input_buffer;
  ScopedHandle<char_type*> output_buffer;
#endif

  static void swap_element(char_type&);
  GobjHandle<GInputStream> find_base_input_stream(const GobjHandle<GInputStream>&);
  GobjHandle<GOutputStream> find_base_output_stream(const GobjHandle<GOutputStream>&);
  void reset_input_buffer_pointers();
  int flush_buffer();
  bool wind_back_input_buffer();
  bool is_input_stored();
  bool is_output_stored();
  void set_input_error(GError*);
  void set_output_error(GError*);

protected:
/**
 * This method will not throw.  This means that the input functions of
 * stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_istream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  This class
 * does not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual int_type underflow();

/**
 * This method will not throw.  This class does not offer concurrent
 * access from multiple threads to the same stream object, and if that
 * is required users should provide their own synchronisation.
 */
  virtual int sync();

/**
 * This method will not throw unless std::basic_streambuf<>::sputc()
 * throws, which it would not do on any sane implementation.  This
 * means that the output functions of stream objects which have this
 * streambuffer as a member will not throw unless the underlying
 * functions of the std::basic_ostream class throw, which they would
 * not normally do unless they have been required to do so on failbit,
 * badbit or eofbit being set by an explicit call to the exceptions()
 * method of that class.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 */
  virtual int_type overflow(int_type);
#ifndef CGU_GSTREAM_USE_STD_N_READ_WRITE
/**
 * This method will not throw.  This means that the input functions of
 * stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_istream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  This class
 * does not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual std::streamsize xsgetn(char_type*, std::streamsize);

/**
 * This method will not throw.  This means that the output functions
 * of stream objects which have this streambuffer as a member will not
 * throw unless the underlying functions of the std::basic_ostream
 * class throw, which they would not normally do unless they have been
 * required to do so on failbit, badbit or eofbit being set by an
 * explicit call to the exceptions() method of that class.  This class
 * does not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 */
  virtual std::streamsize xsputn(const char_type*, std::streamsize);
#endif
/**
 * This method provides random access on GIO streams that implement
 * GSeekable, so supporting the tellg(), tellp(), seekg() and seekp()
 * methods of the basic_gostream, basic_gistream and basic_giostream
 * classes.  Any output buffers will be flushed and if the seek
 * succeeds any input buffers will be reset.  This method does not
 * throw, but if it returns pos_type(off_type(-1)) to indicate
 * failure, it will cause the tellg(), tellp(), seekg() or seekp()
 * methods of the relevant stream class to throw
 * std::ios_base::failure if such an exception has been required by an
 * explicit call to the exceptions() method of that class (but not
 * otherwise).  This class does not offer concurrent access from
 * multiple threads to the same stream object, and if that is required
 * users should provide their own synchronisation.
 *
 * @param off The offset to be applied to the 'way' argument when
 * seeking.  It is a signed integer type, and on wide character
 * streams is dimensioned as the number of wchar_t/char32_t/char16_t
 * units not the number of bytes (that is, it is
 * bytes/sizeof(char_type)).
 *
 * @param way The file position to which the 'off' argument is to be
 * applied (either std::ios_base::beg, std::ios_base::cur or
 * std::ios_base::end).
 *
 * @param m The type of GIO stream which must have been attached to
 * this streambuffer for this method to attempt a seek.  For
 * GInputStream the argument should have the std::ios_base::in bit
 * set, for GOutputStream it should have the std::ios_base::out bit
 * set and for GIOStream it should have either (or both) set.
 * Provided the relevant bit is set, it doesn't matter if others are
 * also set.  However if, with a GIOStream object, both the
 * std::ios_base::in and std::ios_base::out bits are set, a seek on
 * both input and output streams will be attempted, unless the 'way'
 * argument is std::ios_base::cur, in which case a seek on the output
 * stream only will be attempted.  (Note that the only GIOStream which
 * at present supports seeking is GFileIOStream, and because
 * filesystem files only have one file pointer, which is used for both
 * input and output, both input seeking and output seeking have the
 * same result and affect both streams.)  As the tellg() and seekg()
 * stream methods only pass std::ios_base::in, and the tellp() and
 * seekp() methods only std::ios_base::out, these will always produce
 * the expected result, and for GIOStream streams tellg() will be
 * indistinguishable in effect from tellp(), and seekg() from seekp().
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.  If a seek is made on a
 * GIOStream object with both std::ios_base::in and std::ios_base::out
 * set and a 'way' argument of std::ios_base::beg or
 * std::ios_base::end, the result of the seek which succeeds is
 * returned, or if both succeed, the result of the output seek is
 * returned.  (Note that the only GIOStream which at present supports
 * seeking is GFileIOStream, and because files only have one file
 * pointer, which is used for both input and output, both input
 * seeking and output seeking have the same result and affect both
 * streams.)
 */
  virtual pos_type seekoff(off_type off,
			   std::ios_base::seekdir way,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);

/**
 * This method provides random access on GIO streams that implement
 * GSeekable, so supporting the seekg() and seekp() methods of the
 * basic_gostream, basic_gistream and basic_giostream classes.  It is
 * equivalent to seekoff(off_type(p), std::ios_base::beg, m).  Any
 * output buffers will be flushed and if the seek succeeds any input
 * buffers will be reset.  This method does not throw, but if it
 * returns pos_type(off_type(-1)) to indicate failure, it will cause
 * the seekg() or seekp() methods of the relevant stream class to
 * throw std::ios_base::failure if such an exception has been required
 * by an explicit call to the exceptions() method of that class (but
 * not otherwise).  This class does not offer concurrent access from
 * multiple threads to the same stream object, and if that is required
 * users should provide their own synchronisation.
 *
 * @param p The absolute position to which the seek is to be made,
 * obtained by a previous call to seekoff() or to this method.
 *
 * @param m The type of GIO stream which must have been attached to
 * this streambuffer for this method to attempt a seek.  For
 * GInputStream the argument should have the std::ios_base::in bit
 * set, for GOutputStream it should have the std::ios_base::out bit
 * set and for GIOStream it should have either (or both) set.
 * Provided the relevant bit is set, it doesn't matter if others are
 * also set.  However if, with a GIOStream object, both the
 * std::ios_base::in and std::ios_base::out bits are set, a seek on
 * both input and output streams will be attempted.  (Note that the
 * only GIOStream which at present supports seeking is GFileIOStream,
 * and because filesystem files only have one file pointer, which is
 * used for both input and output, both input seeking and output
 * seeking have the same result and affect both streams.)  As the
 * seekg() stream method only passes std::ios_base::in, and the
 * seekp() method only std::ios_base::out, these will always produce
 * the expected result, and seekg() will be indistinguishable in
 * effect from seekp().
 *
 * @return If the seek succeeds, a std::char_traits<T>::pos_type
 * object representing the new stream position of the streambuffer
 * after the seek.  (This type is std::streampos for narrow character
 * (char) streams, std::wstreampos for wide character (wchar_t)
 * streams, std::u16streampos for the char16_t type and
 * std::u32streampos for the char32_t type.)  If the seek failed,
 * pos_type(off_type(-1)) is returned.
 */
  virtual pos_type seekpos(pos_type p,
			   std::ios_base::openmode m = std::ios_base::in | std::ios_base::out);

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_gstreambuf(const basic_gstreambuf&) = delete;

/**
 * This class cannot be copied.  The copy assignment operator is
 * deleted.
 */
  basic_gstreambuf& operator=(const basic_gstreambuf&) = delete;

/**
 * The default constructor: the GIO stream is attached later using the
 * attach_stream() method.  It will not throw unless the default
 * constructor of std::basic_streambuf throws.  This class does not
 * offer concurrent access from multiple threads to the same stream
 * object, and if that is required users should provide their own
 * synchronisation.
 */
  basic_gstreambuf();

 /**
  * The constructor taking a GIO input stream.  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @param input_stream_ A GIO input stream to be attached to the
  * streambuffer.  If the caller wants the input stream to survive
  * this class's destruction or a call to close_stream() or
  * attach_stream(), the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_istream()) and pass 'manage_' as false.  If this is a
  * GFilterInputStream object (that is, a GBufferedInputStream or
  * GConverterInputStream stream), only the underlying base input
  * stream will be attached and the other higher level streams will be
  * closed (buffering of input streams is always provided by this C++
  * streambuffer, and converting is controlled solely by the
  * 'converter_' argument).
  *
  * @param manage_ Whether the streambuffer should call
  * g_input_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted - 'false' only makes sense if the caller keeps a separate
  * GobjHandle object which references the stream to keep it alive
  * (obtained by, say, calling get_istream()).  Unlike its fdstreams
  * equivalent, this parameter does not have a default value of
  * 'true': this is partly to make it less likely that a converter is
  * passed to this argument by mistake (that would not normally cause
  * a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly because, given a GInputStream* p, the construction
  * \"Cgu::gstreambuf str(Cgu::GobjHandle\<GInputStream\>(p));\"
  * without an additional argument or additional parentheses (or the
  * use of uniform initializer syntax using braces) would cause a
  * compiler error as it would be interpreted as a function
  * declaration.
  *
  * @param converter_ A converter (if any) to be attached to the GIO
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg() and seekg()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  basic_gstreambuf(const GobjHandle<GInputStream>& input_stream_,
		   bool manage_,
		   const GobjHandle<GConverter>& converter_ = GobjHandle<GConverter>());

 /**
  * The constructor taking a GIO output stream.  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @param output_stream_ A GIO output stream to be attached to the
  * streambuffer.  If the caller wants the output stream to survive
  * this class's destruction or a call to close_stream() or
  * attach_stream(), the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_ostream()) and pass 'manage_' as false.  If this is a
  * GFilterOutputStream object (that is, a GBufferedOutputStream,
  * GConverterOutputStream or GDataOutputStream stream), only the
  * underlying base output stream will be attached and the other
  * higher level streams will be closed (buffering and converting are
  * controlled solely by the set_output_buffered() method and
  * 'converter_' argument).
  *
  * @param manage_ Whether the streambuffer should call
  * g_output_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted, and is particularly relevant on output streams because
  * unless g_output_stream_close() is called, GIO may not commit to
  * disk - 'false' only makes sense if the caller keeps a separate
  * GobjHandle object which references the stream to keep it alive
  * (obtained by, say, calling get_ostream()).  Unlike its fdstreams
  * equivalent, this parameter does not have a default value of
  * 'true': this is partly to make it less likely that a converter is
  * passed to this argument by mistake (that would not normally cause
  * a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly because, given a GOutputStream* p, the construction
  * \"Cgu::gstreambuf str(Cgu::GobjHandle\<GOutputStream\>(p));\"
  * without an additional argument or additional parentheses (or the
  * use of uniform initializer syntax using braces) would cause a
  * compiler error as it would be interpreted as a function
  * declaration.
  *
  * @param converter_ A converter (if any) to be attached to the GIO
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellp() and seekp()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  basic_gstreambuf(const GobjHandle<GOutputStream>& output_stream_,
		   bool manage_,
		   const GobjHandle<GConverter>& converter_ = GobjHandle<GConverter>());

 /**
  * The constructor taking a GIO input-output stream.  This class does
  * not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @param io_stream_ A GIO input-output stream to be attached to the
  * streambuffer.  If the caller wants the stream to survive this
  * class's destruction or a call to close_stream() or
  * attach_stream(), the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_iostream()) and pass 'manage_' as false.
  *
  * @param manage_ Whether the streambuffer should call
  * g_io_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted, and is particularly relevant on output streams because
  * unless g_io_stream_close() is called, GIO may not commit to disk -
  * 'false' only makes sense if the caller keeps a separate GobjHandle
  * object which references the stream to keep it alive (obtained by,
  * say, calling get_iostream()).  Unlike its fdstreams equivalent,
  * this parameter does not have a default value of 'true': this is
  * partly to make it less likely that a converter is passed to this
  * argument by mistake (that would not normally cause a compiler
  * warning because GobjHandle has a type conversion operator
  * providing the underlying C object by pointer, so GobjHandles are
  * type convertible to pointers, and such a pointer will in turn
  * provide a type match with a bool argument); and partly because,
  * given a GIOStream* p, the construction \"Cgu::gstreambuf
  * str(Cgu::GobjHandle\<GIOStream\>(p));\" without an additional
  * argument or additional parentheses (or the use of uniform
  * initializer syntax using braces) would cause a compiler error as
  * it would be interpreted as a function declaration.
  *
  * @param input_converter_ A converter (if any) to be attached to the
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @param output_converter_ A converter (if any) to be attached to the
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg(), tellp(),
  * seekg() and seekp() will no longer work (they will return
  * pos_type(off_type(-1)).  If the stream to which a converter has
  * been attached represents a file on the file system (rather than a
  * socket), after a read has been made, no further write may be made
  * using the same GFileIOStream object.  These restrictions do not
  * apply to sockets (which are not seekable) so the use of converters
  * with input-output streams (GIOStream) should generally be
  * restricted to sockets.
  */
  basic_gstreambuf(const GobjHandle<GIOStream>& io_stream_,
		   bool manage_,
		   const GobjHandle<GConverter>& input_converter_ = GobjHandle<GConverter>(),
		   const GobjHandle<GConverter>& output_converter_ = GobjHandle<GConverter>());
  
/**
 * The destructor does not throw.
 */
  virtual ~basic_gstreambuf();

 /**
  * Attach a new GIO input stream to the streambuffer (and close any
  * GIO stream at present managed by it).  In the case of wide
  * character input streams, it also switches off byte swapping, if it
  * was previously on.  This class does not offer concurrent access
  * from multiple threads to the same stream object, and if that is
  * required users should provide their own synchronisation.
  *
  * @param input_stream_ The GIO input stream to be attached to the
  * streambuffer.  If the caller wants the input stream to survive a
  * subsequent call to close_stream() or attach_stream() or this
  * class's destruction, the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_istream()) and pass 'manage_' as false.  If this is a
  * GFilterInputStream object (that is, a GBufferedInputStream or
  * GConverterInputStream stream), only the underlying base input
  * stream will be attached and the other higher level streams will be
  * closed (buffering of input streams is always provided by this C++
  * streambuffer, and converting is controlled solely by the
  * 'converter_' argument).
  *
  * @param manage_ Whether the streambuffer should call
  * g_input_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted - 'false' only makes sense if the caller keeps a separate
  * GobjHandle object which references the stream to keep it alive
  * (obtained by, say, calling get_istream()).  Unlike its fdstreams
  * equivalent, this parameter does not have a default value of
  * 'true': this is partly to make it less likely that a converter is
  * passed to this argument by mistake (that would not normally cause
  * a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly to maintain compatibility with the constructor's interface,
  * which has separate syntactic constraints.
  *
  * @param converter_ A converter (if any) to be attached to the GIO
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg() and seekg()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  void attach_stream(const GobjHandle<GInputStream>& input_stream_,
		     bool manage_,
		     const GobjHandle<GConverter>& converter_ = GobjHandle<GConverter>());

 /**
  * Attach a new GIO output stream to the streambuffer (and close any
  * GIO stream at present managed by it).  If output buffering was
  * previously switched off, it is switched back on again.  This class
  * does not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @param output_stream_ The GIO output stream to be attached to the
  * streambuffer.  If the caller wants the output stream to survive a
  * subsequent call to close_stream() or attach_stream() or this
  * class's destruction, the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_ostream()) and pass 'manage_' as false.  If this is a
  * GFilterOutputStream object (that is, a GBufferedOutputStream,
  * GConverterOutputStream or GDataOutputStream stream), only the
  * underlying base output stream will be attached and the other
  * higher level streams will be closed (buffering and converting are
  * controlled solely by the set_output_buffered() method and
  * 'converter_' argument).
  *
  * @param manage_ Whether the streambuffer should call
  * g_output_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted, and is particularly relevant on output streams because
  * unless g_output_stream_close() is called, GIO may not commit to
  * disk - 'false' only makes sense if the caller keeps a separate
  * GobjHandle object which references the stream to keep it alive
  * (obtained by, say, calling get_ostream()).  Unlike its fdstreams
  * equivalent, this parameter does not have a default value of
  * 'true': this is partly to make it less likely that a converter is
  * passed to this argument by mistake (that would not normally cause
  * a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly to maintain compatibility with the constructor's interface,
  * which has separate syntactic constraints.
  *
  * @param converter_ A converter (if any) to be attached to the GIO
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellp() and seekp()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  void attach_stream(const GobjHandle<GOutputStream>& output_stream_,
		     bool manage_,
		     const GobjHandle<GConverter>& converter_ = GobjHandle<GConverter>());

 /**
  * Attach a new GIO input-output stream to the streambuffer (and
  * close any GIO stream at present managed by it).  If output
  * buffering was previously switched off, it is switched back on
  * again.  In the case of wide character input-output streams, it
  * also switches off byte swapping on input, if it was previously on.
  * This class does not offer concurrent access from multiple threads
  * to the same stream object, and if that is required users should
  * provide their own synchronisation.
  *
  * @param io_stream_ The GIO input-output stream to be attached to
  * the streambuffer.  If the caller wants the stream to survive a
  * subsequent call to close_stream() or attach_stream() or this
  * class's destruction, the caller should keep a separate GobjHandle
  * object which references the stream (obtained by, say, calling
  * get_iostream()) and pass 'manage_' as false.
  *
  * @param manage_ Whether the streambuffer should call
  * g_io_stream_close() on the stream in its destructor or when
  * another stream is attached.  Passing 'true' is usually what is
  * wanted, and is particularly relevant on output streams because
  * unless g_io_stream_close() is called, GIO may not commit to disk -
  * 'false' only makes sense if the caller keeps a separate GobjHandle
  * object which references the stream to keep it alive (obtained by,
  * say, calling get_iostream()).  Unlike its fdstreams equivalent,
  * this parameter does not have a default value of 'true': this is
  * partly to make it less likely that a converter is passed to this
  * argument by mistake (that would not normally cause a compiler
  * warning because GobjHandle has a type conversion operator
  * providing the underlying C object by pointer, so GobjHandles are
  * type convertible to pointers, and such a pointer will in turn
  * provide a type match with a bool argument); and partly to maintain
  * compatibility with the constructor's interface, which has separate
  * syntactic constraints.
  *
  * @param input_converter_ A converter (if any) to be attached to the
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @param output_converter_ A converter (if any) to be attached to the
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg(), tellp(),
  * seekg() and seekp() will no longer work (they will return
  * pos_type(off_type(-1)).  If the stream to which a converter has
  * been attached represents a file on the file system (rather than a
  * socket), after a read has been made, no further write may be made
  * using the same GFileIOStream object.  These restrictions do not
  * apply to sockets (which are not seekable) so the use of converters
  * with input-output streams (GIOStream) should generally be
  * restricted to sockets.
  */
  void attach_stream(const GobjHandle<GIOStream>& io_stream_,
		     bool manage_,
		     const GobjHandle<GConverter>& input_converter_ = GobjHandle<GConverter>(),
		     const GobjHandle<GConverter>& output_converter_ = GobjHandle<GConverter>());


 /**
  * Call g_input_stream_close(), g_output_stream_close() or
  * g_io_stream_close(), as the case may be, on the GIO stream at
  * present attached to the streambuffer (if any), and release the
  * streambuffer's reference to that stream (the reference will be
  * released even if an error arose in closing the stream).  If the
  * caller wants the GIO stream to survive the call to this method
  * (albeit in a closed state), the caller should, before the call is
  * made, keep a separate GobjHandle object which references the
  * stream.  This method does not throw.  This class does not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return true if the close succeeded, false if an error arose
  * (including in a case where no GIO stream has been attached or it
  * has already been closed).
  */
  bool close_stream();

 /**
  * Get the GIO input stream at present attached to the streambuffer
  * (if any), by GobjHandle.  If a GOutputStream object rather than a
  * GInputStream or GIOStream object has been attached (or no stream
  * has been attached) or it has been closed, then this method will
  * return an empty GobjHandle object.  If a GIOStream object has been
  * attached, this streambuffer's maintained GInputStream object will
  * be returned, which may be a converting stream manufactured from
  * the GInputStream object maintained by the GIOStream object.
  * Retaining the return value will cause the stream to survive a
  * subsequent call to attach_stream() or the destruction of this
  * object.  The return value may be a different stream from the one
  * originally passed to this object's constructor or to attach().  It
  * will be different if a converter has been attached to it.  This
  * method does not throw.  This class does not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @return The GIO input stream at present attached to the
  * streambuffer, or an empty GobjHandle object if none has been
  * attached
  */
  GobjHandle<GInputStream> get_istream() const;

 /**
  * Get the GIO output stream at present attached to the streambuffer
  * (if any), by GobjHandle.  If a GInputStream object rather than a
  * GOutputStream or GIOStream object has been attached (or no stream
  * has been attached) or it has been closed, then this method will
  * return an empty GobjHandle object.  If a GIOStream object has been
  * attached, this streambuffer's maintained GOutputStream object will
  * be returned, which may be a converting stream manufactured from
  * the GOutputStream object maintained by the GIOStream object.
  * Retaining the return value will cause the stream to survive a
  * subsequent call to attach_stream() or the destruction of this
  * object.  The return value may be a different stream from the one
  * originally passed to this object's constructor or to attach().  It
  * will be different if a converter has been attached to it.  This
  * method does not throw.  This class does not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @return The GIO output stream at present attached to the
  * streambuffer, or an empty GobjHandle object if none has been
  * attached
  */
  GobjHandle<GOutputStream> get_ostream() const;

 /**
  * Get the GIOStream input-output stream at present attached to the
  * streambuffer (if any), by GobjHandle.  If a GInputStream or
  * GOutputStream object rather than a GIOStream object has been
  * attached (or no stream has been attached) or it has been closed,
  * then this method will return an empty GobjHandle object.
  * Retaining the return value will cause the stream to survive a
  * subsequent call to attach_stream() or the destruction of this
  * object.  This method does not throw.  This class does not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The GIOStream stream at present attached to the
  * streambuffer, or an empty GobjHandle object if none has been
  * attached
  */
  GobjHandle<GIOStream> get_iostream() const;

 /**
  * Causes the streambuffer to swap bytes in incoming text, so as to
  * convert big endian text to little endian text, or little endian
  * text to big endian text.  It is called by the user in response to
  * finding a byte order marker (BOM) 0xfffe (UTF-16) or 0xfffe0000
  * (UTF-32) as the first character of a newly opened file/stream, or
  * if the user knows by some other means that the native endianness
  * of the machine doing the reading differs from the endianness of
  * the file/stream being read.  This only has effect on wide
  * character streambuffers for input (for example, a wgstreambuf to
  * which a GInputStream or GIOStream object has been attached), and
  * not the gstreambuf narrow character stream buffer.  Note that
  * characters held for output are always outputted in native endian
  * format unless a GConverter object has been attached, and this
  * method does not affect that.  This method does not throw.  This
  * class does not offer concurrent access from multiple threads to
  * the same stream object, and if that is required users should
  * provide their own synchronisation.
  *
  * @param swap 'true' if byte swapping for input is to be turned on,
  * 'false' if it is to be turned off.  This will affect all
  * characters extracted from the underlying streambuffer after this
  * call is made.  If a previously extracted character is to be
  * putback(), it must be put back before this function is called (or
  * unget() should be called instead) to avoid a putback mismatch,
  * because this call will byte-swap anything already in the buffers.
  * (Characters extracted after the call to this method may be putback
  * normally.)
  */
  void set_byteswap(bool swap);

/**
 * If the GIO stream attached to this object is GOutputStream or
 * GIOStream, this method converts it to an unbuffered stream for
 * output if 'buffered' is false, or back to a buffered stream if
 * buffering has previously been switched off and 'buffered' is true.
 * Buffering is on by default for any newly created gstreambuf object
 * and any newly attached GIO output stream or input-output stream.
 * If buffering is turned off, all characters at present in the
 * buffers which are stored for output are flushed (but if writing to
 * a file which is being written over/replaced, output from this
 * streambuffer may not appear in the destination until the GIO stream
 * is closed).  This method has no effect if no GIO output stream or
 * input-output stream has yet been attached to this streambuffer.
 * Switching output buffering off is similar in effect to setting the
 * std::ios_base::unitbuf flag in the relevant gostream or giostream
 * object, except that switching buffering off is slightly more
 * efficient, and setting the std::ios_base::unitbuf flag will not
 * retain the automatic tying of logical and actual file positions
 * that occurs when output buffering is switched off, as explained
 * @ref GioRandomAccessAnchor "here".  This class does not offer
 * concurrent access from multiple threads to the same stream object,
 * and if that is required users should provide their own
 * synchronisation.
 *
 * @param buffered 'false' if buffering is to be turned off, 'true' if
 * it is to be turned back on.
 *
 * @exception std::bad_alloc This method will throw std::bad_alloc if
 * 'buffered' is true, output buffering had previously been switched
 * off, memory is exhausted and the system throws on such exhaustion
 * (unless the library has been installed using the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option, in which
 * case glib will terminate the program if it is unable to obtain
 * memory from the operating system).
 */
  void set_output_buffered(bool buffered);

/**
 * This method indicates whether the attached GIO stream implements
 * GSeekable, so that a call to seekoff() or seekpos() can succeed.
 * This method does not throw.  This class does not offer concurrent
 * access from multiple threads to the same stream object, and if that
 * is required users should provide their own synchronisation.
 *
 * @return true if random access is supported, otherwise false.  The
 * result is only meaningful if a GIO stream has been attached to this
 * streambuffer.
 */
  bool can_seek() const {return seekable;}

/**
 * This method indicates whether any attached GIO input stream is in
 * an error state.  It can be useful for detecting conversion errors
 * on converting streams.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return NULL if no input stream is attached, or it is not in an
 * error state.  If an attached input stream is in an error state, say
 * because it is a converting input stream which has encountered a
 * conversion error, the most recent GError object emitted by a read
 * operation on it is returned.  Ownership of the return value is
 * retained, so if it is intended to be used after the next read
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_input_error();

/**
 * This method indicates whether any attached GIO output stream is in
 * an error state.  It can be useful for detecting conversion errors
 * on converting streams.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return NULL if no output stream is attached, or it is not in an
 * error state.  If an attached output stream is in an error state,
 * say because it is a converting output stream which has encountered
 * a conversion error, the most recent GError object emitted by a
 * write operation on it is returned.  Ownership of the return value
 * is retained, so if it is intended to be used after the next write
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_output_error();

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};

/**
 * @headerfile gstream.h c++-gtk-utils/gstream.h
 * @brief C++ output stream for GIO streams
 * @sa gstreams
 * @ingroup gstreams
 *
 * This class provides standard ostream services for GIO output
 * streams.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_gostream: public std::basic_ostream<charT, Traits> {

  basic_gstreambuf<charT, Traits> buf;

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_gostream(const basic_gostream&) = delete;

/**
 * This class cannot be copied.  The copy assignment operator is
 * deleted.
 */
  basic_gostream& operator=(const basic_gostream&) = delete;

 /**
  * The constructor taking a GIO output stream.  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @param stream A GIO output stream to be attached.  If the caller
  * wants the output stream to survive this class's destruction or a
  * call to close() or attach(), the caller should keep a separate
  * GobjHandle object which references the stream (obtained by, say,
  * calling get_gio_stream()) and pass 'manage' as false.  If this is
  * a GFilterOutputStream object (that is, a GBufferedOutputStream,
  * GConverterOutputStream or GDataOutputStream stream), only the
  * underlying base output stream will be attached and the other
  * higher level streams will be closed (buffering and converting are
  * controlled solely by the set_buffered() method and 'converter'
  * argument).
  *
  * @param manage Whether the underlying streambuffer should call
  * g_output_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted, and is particularly relevant on output
  * streams because unless g_output_stream_close() is called, GIO may
  * not commit to disk - 'false' only makes sense if the caller keeps
  * a separate GobjHandle object which references the stream to keep
  * it alive (obtained by, say, calling get_gio_stream()).  Unlike its
  * fdstreams equivalent, this parameter does not have a default value
  * of 'true': this is partly to make it less likely that a converter
  * is passed to this argument by mistake (that would not normally
  * cause a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly because, given a GOutputStream* p, the construction
  * \"Cgu::gostream str(Cgu::GobjHandle\<GOutputStream\>(p));\"
  * without an additional argument or additional parentheses (or the
  * use of uniform initializer syntax using braces) would cause a
  * compiler error as it would be interpreted as a function
  * declaration.
  *
  * @param converter A converter (if any) to be attached to the GIO
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf or
  * std::basic_ostream throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellp() and seekp()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  // using uniform initializer syntax here confuses doxygen
  basic_gostream(const GobjHandle<GOutputStream>& stream,
		 bool manage,
		 const GobjHandle<GConverter>& converter = GobjHandle<GConverter>()):
                                      std::basic_ostream<charT, Traits>(0),
                                      buf(stream, manage, converter) {
    this->rdbuf(&buf);
  }

 /**
  * With this constructor, the GIO output stream must be attached
  * later with the attach() method.  It will not throw unless the
  * default constructor of std::basic_streambuf or std::basic_ostream
  * throws.  This class does not offer concurrent access from multiple
  * threads to the same stream object, and if that is required users
  * should provide their own synchronisation.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_gostream(): std::basic_ostream<charT, Traits>(0) {
    this->rdbuf(&buf);
  }

 /**
  * Attach a new GIO output stream to this object (and close any GIO
  * stream at present managed by it).  If output buffering was
  * previously switched off, it is switched back on again.  If any
  * stream state flags were set (eofbit, failbit or badbit), they will
  * be cleared by a call to clear().  If this method closes a stream
  * at present managed by it and the close fails, failbit is not set
  * and no exception will be thrown.  Accordingly, if the user needs
  * to know whether there was an error in this method closing any
  * managed stream, she should call close() explicitly before calling
  * this method.  This class does not offer concurrent access from
  * multiple threads to the same stream object, and if that is
  * required users should provide their own synchronisation.
  *
  * @param stream A GIO output stream to be attached.  If the caller
  * wants the GIO output stream to survive a subsequent call to
  * close() or attach() or this class's destruction, the caller should
  * keep a separate GobjHandle object which references the stream
  * (obtained by, say, calling get_gio_stream()) and pass 'manage' as
  * false.  If this is a GFilterOutputStream object (that is, a
  * GBufferedOutputStream, GConverterOutputStream or GDataOutputStream
  * stream), only the underlying base output stream will be attached
  * and the other higher level streams will be closed (buffering and
  * converting are controlled solely by the set_buffered() method and
  * 'converter' argument).
  *
  * @param manage Whether the underlying streambuffer should call
  * g_output_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted, and is particularly relevant on output
  * streams because unless g_output_stream_close() is called, GIO may
  * not commit to disk - 'false' only makes sense if the caller keeps
  * a separate GobjHandle object which references the stream to keep
  * it alive (obtained by, say, calling get_gio_stream()).  Unlike its
  * fdstreams equivalent, this parameter does not have a default value
  * of 'true': this is partly to make it less likely that a converter
  * is passed to this argument by mistake (that would not normally
  * cause a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly to maintain compatibility with the constructor's interface,
  * which has separate syntactic constraints.
  *
  * @param converter A converter (if any) to be attached to the GIO
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellp() and seekp()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  void attach(const GobjHandle<GOutputStream>& stream,
	      bool manage,
	      const GobjHandle<GConverter>& converter = GobjHandle<GConverter>())
  {buf.attach_stream(stream, manage, converter); this->clear();}

 /**
  * Call g_output_stream_close() on the GIO stream at present attached
  * (if any), and release the underlying C++ streambuffer's reference
  * to that stream.  If the caller wants the GIO stream to survive the
  * call to this method (albeit in a closed state), the caller should,
  * before the call is made, keep a separate GobjHandle object which
  * references the stream.  If the close fails, the failbit will be
  * set with setstate(std::ios_base::failbit).  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @exception std::ios_base::failure This exception will be thrown if
  * an error arises on closing the stream and such an exception has
  * been required by a call to the exceptions() method of this class
  * (inherited from std::basic_ios<>).  No exception will be thrown if
  * exceptions() has not been called.
  */
  void close() {if (!buf.close_stream()) this->setstate(std::ios_base::failbit);}

 /**
  * Get the GIO output stream at present attached (if any), by
  * GobjHandle.  If no stream has been attached, this method will
  * return an empty GobjHandle object.  Retaining the return value
  * will cause the GIO output stream to survive the destruction of
  * this object.  The return value may be a different stream from the
  * one originally passed to this object's constructor or to attach().
  * It will be different if a converter has been attached to it.  This
  * method does not throw.  This class does not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @return The GIO output stream at present attached, or an empty
  * GobjHandle object if none has been attached
  */
  GobjHandle<GOutputStream> get_gio_stream() const {return buf.get_ostream();}

/**
 * This method converts the attached GIO output stream to an
 * unbuffered stream for output if 'buffered' is false, or back to a
 * buffered stream if buffering has previously been switched off and
 * 'buffered' is true.  Buffering is on by default for any newly
 * created gostream object and any newly attached GIO output stream.
 * If buffering is turned off, all characters at present in the
 * buffers which are stored for output are flushed (but if writing to
 * a file which is being written over/replaced, output may not appear
 * in the destination until the GIO stream is closed).  This method
 * has no effect if no GIO output stream has yet been attached.
 * Switching output buffering off is similar in effect to setting the
 * std::ios_base::unitbuf flag, but is slightly more efficient.  This
 * class does not offer concurrent access from multiple threads to the
 * same stream object, and if that is required users should provide
 * their own synchronisation.
 *
 * @param buffered 'false' if buffering is to be turned off, 'true' if
 * it is to be turned back on.
 *
 * @exception std::bad_alloc This method will throw std::bad_alloc if
 * 'buffered' is true, output buffering had previously been switched
 * off, memory is exhausted and the system throws on such exhaustion
 * (unless the library has been installed using the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option, in which
 * case glib will terminate the program if it is unable to obtain
 * memory from the operating system).
 */
  void set_buffered(bool buffered) {buf.set_output_buffered(buffered);}

/**
 * This method indicates whether the attached GIO output stream
 * implements GSeekable, so that a call to tellp() or seekp() can
 * succeed.  Note that in the seekp(off_type off, ios_base::seekdir
 * dir) variant, on wide character streams the 'off' argument is
 * dimensioned as the number of wchar_t/char32_t/char16_t units not
 * the number of bytes (that is, it is bytes/sizeof(char_type)).  This
 * method does not throw.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return true if the attached GIO stream implements GSeekable,
 * otherwise false.  The result is only meaningful if a GIO stream has
 * been attached to this C++ stream object.
 */
  bool can_seek() const {return buf.can_seek();}

/**
 * This method reports the error status of any attached GIO output
 * stream, and is intended to be called where failbit or badbit has
 * been set.  It can be useful for interpreting conversion errors on
 * converting streams where one of those bits is set.  This class does
 * not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 *
 * @return NULL if no output stream is attached, or it is not in an
 * error state.  If an attached output stream is in an error state,
 * say because it is a converting output stream which has encountered
 * a conversion error, the most recent GError object emitted by a
 * write operation on it is returned.  Ownership of the return value
 * is retained, so if it is intended to be used after the next write
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_error() {return buf.is_output_error();}

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};


/**
 * @headerfile gstream.h c++-gtk-utils/gstream.h
 * @brief C++ input stream for GIO streams
 * @sa gstreams
 * @ingroup gstreams
 *
 * This class provides standard istream services for GIO input
 * streams.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_gistream : public std::basic_istream<charT, Traits> {

  basic_gstreambuf<charT , Traits> buf;

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_gistream(const basic_gistream&) = delete;

/**
 * This class cannot be copied.  The copy assignment operator is
 * deleted.
 */
  basic_gistream& operator=(const basic_gistream&) = delete;

 /**
  * The constructor taking a GIO input stream.  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @param stream A GIO input stream to be attached.  If the caller
  * wants the GIO input stream to survive this class's destruction or
  * a call to close() or attach(), the caller should keep a separate
  * GobjHandle object which references the stream (obtained by, say,
  * calling get_gio_stream()) and pass 'manage' as false.  If this is
  * a GFilterInputStream object (that is, a GBufferedInputStream or
  * GConverterInputStream stream), only the underlying base input
  * stream will be attached and the other higher level streams will be
  * closed (buffering of input streams is always provided by the
  * underlying C++ streambuffer, and converting is controlled solely
  * by the 'converter' argument).
  *
  * @param manage Whether the underlying streambuffer should call
  * g_input_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted - 'false' only makes sense if the caller
  * keeps a separate GobjHandle object which references the stream to
  * keep it alive (obtained by, say, calling get_gio_stream()).
  * Unlike its fdstreams equivalent, this parameter does not have a
  * default value of 'true': this is partly to make it less likely
  * that a converter is passed to this argument by mistake (that would
  * not normally cause a compiler warning because GobjHandle has a
  * type conversion operator providing the underlying C object by
  * pointer, so GobjHandles are type convertible to pointers, and such
  * a pointer will in turn provide a type match with a bool argument);
  * and partly because, given a GInputStream* p, the construction
  * \"Cgu::gistream str(Cgu::GobjHandle\<GInputStream\>(p));\" without
  * an additional argument or additional parentheses (or the use of
  * uniform initializer syntax using braces) would cause a compiler
  * error as it would be interpreted as a function declaration.
  *
  * @param converter A converter (if any) to be attached to the GIO
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf or
  * std::basic_istream throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg() and seekg()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  // using uniform initializer syntax here confuses doxygen
  basic_gistream(const GobjHandle<GInputStream>& stream,
		 bool manage,
		 const GobjHandle<GConverter>& converter = GobjHandle<GConverter>()):
                                      std::basic_istream<charT, Traits>(0),
                                      buf(stream, manage, converter) {
    this->rdbuf(&buf);
  }

 /**
  * With this constructor, the GIO input stream must be attached later
  * with the attach() method.  It will not throw unless the default
  * constructor of std::basic_streambuf or std::basic_istream throws.
  * This class does not offer concurrent access from multiple threads
  * to the same stream object, and if that is required users should
  * provide their own synchronisation.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_gistream(): std::basic_istream<charT, Traits>(0) {
    this->rdbuf(&buf);
  }

 /**
  * Attach a new GIO input stream to this object (and close any GIO
  * stream at present managed by it).  In the case of wide character
  * input streams, it also switches off byte swapping, if it was
  * previously on.  If any stream state flags were set (eofbit,
  * failbit or badbit), they will be cleared by a call to clear().  If
  * this method closes a stream at present managed by it and the close
  * fails, failbit is not set and no exception will be thrown.
  * Accordingly, if the user needs to know whether there was an error
  * in this method closing any managed stream, she should call close()
  * explicitly before calling this method.  This class does not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @param stream A GIO input stream to be attached.  If the caller
  * wants the GIO input stream to survive a subsequent call to close()
  * or attach() or this class's destruction, the caller should keep a
  * separate GobjHandle object which references the stream (obtained
  * by, say, calling get_gio_stream()) and pass 'manage' as false.  If
  * this is a GFilterInputStream object (that is, a
  * GBufferedInputStream or GConverterInputStream stream), only the
  * underlying base input stream will be attached and the other higher
  * level streams will be closed (buffering of input streams is always
  * provided by the underlying C++ streambuffer, and converting is
  * controlled solely by the 'converter' argument).
  *
  * @param manage Whether the underlying streambuffer should call
  * g_input_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted - 'false' only makes sense if the caller
  * keeps a separate GobjHandle object which references the stream to
  * keep it alive (obtained by, say, calling get_gio_stream()).
  * Unlike its fdstreams equivalent, this parameter does not have a
  * default value of 'true': this is partly to make it less likely
  * that a converter is passed to this argument by mistake (that would
  * not normally cause a compiler warning because GobjHandle has a
  * type conversion operator providing the underlying C object by
  * pointer, so GobjHandles are type convertible to pointers, and such
  * a pointer will in turn provide a type match with a bool argument);
  * and partly to maintain compatibility with the constructor's
  * interface, which has separate syntactic constraints.
  *
  * @param converter A converter (if any) to be attached to the GIO
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg() and seekg()
  * will no longer work (they will return pos_type(off_type(-1)).
  */
  void attach(const GobjHandle<GInputStream>& stream,
              bool manage,
	      const GobjHandle<GConverter>& converter = GobjHandle<GConverter>())
    {buf.attach_stream(stream, manage, converter); this->clear();}

 /**
  * Call g_input_stream_close() on the GIO stream at present attached
  * (if any), and release the underlying C++ streambuffer's reference
  * to that stream.  If the caller wants the GIO stream to survive the
  * call to this method (albeit in a closed state), the caller should,
  * before the call is made, keep a separate GobjHandle object which
  * references the stream.  If the close fails, the failbit will be
  * set with setstate(std::ios_base::failbit).  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @exception std::ios_base::failure This exception will be thrown if
  * an error arises on closing the stream and such an exception has
  * been required by a call to the exceptions() method of this class
  * (inherited from std::basic_ios<>).  No exception will be thrown if
  * exceptions() has not been called.
  */
  void close() {if (!buf.close_stream()) this->setstate(std::ios_base::failbit);}

  /**
  * Get the GIO input stream at present attached (if any), by
  * GobjHandle.  If no stream has been attached, this method will
  * return an empty GobjHandle object.  Retaining the return value
  * will cause the GIO input stream to survive the destruction of this
  * object.  The return value may be a different stream from the one
  * originally passed to this object's constructor or to attach().  It
  * will be different if a converter has been attached to it.  This
  * method does not throw.  This class does not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @return The GIO input stream at present attached, or an empty
  * GobjHandle object if none has been attached
  */
  GobjHandle<GInputStream> get_gio_stream() const {return buf.get_istream();}

 /**
  * Causes the underlying streambuffer to swap bytes in the incoming
  * text, so as to convert big endian text to little endian text, or
  * little endian text to big endian text.  It is called by the user
  * in response to finding a byte order marker (BOM) 0xfffe (UTF-16)
  * or 0xfffe0000 (UTF-32) as the first character of a newly opened
  * file/stream, or if the user knows by some other means that the
  * native endianness of the machine doing the reading differs from
  * the endianness of the file/stream being read.  This only has
  * effect on wide character streams (for example, a wgistream
  * object), and not the gistream narrow character stream.  This
  * method does not throw.  This class does not offer concurrent
  * access from multiple threads to the same stream object, and if
  * that is required users should provide their own synchronisation.
  *
  * @param swap 'true' if byte swapping is to be turned on, 'false' if
  * it is to be turned off.  This will affect all characters extracted
  * from the underlying streambuffer after this call is made.  If a
  * previously extracted character is to be putback(), it must be put
  * back before this function is called (or unget() should be called
  * instead) to avoid a putback mismatch, because this call will
  * byte-swap anything already in the buffers.  (Characters extracted
  * after the call to this method may be putback normally.)
  */
  void set_byteswap(bool swap) {buf.set_byteswap(swap);}

/**
 * This method indicates whether the attached GIO input stream
 * implements GSeekable, so that a call to tellg() or seekg() can
 * succeed.  Note that in the seekg(off_type off, ios_base::seekdir
 * dir) variant, on wide character streams the 'off' argument is
 * dimensioned as the number of wchar_t/char32_t/char16_t units not
 * the number of bytes (that is, it is bytes/sizeof(char_type)).  This
 * method does not throw.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return true if the attached GIO stream implements GSeekable,
 * otherwise false.  The result is only meaningful if a GIO stream has
 * been attached to this C++ stream object.
 */
  bool can_seek() const {return buf.can_seek();}

/**
 * This method reports the error status of any attached GIO input
 * stream, and is intended to be called where failbit has been set.
 * It can be useful for establishing, where that bit is set, whether
 * failbit indicates normal end-of-file or a conversion error on a
 * converting stream.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return NULL if no input stream is attached, or it is not in an
 * error state.  If an attached input stream is in an error state, say
 * because it is a converting input stream which has encountered a
 * conversion error, the most recent GError object emitted by a read
 * operation on it is returned.  Ownership of the return value is
 * retained, so if it is intended to be used after the next read
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_error() {return buf.is_input_error();}

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};



/**
 * @headerfile gstream.h c++-gtk-utils/gstream.h
 * @brief C++ input-output stream for GIO streams
 * @sa gstreams
 * @ingroup gstreams
 *
 * This class provides standard iostream services for GIO streams.
 */
template <class charT , class Traits = std::char_traits<charT> >
class basic_giostream : public std::basic_iostream<charT, Traits> {

  basic_gstreambuf<charT , Traits> buf;

public:
/**
 * This class cannot be copied.  The copy constructor is deleted.
 */
  basic_giostream(const basic_giostream&) = delete;

/**
 * This class cannot be copied.  The copy assignment operator is
 * deleted.
 */
  basic_giostream& operator=(const basic_giostream&) = delete;

 /**
  * The constructor taking a GIO input-output stream.  This class does
  * not offer concurrent access from multiple threads to the same
  * stream object, and if that is required users should provide their
  * own synchronisation.
  *
  * @param stream A GIO input-output stream to be attached.  If the
  * caller wants the GIO stream to survive this class's destruction or
  * a call to close() or attach(), the caller should keep a separate
  * GobjHandle object which references the stream (obtained by, say,
  * calling get_gio_io_stream()) and pass 'manage' as false.
  *
  * @param manage Whether the underlying streambuffer should call
  * g_io_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted, and is particularly relevant on output
  * streams because unless g_io_stream_close() is called, GIO may not
  * commit to disk - 'false' only makes sense if the caller keeps a
  * separate GobjHandle object which references the stream to keep it
  * alive (obtained by, say, calling get_gio_io_stream()).  Unlike its
  * fdstreams equivalent, this parameter does not have a default value
  * of 'true': this is partly to make it less likely that a converter
  * is passed to this argument by mistake (that would not normally
  * cause a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly because, given a GIOStream* p, the construction
  * \"Cgu::giostream str(Cgu::GobjHandle\<GIOStream\>(p));\" without
  * an additional argument or additional parentheses (or the use of
  * uniform initializer syntax using braces) would cause a compiler
  * error as it would be interpreted as a function declaration.
  *
  * @param input_converter A converter (if any) to be attached to the
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @param output_converter A converter (if any) to be attached to the
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This constructor will throw
  * std::bad_alloc if memory is exhausted and the system throws on
  * such exhaustion (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).  No other exception will
  * be thrown unless the constructor of std::basic_streambuf or
  * std::basic_iostream throws.
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg(), tellp(),
  * seekg() and seekp() will no longer work (they will return
  * pos_type(off_type(-1)).  If the stream to which a converter has
  * been attached represents a file on the file system (rather than a
  * socket), after a read has been made, no further write may be made
  * using the same GFileIOStream object.  These restrictions do not
  * apply to sockets (which are not seekable) so the use of converters
  * with input-output streams (GIOStream) should generally be
  * restricted to sockets.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_giostream(const GobjHandle<GIOStream>& stream,
		  bool manage,
		  const GobjHandle<GConverter>& input_converter = GobjHandle<GConverter>(),
		  const GobjHandle<GConverter>& output_converter = GobjHandle<GConverter>()):
                                 std::basic_iostream<charT, Traits>(0),
                                 buf(stream, manage, input_converter, output_converter) {
    this->rdbuf(&buf);  // std::basic_ios is a virtual base class
  }

 /**
  * With this constructor, the GIO input-output stream must be
  * attached later with the attach() method.  It will not throw unless
  * the constructor of std::basic_streambuf or std::basic_iostream
  * throws.  This class does not offer concurrent access from multiple
  * threads to the same stream object, and if that is required users
  * should provide their own synchronisation.
  */
  // using uniform initializer syntax here confuses doxygen
  basic_giostream() : std::basic_iostream<charT, Traits>(0) {
    this->rdbuf(&buf);  // std::basic_ios is a virtual base class
  }

 /**
  * Attach a new GIO input-output stream to this object (and close any
  * GIO stream at present managed by it).  If output buffering was
  * previously switched off, it is switched back on again.  In the
  * case of wide character input-output streams, it also switches off
  * byte swapping on input, if it was previously on.  If any stream
  * state flags were set (eofbit, failbit or badbit), they will be
  * cleared by a call to clear().  If this method closes a stream at
  * present managed by it and the close fails, failbit is not set and
  * no exception will be thrown.  Accordingly, if the user needs to
  * know whether there was an error in this method closing any managed
  * stream, she should call close() explicitly before calling this
  * method.  This class does not offer concurrent access from multiple
  * threads to the same stream object, and if that is required users
  * should provide their own synchronisation.
  *
  * @param stream A GIO input-output stream to be attached.  If the
  * caller wants the GIO stream to survive a subsequent call to
  * close() or attach() or this class's destruction, the caller should
  * keep a separate GobjHandle object which references the stream
  * (obtained by, say, calling get_gio_io_stream()) and pass 'manage'
  * as false.
  *
  * @param manage Whether the underlying streambuffer should call
  * g_io_stream_close() on the GIO stream in the streambuffer's
  * destructor or when another stream is attached.  Passing 'true' is
  * usually what is wanted, and is particularly relevant on output
  * streams because unless g_io_stream_close() is called, GIO may not
  * commit to disk - 'false' only makes sense if the caller keeps a
  * separate GobjHandle object which references the stream to keep it
  * alive (obtained by, say, calling get_gio_io_stream()).  Unlike its
  * fdstreams equivalent, this parameter does not have a default value
  * of 'true': this is partly to make it less likely that a converter
  * is passed to this argument by mistake (that would not normally
  * cause a compiler warning because GobjHandle has a type conversion
  * operator providing the underlying C object by pointer, so
  * GobjHandles are type convertible to pointers, and such a pointer
  * will in turn provide a type match with a bool argument); and
  * partly to maintain compatibility with the constructor's interface,
  * which has separate syntactic constraints.
  *
  * @param input_converter A converter (if any) to be attached to the
  * input stream (note that this does not affect the operation of
  * set_byteswap()).  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @param output_converter A converter (if any) to be attached to the
  * output stream.  The default value of an empty
  * GobjHandle<GConverter> object indicates no converter.
  *
  * @exception std::bad_alloc This method will throw std::bad_alloc if
  * memory is exhausted and the system throws on such exhaustion
  * (unless the library has been installed using the
  * \--with-glib-memory-slices-compat or
  * \--with-glib-memory-slices-no-compat configuration option, in
  * which case glib will terminate the program if it is unable to
  * obtain memory from the operating system).
  *
  * @note If a converter is provided, the stream will no longer be
  * seekable even if it otherwise would be, so tellg(), tellp(),
  * seekg() and seekp() will no longer work (they will return
  * pos_type(off_type(-1)).  If the stream to which a converter has
  * been attached represents a file on the file system (rather than a
  * socket), after a read has been made, no further write may be made
  * using the same GFileIOStream object.  These restrictions do not
  * apply to sockets (which are not seekable) so the use of converters
  * with input-output streams (GIOStream) should generally be
  * restricted to sockets.
  */
  void attach(const GobjHandle<GIOStream>& stream,
              bool manage,
	      const GobjHandle<GConverter>& input_converter = GobjHandle<GConverter>(),
	      const GobjHandle<GConverter>& output_converter = GobjHandle<GConverter>())
    {buf.attach_stream(stream, manage, input_converter, output_converter); this->clear();}

 /**
  * Call g_io_stream_close() on the GIO stream at present attached (if
  * any), and release the underlying C++ streambuffer's reference to
  * that stream.  If the caller wants the GIO stream to survive the
  * call to this method (albeit in a closed state), the caller should,
  * before the call is made, keep a separate GobjHandle object which
  * references the stream.  If the close fails, the failbit will be
  * set with setstate(std::ios_base::failbit).  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @exception std::ios_base::failure This exception will be thrown if
  * an error arises on closing the stream and such an exception has
  * been required by a call to the exceptions() method of this class
  * (inherited from std::basic_ios<>).  No exception will be thrown if
  * exceptions() has not been called.
  */
  void close() {if (!buf.close_stream()) this->setstate(std::ios_base::failbit);}

  /**
  * Get the GIO input-output stream at present attached (if any), by
  * GobjHandle.  If no stream has been attached, this method will
  * return an empty GobjHandle object.  Retaining the return value
  * will cause the GIO input-output stream to survive the destruction
  * of this object.  This method does not throw.  This class does not
  * offer concurrent access from multiple threads to the same stream
  * object, and if that is required users should provide their own
  * synchronisation.
  *
  * @return The GIO input-output stream at present attached, or an
  * empty GobjHandle object if none has been attached
  */
  GobjHandle<GIOStream> get_gio_io_stream() const {return buf.get_iostream();}

 /**
  * Get the underlying GIO output stream at present attached (if any),
  * by GobjHandle.  If none has been attached, this method will return
  * an empty GobjHandle object.  Retaining the return value will cause
  * the GIO output stream to survive the destruction of this object.
  * The return value may be a different stream from the one kept by
  * the GIOStream object passed to this object's constructor or to
  * attach().  It will be different if a converter has been attached
  * to it.  This method does not throw.  This class does not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The GIO output stream at present attached, or an empty
  * GobjHandle object if none has been attached
  */
  GobjHandle<GOutputStream> get_gio_output_stream() const {return buf.get_ostream();}

  /**
  * Get the GIO input stream at present attached (if any), by
  * GobjHandle.  If none has been attached, this method will return an
  * empty GobjHandle object.  Retaining the return value will cause
  * the GIO input stream to survive the destruction of this object.  The
  * return value may be a different stream from the one kept by the
  * GIOStream object passed to this object's constructor or to
  * attach().  It will be different if a converter has been attached
  * to it.  This method does not throw.  This class does not offer
  * concurrent access from multiple threads to the same stream object,
  * and if that is required users should provide their own
  * synchronisation.
  *
  * @return The GIO input stream at present attached, or an empty
  * GobjHandle object if none has been attached
  */
  GobjHandle<GInputStream> get_gio_input_stream() const {return buf.get_istream();}

 /**
  * Causes the underlying streambuffer to swap bytes in the incoming
  * text, so as to convert big endian text to little endian text, or
  * little endian text to big endian text.  It is called by the user
  * in response to finding a byte order marker (BOM) 0xfffe (UTF-16)
  * or 0xfffe0000 (UTF-32) as the first character of a newly opened
  * file/stream, or if the user knows by some other means that the
  * native endianness of the machine doing the reading differs from
  * the endianness of the file/stream being read.  This only has
  * effect on wide character streams for input (for example, a
  * wgiostream object), and not the giostream narrow character stream.
  * Note also that characters held for output are always outputted in
  * native endian format unless a GConverter object has been attached,
  * and this method does not affect that.  This method does not throw.
  * This class does not offer concurrent access from multiple threads
  * to the same stream object, and if that is required users should
  * provide their own synchronisation.
  *
  * @param swap 'true' if byte swapping for input is to be turned on,
  * 'false' if it is to be turned off.  This will affect all
  * characters extracted from the underlying streambuffer after this
  * call is made.  If a previously extracted character is to be
  * putback(), it must be put back before this function is called (or
  * unget() should be called instead) to avoid a putback mismatch,
  * because this call will byte-swap anything already in the buffers.
  * (Characters extracted after the call to this method may be putback
  * normally.)
  */
  void set_byteswap(bool swap) {buf.set_byteswap(swap);}

/**
 * This method converts the attached GIO input-output stream to an
 * unbuffered stream for output if 'buffered' is false, or back to a
 * buffered stream if buffering has previously been switched off and
 * 'buffered' is true.  Buffering is on by default for any newly
 * created giostream object and any newly attached GIO input-output
 * stream.  If buffering is turned off, all characters at present in
 * the buffers which are stored for output are flushed (but if writing
 * to a file which is being written over/replaced, output may not
 * appear in the destination until the GIO stream is closed).  This
 * method has no effect if no GIO input-output stream has yet been
 * attached.  Switching output buffering off is similar in effect to
 * setting the std::ios_base::unitbuf flag, except that switching
 * buffering off is slightly more efficient, and setting the
 * std::ios_base::unitbuf flag will not retain the automatic tying of
 * logical and actual file positions that occurs when output buffering
 * is switched off, as explained @ref GioRandomAccessAnchor "here".
 * This class does not offer concurrent access from multiple threads
 * to the same stream object, and if that is required users should
 * provide their own synchronisation.
 *
 * @param buffered 'false' if buffering for output is to be turned
 * off, 'true' if it is to be turned back on.
 *
 * @exception std::bad_alloc This method will throw std::bad_alloc if
 * 'buffered' is true, output buffering had previously been switched
 * off, memory is exhausted and the system throws on such exhaustion
 * (unless the library has been installed using the
 * \--with-glib-memory-slices-compat or
 * \--with-glib-memory-slices-no-compat configuration option, in which
 * case glib will terminate the program if it is unable to obtain
 * memory from the operating system).
 */
  void set_output_buffered(bool buffered) {buf.set_output_buffered(buffered);}

/**
 * This method indicates whether the attached GIO stream implements
 * GSeekable, so that a call to tellg(), tellp(), seekg() or seekp()
 * can succeed.  Note that in the seekg(off_type off,
 * ios_base::seekdir dir) and seekp(off_type off, ios_base::seekdir
 * dir) variants, on wide character streams the 'off' argument is
 * dimensioned as the number of wchar_t/char32_t/char16_t units not
 * the number of bytes (that is, it is bytes/sizeof(char_type)).  This
 * method does not throw.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return true if the attached GIO stream implements GSeekable,
 * otherwise false.  The result is only meaningful if a GIO stream has
 * been attached to this C++ stream object.
 */
  bool can_seek() const {return buf.can_seek();}

/**
 * This method reports the error status of any attached GIO output
 * stream, and is intended to be called where failbit or badbit has
 * been set.  It can be useful for interpreting conversion errors on
 * converting streams where one of those bits is set.  This class does
 * not offer concurrent access from multiple threads to the same
 * stream object, and if that is required users should provide their
 * own synchronisation.
 *
 * @return NULL if no output stream is attached, or it is not in an
 * error state.  If an attached output stream is in an error state,
 * say because it is a converting output stream which has encountered
 * a conversion error, the most recent GError object emitted by a
 * write operation on it is returned.  Ownership of the return value
 * is retained, so if it is intended to be used after the next write
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_output_error() {return buf.is_output_error();}

/**
 * This method reports the error status of any attached GIO input
 * stream, and is intended to be called where failbit has been set.
 * It can be useful for establishing, where that bit is set, whether
 * failbit indicates normal end-of-file or a conversion error on a
 * converting stream.  This class does not offer concurrent access
 * from multiple threads to the same stream object, and if that is
 * required users should provide their own synchronisation.
 *
 * @return NULL if no input stream is attached, or it is not in an
 * error state.  If an attached input stream is in an error state, say
 * because it is a converting input stream which has encountered a
 * conversion error, the most recent GError object emitted by a read
 * operation on it is returned.  Ownership of the return value is
 * retained, so if it is intended to be used after the next read
 * operation, it should be copied using g_error_copy().
 *
 * Since 2.0.5
 */
  GError* is_input_error() {return buf.is_input_error();}

/* Only has effect if --with-glib-memory-slices-compat or
 * --with-glib-memory-slices-no-compat option picked */
  CGU_GLIB_MEMORY_SLICES_FUNCS
};

/**
 * @defgroup gstreams gstreams
 */
/**
 * @typedef gstreambuf.
 * @brief C++ stream buffer for GIO streams for char type
 * @ingroup gstreams
 */
typedef basic_gstreambuf<char> gstreambuf;

/**
 * @typedef gistream.
 * @brief C++ input stream for GIO streams for char type
 * @anchor gistreamAnchor
 * @ingroup gstreams
 */
typedef basic_gistream<char> gistream;

/**
 * @typedef gostream.
 * @brief C++ output stream for GIO streams for char type
 * @anchor gostreamAnchor
 * @ingroup gstreams
 */
typedef basic_gostream<char> gostream;

/**
 * @typedef giostream.
 * @brief C++ input/output stream for GIO streams for char type
 * @anchor giostreamAnchor
 * @ingroup gstreams
 */
typedef basic_giostream<char> giostream;

/**
 * @typedef wgstreambuf.
 * @brief C++ stream buffer for GIO streams for wchar_t type
 * @ingroup gstreams
 */
typedef basic_gstreambuf<wchar_t> wgstreambuf;

/**
 * @typedef wgistream.
 * @brief C++ input stream for GIO streams for wchar_t type
 * @anchor wgistreamAnchor
 * @ingroup gstreams
 */
typedef basic_gistream<wchar_t> wgistream;

/**
 * @typedef wgostream.
 * @brief C++ output stream for GIO streams for wchar_t type
 * @anchor wgostreamAnchor
 * @ingroup gstreams
 */
typedef basic_gostream<wchar_t> wgostream;

/**
 * @typedef wgiostream.
 * @brief C++ input/output stream for GIO streams for wchar_t type
 * @anchor wgiostreamAnchor
 * @ingroup gstreams
 */
typedef basic_giostream<wchar_t> wgiostream;

/**
 * @typedef u16gstreambuf.
 * @brief C++ stream buffer for GIO streams for char16_t type
 * @ingroup gstreams
 */
typedef basic_gstreambuf<char16_t> u16gstreambuf;

/**
 * @typedef u16gistream.
 * @brief C++ input stream for GIO streams for char16_t type
 * @anchor u16gistreamAnchor
 * @ingroup gstreams
 */
typedef basic_gistream<char16_t> u16gistream;

/**
 * @typedef u16gostream.
 * @brief C++ output stream for GIO streams for char16_t type
 * @anchor u16gostreamAnchor
 * @ingroup gstreams
 */
typedef basic_gostream<char16_t> u16gostream;

/**
 * @typedef u16giostream.
 * @brief C++ input/output stream for GIO streams for char16_t type
 * @anchor u16giostreamAnchor
 * @ingroup gstreams
 */
typedef basic_giostream<char16_t> u16giostream;

/**
 * @typedef u32gstreambuf.
 * @brief C++ stream buffer for GIO streams for char32_t type
 * @ingroup gstreams
 */
typedef basic_gstreambuf<char32_t> u32gstreambuf;

/**
 * @typedef u32gistream.
 * @brief C++ input stream for GIO streams for char32_t type
 * @anchor u32gistreamAnchor
 * @ingroup gstreams
 */
typedef basic_gistream<char32_t> u32gistream;

/**
 * @typedef u32gostream.
 * @brief C++ output stream for GIO streams for char32_t type
 * @anchor u32gostreamAnchor
 * @ingroup gstreams
 */
typedef basic_gostream<char32_t> u32gostream;

/**
 * @typedef u32giostream.
 * @brief C++ input/output stream for GIO streams for char32_t type
 * @anchor u32giostreamAnchor
 * @ingroup gstreams
 */
typedef basic_giostream<char32_t> u32giostream;

} // namespace Cgu

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

#else
#warning gstreams are not available: glib >= 2.16.0 is required
#endif /*GLIB_CHECK_VERSION(2,16,0)*/

#endif /*CGU_GSTREAM_H*/
