/* Compression efun stuff. * Started Wed Mar 21 01:52:25 PST 2001 * by David Bennett (ddt@discworld.imaginary.com) */ #ifdef LATTICE #include "/lpc_incl.h" #include "/file.h" #include "/efun_protos.h" #else #include "../lpc_incl.h" #include "../file.h" #include "../efun_protos.h" #endif #include <zlib.h> #define GZ_EXTENSION ".gz" #define COMPRESS_BUF_SIZE 8096 #ifdef F_COMPRESS_FILE void f_compress_file PROT((void)) { int read; int len; int num_arg = st_num_arg; char* input_file; char* output_file; char* real_input_file; char* real_output_file; gzFile out_file; FILE* in_file; char buf[4096]; /* Not a string? Error! */ if ((sp - num_arg + 1)->type != T_STRING) { pop_n_elems(num_arg); push_number(0); return ; } input_file = (sp - num_arg + 1)->u.string; if (num_arg == 2) { if (((sp - num_arg + 2)->type != T_STRING)) { pop_n_elems(num_arg); push_number(0); return ; } output_file = (sp - num_arg + 2)->u.string; } else { len = strlen(input_file); if (!strcmp(input_file + len - strlen(GZ_EXTENSION), GZ_EXTENSION)) { /* Already compressed... */ pop_n_elems(num_arg); push_number(0); return ; } output_file = new_string(strlen(input_file) + strlen(GZ_EXTENSION), "compress_file"); strcpy(output_file, input_file); strcat(output_file, GZ_EXTENSION); } real_output_file = check_valid_path(output_file, current_object, "compress_file", 1); if (!real_output_file) { pop_n_elems(num_arg); push_number(0); return ; } /* Copy it into our little buffer. */ strcpy(output_file, real_output_file); real_input_file = check_valid_path(input_file, current_object, "compress_file", 0); if (!real_input_file) { pop_n_elems(num_arg); push_number(0); return ; } in_file = fopen(real_input_file, "r"); if (!in_file) { pop_n_elems(num_arg); push_number(0); return ; } out_file = gzopen(output_file, "w"); if (!out_file) { fclose(in_file); pop_n_elems(num_arg); push_number(0); return ; } do { read = fread(buf, 1, 4096, in_file); gzwrite(out_file, buf, read); } while (read == 4096); fclose(in_file); gzclose(out_file); unlink(real_input_file); if (num_arg != 2) { FREE_MSTR(output_file); } pop_n_elems(num_arg); push_number(1); } #endif #ifdef F_UNCOMPRESS_FILE void f_uncompress_file PROT((void)) { int read; int len; int num_arg = st_num_arg; char* input_file; char* output_file; char* real_input_file; char* real_output_file; FILE* out_file; gzFile in_file; char buf[4096]; /* Not a string? Error! */ if ((sp - num_arg + 1)->type != T_STRING) { pop_n_elems(num_arg); push_number(0); return ; } input_file = (sp - num_arg + 1)->u.string; if (num_arg == 2) { if (((sp - num_arg + 2)->type != T_STRING)) { pop_n_elems(num_arg); push_number(0); return ; } output_file = (sp - num_arg + 2)->u.string; } else { len = strlen(input_file); if (strcmp(input_file + len - strlen(GZ_EXTENSION), GZ_EXTENSION)) { /* Not compressed... */ pop_n_elems(num_arg); push_number(0); return ; } output_file = new_string(strlen(input_file), "compress_file"); strcpy(output_file, input_file); output_file[len - strlen(GZ_EXTENSION)] = 0; } real_output_file = check_valid_path(output_file, current_object, "compress_file", 1); if (!real_output_file) { pop_n_elems(num_arg); push_number(0); return ; } /* Copy it into our little buffer. */ strcpy(output_file, real_output_file); real_input_file = check_valid_path(input_file, current_object, "compress_file", 0); if (!real_input_file) { pop_n_elems(num_arg); push_number(0); return ; } in_file = gzopen(real_input_file, "r"); if (!in_file) { gzclose(in_file); pop_n_elems(num_arg); push_number(0); return ; } out_file = fopen(output_file, "w"); if (!out_file) { fclose(out_file); pop_n_elems(num_arg); push_number(0); return ; } do { read = gzread(in_file, buf, 4096); fwrite(buf, 1, read, out_file); } while (read == 4096); gzclose(in_file); fclose(out_file); unlink(real_input_file); if (num_arg != 2) { FREE_MSTR(output_file); } pop_n_elems(num_arg); push_number(1); } #endif #ifdef F_COMPRESS void f_compress PROT((void)) { unsigned char* buffer; unsigned char* input; int size; buffer_t* real_buffer; uLongf new_size; if (sp->type == T_STRING) { size = SVALUE_STRLEN(sp); input = (unsigned char*)sp->u.string; } else if (sp->type == T_BUFFER) { size = sp->u.buf->size; input = sp->u.buf->item; } else { pop_n_elems(st_num_arg); push_undefined(); return ; } new_size = size; /* Make it a little larger as specified in the docs. */ buffer = (unsigned char*)DXALLOC(size * 101 / 100 + 12, TAG_TEMPORARY, "compress"); compress(buffer, &new_size, input, size); /* Shrink it down. */ pop_n_elems(st_num_arg); real_buffer = allocate_buffer(new_size); write_buffer(real_buffer, 0, (char *)buffer, new_size); FREE(buffer); push_buffer(real_buffer); } #endif #ifdef F_UNCOMPRESS static void* zlib_alloc(void* opaque, unsigned int items, unsigned int size) { return CALLOC(items, size); } static void zlib_free(void* opaque, void* address) { FREE(address); } void f_uncompress PROT((void)) { z_stream* compress; unsigned char compress_buf[COMPRESS_BUF_SIZE]; unsigned char* output_data = NULL; int len; int pos; buffer_t* buffer; int ret; if (sp->type == T_BUFFER) { buffer = sp->u.buf; } else { pop_n_elems(st_num_arg); push_undefined(); return ; } compress = (z_stream *) DXALLOC(sizeof(z_stream), TAG_INTERACTIVE, "start_compression"); compress->next_in = buffer->item; compress->avail_in = buffer->size; compress->next_out = compress_buf; compress->avail_out = COMPRESS_BUF_SIZE; compress->zalloc = zlib_alloc; compress->zfree = zlib_free; compress->opaque = NULL; if (inflateInit(compress) != Z_OK) { FREE(compress); pop_n_elems(st_num_arg); push_undefined(); return ; } len = 0; output_data = NULL; do { ret = inflate(compress, 0); if (ret == Z_OK) { pos = len; len += COMPRESS_BUF_SIZE - compress->avail_out; if (!output_data) { output_data = (unsigned char*)DXALLOC(len, TAG_TEMPORARY, "uncompress"); } else { output_data = REALLOC(output_data, len); } memcpy(output_data + pos, compress_buf, len - pos); compress->next_out = compress_buf; compress->avail_out = COMPRESS_BUF_SIZE; } } while (ret == Z_OK); inflateEnd(compress); pop_n_elems(st_num_arg); if (ret == Z_STREAM_END) { buffer = allocate_buffer(len); memcpy(buffer->item, output_data, len); FREE(output_data); push_buffer(buffer); } else { push_undefined(); } } #endif