diff --git a/development/scons/scons_manifest.py b/development/scons/scons_manifest.py index f5519e3fc6..e06d915d88 100644 --- a/development/scons/scons_manifest.py +++ b/development/scons/scons_manifest.py @@ -310,6 +310,7 @@ src_support_header_files = Split(''' environment.h filetools.h fs_extras.h + gzstream.h limited_stack.h lstrings.h lyxalgo.h @@ -347,6 +348,7 @@ src_support_files = Split(''' environment.cpp filetools.cpp fs_extras.cpp + gzstream.cpp getcwd.cpp kill.cpp lstrings.cpp diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 6339ab3776..d55b596147 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -68,15 +68,13 @@ #include "support/lyxalgo.h" #include "support/filetools.h" #include "support/fs_extras.h" +#include "support/gzstream.h" #include "support/lyxlib.h" #include "support/os.h" #include "support/Path.h" #include "support/textutils.h" #include "support/convert.h" -#include -#include -#include #include #include #include @@ -137,7 +135,6 @@ using support::trim; namespace Alert = frontend::Alert; namespace os = support::os; namespace fs = boost::filesystem; -namespace io = boost::iostreams; namespace { @@ -813,7 +810,7 @@ bool Buffer::writeFile(FileName const & fname) const bool retval = false; if (params().compressed) { - io::filtering_ostream ofs(io::gzip_compressor() | io::file_sink(fname.toFilesystemEncoding())); + gz::ogzstream ofs(fname.toFilesystemEncoding().c_str(), ios::out|ios::trunc); if (!ofs) return false; diff --git a/src/Lexer.cpp b/src/Lexer.cpp index 38465f92ed..f9146a296b 100644 --- a/src/Lexer.cpp +++ b/src/Lexer.cpp @@ -19,18 +19,14 @@ #include "support/convert.h" #include "support/filetools.h" +#include "support/gzstream.h" #include "support/lstrings.h" #include "support/lyxalgo.h" #include "support/types.h" #include "support/unicode.h" -#include -#include -#include #include -namespace io = boost::iostreams; - #include #include #include @@ -110,7 +106,7 @@ public: std::filebuf fb_; /// gz_ is only used to open files, the stream is accessed through is. - io::filtering_istreambuf gz_; + gz::gzstreambuf gz_; /// the stream that we use. std::istream is; @@ -261,19 +257,17 @@ bool Lexer::Pimpl::setFile(FileName const & filename) if (format == "gzip" || format == "zip" || format == "compress") { LYXERR(Debug::LYXLEX) << "lyxlex: compressed" << endl; - // The check only outputs a debug message, because it triggers // a bug in compaq cxx 6.2, where is_open() returns 'true' for // a fresh new filebuf. (JMarc) - if (!gz_.empty() || istream::off_type(is.tellg()) > -1) - LYXERR(Debug::LYXLEX) << "Error in Lexer::setFile: " + if (gz_.is_open() || istream::off_type(is.tellg()) > -1) + lyxerr[Debug::LYXLEX] << "Error in LyXLex::setFile: " "file or stream already set." << endl; - gz_.push(io::gzip_decompressor()); - gz_.push(io::file_source(filename.toFilesystemEncoding())); + gz_.open(filename.toFilesystemEncoding().c_str(), ios::in); is.rdbuf(&gz_); name = filename.absFilename(); lineno = 0; - return gz_.component(1)->is_open() && is.good(); + return gz_.is_open() && is.good(); } else { LYXERR(Debug::LYXLEX) << "lyxlex: UNcompressed" << endl; diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 598c3fb996..f056420900 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -51,6 +51,8 @@ libsupport_la_SOURCES = \ fs_extras.cpp \ fs_extras.h \ getcwd.cpp \ + gzstream.cpp \ + gzstream.h \ kill.cpp \ limited_stack.h \ lstrings.cpp \ diff --git a/src/support/gzstream.cpp b/src/support/gzstream.cpp new file mode 100644 index 0000000000..13013abdc0 --- /dev/null +++ b/src/support/gzstream.cpp @@ -0,0 +1,169 @@ +// ============================================================================ +// gzstream, C++ iostream classes wrapping the zlib compression library. +// Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner +// +// 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 along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// ============================================================================ +// +// File : gzstream.C +// Revision : $Revision: 1.4 $ +// Revision_date : $Date: 2005/04/26 10:30:24 $ +// Author(s) : Deepak Bandyopadhyay, Lutz Kettner +// +// Standard streambuf implementation following Nicolai Josuttis, "The +// Standard C++ Library". +// ============================================================================ + +#include + +#include "gzstream.h" +#include +#ifdef HAVE_STRING_H +# include // for memcpy +#endif + +#ifdef GZSTREAM_NAMESPACE +namespace GZSTREAM_NAMESPACE { +#endif + +// ---------------------------------------------------------------------------- +// Internal classes to implement gzstream. See header file for user classes. +// ---------------------------------------------------------------------------- + +// -------------------------------------- +// class gzstreambuf: +// -------------------------------------- + +gzstreambuf* gzstreambuf::open( const char* name, int open_mode) { + if ( is_open()) + return (gzstreambuf*)0; + mode = open_mode; + // no append nor read/write mode + if ((mode & std::ios::ate) || (mode & std::ios::app) + || ((mode & std::ios::in) && (mode & std::ios::out))) + return (gzstreambuf*)0; + char fmode[10]; + char* fmodeptr = fmode; + if ( mode & std::ios::in) + *fmodeptr++ = 'r'; + else if ( mode & std::ios::out) + *fmodeptr++ = 'w'; + *fmodeptr++ = 'b'; + *fmodeptr = '\0'; + file = gzopen( name, fmode); + if (file == 0) + return (gzstreambuf*)0; + opened = 1; + return this; +} + +gzstreambuf * gzstreambuf::close() { + if ( is_open()) { + sync(); + opened = 0; + if ( gzclose( file) == Z_OK) + return this; + } + return (gzstreambuf*)0; +} + +int gzstreambuf::underflow() { // used for input buffer only + if ( gptr() && ( gptr() < egptr())) + return * reinterpret_cast( gptr()); + + if ( ! (mode & std::ios::in) || ! opened) + return EOF; + // Josuttis' implementation of inbuf + int n_putback = gptr() - eback(); + if ( n_putback > 4) + n_putback = 4; + memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback); + + int num = gzread( file, buffer+4, bufferSize-4); + if (num <= 0) // ERROR or EOF + return EOF; + + // reset buffer pointers + setg( buffer + (4 - n_putback), // beginning of putback area + buffer + 4, // read position + buffer + 4 + num); // end of buffer + + // return next character + return * reinterpret_cast( gptr()); +} + +int gzstreambuf::flush_buffer() { + // Separate the writing of the buffer from overflow() and + // sync() operation. + int w = pptr() - pbase(); + if ( gzwrite( file, pbase(), w) != w) + return EOF; + pbump( -w); + return w; +} + +int gzstreambuf::overflow( int c) { // used for output buffer only + if ( ! ( mode & std::ios::out) || ! opened) + return EOF; + if (c != EOF) { + *pptr() = c; + pbump(1); + } + if ( flush_buffer() == EOF) + return EOF; + return c; +} + +int gzstreambuf::sync() { + // Changed to use flush_buffer() instead of overflow( EOF) + // which caused improper behavior with std::endl and flush(), + // bug reported by Vincent Ricard. + if ( pptr() && pptr() > pbase()) { + if ( flush_buffer() == EOF) + return -1; + } + return 0; +} + +// -------------------------------------- +// class gzstreambase: +// -------------------------------------- + +gzstreambase::gzstreambase( const char* name, int mode) { + init( &buf); + open( name, mode); +} + +gzstreambase::~gzstreambase() { + buf.close(); +} + +void gzstreambase::open( const char* name, int open_mode) { + if ( ! buf.open( name, open_mode)) + clear( rdstate() | std::ios::badbit); +} + +void gzstreambase::close() { + if ( buf.is_open()) + if ( ! buf.close()) + clear( rdstate() | std::ios::badbit); +} + +#ifdef GZSTREAM_NAMESPACE +} // namespace GZSTREAM_NAMESPACE +#endif + +// ============================================================================ +// EOF // diff --git a/src/support/gzstream.h b/src/support/gzstream.h new file mode 100644 index 0000000000..858784dae9 --- /dev/null +++ b/src/support/gzstream.h @@ -0,0 +1,123 @@ +// ============================================================================ +// gzstream, C++ iostream classes wrapping the zlib compression library. +// Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner +// +// 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 along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// ============================================================================ +// +// File : gzstream.h +// Revision : $Revision: 1.2 $ +// Revision_date : $Date: 2005/04/26 10:30:24 $ +// Author(s) : Deepak Bandyopadhyay, Lutz Kettner +// +// Standard streambuf implementation following Nicolai Josuttis, "The +// Standard C++ Library". +// ============================================================================ + +#ifndef GZSTREAM_H +#define GZSTREAM_H 1 + +// standard C++ with new header file names and std:: namespace +#include +#include +#include + +// For LyX +#define GZSTREAM_NAMESPACE gz + +#ifdef GZSTREAM_NAMESPACE +namespace GZSTREAM_NAMESPACE { +#endif + +// ---------------------------------------------------------------------------- +// Internal classes to implement gzstream. See below for user classes. +// ---------------------------------------------------------------------------- + +class gzstreambuf : public std::streambuf { +private: + static 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(); +}; + +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; } +}; + +// ---------------------------------------------------------------------------- +// 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. +// ---------------------------------------------------------------------------- + +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); + } +}; + +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); + } +}; + +#ifdef GZSTREAM_NAMESPACE +} // namespace GZSTREAM_NAMESPACE +#endif + +#endif // GZSTREAM_H +// ============================================================================ +// EOF //