mirror of
https://github.com/corda/corda.git
synced 2025-01-07 13:38:47 +00:00
adding zipentry and zipoutputstream classes
This commit is contained in:
parent
a9d9bc5d20
commit
055f820cac
@ -1,21 +1,160 @@
|
|||||||
/* Copyright (c) 2008-2013, Avian Contributors
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software
|
|
||||||
for any purpose with or without fee is hereby granted, provided
|
|
||||||
that the above copyright notice and this permission notice appear
|
|
||||||
in all copies.
|
|
||||||
|
|
||||||
There is NO WARRANTY for this software. See license.txt for
|
|
||||||
details. */
|
|
||||||
|
|
||||||
package java.util.zip;
|
package java.util.zip;
|
||||||
|
|
||||||
public abstract class ZipEntry {
|
import java.util.Calendar;
|
||||||
public abstract String getName();
|
import java.util.Date;
|
||||||
public abstract int getCompressedSize();
|
|
||||||
public abstract int getSize();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class ZipEntry:
|
||||||
|
*
|
||||||
|
* Class to store and retrieve information for entries in a zip file
|
||||||
|
* Contains variables for all standard zip format field as well as
|
||||||
|
* setter and accessor methods
|
||||||
|
*
|
||||||
|
* @author ReadyTalk Summer 2013 Intern Team
|
||||||
|
**/
|
||||||
|
public class ZipEntry {
|
||||||
|
String name;
|
||||||
|
//Minimum version needed to extract the file(s) from a compressed state
|
||||||
|
short reqVersion;
|
||||||
|
|
||||||
|
//Method used to compress file
|
||||||
|
short compressionMethod;
|
||||||
|
|
||||||
|
//Format of date and time are both 2 byte fields
|
||||||
|
short modTime;
|
||||||
|
short modDate;
|
||||||
|
|
||||||
|
//CRC-32
|
||||||
|
int crc;
|
||||||
|
|
||||||
|
//Sizes of file
|
||||||
|
int compSize;
|
||||||
|
int uncompSize;
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
public ZipEntry(String name) {
|
||||||
|
this.name = name;
|
||||||
|
setTimeDate();
|
||||||
|
compSize = 0;
|
||||||
|
uncompSize = 0;
|
||||||
|
crc = 0;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Method to return name of the file
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Method to check if file is a directory
|
||||||
public boolean isDirectory() {
|
public boolean isDirectory() {
|
||||||
return getName().endsWith("/");
|
return getName().endsWith("/");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
//Method to return the compressed size of the file
|
||||||
|
public int getCompressedSize() {
|
||||||
|
return compSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Method to return the uncompressed size of the file
|
||||||
|
public int getSize() {
|
||||||
|
return uncompSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method setTime Date():
|
||||||
|
* Creates a calendar object to retrieve date and time information
|
||||||
|
*
|
||||||
|
* Time is stored in the MSDOS format 5 bits for hour, 6 bits for min, 5 bits for seconds
|
||||||
|
* Hours are in military time and must be adjusted to time zone
|
||||||
|
* Seconds are divided by two before storing and must be multiplied by two to retrieve
|
||||||
|
*
|
||||||
|
* Date is stored in the MSDOS format 7 bit for year, 4 bit for month, 5 bits for day of month
|
||||||
|
* Year is the number of years since 1980 per, the month is stored starting at 0
|
||||||
|
* for January. Day of month is stored with nature numbering
|
||||||
|
*
|
||||||
|
* Bit masks and shifting are used to build the time and date bytes
|
||||||
|
*
|
||||||
|
* @author cjordan
|
||||||
|
**/
|
||||||
|
public void setTimeDate(){
|
||||||
|
final int DAY_OF_MONTH = 5;
|
||||||
|
final int HOUR_OF_DAY = 11;
|
||||||
|
final int MINUTE = 12;
|
||||||
|
final int MONTH = 2;
|
||||||
|
final int SECOND = 13;
|
||||||
|
final int YEAR = 1;
|
||||||
|
|
||||||
|
Calendar modCalendar = Calendar.getInstance();
|
||||||
|
|
||||||
|
//Hour
|
||||||
|
int timeBits = modCalendar.get(HOUR_OF_DAY);
|
||||||
|
timeBits = timeBits - 6;
|
||||||
|
timeBits = timeBits << 6;
|
||||||
|
|
||||||
|
//Minutes
|
||||||
|
int minBits = 0x3f & (modCalendar.get(MINUTE));;
|
||||||
|
timeBits = timeBits ^ minBits;
|
||||||
|
timeBits = timeBits << 5;
|
||||||
|
|
||||||
|
//Seconds
|
||||||
|
int secBits = 0x1f & (modCalendar.get(SECOND));
|
||||||
|
secBits = secBits >> 1;
|
||||||
|
timeBits = timeBits ^ secBits;
|
||||||
|
|
||||||
|
//Store Time
|
||||||
|
modTime = (short)timeBits;
|
||||||
|
|
||||||
|
//Year
|
||||||
|
int dateBits = (modCalendar.get(YEAR) -1980);
|
||||||
|
dateBits = dateBits << 4;
|
||||||
|
|
||||||
|
//Month
|
||||||
|
int month = 0xf & ((modCalendar.get(MONTH)) + 1);
|
||||||
|
dateBits = dateBits ^ month;
|
||||||
|
dateBits = dateBits << 5;
|
||||||
|
|
||||||
|
//Day of month
|
||||||
|
int dayBits = 0x1f & modCalendar.get(DAY_OF_MONTH);
|
||||||
|
dateBits = dateBits ^ dayBits;
|
||||||
|
|
||||||
|
//Store Date
|
||||||
|
modDate = (short)dateBits;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Method to set the minimum version required to open the zip file
|
||||||
|
//Valid values for the compression method are the numbers 1.0 to 10.0
|
||||||
|
public boolean setRequiredVersion(float versionFloat){
|
||||||
|
//Check for valid version numbers
|
||||||
|
if (versionFloat < 1 || versionFloat > 100){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert to short value for storage
|
||||||
|
versionFloat = versionFloat * 10;
|
||||||
|
short versionShort = (short)versionFloat;
|
||||||
|
|
||||||
|
//Set value of version
|
||||||
|
reqVersion = versionShort;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Method to set the compression method for the file
|
||||||
|
//Valid values for the compression method are the numbers 0 to 19 and 99
|
||||||
|
public boolean setCompressionMethod(short compMethod){
|
||||||
|
if (compMethod == 99){
|
||||||
|
compressionMethod = compMethod;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (compMethod < 0 || compMethod > 19){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
compressionMethod = compMethod;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
200
classpath/java/util/zip/ZipOutputStream.java
Normal file
200
classpath/java/util/zip/ZipOutputStream.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package java.util.zip;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An as simple as possible implementation of ZipOutputStream
|
||||||
|
* Compression method defaults to DEFLATE
|
||||||
|
* All hardcoded defaults match the defaults for openJDK,
|
||||||
|
* including PKZip version, bit flags set, compression level, etc
|
||||||
|
*
|
||||||
|
* @author ReadyTalk Summer 2013 Intern Team
|
||||||
|
*/
|
||||||
|
public class ZipOutputStream extends DeflaterOutputStream {
|
||||||
|
private static final int SIGNATURE = 0x04034b50;
|
||||||
|
private static final short VERSION = 0x0014;
|
||||||
|
private static final short BITFLAG = 0x0008;
|
||||||
|
private static final short METHOD = 0x0008;
|
||||||
|
private static final int CENTRAL_FILE_HEADER = 0x02014b50;
|
||||||
|
private static final int DATA_DESCRIPTER_HEADER = 0x08074b50;
|
||||||
|
private static final int END_OF_CENTRAL_DIRECTORY_SIG = 0x06054b50;
|
||||||
|
private static final int DEFAULT_LEVEL = 6;
|
||||||
|
|
||||||
|
private final OutputStream out;
|
||||||
|
private DeflaterOutputStream deflaterStream;
|
||||||
|
private Deflater deflater;
|
||||||
|
private List<ZipEntry> entries;
|
||||||
|
private CRC32 crc = new CRC32();
|
||||||
|
private ZipEntry currentEntry;
|
||||||
|
|
||||||
|
private int bytesWritten;
|
||||||
|
private int sizeOfCentralDirectory;
|
||||||
|
private byte[] buffer;
|
||||||
|
|
||||||
|
public ZipOutputStream(OutputStream outStream, int bufferSize) {
|
||||||
|
super(outStream);
|
||||||
|
out = outStream;
|
||||||
|
bytesWritten = 0;
|
||||||
|
sizeOfCentralDirectory = 0;
|
||||||
|
entries = new ArrayList<ZipEntry>();
|
||||||
|
buffer = new byte[bufferSize];
|
||||||
|
deflater = new Deflater(DEFAULT_LEVEL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZipOutputStream(OutputStream outStream) {
|
||||||
|
this(outStream, 4 * 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putNextEntry(ZipEntry e) throws IOException {
|
||||||
|
e.offset = bytesWritten;
|
||||||
|
currentEntry = e;
|
||||||
|
entries.add(e);
|
||||||
|
writeLocalHeader(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeEntry() throws IOException {
|
||||||
|
deflater.finish();
|
||||||
|
while (!deflater.finished()) {
|
||||||
|
deflate();
|
||||||
|
}
|
||||||
|
deflater.dispose();
|
||||||
|
deflater.reset();
|
||||||
|
|
||||||
|
currentEntry.crc = (int) crc.getValue();
|
||||||
|
crc.reset();
|
||||||
|
writeDataDescriptor(currentEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLocalHeader(ZipEntry e) throws IOException {
|
||||||
|
writeFourBytes(SIGNATURE); // local header signature
|
||||||
|
writeTwoBytes(VERSION); // version used
|
||||||
|
writeTwoBytes(BITFLAG); // flags
|
||||||
|
writeTwoBytes(METHOD); // compression method
|
||||||
|
writeTwoBytes(e.modTime); // last modified time
|
||||||
|
writeTwoBytes(e.modDate); // last modified date
|
||||||
|
writeFourBytes(0); // CRC is 0 for local header
|
||||||
|
|
||||||
|
// with default flag settings, the compressed and uncompressed size
|
||||||
|
// is written here as 0 and written correctly in the data descripter
|
||||||
|
writeFourBytes(0); // compressed size
|
||||||
|
writeFourBytes(0); // uncompressed size
|
||||||
|
writeTwoBytes(e.name.length()); // length of file name
|
||||||
|
|
||||||
|
// extra field length, in this implementation extra field in not used
|
||||||
|
writeTwoBytes(0);
|
||||||
|
|
||||||
|
// write file name, return the number of bytes written
|
||||||
|
int len = writeVariableByteLength(e.getName());
|
||||||
|
|
||||||
|
bytesWritten += 30 + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDataDescriptor(ZipEntry currentEntry) throws IOException {
|
||||||
|
writeFourBytes(DATA_DESCRIPTER_HEADER); // data descripter header
|
||||||
|
writeFourBytes(currentEntry.crc); // crc value
|
||||||
|
writeFourBytes(currentEntry.compSize); // compressed size
|
||||||
|
writeFourBytes(currentEntry.uncompSize); // uncompressed size
|
||||||
|
bytesWritten += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b, int offset, int length) throws IOException {
|
||||||
|
currentEntry.uncompSize += length;
|
||||||
|
crc.update(b, offset, length);
|
||||||
|
currentEntry.crc = (int) crc.getValue();
|
||||||
|
|
||||||
|
deflater.setInput(b, offset, length);
|
||||||
|
while (deflater.getRemaining() > 0)
|
||||||
|
deflate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
byte[] buf = new byte[1];
|
||||||
|
buf[0] = (byte)(b & 0xff);
|
||||||
|
write(buf, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deflate() throws IOException {
|
||||||
|
int len = deflater.deflate(buffer, 0, buffer.length);
|
||||||
|
currentEntry.compSize += len;
|
||||||
|
bytesWritten += len;
|
||||||
|
if (len > 0)
|
||||||
|
out.write(buffer, 0 , len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeCentralDirectoryHeader(ZipEntry e) throws IOException {
|
||||||
|
writeFourBytes(CENTRAL_FILE_HEADER); // central directory header signature
|
||||||
|
writeTwoBytes(VERSION); // version made by
|
||||||
|
writeTwoBytes(VERSION); // version needed
|
||||||
|
writeTwoBytes(BITFLAG); // flags
|
||||||
|
writeTwoBytes(METHOD); // compression method
|
||||||
|
|
||||||
|
writeTwoBytes(e.modTime); // last mod time
|
||||||
|
writeTwoBytes(e.modDate); // last mod date
|
||||||
|
writeFourBytes(e.crc); // crc
|
||||||
|
writeFourBytes(e.compSize); // compressed size
|
||||||
|
writeFourBytes(e.uncompSize); // uncompressed size
|
||||||
|
|
||||||
|
writeTwoBytes(e.getName().length()); // file name length
|
||||||
|
|
||||||
|
// the following 5 fields are all 0 for a simple default compression
|
||||||
|
writeTwoBytes(0); // extra field length (not used)
|
||||||
|
writeTwoBytes(0); // comment length (not used)
|
||||||
|
writeTwoBytes(0); // disk number start
|
||||||
|
writeTwoBytes(0); // internal file attribute
|
||||||
|
writeFourBytes(0); // external file attribute
|
||||||
|
|
||||||
|
writeFourBytes((int) e.offset); // relative offset of local header
|
||||||
|
|
||||||
|
int len = writeVariableByteLength(e.getName());
|
||||||
|
|
||||||
|
bytesWritten += 46 + len;
|
||||||
|
sizeOfCentralDirectory += 46 + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeEndofCentralDirectory(int offset) throws IOException {
|
||||||
|
short numEntries = (short) entries.size();
|
||||||
|
writeFourBytes(END_OF_CENTRAL_DIRECTORY_SIG); // end of central directory signature
|
||||||
|
writeTwoBytes(0); // disk number
|
||||||
|
writeTwoBytes(0); // disk number where central dir starts
|
||||||
|
writeTwoBytes(numEntries); // number of entries on this disk
|
||||||
|
writeTwoBytes(numEntries); // number of entries in central dir
|
||||||
|
writeFourBytes(sizeOfCentralDirectory); // length of central directory
|
||||||
|
writeFourBytes(offset); // offset of central directory
|
||||||
|
writeTwoBytes(0); // length of added comments (not used)
|
||||||
|
bytesWritten += 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
int centralDirOffset = bytesWritten;
|
||||||
|
for (ZipEntry e : entries)
|
||||||
|
writeCentralDirectoryHeader(e);
|
||||||
|
writeEndofCentralDirectory(centralDirOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTwoBytes(int bytes) throws IOException {
|
||||||
|
out.write(bytes & 0xff);
|
||||||
|
out.write((bytes >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFourBytes(int bytes) throws IOException {
|
||||||
|
out.write(bytes & 0xff);
|
||||||
|
out.write((bytes >> 8) & 0xff);
|
||||||
|
out.write((bytes >> 16) & 0xff);
|
||||||
|
out.write((bytes >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int writeVariableByteLength(String text) throws IOException {
|
||||||
|
byte[] bytes = text.getBytes("UTF-8");
|
||||||
|
out.write(bytes, 0, bytes.length);
|
||||||
|
return bytes.length;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user