#if defined(JAVA)

/*
 * @(#)zip.c	1.15 97/01/27
 * 
 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 * 
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
 * THIS SOFTWARE OR ITS DERIVATIVES.
 * 
 * CopyrightVersion 1.1_beta
 * 
 */

/*
 * Native method support for compression classes.
 */

#include "sys_api.h"
#if !(XP_MAC)
#ifdef BSDI
#include <sys/malloc.h>
#else
#include <malloc.h>
#endif 
#else
#include <stdlib.h>
#endif

#include <errno.h>
#include "zlib.h"

#include "java_util_zip_CRC32.h"
#include "java_util_zip_Adler32.h"
#include "java_util_zip_Inflater.h"
#include "java_util_zip_Deflater.h"

#define ZIPPKG "java/util/zip/"

#define DEF_MEM_LEVEL 8

void
java_util_zip_CRC32_update(Hjava_util_zip_CRC32 *Hthis, HArrayOfByte *Hbuf,
			   long off, long len)
{
    Classjava_util_zip_CRC32 *this = unhand(Hthis);

    if (Hbuf == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
    } else if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	       len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
    } else if (len > 0) {
	this->crc = crc32(this->crc, (Bytef *)unhand(Hbuf)->body + off, len);
    }
}

void
java_util_zip_CRC32_update1(Hjava_util_zip_CRC32 *Hthis, long b)
{
    Classjava_util_zip_CRC32 *this = unhand(Hthis);
    Bytef buf[1];

    buf[0] = (Bytef)b;
    this->crc = crc32(this->crc, buf, 1);
}

void
java_util_zip_Adler32_update(Hjava_util_zip_Adler32 *Hthis,
			     HArrayOfByte *Hbuf, long off, long len)
{
    Classjava_util_zip_Adler32 *this = unhand(Hthis);

    if (Hbuf == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
    } else if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	       len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
    } else if (len > 0) {
	this->adler = adler32(this->adler,
			      (Bytef *)unhand(Hbuf)->body + off, len);
    }
}

void
java_util_zip_Adler32_update1(Hjava_util_zip_Adler32 *Hthis, long b)
{
    Classjava_util_zip_Adler32 *this = unhand(Hthis);
    Bytef buf[1];

    buf[0] = (Bytef)b;
    this->adler = adler32(this->adler, buf, 1);
}

void
java_util_zip_Inflater_init(Hjava_util_zip_Inflater *Hthis, long nowrap)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = calloc(1, sizeof(z_stream));

    if (strm == 0) {
	SignalError(0, JAVAPKG "OutOfMemory", 0);
    } else {
	char *msg;
	switch (inflateInit2(strm, nowrap ? -MAX_WBITS : MAX_WBITS)) {
	  case Z_OK:
	    this->strm = (long)strm;
	    return;
	  case Z_MEM_ERROR:
	    free(strm);
	    SignalError(0, JAVAPKG "OutOfMemoryError", 0);
	    return;
	  default:
	    msg = strm->msg;
	    free(strm);
	    SignalError(0, JAVAPKG "InternalError", msg);
	    return;
	}
    }
}

void
java_util_zip_Inflater_setDictionary(Hjava_util_zip_Inflater *Hthis,
				     HArrayOfByte *Hbuf, long off, long len)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;
    
    if (Hbuf == 0 || strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
    } else if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	       len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
    } else {
	Bytef *buf = (Bytef *)unhand(Hbuf)->body + off;
	switch (inflateSetDictionary(strm, buf, len)) {
	  case Z_OK:
	    this->needsDictionary = FALSE;
	    break;
	  case Z_STREAM_ERROR:
	  case Z_DATA_ERROR:
	    SignalError(0, JAVAPKG "IllegalArgumentException", strm->msg);
	    break;
	  default:
	    SignalError(0, JAVAPKG "InternalError", strm->msg);
	    break;
	}
    }
    return;
}

