[Kaffe] test/regression/ZipVerify.java update
Mo DeJong
mdejong at cygnus.com
Mon Feb 28 15:55:17 PST 2000
The test/regression/ZipVerify.java tests should be updated with
the file I have attached to this email. I have also attached
a new file called ZipVerifyUtils.java that is needed by the
ZipVerify.java class. This new regression test now checks the
output of 1 entry, 2 entry, and directory entry zip files.
Mo Dejong
Red Hat Inc.
-------------- next part --------------
// This class will write a zip file into memory and verify that the
// contents being written matches the expected output.
import java.io.*;
import java.util.*;
import java.util.zip.*;
public class ZipVerify extends ZipVerifyUtils {
public static void main(String[] argv) throws Exception
{
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
// Set debug to false and no "output" messages will be displayed
// Error messages will still be displayed
debug = false;
// This will dump the entire stream unless set to false
debug_stream = false;
checkSingleEntry(false);
checkSingleEntry(true);
checkSingleEntry2(false);
checkSingleEntry2(true);
checkDirectoryEntry();
checkTwoEntries(false);
checkTwoEntries(true);
}
public static void checkSingleEntry(boolean compressed) throws Exception
{
// 1/1/1984 12:30 and 30 seconds
long expected_unix_time = 0x66ddd29670L;
// 1/1/1984 12:30 and 30 seconds ( this is 0x66ddd29670L converted to dostime)
byte[] expected_dostime = {-49, 99, 33, 8};
// The entry name we pass to ZipEntry(String)
byte[] expected_file_name = toBytes("data");
// "extra" data segment that is added to a ZipEntry
byte[] expected_extra_field = toBytes("hi");
byte[] uncompressed_file_data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] compressed_file_data = {99, 96, 100, 98, 102, 97, 101, 99, -25, -32, 4, 0};
// The total size of the zip file
int uncompressed_zipfile_length = 120;
int compressed_zipfile_length = 138;
// The CRC checksum we expect to find
long expected_checksum = 1164760902L;
// Zip internal data
long uncompressed_rel_header_offset = 0;
long compressed_rel_header_offset = 0;
int total_disknumber = 1;
int total_central = 1;
long expected_cen_size = 52;
long uncompressed_cen_offset = 46;
long compressed_cen_offset = 64;
// ---------------------------------------------
EntryRecord[] entries = new EntryRecord[1];
entries[0] = new EntryRecord(expected_file_name,
uncompressed_file_data,
expected_extra_field,
expected_unix_time);
byte[] data = generateAndVerifyZipData(compressed,
entries,
uncompressed_zipfile_length,
compressed_zipfile_length);
// file offset used to keep track of each field position in the stream
int zip_offset = 0;
zip_offset += verifyLOCHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
zip_offset += verifyFileData(compressed,
uncompressed_file_data,
compressed_file_data,
data,
zip_offset);
// If we used compression, a DATA header should show up next
if (compressed) {
zip_offset += verifyDATAHeader(uncompressed_file_data,
compressed_file_data,
expected_checksum,
data,
zip_offset);
}
zip_offset += verifyCENHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
expected_checksum,
uncompressed_rel_header_offset,
compressed_rel_header_offset,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
zip_offset += verifyENDHeader(compressed,
total_disknumber,
total_central,
expected_cen_size,
uncompressed_cen_offset,
compressed_cen_offset,
data,
zip_offset);
verifyEOF(data, zip_offset);
}
public static void checkSingleEntry2(boolean compressed) throws Exception
{
// 1/1/1984 12:30 and 30 seconds
long expected_unix_time = 0x66ddd29670L;
// 1/1/1984 12:30 and 30 seconds ( this is 0x66ddd29670L converted to dostime)
byte[] expected_dostime = {-49, 99, 33, 8};
// The entry name we pass to ZipEntry(String)
byte[] expected_file_name = toBytes("file1");
// "extra" data segment that is added to a ZipEntry
byte[] expected_extra_field = null;
byte[] uncompressed_file_data = {5, 4, 3, 2, 1, 0};
byte[] compressed_file_data = {99, 101, 97, 102, 98, 100, 0, 0};
// The total size of the zip file
int uncompressed_zipfile_length = 114;
int compressed_zipfile_length = 132;
// The CRC checksum we expect to find
long expected_checksum = 480631825L;
// Zip internal data
long uncompressed_rel_header_offset = 0;
long compressed_rel_header_offset = 0;
int total_disknumber = 1;
int total_central = 1;
long expected_cen_size = 51;
long uncompressed_cen_offset = 41;
long compressed_cen_offset = 59;
// ---------------------------------------------
EntryRecord[] entries = new EntryRecord[1];
entries[0] = new EntryRecord(expected_file_name,
uncompressed_file_data,
expected_extra_field,
expected_unix_time);
byte[] data = generateAndVerifyZipData(compressed,
entries,
uncompressed_zipfile_length,
compressed_zipfile_length);
// file offset used to keep track of each field position in the stream
int zip_offset = 0;
zip_offset += verifyLOCHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
zip_offset += verifyFileData(compressed,
uncompressed_file_data,
compressed_file_data,
data,
zip_offset);
// If we used compression, a DATA header should show up next
if (compressed) {
zip_offset += verifyDATAHeader(uncompressed_file_data,
compressed_file_data,
expected_checksum,
data,
zip_offset);
}
zip_offset += verifyCENHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
expected_checksum,
uncompressed_rel_header_offset,
compressed_rel_header_offset,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
zip_offset += verifyENDHeader(compressed,
total_disknumber,
total_central,
expected_cen_size,
uncompressed_cen_offset,
compressed_cen_offset,
data,
zip_offset);
verifyEOF(data, zip_offset);
}
// The trick about directory entries is that they are never compressed
public static void checkDirectoryEntry() throws Exception
{
// 1/1/1984 12:30 and 30 seconds
long expected_unix_time = 0x66ddd29670L;
// 1/1/1984 12:30 and 30 seconds ( this is 0x66ddd29670L converted to dostime)
byte[] expected_dostime = {-49, 99, 33, 8};
// The entry name we pass to ZipEntry(String)
byte[] expected_file_name = toBytes("foo/");
// "extra" data segment that is added to a ZipEntry
byte[] expected_extra_field = null;
byte[] uncompressed_file_data = null;
byte[] compressed_file_data = null;
// The total size of the zip file
int uncompressed_zipfile_length = 106;
int compressed_zipfile_length = 106;
// The CRC checksum we expect to find
long expected_checksum = 0;
// Zip internal data
long uncompressed_rel_header_offset = 0;
long compressed_rel_header_offset = 0;
int total_disknumber = 1;
int total_central = 1;
long expected_cen_size = 50;
long uncompressed_cen_offset = 34;
long compressed_cen_offset = 34;
boolean compressed = false;
// ---------------------------------------------
EntryRecord[] entries = new EntryRecord[1];
entries[0] = new EntryRecord(expected_file_name,
uncompressed_file_data,
expected_extra_field,
expected_unix_time);
byte[] data = generateAndVerifyZipData(compressed,
entries,
uncompressed_zipfile_length,
compressed_zipfile_length);
// file offset used to keep track of each field position in the stream
int zip_offset = 0;
zip_offset += verifyLOCHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
// No file_data or DATA header for a directory entry
zip_offset += verifyCENHeader(compressed,
expected_file_name,
uncompressed_file_data,
compressed_file_data,
expected_extra_field,
expected_dostime,
expected_checksum,
uncompressed_rel_header_offset,
compressed_rel_header_offset,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name,
expected_extra_field,
data,
zip_offset);
zip_offset += verifyENDHeader(compressed,
total_disknumber,
total_central,
expected_cen_size,
uncompressed_cen_offset,
compressed_cen_offset,
data,
zip_offset);
verifyEOF(data, zip_offset);
}
// Write two entries to a zip file and verify the output
public static void checkTwoEntries(boolean compressed) throws Exception
{
// 1/1/1984 12:30 and 30 seconds
long expected_unix_time = 0x66ddd29670L;
// 1/1/1984 12:30 and 30 seconds ( this is 0x66ddd29670L converted to dostime)
byte[] expected_dostime = {-49, 99, 33, 8};
// The entry name we pass to ZipEntry(String)
byte[] expected_file_name_one = toBytes("data");
// "extra" data segment that is added to a ZipEntry
byte[] expected_extra_field_one = toBytes("hi");
byte[] uncompressed_file_data_one = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
byte[] compressed_file_data_one = {99, 96, 100, 98, 102, 97, 101, 99, -25, -32, 4, 0};
// The entry name we pass to ZipEntry(String)
byte[] expected_file_name_two = toBytes("file1");
// "extra" data segment that is added to a ZipEntry
byte[] expected_extra_field_two = null;
byte[] uncompressed_file_data_two = {5, 4, 3, 2, 1, 0};
byte[] compressed_file_data_two = {99, 101, 97, 102, 98, 100, 0, 0};
// The total size of the zip file
int uncompressed_zipfile_length = 212;
int compressed_zipfile_length = 248;
// The CRC checksums we expect to find
long expected_checksum_one = 1164760902L;
long expected_checksum_two = 480631825L;
// Zip internal data
long uncompressed_rel_header_offset_one = 0;
long compressed_rel_header_offset_one = 0;
long uncompressed_rel_header_offset_two = 46;
long compressed_rel_header_offset_two = 64;
int total_disknumber = 2;
int total_central = 2;
long expected_cen_size = 103;
long uncompressed_cen_offset = 87;
long compressed_cen_offset = 123;
// ---------------------------------------------
EntryRecord[] entries = new EntryRecord[2];
entries[0] = new EntryRecord(expected_file_name_one,
uncompressed_file_data_one,
expected_extra_field_one,
expected_unix_time);
entries[1] = new EntryRecord(expected_file_name_two,
uncompressed_file_data_two,
expected_extra_field_two,
expected_unix_time);
byte[] data = generateAndVerifyZipData(compressed,
entries,
uncompressed_zipfile_length,
compressed_zipfile_length);
// file offset used to keep track of each field position in the stream
int zip_offset = 0;
zip_offset += verifyLOCHeader(compressed,
expected_file_name_one,
uncompressed_file_data_one,
compressed_file_data_one,
expected_extra_field_one,
expected_dostime,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name_one,
expected_extra_field_one,
data,
zip_offset);
zip_offset += verifyFileData(compressed,
uncompressed_file_data_one,
compressed_file_data_one,
data,
zip_offset);
// If we used compression, a DATA header should show up next
if (compressed) {
zip_offset += verifyDATAHeader(uncompressed_file_data_one,
compressed_file_data_one,
expected_checksum_one,
data,
zip_offset);
}
zip_offset += verifyLOCHeader(compressed,
expected_file_name_two,
uncompressed_file_data_two,
compressed_file_data_two,
expected_extra_field_two,
expected_dostime,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name_two,
expected_extra_field_two,
data,
zip_offset);
zip_offset += verifyFileData(compressed,
uncompressed_file_data_two,
compressed_file_data_two,
data,
zip_offset);
// If we used compression, a DATA header should show up next
if (compressed) {
zip_offset += verifyDATAHeader(uncompressed_file_data_two,
compressed_file_data_two,
expected_checksum_two,
data,
zip_offset);
}
// CEN for entry one
zip_offset += verifyCENHeader(compressed,
expected_file_name_one,
uncompressed_file_data_one,
compressed_file_data_one,
expected_extra_field_one,
expected_dostime,
expected_checksum_one,
uncompressed_rel_header_offset_one,
compressed_rel_header_offset_one,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name_one,
expected_extra_field_one,
data,
zip_offset);
// CEN for entry two
zip_offset += verifyCENHeader(compressed,
expected_file_name_two,
uncompressed_file_data_two,
compressed_file_data_two,
expected_extra_field_two,
expected_dostime,
expected_checksum_two,
uncompressed_rel_header_offset_two,
compressed_rel_header_offset_two,
data,
zip_offset);
zip_offset += verifyNameAndExtra(expected_file_name_two,
expected_extra_field_two,
data,
zip_offset);
zip_offset += verifyENDHeader(compressed,
total_disknumber,
total_central,
expected_cen_size,
uncompressed_cen_offset,
compressed_cen_offset,
data,
zip_offset);
verifyEOF(data, zip_offset);
}
}
-------------- next part --------------
// Utils used by the ZipVerify class
import java.io.*;
import java.util.zip.*;
import java.util.*;
public class ZipVerifyUtils {
public static boolean debug = true;
public static boolean debug_stream = true;
// A Util class used to pass entry data to generateAndVerifyZipData()
public static class EntryRecord {
public EntryRecord(byte[] expected_file_name,
byte[] uncompressed_file_data,
byte[] expected_extra_field,
long expected_unix_time) {
this.expected_file_name = expected_file_name;
this.uncompressed_file_data = uncompressed_file_data;
this.expected_extra_field = expected_extra_field;
this.expected_unix_time = expected_unix_time;
}
byte[] expected_file_name;
byte[] uncompressed_file_data;
byte[] expected_extra_field;
long expected_unix_time;
}
public static long getTime(int year, int month, int date, int hour,
int minute, int second)
{
GregorianCalendar c;
// This is broken, need to call constructor with times!
//c = new GregorianCalendar();
//c.set(year, month, date, hour, minute, second);
c = new GregorianCalendar(year, month, date, hour, minute, second);
return c.getTime().getTime();
}
public static int get16(byte[] buf, int base) {
int val = (int)buf[base] & 0xFF;
val |= ((int)buf[base+1] & 0xFF) << 8;
return (val);
}
public static int get32(byte[] buf, int base) {
int val = (int)buf[base] & 0xFF;
val |= ((int)buf[base+1] & 0xFF) << 8;
val |= ((int)buf[base+2] & 0xFF) << 16;
val |= ((int)buf[base+3] & 0xFF) << 24;
return (val);
}
public static void put16(byte[] array, int pos, int val) {
array[pos] = (byte)val;
array[pos+1] = (byte)(val >>> 8);
}
public static void put32(byte[] array, int pos, int val) {
array[pos] = (byte) val;
array[pos+1] = (byte)(val >>> 8);
array[pos+2] = (byte)(val >>> 16);
array[pos+3] = (byte)(val >>> 24);
}
// This is a quick little helper method to convert a String
// into an array of bytes
public static byte[] toBytes(String value) {
final int len = value.length();
byte[] bytes = new byte[len];
for (int i=0; i < len; i++) {
bytes[i] = (byte) value.charAt(i);
}
return bytes;
}
// This method will do something to signal an error
// but it should not actually stop execution
public static void error(String err) throws Exception
{
// throw new RuntimeError(err);
System.err.println(err);
}
// Just print the given message without an "error"
public static void output(String msg) throws Exception
{
System.out.println(msg);
}
// Compare the bytes in data at the given offset to the expected array
// if there is a mismatch, print those bytes that do not match
static int expect(String field, byte[] data, int zip_offset, byte[] expected)
throws Exception
{
if (expected == null)
return 0;
for (int i=0; i < expected.length; i++) {
if (expected[i] != data[i + zip_offset]) {
error(field + "[" + i + "] is " +
data[i + zip_offset] + " expected " +
expected[i] + " at field offset " + zip_offset);
}
}
return expected.length;
}
// Same as expect() above except mismatches are printed as char types
static int expectC(String field, byte[] data, int zip_offset, byte[] expected)
throws Exception
{
if (expected == null)
return 0;
for (int i=0; i < expected.length; i++) {
if (expected[i] != data[i + zip_offset]) {
error(field + "[" + i + "] is '" +
(char) data[i + zip_offset] + "' expected '" +
(char) expected[i] + "' at field offset " + zip_offset);
}
}
return expected.length;
}
// Compare two 16 bit numbers and display and error if they do not match
static int expect(String field, byte[] data, int zip_offset, int expected)
throws Exception
{
int num = get16(data, zip_offset);
if (num != expected) {
error(field + " is " + num +
" expected " + expected
+ " at field offset " + zip_offset);
}
return 2; // Return the number of bytes to advance in the stream
}
// Compare two 32 bit numbers and display and error if they do not match
static int expectL(String field, byte[] data, int zip_offset, long expected)
throws Exception
{
long num = (long) get32(data, zip_offset);
if (num != expected) {
error(field + " is " + num +
" expected " + expected
+ " at field offset " + zip_offset);
}
return 4; // Return the number of bytes to advance in the stream
}
// This method is used to add an uncompressed entry to the given ZipOutputStream
public static void addEntry(ZipOutputStream zout, boolean compressed,
byte[] name, byte[] bytes, byte[] extra, long unix_time)
throws Exception
{
// Convert byte[] to String
StringBuffer name_buf = new StringBuffer();
for (int i=0; i < name.length; i++) {
name_buf.append( (char) name[i] );
}
String name_str = name_buf.toString();
ZipEntry ze = new ZipEntry(name_str);
int bytes_length = (bytes == null ? 0 : bytes.length);
if (compressed) {
ze.setMethod(ZipEntry.DEFLATED);
} else {
ze.setMethod(ZipEntry.STORED);
ze.setSize(bytes_length);
ze.setCrc(0);
}
ze.setExtra(extra);
ze.setTime(unix_time);
zout.putNextEntry(ze);
if (bytes_length > 0) {
zout.write(bytes);
if (! compressed) {
CRC32 crc = new CRC32();
crc.update(bytes);
ze.setCrc( crc.getValue() );
}
}
zout.closeEntry();
if (debug) {
output("added entry \"" + name_str
+ "\", data size = " + bytes_length);
}
}
// This method will create a byte[] containing data from a zip stream
// and do some simple checks on the size of the data generated
public static byte[] generateAndVerifyZipData(boolean compressed,
EntryRecord[] entries,
int uncompressed_zipfile_length,
int compressed_zipfile_length)
throws Exception
{
// Create the in-memory output stream the zip will be written to
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Write a zip stream containing the data we want to add
ZipOutputStream zout = new ZipOutputStream(baos);
for (int i=0; i < entries.length; i++) {
EntryRecord er = entries[i];
addEntry(zout, compressed, er.expected_file_name,
er.uncompressed_file_data, er.expected_extra_field,
er.expected_unix_time);
}
zout.close();
// Get the bytes written to the stream as an array
byte[] data = baos.toByteArray();
// Display all the bytes that were written to the zip file!
if (debug_stream) {
for (int i=0; i < data.length; i++) {
output(i + "\t" + data[i] +
"\t (char) " + ((char) data[i]));
}
}
if (debug) {
output((compressed ? "compressed" : "uncompressed") + " zip file written");
}
// Display the total number of bytes written
if (debug) {
output("zip bytes written = " + data.length);
}
int zipfile_length = uncompressed_zipfile_length;
if (compressed) {
zipfile_length = compressed_zipfile_length;
}
if (data.length != zipfile_length){
error("length of zip file should be " + zipfile_length + " bytes it was " +
data.length + " bytes");
}
return data;
}
// This method will read a LOC header and verify that
// the fields in the header match the expected results.
// This method returns the new zip_offset.
public static int verifyLOCHeader(boolean compressed,
byte[] expected_file_name,
byte[] uncompressed_file_data,
byte[] compressed_file_data,
byte[] expected_extra_field,
byte[] expected_dostime,
byte[] data,
int zip_offset)
throws Exception
{
// u4 LOC signature {80, 75, 3, 4}
byte[] expected_loc_signature = {80, 75, 3, 4};
int old_zip_offset = zip_offset;
int uncompressed_file_data_length = (uncompressed_file_data == null ? 0 :
uncompressed_file_data.length);
int compressed_file_data_length = (compressed_file_data == null ? 0 :
compressed_file_data.length);
int expected_extra_field_length = (expected_extra_field == null ? 0
: expected_extra_field.length);
zip_offset += expect("loc_signature", data, zip_offset, expected_loc_signature);
// u2 version_needed_to_extract (10 or 20)
zip_offset += expect("extract_version", data, zip_offset,
(compressed ? 20 : 10));
// u2 zip entry flags (seems to be set to 0 or 8)
// what is this for ??? is it like the compression method ???
zip_offset += expect("flags", data, zip_offset,
(compressed ? 8 : 0));
// u2 compression_method (0 or 8)
zip_offset += expect("compression_method", data, zip_offset,
(compressed ? 8 : 0));
// u4 dostime
zip_offset += expect("dostime", data, zip_offset, expected_dostime);
// u4 CRC32 checksum
zip_offset += expectL("crc32", data, zip_offset, 0L);
// u4 compressed_size
zip_offset += expectL("compressed_size", data, zip_offset,
(compressed ? 0 : uncompressed_file_data_length));
// u4 uncompressed_size
zip_offset += expectL("uncompressed_size", data, zip_offset,
(compressed ? 0 : uncompressed_file_data_length));
// u2 filename_length
zip_offset += expect("filename_length", data, zip_offset,
expected_file_name.length);
// u2 extra_field_length
zip_offset += expect("extra_field_length", data, zip_offset,
expected_extra_field_length);
if (debug) {
output("after reading LOC Header, zip_offset is " + zip_offset);
}
if ((zip_offset - old_zip_offset) != 30) {
error("LOC header size should be 30, it was " + (zip_offset - old_zip_offset));
}
return (zip_offset - old_zip_offset);
}
// verify the name, extra, and data fields that show up after
// a LOC header. This method returns the new zip_offset.
public static int verifyNameAndExtra(byte[] expected_file_name,
byte[] expected_extra_field,
byte[] data,
int zip_offset)
throws Exception
{
int old_zip_offset = zip_offset;
// The entry name, we called ZipEntry() with it
zip_offset += expectC("file_name", data, zip_offset, expected_file_name);
// Check for "extra" data segment, it can be zero so
// there may not be any data here!
zip_offset += expectC("extra_field", data, zip_offset, expected_extra_field);
if (debug) {
output("after reading Name-Extra, zip_offset is " + zip_offset);
}
return (zip_offset - old_zip_offset);
}
// verify the actual file data from the entry
public static int verifyFileData(boolean compressed,
byte[] uncompressed_file_data,
byte[] compressed_file_data,
byte[] data,
int zip_offset)
throws Exception
{
int old_zip_offset = zip_offset;
zip_offset += expect("file_data", data, zip_offset,
(compressed ? compressed_file_data :
uncompressed_file_data) );
if (debug) {
output("after reading File-Data, zip_offset is " + zip_offset);
}
return (zip_offset - old_zip_offset);
}
// This method will read a DATA header and verify that
// the fields in the header match the expected results.
// This method returns the new zip_offset.
public static int verifyDATAHeader(byte[] uncompressed_file_data,
byte[] compressed_file_data,
long expected_checksum,
byte[] data,
int zip_offset)
throws Exception
{
// A DATA header should show up after a compressed entry
byte[] compressed_post_data_header = {80, 75, 7, 8}; // aka DATA
int old_zip_offset = zip_offset;
int uncompressed_file_data_length = (uncompressed_file_data == null ? 0 :
uncompressed_file_data.length);
int compressed_file_data_length = (compressed_file_data == null ? 0 :
compressed_file_data.length);
zip_offset += expect("data_header", data, zip_offset, compressed_post_data_header);
// u4 CRC32 checksum
zip_offset += expectL("crc32", data, zip_offset, expected_checksum);
// u4 compressed_size
zip_offset += expectL("compressed_size", data, zip_offset,
compressed_file_data_length);
// u4 uncompressed_size
zip_offset += expectL("uncompressed_size", data, zip_offset,
uncompressed_file_data_length);
if (debug) {
output("after reading DATA header, zip_offset is " + zip_offset);
}
if ((zip_offset - old_zip_offset) != 16) {
error("DATA header size should be 16, it was " + (zip_offset - old_zip_offset));
}
return (zip_offset - old_zip_offset);
}
// This method will read a CEN header and verify that
// the fields in the header match the expected results.
// This method returns the new zip_offset.
public static int verifyCENHeader(boolean compressed,
byte[] expected_file_name,
byte[] uncompressed_file_data,
byte[] compressed_file_data,
byte[] expected_extra_field,
byte[] expected_dostime,
long expected_checksum,
long uncompressed_rel_header_offset,
long compressed_rel_header_offset,
byte[] data,
int zip_offset)
throws Exception
{
// A CEN header should show up after an uncompressed entry or
// after the DATA header that follows a compressed entry
byte[] uncompressed_post_data_header = {80, 75, 1, 2}; // aka CEN
int old_zip_offset = zip_offset;
int uncompressed_file_data_length = (uncompressed_file_data == null ? 0 :
uncompressed_file_data.length);
int compressed_file_data_length = (compressed_file_data == null ? 0 :
compressed_file_data.length);
int expected_extra_field_length = (expected_extra_field == null ? 0
: expected_extra_field.length);
zip_offset += expect("cen_header", data, zip_offset, uncompressed_post_data_header);
// u2 version_used_to_write (10 or 20)
zip_offset += expect("write_version", data, zip_offset,
(compressed ? 20 : 10));
// u2 version_needed_to_extract (10 or 20)
zip_offset += expect("extract_version", data, zip_offset,
(compressed ? 20 : 10));
// u2 zip entry flags (seems to be set to 0 or 8)
// what is this for ??? is it like the compression method ???
zip_offset += expect("flags", data, zip_offset,
(compressed ? 8 : 0));
// u2 compression_method (0 or 8)
zip_offset += expect("compression_method", data, zip_offset,
(compressed ? 8 : 0));
// u4 dostime
zip_offset += expect("dostime", data, zip_offset, expected_dostime);
// u4 CRC32 checksum
zip_offset += expectL("crc32", data, zip_offset, expected_checksum);
// u4 compressed_size
zip_offset += expectL("compressed_size", data, zip_offset,
(compressed ? compressed_file_data_length :
uncompressed_file_data_length));
// u4 uncompressed_size
zip_offset += expectL("uncompressed_size", data, zip_offset,
uncompressed_file_data_length);
// u2 filename_length
zip_offset += expect("filename_length", data, zip_offset,
expected_file_name.length);
// u2 extra_field_length
zip_offset += expect("extra_field_length", data, zip_offset,
expected_extra_field_length);
// u2 comment_length
zip_offset += expect("comment_length", data, zip_offset, 0);
// u2 disknum
zip_offset += expect("disknum", data, zip_offset, 0);
// u2 internal_file_attributes
zip_offset += expect("internal_file_attributes", data, zip_offset, 0);
// u4 external_file_attributes
zip_offset += expectL("external_file_attributes", data, zip_offset, 0);
// u4 relative_offset_of_local_header
zip_offset += expectL("relative_offset_of_local_header", data, zip_offset,
(compressed ? compressed_rel_header_offset :
uncompressed_rel_header_offset));
if (debug) {
output("after reading CEN header, zip_offset is " + zip_offset);
}
if ((zip_offset - old_zip_offset) != 46) {
error("CEN header size should be 46, it was " + (zip_offset - old_zip_offset));
}
return (zip_offset - old_zip_offset);
}
// This method will read an END header and verify that
// the fields in the header match the expected results.
// This method returns the new zip_offset.
public static int verifyENDHeader(boolean compressed,
int total_disknumber,
int total_central,
long expected_cen_size,
long uncompressed_cen_offset,
long compressed_cen_offset,
byte[] data,
int zip_offset)
throws Exception
{
byte[] expected_end_signature = {80, 75, 5, 6}; // aka END
int old_zip_offset = zip_offset;
zip_offset += expect("end_signature", data, zip_offset, expected_end_signature);
// u2 disknumber
zip_offset += expect("disknumber", data, zip_offset, 0);
// u2 central_disknumber
zip_offset += expect("central_disknumber", data, zip_offset, 0);
// u2 total_disknumber
zip_offset += expect("total_disknumber", data, zip_offset, total_disknumber);
// u2 total_central
zip_offset += expect("total_central", data, zip_offset, total_central);
// u4 cen_size
zip_offset += expectL("cen_size", data, zip_offset, expected_cen_size);
// u2 cen_offset (index into file where CEN header begins)
zip_offset += expectL("cen_offset", data, zip_offset,
(compressed ? compressed_cen_offset : uncompressed_cen_offset));
// u2 comment_length
zip_offset += expect("comment_length", data, zip_offset, 0);
if (debug) {
output("after reading END header, zip_offset is " + zip_offset);
}
if ((zip_offset - old_zip_offset) != 22) {
error("END header size should be 22, it was " + (zip_offset - old_zip_offset));
}
return (zip_offset - old_zip_offset);
}
// This method will check that all the data in the stream
// has been verified by comparing the zip_offset to the
// length of the data array.
public static void verifyEOF(byte[] data,
int zip_offset)
throws Exception
{
if (debug) {
output("verified " + zip_offset + " bytes");
}
if (zip_offset != data.length) {
error("zip_offset not at EOF");
} else {
if (debug) {
output("zip_offset is at EOF");
}
}
}
// --------------------------------------------------------------------------------
// Zip file format
// Byte offset -> Size DESCRIPTION
// zo is the zip_offset, the integer index into the stream
// z0 = 0
// First the LOC header appears
// zo + 0 -> u4 LOC signature {80, 75, 3, 4}
// zo + 4 -> u2 version_needed_to_extract (10 or 20)
// zo + 6 -> u2 zip entry flags
// zo + 8 -> u2 compression_method (0 or 8)
// zo + 10 -> u4 dostime
// zo + 14 -> u4 crc32
// zo + 18 -> u4 compressed_size
// zo + 22 -> u4 uncompressed_size
// zo + 26 -> u2 filename_length
// zo + 28 -> u2 extra_field_length
// zo = 30
// zo - (zo + filename_length) filename
// zo - (zo + extra_field_length) extra_field
// then the actual data from the file appears in the zip file
// zo = (zo + filename_length + extra_field_length + data_length)
// If the entry was compressed, then the DATA header will appear
// zo + 0 -> u4 DATA signature {80, 75, 7, 8}
// zo + 4 -> u4 data_crc
// zo + 8 -> u4 data_compressedsize
// zo + 12 -> u4 data_uncompressedsize
// Now the CEN header will appear
// zo + 0 -> u4 CEN signature {80, 75, 1, 2}
// zo + 4 -> u2 version used to write zipfile (10 or 20)
// zo + 6 -> u2 version needed to extract (10 or 20)
// zo + 8 -> u2 flags
// zo + 10 -> u2 compression_method
// zo + 12 -> u4 dostime
// zo + 16 -> u4 crc
// zo + 20 -> u4 compressed_size
// zo + 24 -> u4 uncompressed_size
// zo + 28 -> u2 filename_length
// zo + 30 -> u2 extra_field_length
// zo + 32 -> u2 comment_length
// zo + 34 -> u2 disknum
// zo + 36 -> u2 internal_file_attributes
// zo + 38 -> u4 external_file_attributes
// zo + 42 -> u4 relative_offset_of_local_header
// zo = zo + 46
// zo - (zo + filename_length) filename
// zo - (zo + extra_field_length) extra_field
// Now the END header will appear
// zo + 0 -> u4 END signature {80, 75, 5, 6}
// zo + 4 -> u2 disknumber
// zo + 6 -> u2 central_disknumber
// zo + 8 -> u2 total_disknumber
// zo + 10 -> u2 total_central
// zo + 12 -> u4 cen_size
// zo + 16 -> u4 cen_offset (index into file where CEN header begins)
// zo + 20 -> u2 comment_length
// ----------------------------------------------------------------------
// If there are two entries in the zip file the headers appear like this
// LOC (one)
// ?DATA (one)?
// LOC (two)
// ?DATA (two)?
// CEN (one)
// CEN (two)
// END
// Three entries would look like this
// LOC (one)
// ?DATA (one)?
// LOC (two)
// ?DATA (two)?
// LOC (three)
// ?DATA (three)?
// CEN (one)
// CEN (two)
// CEN (three)
// END
}
More information about the kaffe
mailing list