Invalid input compression size

I use the bytecode library known as ASM to modify class files, and then I want to write each class file back to the jar file, and not to the folder filled with class files. I do this by running this code:

My problem occurs when a ZipException is thrown for an not expected size, i.e.

java.util.zip.ZipException: invalid entry compressed size (expected 695 but got 693 bytes) at java.util.zip.ZipOutputStream.closeEntry(Unknown Source) at org.steinburg.client.accessor.Accessor.accessJar(Accessor.java:64) at org.steinburg.client.accessor.Accessor.<init>(Accessor.java:41) at Loader.main(Loader.java:5) package org.steinburg.client.accessor; import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; public class Accessor { private String input; private File inFile; private JarEntry jarEntry; private JarFile jarFile; private Enumeration<JarEntry> entries; private InputStream is; private String out; private File outFile; private FileOutputStream fos; private JarOutputStream jos; private byte[] bytes; public Accessor(){ try{ input = new String("Input Jar.jar"); inFile = new File(input); jarFile = new JarFile(inFile); entries = jarFile.entries(); out = new String("Output Jar.jar"); outFile = new File(out); fos = new FileOutputStream(outFile); jos = new JarOutputStream(fos); accessJar(); } catch (Exception e) { e.printStackTrace(); } } protected final void accessJar(){ try { while (entries.hasMoreElements()){ jarEntry = entries.nextElement(); is = jarFile.getInputStream(jarEntry); if (jarEntry.getName().endsWith(".class")){ ClassReader cr = new ClassReader(is); ClassWriter cw = new ClassWriter(cr, 0); FieldAdapter fa = new FieldAdapter(cw); cr.accept(fa, 0); bytes = cw.toByteArray(); } else { bytes = readBytes(is); } JarEntry je = new JarEntry(jarEntry); jos.putNextEntry(je); jos.write(bytes); jos.closeEntry(); } jos.close(); } catch (Exception e) { e.printStackTrace(); } } protected byte[] readBytes(InputStream inputStream){ try{ DataInputStream reader = new DataInputStream(inputStream); byte[] toReturn = new byte[reader.available()]; reader.readFully(toReturn); reader.close(); return toReturn; } catch (Exception e){ e.printStackTrace(); return null; } } } 

ClassReader, ClassWriter (each part of the library) and FieldAdapter (made by me) simply despise the code, and to get the bytes of the whole class I use cw.toByteArray (). There is no problem how to manipulate bytecode, it is just writing to a new jar file via JarOutputStream. Does anyone know how to solve this problem?

+6
source share
2 answers

The problem line is this:

 JarEntry je = new JarEntry(jarEntry); 

as it will also copy the compressed size.

If you do not care about saving fields other than the name, you should use this constructor and specify only the file name, since this:

 JarEntry je = new JarEntry(jarEntry.getName ()); 

Then the compressed size is automatically calculated.

+9
source

by doing so, it will not copy Jar attributes and other meta information. The problem occurs when the jar / zip file changes after its initial packaging.

You can do it:

 JarEntry je = new JarEntry(jarEntry); je.setCompressedSize(-1); 

This will recalculate the record size and you will copy all other attributes from the original jarEntry

+5
source

All Articles