#include "config.h"
#include <zlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef STDC_HEADERS
#include <stdlib.h>
#endif
#include <sys/types.h>
#include "jartool.h"
#include "pushback.h"
#include "compress.h"
#include "shift.h"
int write_data (int, void *, size_t, struct zipentry *);
extern int seekable;
extern off_t end_of_entries;
static z_stream zs;
void init_compression(){
memset(&zs, 0, sizeof(z_stream));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
if(deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
9, Z_DEFAULT_STRATEGY) != Z_OK){
fprintf(stderr, "Error initializing deflation!\n");
exit(1);
}
}
int
write_data (int fd, void *buf, size_t len, struct zipentry *ze)
{
#ifdef WITH_SHIFT_DOWN
struct zipentry *next = NULL;
off_t here = lseek (fd, 0, SEEK_CUR);
if (ze)
{
next = ze->next_entry;
if (next && here + len >= next->offset)
{
if (shift_down (fd, next->offset, (here + len) - next->offset, next))
{
perror ("can't expand file");
exit (1);
}
}
}
#endif
return write (fd, buf, len);
}
int compress_file(int in_fd, int out_fd, struct zipentry *ze,
struct zipentry *existing)
{
Bytef in_buff[RDSZ];
Bytef out_buff[RDSZ];
unsigned int rdamt, wramt;
unsigned long tr = 0;
int rtval;
rdamt = 0;
zs.avail_in = 0;
zs.next_in = in_buff;
zs.next_out = out_buff;
zs.avail_out = (uInt)RDSZ;
ze->crc = crc32(0L, Z_NULL, 0);
for(; ;){
if(zs.avail_in == 0 && zs.avail_out > 0){
if((rtval = read(in_fd, in_buff, RDSZ)) == 0)
break;
if(rtval == -1){
perror("read");
exit(1);
}
rdamt = rtval;
ze->crc = crc32(ze->crc, in_buff, rdamt);
tr += rdamt;
zs.next_in = in_buff;
zs.avail_in = rdamt;
}
if(deflate(&zs, 0) != Z_OK){
fprintf(stderr, "Error deflating! %s:%d\n", __FILE__, __LINE__);
exit(1);
}
if(zs.avail_out == 0){
if (write_data (out_fd, out_buff, RDSZ, existing) != RDSZ)
{
perror("write");
exit(1);
}
zs.next_out = out_buff;
zs.avail_out = (uInt)RDSZ;
}
}
if(zs.avail_out < RDSZ){
wramt = RDSZ - zs.avail_out;
if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
{
perror("write");
exit(1);
}
zs.next_out = out_buff;
zs.avail_out = (uInt)RDSZ;
}
while(deflate(&zs, Z_FINISH) == Z_OK){
wramt = RDSZ - zs.avail_out;
if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
{
perror("write");
exit(1);
}
zs.next_out = out_buff;
zs.avail_out = (uInt)RDSZ;
}
if(zs.avail_out != RDSZ){
wramt = RDSZ - zs.avail_out;
if (write_data (out_fd, out_buff, wramt, existing) != (int)wramt)
{
perror("write");
exit(1);
}
}
ze->usize = (ub4)zs.total_in;
ze->csize = (ub4)zs.total_out;
if(deflateReset(&zs) != Z_OK){
fprintf(stderr, "Error resetting deflation\n");
exit(1);
}
return 0;
}
void end_compression(){
int rtval;
if((rtval = deflateEnd(&zs)) != Z_OK && rtval != Z_DATA_ERROR){
fprintf(stderr, "Error calling deflateEnd\n");
fprintf(stderr, "error: (%d) %s\n", rtval, zs.msg);
exit(1);
}
}
void init_inflation(){
memset(&zs, 0, sizeof(z_stream));
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
if(inflateInit2(&zs, -15) != Z_OK){
fprintf(stderr, "Error initializing deflation!\n");
exit(1);
}
}
int inflate_file(pb_file *pbf, int out_fd, struct zipentry *ze){
Bytef in_buff[RDSZ];
Bytef out_buff[RDSZ];
unsigned int rdamt;
int rtval;
ub4 crc = 0;
zs.avail_in = 0;
crc = crc32(crc, NULL, 0);
for(;;){
if(zs.avail_in == 0){
if((rdamt = pb_read(pbf, in_buff, RDSZ)) == 0)
break;
else if((int)rdamt < 0){
perror("read");
exit(1);
}
#ifdef DEBUG
printf("%d bytes read\n", rdamt);
#endif
zs.next_in = in_buff;
zs.avail_in = rdamt;
}
zs.next_out = out_buff;
zs.avail_out = RDSZ;
if((rtval = inflate(&zs, 0)) != Z_OK){
if(rtval == Z_STREAM_END){
#ifdef DEBUG
printf("end of stream\n");
#endif
if(zs.avail_out != RDSZ){
crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
if(out_fd >= 0)
if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
(int)(RDSZ - zs.avail_out)){
perror("write");
exit(1);
}
}
break;
} else {
fprintf(stderr, "Error inflating file! (%d)\n", rtval);
exit(1);
}
} else {
if(zs.avail_out != RDSZ){
crc = crc32(crc, out_buff, (RDSZ - zs.avail_out));
if(out_fd >= 0)
if(write(out_fd, out_buff, (RDSZ - zs.avail_out)) !=
(int)(RDSZ - zs.avail_out)){
perror("write");
exit(1);
}
zs.next_out = out_buff;
zs.avail_out = RDSZ;
}
}
}
#ifdef DEBUG
printf("done inflating\n");
#endif
#ifdef DEBUG
printf("%d bytes left over\n", zs.avail_in);
#endif
#ifdef DEBUG
printf("CRC is %x\n", crc);
#endif
ze->crc = crc;
pb_push(pbf, zs.next_in, zs.avail_in);
ze->usize = zs.total_out;
inflateReset(&zs);
return 0;
}
static void report_str_error(int val) {
switch(val) {
case Z_STREAM_END:
break;
case Z_NEED_DICT:
fprintf(stderr, "Need a dictionary?\n");
exit(1);
case Z_DATA_ERROR:
fprintf(stderr, "Z_DATA_ERROR\n");
exit(1);
case Z_STREAM_ERROR:
fprintf(stderr, "Z_STREAM_ERROR\n");
exit(1);
case Z_MEM_ERROR:
fprintf(stderr, "Z_MEM_ERROR\n");
exit(1);
case Z_BUF_ERROR:
fprintf(stderr, "Z_BUF_ERROR\n");
exit(1);
case Z_OK:
break;
default:
fprintf(stderr, "Unknown behavior from inflate\n");
exit(1);
}
}
static Bytef *ez_inflate_str(pb_file *pbf, ub4 csize, ub4 usize) {
Bytef *out_buff;
Bytef *in_buff;
unsigned int rdamt;
if((zs.next_in = in_buff = (Bytef *) malloc(csize))) {
if((zs.next_out = out_buff = (Bytef *) malloc(usize + 1))) {
if((rdamt = pb_read(pbf, zs.next_in, csize)) == csize) {
zs.avail_in = csize;
zs.avail_out = usize;
report_str_error(inflate(&zs, 0));
free(in_buff);
inflateReset(&zs);
out_buff[usize] = '\0';
}
else {
fprintf(stderr, "Read failed on input file.\n");
fprintf(stderr, "Tried to read %u but read %u instead.\n", csize, rdamt);
free(in_buff);
free(out_buff);
exit(1);
}
}
else {
fprintf(stderr, "Malloc of out_buff failed.\n");
fprintf(stderr, "Error: %s\n", strerror(errno));
free(in_buff);
exit(1);
}
}
else {
fprintf(stderr, "Malloc of in_buff failed.\n");
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(1);
}
return out_buff;
}
static Bytef *hrd_inflate_str(pb_file *pbf, ub4 *csize, ub4 *usize) {
Bytef *out_buff;
Bytef *tmp;
Bytef in_buff[RDSZ];
unsigned int rdamt;
int i;
int zret;
i = 1;
out_buff = NULL;
zret = Z_OK;
while(zret != Z_STREAM_END && (rdamt = pb_read(pbf, in_buff, RDSZ)))
{
zs.avail_in = rdamt;
zs.avail_out = 0;
zs.next_in = in_buff;
do {
if((tmp = (Bytef *) realloc(out_buff, (RDSZ * i) + 1))) {
out_buff = tmp;
zs.next_out = &(out_buff[(RDSZ * (i - 1)) - zs.avail_out]);
zs.avail_out += RDSZ;
i++;
}
else {
fprintf(stderr, "Realloc of out_buff failed.\n");
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(1);
}
} while((zret = inflate(&zs, 0)) == Z_OK);
report_str_error(zret);
}
pb_push(pbf, zs.next_in, zs.avail_in);
out_buff[(RDSZ * (i - 1)) - zs.avail_out] = '\0';
*usize = zs.total_out;
*csize = zs.total_in;
inflateReset(&zs);
return out_buff;
}
Bytef *inflate_string(pb_file *pbf, ub4 *csize, ub4 *usize) {
Bytef *ret_buf;
if(*csize && *usize) ret_buf = ez_inflate_str(pbf, *csize, *usize);
else ret_buf = hrd_inflate_str(pbf, csize, usize);
return ret_buf;
}