//
// aegis - project change supervisor
// Copyright (C) 1999, 2002-2006, 2008, 2011, 2012 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
#include
#ifndef Z_BUFSIZE
#ifdef MAXSEG_64K
#define Z_BUFSIZE 4096 // minimize memory usage for 16-bit DOS
#else
#define Z_BUFSIZE 16384
#endif
#endif
static int gzip_magic[2] = {0x1f, 0x8b}; // gzip magic header
void
output_filter_gzip::drop_dead(int err)
{
sub_context_ty sc;
sc.var_set_charstar("ERRNO", z_error(err));
sc.var_override("ERRNO");
sc.var_set_string("File_Name", output_filter::filename());
sc.fatal_intl(i18n("gzip $filename: $errno"));
}
//
// Outputs a long in LSB order to the given file
// (little endian)
//
void
output_filter_gzip::output_long_le(unsigned long x)
{
for (int n = 0; n < 4; n++)
{
deeper_fputc((unsigned char)x);
x >>= 8;
}
}
output_filter_gzip::~output_filter_gzip(void)
{
//
// Make sure all buffered data has been passed to our write_inner
// method.
//
flush();
//
// finish sending the compressed stream
//
stream.avail_in = 0; // should be zero already anyway
if (stream.avail_out == 0)
{
deeper_write(outbuf, Z_BUFSIZE);
stream.next_out = outbuf;
stream.avail_out = Z_BUFSIZE;
}
for (;;)
{
int err = deflate(&stream, Z_FINISH);
if (err < 0)
drop_dead(err);
uInt len = Z_BUFSIZE - stream.avail_out;
if (!len)
break;
deeper_write(outbuf, len);
stream.next_out = outbuf;
stream.avail_out = Z_BUFSIZE;
}
//
// and the trailer
//
output_long_le(crc);
output_long_le(stream.total_in);
//
// Clean up any resources we were using.
//
if (stream.state != NULL)
deflateEnd(&stream);
delete [] outbuf;
outbuf = 0;
}
output_filter_gzip::output_filter_gzip(const output::pointer &a_deeper) :
output_filter(a_deeper),
outbuf(new Byte [Z_BUFSIZE]),
crc(0),
pos(0),
bol(true)
{
crc = crc32(0L, Z_NULL, 0);
stream.avail_in = 0;
stream.avail_out = 0;
stream.next_in = NULL;
stream.next_out = NULL;
stream.opaque = (voidpf)0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
//
// Set the parameters for the compression.
// Note: windowBits is passed < 0 to suppress zlib header.
//
int err =
deflateInit2
(
&stream,
Z_BEST_COMPRESSION, // level
Z_DEFLATED, // method
-MAX_WBITS, // windowBits
DEF_MEM_LEVEL, // memLevel
Z_DEFAULT_STRATEGY // strategy
);
if (err != Z_OK)
drop_dead(err);
stream.next_out = outbuf;
stream.avail_out = Z_BUFSIZE;
//
// Write a very simple .gz header:
//
deeper_fputc(gzip_magic[0]);
deeper_fputc(gzip_magic[1]);
deeper_fputc(Z_DEFLATED);
deeper_fputc(0); // flags
output_long_le(0L); // time
deeper_fputc(0); // xflags
deeper_fputc(3); // always use unix OS_CODE
}
output::pointer
output_filter_gzip::create(const output::pointer &a_deeper)
{
return pointer(new output_filter_gzip(a_deeper));
}
long
output_filter_gzip::ftell_inner(void)
const
{
return pos;
}
void
output_filter_gzip::write_inner(const void *buf, size_t len)
{
if (len > 0)
bol = (((const char *)buf)[len - 1] == '\n');
stream.next_in = (Bytef *)buf;
stream.avail_in = len;
while (stream.avail_in != 0)
{
if (stream.avail_out == 0)
{
deeper_write(outbuf, Z_BUFSIZE);
stream.next_out = outbuf;
stream.avail_out = Z_BUFSIZE;
}
int err = deflate(&stream, Z_NO_FLUSH);
if (err != Z_OK)
drop_dead(err);
}
crc = crc32(crc, (Bytef *)buf, len);
pos += len;
}
void
output_filter_gzip::end_of_line_inner(void)
{
if (!bol)
write_inner("\n", 1);
}
nstring
output_filter_gzip::type_name(void)
const
{
return ("gzip " + output_filter::type_name());
}
// vim: set ts=8 sw=4 et :