long
java_util_zip_Inflater_inflate(Hjava_util_zip_Inflater *Hthis,
			       HArrayOfByte *Hbuf, long off, long len)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (this->buf == 0 || Hbuf == 0 || strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
	return 0;
    }
    strm->next_in  = (Bytef *)unhand(this->buf)->body + this->off;
    strm->next_out = (Bytef *)unhand(Hbuf)->body + off;
    strm->avail_in  = this->len;
    strm->avail_out = len;
    switch (inflate(strm, Z_PARTIAL_FLUSH)) {
      case Z_STREAM_END:
	this->finished = TRUE;
      case Z_OK:
	this->off += this->len - strm->avail_in;
	this->len = strm->avail_in;
	return len - strm->avail_out;
      case Z_NEED_DICT:
	this->needsDictionary = TRUE;
	/* We actually will have consumed some input here! */
	this->off += this->len - strm->avail_in;
	this->len = strm->avail_in;
      case Z_BUF_ERROR:
	return 0;
      case Z_DATA_ERROR:
	SignalError(0, ZIPPKG "DataFormatException", strm->msg);
	return 0;
      case Z_MEM_ERROR:
	SignalError(0, JAVAPKG "OutOfMemoryError", 0);
	return 0;
      default:
	SignalError(0, JAVAPKG "InternalError", strm->msg);
	return 0;
    }
}

long
java_util_zip_Inflater_getAdler(Hjava_util_zip_Inflater *Hthis)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->adler;
}

long
java_util_zip_Inflater_getTotalIn(Hjava_util_zip_Inflater *Hthis)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->total_in;
}

long
java_util_zip_Inflater_getTotalOut(Hjava_util_zip_Inflater *Hthis)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->total_out;
}

void
java_util_zip_Inflater_reset(Hjava_util_zip_Inflater *Hthis)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return;
    }
    if (inflateReset(strm) != Z_OK) {
	SignalError(0, JAVAPKG "InternalError", 0);
	return;
    }
    this->finished = FALSE;
    this->needsDictionary = FALSE;
    this->off = this->len = 0;
}

void
java_util_zip_Inflater_end(Hjava_util_zip_Inflater *Hthis)
{
    Classjava_util_zip_Inflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm != 0) {
	if (inflateEnd(strm) == Z_STREAM_ERROR) {
	    SignalError(0, JAVAPKG "InternalError", 0);
	} else {
	    free(strm);
	    this->strm = 0;
	}
    }
}

void
java_util_zip_Deflater_init(Hjava_util_zip_Deflater *Hthis, long nowrap)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = calloc(1, sizeof(z_stream));
    char *msg;

    if (strm == 0) {
	SignalError(0, JAVAPKG "OutOfMemory", 0);
    } else {
	switch (deflateInit2(strm, this->level, Z_DEFLATED,
			     nowrap ? -MAX_WBITS : MAX_WBITS,
			     DEF_MEM_LEVEL, this->strategy)) {
	  case Z_OK:
	    this->strm = (long)strm;
	    return;
	  case Z_MEM_ERROR:
	    free(strm);
	    SignalError(0, JAVAPKG "OutOfMemoryError", 0);
	    return;
	  case Z_STREAM_ERROR:
	    free(strm);
	    SignalError(0, JAVAPKG "IllegalArgumentException", 0);
	    return;
	  default:
	    msg = strm->msg;
	    free(strm);
	    SignalError(0, JAVAPKG "InternalError", msg);
	    return;
	}
    }
}

void
java_util_zip_Deflater_setDictionary(Hjava_util_zip_Deflater *Hthis,
				     HArrayOfByte *Hbuf, long off, long len)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;
    
    if (Hbuf == 0 || strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
    } else if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	       len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
    } else {
	Bytef *buf = (Bytef *)unhand(Hbuf)->body + off;
	switch (deflateSetDictionary(strm, buf, len)) {
	  case Z_OK:
	    break;
	  case Z_STREAM_ERROR:
	    SignalError(0, JAVAPKG "IllegalArgumentException", 0);
	    break;
	  default:
	    SignalError(0, JAVAPKG "InternalError", strm->msg);
	    break;
	}
    }
    return;
}

