Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

ZipBlockWriter trouble

Moderators: kris

Posted: 05/17/09 15:48:54

Hi!

I want to modify a Java JAR file. Basically, I want to exchange to manifest.mf file. For that purpose, I created the following piece of code:

	ZipBlockReader zr = new ZipBlockReader("..\\test.jar");
	ZipBlockWriter zw = new ZipBlockWriter("..\\test-neu.jar");
	zw.method = Method.Deflate;
	while (zr.more()) {
		ZipEntry ze = zr.get();
		if (ze.info.name == "META-INF/MANIFEST.MF") {
			zw.putData(ze.info, MANIFEST);
		}
		else if (ze.info.name[ze.info.name.length-1] != '/') {
			zw.putEntry(ze.info, ze);
		}
	}
	zw.finish();
	zr.close();

(MANIFEST is a const char[] holding the content of the manifest.mf file.)

On execution, an exception is thrown: tango.io.compress.Zip.ZipException?: inconsistent headers for file "de/redstar/test/Main.class"; archive is likely corrupted

After looking at some zip format documentation, I think that the problem is in method LocalFileHeader?.agrees_with():

        if( data.extract_version != h.data.extract_version
                || data.general_flags != h.data.general_flags
                || data.compression_method != h.data.compression_method
                || data.modification_file_time != h.data.modification_file_time
                || data.modification_file_date != h.data.modification_file_date
                || data.crc_32 != h.data.crc_32
                || data.compressed_size != h.data.compressed_size
                || data.uncompressed_size != h.data.uncompressed_size
                || file_name != h.file_name )
            return false;
        
        // We need a separate check for the sizes and crc32, since these will
        // be zero if a trailing descriptor was used.
        if( !h.usingDataDescriptor && (
                   data.crc_32 != h.data.crc_32
                || data.compressed_size != h.data.compressed_size
                || data.uncompressed_size != h.data.uncompressed_size ) )
            return false;

My jar file uses the data descriptor, therefore crc_32, compressed_size and uncompressed_size are zero in the local file header (as the comment before the second if states). But this line is never reached, because all 3 attributes are already used in the first if.

Since I am really new to D and Tango, I am unsure if this is really a bug or if I am misusing the Zip classes... (BTW: I use Tango 0.99.8 on Windows XP.)

Thanks for your help!

Kai

Author Message

Posted: 05/18/09 03:54:48

Opened a ticket for this: http://www.dsource.org/projects/tango/ticket/1659

If the test JAR isn't too large, could you attach it so I can verify the changes work?

Posted: 05/20/09 02:49:23

I attached the jar file to the bug report.

But my solution is only half way: if the entry has a data descriptor, then putEntry() copies the original local file header. This means that the 'data descriptor bit' is set, but no data descriptor is written.