/* -*- Mode: C; c-file-style: "gnu" -*-
   zipfile.c -- native methods for java/util/zip/ZipFile
   Created: Chris Toshok <toshok@hungry.com>, 22-Nov-1998
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  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 GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "jni.h"
#include "runtime.h"
#include "zipfile.h"
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#ifdef HAVE_IO_H
#  include <io.h>
#endif

JNIEXPORT void JNICALL
Java_java_util_zip_ZipFile_initIDs(JNIEnv *env,
				   jclass cls)
{
}

JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_open(JNIEnv *env,
				jclass cls,
				jstring name)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  ZipFile *zipf = (ZipFile*)calloc(1, sizeof(ZipFile));
  char *zip_name = HVM_StringToCString(henv, name);

  /* XXX O_BINARY? */
  zipf->fd = PR_Open(zip_name, PR_RDONLY, 0);

  free(zip_name);

  read_zip_archive(zipf);

  return (jlong)zipf;
}

JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_getTotal(JNIEnv *env,
				    jclass cls,
				    jlong jzfile)
{
  ZipFile *zipf = (ZipFile*)jzfile;

  return zipf->count;
}

JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntry(JNIEnv *env,
				    jclass cls,
				    jlong jzfile,
				    jstring entry_name)
{
  HungryEnv *henv = HVM_ThreadGetEnv();
  ZipFile *zipf = (ZipFile*)jzfile;
  char *real_entry_name = HVM_StringToCString(henv, entry_name);
  ZipDirectory *dir;

  int first, last, middle;
  
  first = 0;
  last = zipf->count - 1;
  
  do {
    int r;
    middle = (first + last) / 2;
    
    dir = zipf->sorted_entries[middle];
    r = strcmp(real_entry_name, ZIPDIR_FILENAME(dir));
    if (r < 0)
      {
	last = middle - 1;
	continue;
      }
    else if (r > 0)
      {
	first = middle + 1;
	continue;
      }
    else
      {
	free(real_entry_name);
	return (jlong)dir;
      }
  } while (first <= last);

  free(real_entry_name);
  return 0;
}

JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_getMethod(JNIEnv *env,
				     jclass cls,
				     jlong jzentry)
{
  ZipDirectory *dir = (ZipDirectory*)jzentry;

  return dir->compression_method;
}

JNIEXPORT jint JNICALL
Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env,
					jclass cls,
					jlong jzfile,
					jint i)
{
  ZipFile *zipf = (ZipFile*)jzfile;
  (*env)->FatalError(env, "Java_java_util_zip_ZipFile_getNextEntry not implemented");
  return 0;
}
				     
JNIEXPORT void JNICALL
Java_java_util_zip_ZipFile_close(JNIEnv *env,
				 jclass cls,
				 jlong jzfile)
{
  ZipFile *zipf = (ZipFile*)jzfile;
}

JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getCSize(JNIEnv *env,
				    jclass cls,
				    jlong jzentry)
{
  ZipDirectory *dir = (ZipDirectory*)jzentry;

  return dir->compressed_size;
}

JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_read(JNIEnv *env,
				jclass cls,
				jlong jzfile,
				jlong jzentry,
				jint pos,
				jbyteArray b,
				jint off, jint len)
{
  ZipFile *zipf = (ZipFile*)jzfile;
  ZipDirectory *dir = (ZipDirectory*)jzentry;
  jbyte *out_bytes;
  int r;

  out_bytes = (*env)->GetByteArrayElements(env, b, NULL);

  r = PR_Seek(zipf->fd,
	      dir->filestart + pos, /* XXX ? */
	      PR_SEEK_SET);

  r = PR_Read(zipf->fd, out_bytes + off, len);

  (*env)->ReleaseByteArrayElements(env, b, out_bytes, JNI_COMMIT);

  return (jlong)r;
}