long
java_util_zip_Deflater_deflate(Hjava_util_zip_Deflater *Hthis,
			       HArrayOfByte *Hbuf, long off, long len)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (this->buf == 0 || Hbuf == 0 || strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    if (off < 0 || (unsigned long)off >= obj_length(Hbuf) ||
	len < 0 || (unsigned long)off + len > obj_length(Hbuf)) {
	SignalError(0, JAVAPKG "ArrayIndexOutOfBoundsException", 0);
	return 0;
    }
    strm->next_in = (Bytef *)unhand(this->buf) + this->off;
    strm->next_out = (Bytef *)unhand(Hbuf)->body + off;
    strm->avail_in = this->len;
    strm->avail_out = len;
    if (this->setParams) {
	switch (deflateParams(strm, this->level, this->strategy)) {
	  case Z_OK:
	    this->setParams = FALSE;
	    this->off += this->len - strm->avail_in;
	    this->len = strm->avail_in;
	    return len - strm->avail_out;
	  case Z_BUF_ERROR:
	    this->setParams = FALSE;
	    return 0;
	  default:
	    SignalError(0, JAVAPKG "InternalError", strm->msg);
	    return 0;
	}
    } else {
	switch (deflate(strm, this->finish ? Z_FINISH : Z_NO_FLUSH)) {
	  case Z_STREAM_END:
	    this->finished = TRUE;
	  case Z_OK:
	    this->off += this->len - strm->avail_in;
	    this->len = strm->avail_in;
	    return len - strm->avail_out;
	  case Z_BUF_ERROR:
	    return 0;
	  default:
	    SignalError(0, JAVAPKG "InternalError", strm->msg);
	    return 0;
	}
    }
}

long
java_util_zip_Deflater_getTotalIn(Hjava_util_zip_Deflater *Hthis)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->total_in;
}

long
java_util_zip_Deflater_getTotalOut(Hjava_util_zip_Deflater *Hthis)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->total_out;
}

long
java_util_zip_Deflater_getAdler(Hjava_util_zip_Deflater *Hthis)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return 0;
    }
    return strm->adler;
}

void
java_util_zip_Deflater_reset(Hjava_util_zip_Deflater *Hthis)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm == 0) {
	SignalError(0, JAVAPKG "NullPointerException", 0);
	return;
    }
    if (deflateReset(strm) != Z_OK) {
	SignalError(0, JAVAPKG "InternalError", 0);
	return;
    }
    this->off = this->len = 0;
    this->finish = this->finished = FALSE;
}

void
java_util_zip_Deflater_end(Hjava_util_zip_Deflater *Hthis)
{
    Classjava_util_zip_Deflater *this = unhand(Hthis);
    z_stream *strm = (z_stream *)this->strm;

    if (strm != 0) {
	if (deflateEnd(strm) == Z_STREAM_ERROR) {
	    SignalError(0, JAVAPKG "InternalError", 0);
	} else {
	    free(strm);
	    this->strm = 0;
	}
    }
}

#if 0
/*
 * This function is used by the runtime system to load compressed entries
 * from ZIP/JAR files specified in the class path. It is defined here
 * so that it can be dynamically loaded by the runtime if the zip library
 * is found.
 */
JRI_PUBLIC_API(bool_t)
inflateFully(int fd, int size, void *buf, int len, char **msg)
{
    static z_stream *strm;
    char tmp[512];
    bool_t ok = TRUE;

    if (strm == 0) {
	strm = sysCalloc(1, sizeof(z_stream));
	if (inflateInit2(strm, -MAX_WBITS) != Z_OK) {
	    *msg = strm->msg;
	    sysFree(strm);
	    return FALSE;
	}
    }
    strm->next_out = buf;
    strm->avail_out = len;

    while (strm->total_in <= size) {
	int n = size - strm->total_in;
	if (n > 0) {
	    n = sysRead(fd, tmp, n > sizeof(tmp) ? sizeof(tmp) : n);
	    if (n == 0) {
		*msg = "Unexpected EOF";
		ok = FALSE;
		goto stop;
	    }
	    if (n < 0) {
		*msg = strerror(errno);
		ok = FALSE;
		goto stop;
	    }
	}
	strm->next_in = (Bytef *)tmp;
	strm->avail_in = n;
	do {
	    switch (inflate(strm, Z_PARTIAL_FLUSH)) {
	    case Z_OK:
		break;
	    case Z_STREAM_END:
		if (strm->total_in != size || strm->total_out != len) {
		    *msg = "Invalid entry compressed size";
		    ok = FALSE;
		}
		goto stop;
	    default:
		*msg = strm->msg;
		goto stop;
	    }
	} while (strm->avail_in > 0);
    }
    *msg = "Invalid entry compressed size";
    ok = FALSE;

stop:
    inflateReset(strm);
    return ok;
}
#endif

#endif /* JAVA */
