2005/5/9

     
 

DeflateWriter.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_vfile/src/acdk/vfile/DeflateWriter.cpp,v 1.9 2005/02/05 10:45:33 kommer Exp $

#include <acdk.h>
#include "Config.h"
#include "DeflateWriter.h"
#include "zlib/zlib.h"
#include <acdk/lang/Math.h>
#include <acdk/io/IOException.h>

namespace acdk {
namespace vfile {

namespace {
const int BufferSize = 1024;
}

using acdk::io::AbstractFilterWriter;

DeflateWriter::DeflateWriter(IN(::acdk::io::RWriter) out)
: AbstractFilterWriter(out)
, _initialized(false)
, _inbuf(BufferSize)
, _outbuf(BufferSize)
, _inpos(0)
{
  memset(&_zstream, 0, sizeof(_zstream));
}

DeflateWriter::~DeflateWriter()
{
  if (_initialized)
    deflateEnd(&_zstream);
}

void 
DeflateWriter::write(byte c)
{
  byte b[1];
  b[0] = c;
  write(b, 0, 1);
}


void 
DeflateWriter::write(const byte* cstr, int offset, int len)
{
  cstr += offset;
  while (len > 0) 
  {
    if (_inpos == BufferSize)
      flushBuffer(Z_NO_FLUSH);
    int towrite = Math::min(len, BufferSize - _inpos);
    memcpy(_inbuf.data() + _inpos, cstr, towrite);
    len -= towrite;
    _inpos += towrite;
    
  }
}

void 
DeflateWriter::write(IN(RbyteArray) ch, int offset/* = 0*/, int len/* = -1*/)
{
  if (len == -1)
    len = ch->length() - offset;
  write(ch->data(), offset, len);
}


void 
DeflateWriter::flush()
{
  flushBuffer(Z_SYNC_FLUSH);
  _out->flush();
}




void 
DeflateWriter::close()
{
  flushBuffer(Z_FINISH);
  _out->flush();
  _out->close();
}


void 
DeflateWriter::init()
{
  int erg = deflateInit(&_zstream, Z_DEFAULT_COMPRESSION);
  
  if (erg != Z_OK) 
    THROW1_FQ(acdk::io::, IOException, RCS("Initializing zlib failed: ") + zError(erg));
  _zstream.next_in = _inbuf.data();
  _zstream.avail_in = _inpos;
  
  _initialized = true;
}

void 
DeflateWriter::flushBuffer(int flushtype)
{
  if (_initialized == false)
    init();
  
  _zstream.next_in = _inbuf.data();
  _zstream.avail_in = _inpos;
  int erg = Z_OK;
  while ((_zstream.avail_in > 0 && Z_FINISH != flushtype) || 
        (Z_FINISH == flushtype && erg == Z_OK))
  {
    _zstream.next_out = _outbuf.data();
    _zstream.avail_out = BufferSize;
    erg = deflate( &_zstream, flushtype );
    if (erg != Z_OK && erg != Z_STREAM_END) {
      THROW1_FQ(acdk::io::, IOException, RCS("error in deflating zlib: ") + zError(erg));
    }
    if (BufferSize - _zstream.avail_out > 0)
      _out->write(_outbuf.data(), 0, BufferSize - _zstream.avail_out);
  }
  _inpos = 0;
}

} // vfile
} // acdk