/*
* DictZip library.
*
- * Copyright (C) 2001-2004 JDictd project.
+ * Copyright (C) 2001-2004 Ho Ngoc Duc
* Copyright (C) 2016 Hiroshi Miura
*
* This program is free software; you can redistribute it and/or
package org.dict.zip;
-import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.SequenceInputStream;
-import java.text.MessageFormat;
import java.util.zip.CRC32;
import java.util.zip.Inflater;
/**
* DictZipInputStream.
*
- * @author jdictd project
+ * @author Ho Ngoc Duc
* @author Hiroshi Miura
*/
public class DictZipInputStream extends InflaterInputStream {
private long totalLength = 0;
private long compLength = 0;
- private int bufferSize;
private int offset = 0;
+ private static final int BUF_LEN = 8192;
+
/**
* Indicates end of input stream.
*/
private boolean eos;
+ /*
+ * Super class has three protected variables.
+ * protected byte[] buf
+ * Input buffer for decompression.
+ * protected Inflater inf
+ * Decompressor for this stream.
+ * protected int len
+ * Length of input buffer.
+ *
+ * We should not use these names in order to avoid confusion.
+ */
+
+ /**
+ * Creates a new input stream with a default buffer size from given filepath.
+ *
+ * @param filename the input filename
+ * @exception IOException if an I/O error has occurred
+ */
+ public DictZipInputStream(final String filename) throws IOException {
+ this(new RandomAccessInputStream(filename, "r"), BUF_LEN);
+ }
+
/**
* Creates a new input stream with a default buffer size.
*
* @exception IOException if an I/O error has occurred
*/
public DictZipInputStream(final RandomAccessInputStream in) throws IOException {
- this(in, 512);
+ this(in, BUF_LEN);
}
/**
public DictZipInputStream(final RandomAccessInputStream in, final int size) throws IOException {
super(in, new Inflater(true), size);
header = readHeader();
- bufferSize = size;
+ readTrailer();
}
/**
* Reads uncompressed data into an array of bytes. Blocks until enough input is available for
* decompression.
*
- * @param buf the buffer into which the data is read
+ * @param buffer the buffer into which the data is read
* @param off the start offset of the data
* @param size the maximum number of bytes read
* @return the actual number of bytes read, or -1 if the end of the compressed input stream is
* @exception IOException if an I/O error has occurred or the compressed input data is corrupt
*/
@Override
- public final int read(final byte[] buf, final int off, final int size) throws IOException {
+ public final int read(final byte[] buffer, final int off, final int size) throws IOException {
if (eos) {
return -1;
}
- int readLen;
- if (offset == 0) {
- readLen = super.read(buf, off, size);
- } else {
- byte[] tmpBuf = new byte[Math.min(offset + size, bufferSize - off)];
- readLen = super.read(tmpBuf, 0, Math.min(offset + size, bufferSize - off));
- int copyLen = Math.min(readLen - offset, size);
- for (int i = 0; i < copyLen; i++) {
- buf[off + i] = tmpBuf[offset + i];
+ if (buffer == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || size < 0 || size > buffer.length - off || off >= buffer.length) {
+ throw new IndexOutOfBoundsException();
+ } else if (size == 0) {
+ return 0;
+ }
+ // skip to offset
+ if (offset > 0) {
+ int total;
+ int len;
+ byte[] b = new byte[512];
+ for (total = 0; total < offset; total += len) {
+ len = offset - total;
+ if (len > b.length) {
+ len = b.length;
+ }
+
+ len = super.read(b, 0, len);
+ if (len == -1) {
+ eos = true;
+ return -1;
+ }
}
+ offset = 0;
}
+ // read for buffer size.
+ int readLen = super.read(buffer, off, size);
if (readLen == -1) {
eos = true;
} else {
- crc.update(buf, off, readLen);
+ crc.update(buffer, off, readLen);
}
return readLen;
}
/**
* Read full data.
*
- * @param buf the buffer into which the data is read
+ * @param buffer the buffer into which the data is read
* @exception IOException if an I/O error has occurred or the compressed input data is corrupt
*/
- public final void readFully(final byte[] buf) throws IOException {
- readFully(buf, 0, buf.length);
+ public final void readFully(final byte[] buffer) throws IOException {
+ readFully(buffer, 0, buffer.length);
}
/**
* Read full data by offset/length.
*
- * @param buf the buffer into which the data is read
+ * @param buffer the buffer into which the data is read
* @param off offset
- * @param len length
+ * @param size length
* @exception IOException if an I/O error has occurred or the compressed input data is corrupt
*/
- public final void readFully(final byte[] buf, final int off, final int len)
+ public final void readFully(final byte[] buffer, final int off, final int size)
throws IOException {
int num = 0;
- while (num < len) {
- int count = read(buf, off + num, len - num);
+ while (num < size) {
+ int count = read(buffer, off + num, size - num);
if (count < 0) {
throw new EOFException();
}
* @return header object.
* @exception IOException if an I/O error has occurred.
*/
- public final DictZipHeader readHeader() throws IOException {
+ private DictZipHeader readHeader() throws IOException {
if (header == null) {
header = DictZipHeader.readHeader(in, crc);
crc.reset();
offset = header.getOffset(next);
long pos = header.getPosition(next);
rain.seek(pos);
+ inf.reset();
+ eos = false;
} else {
throw new IOException("Illegal type of InputStream.");
}
}
/**
- * Check gzip member trailer; CRC and length.
- * @throws IOException when CRC error or total length error.
+ * Get type of compression.
+ *
+ * @return "DZIP" or "GZIP"
+ * @throws IOException if I/O error occurred.
*/
- private void checkTrailer() throws IOException {
- InputStream in = this.in;
- int num = inf.getRemaining();
- if (num > 0) {
- in = new SequenceInputStream(
- new ByteArrayInputStream(buf, len - num, num), in);
- }
- long val = crc.getValue();
- long crcValue = readUInt(in);
- if (crcValue != val) {
- throw new IOException(MessageFormat
- .format("Incorrect CRC: Computed CRC = %8x / From input %8x", val, crcValue));
- }
- long total = inf.getTotalOut();
- long trailerTotal = readUInt(in);
- if (trailerTotal != total) {
- throw new IOException(MessageFormat
- .format("False number of uncompressed bytes: Computed size =%d / From input %d",
- total, trailerTotal));
- }
+ public String getType() throws IOException {
+ return header.getType();
+ }
+
+ /**
+ * Get length of each chunk.
+ * @return size of chunk.
+ * @throws IOException if I/O error occurred.
+ */
+ public int getChunkLength() throws IOException {
+ return header.getChunkLength();
+ }
+
+ /**
+ * Get number of chunks.
+ * @return number of chunks.
+ * @throws IOException if I/O error occurred.
+ */
+ public int getChunkCount() throws IOException {
+ return header.getChunkCount();
+ }
+
+ /**
+ * Get mtime in long.
+ * @return mtime in long.
+ * @throws IOException if I/O error occurred.
+ */
+ public long getMtime() throws IOException {
+ return header.getMtime();
+ }
+
+ /**
+ * Get Filename field if exist.
+ * @return filename or null.
+ * @throws IOException if I/O error occurred.
+ */
+ public String getFilename() throws IOException {
+ return header.getFilename();
}
/**
* Reads GZIP member trailer.
* @throws java.io.IOException If file I/O error
*/
- public void readTrailer() throws IOException {
+ void readTrailer() throws IOException {
if (in instanceof RandomAccessInputStream) {
RandomAccessInputStream rain = (RandomAccessInputStream) in;
compLength = rain.getLength();
rain.seek(compLength - 8);
- crcVal = readUInt(rain);
- totalLength = readUInt(rain);
+ crcVal = DictZipFileUtils.readUInt(rain);
+ totalLength = DictZipFileUtils.readUInt(rain);
} else {
throw new IOException("Illegal type of InputStream.");
}
}
-
- private long readUInt(final InputStream in) throws IOException {
- return DictZipHeader.readUInt(in);
- }
}