/******************************************************************************
 * $LastChangedDate: 2010-01-24 20:49:54 -0500 (Sun, 24 Jan 2010) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   gzstream : C++ iostream classes wrapping the zlib compression library
 * @remarks See stream_zlib.cc
 *//*
 * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *------------------------------------------------------------------------------
 * Copyright (C) 2001  Deepak Bandyopadhyay, Lutz Kettner
 * License: LGPL (GNU Lesser General Public License 2.1)
 * http://www.cs.unc.edu/Research/compgeom/gzstream/
 ******************************************************************************/

#if COMPILE_ZLIB
#ifndef STREAM_ZLIB_HH
#define STREAM_ZLIB_HH 1

#include <iostream>
#include <fstream>
#include <zlib.h>

namespace base {

////////////////////////////////////////////////////////////////////////////////
/// @brief Internal classes to implement gzstream. See below for user classes.
///
class gzstreambuf : public std::streambuf {
private:
    CLASS_CONST int bufferSize = 47+256;    // size of data buff
    // totals 512 bytes under g++ for igzstream at the end.

    gzFile           file;               // file handle for compressed file
    char             buffer[bufferSize]; // data buffer
    char             opened;             // open/close state of stream
    int              mode;               // I/O mode

    int flush_buffer();
public:
    gzstreambuf() : opened(0) {
        setp( buffer, buffer + (bufferSize-1));
        setg( buffer + 4,     // beginning of putback area
              buffer + 4,     // read position
              buffer + 4);    // end position      
        // ASSERT: both input & output capabilities will not be used together
    }
    int is_open() { return opened; }
    gzstreambuf* open( const char* name, int open_mode);
    gzstreambuf* close();
    ~gzstreambuf() { close(); }
    
    virtual int     overflow( int c = EOF);
    virtual int     underflow();
    virtual int     sync();
};

////////////////////////////////////////////////////////////////////////////////
/// @brief Internal classes to implement gzstream. See below for user classes.
///
class gzstreambase : virtual public std::ios {
protected:
    gzstreambuf buf;
public:
    gzstreambase() { init(&buf); }
    gzstreambase( const char* name, int open_mode);
    ~gzstreambase();
    void open( const char* name, int open_mode);
    void close();
    gzstreambuf* rdbuf() { return &buf; }
};

////////////////////////////////////////////////////////////////////////////////
/// @brief C++ stream class (input) to decompress using zlib/gzip.
/// User classes.  Use igzstream and ogzstream analogously to ifstream and
/// ofstream respectively.  They read and write files based on the gz* 
/// function interface of the zlib.  Files are compatible with gzip compression.
/// http://www.cs.unc.edu/Research/compgeom/gzstream/
///
class igzstream : public gzstreambase, public std::istream {
public:
    igzstream() : std::istream( &buf) {} 
    igzstream( const char* name, int open_mode = std::ios::in)
        : gzstreambase( name, open_mode), std::istream( &buf) {}  
    gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); }
    void open( const char* name, int open_mode = std::ios::in) {
        gzstreambase::open( name, open_mode);
    }
};

////////////////////////////////////////////////////////////////////////////////
/// @brief C++ stream class (output) to compress using zlib/gzip.
/// http://www.cs.unc.edu/Research/compgeom/gzstream/
///
class ogzstream : public gzstreambase, public std::ostream {
public:
    ogzstream() : std::ostream( &buf) {}
    ogzstream( const char* name, int mode = std::ios::out)
        : gzstreambase( name, mode), std::ostream( &buf) {}  
    gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); }
    void open( const char* name, int open_mode = std::ios::out) {
        gzstreambase::open( name, open_mode);
    }
};

} // namespace base

#endif // STREAM_ZLIB_HH
#endif // COMPILE_ZLIB
