2012-11-17 9 views
5

Używam biblioteki kodu bajtowego znanej jako ASM do zmiany plików klas, a następnie chcę zapisać każdy plik klasy z powrotem w pliku jar, a nie w folderze wypełnionym plikami klas. Robię to, uruchamiając ten kod:Nieprawidłowy wpis Skompresowany rozmiar

Mój problem pojawia się, gdy ZipException jest rzut za brak oczekiwanej wielkości, tj

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 (każda część biblioteki), a FieldAdapter (wykonane samodzielnie) po prostu ołtarza kod, a aby uzyskać bajty całej klasy używam cw.toByteArray(). Nie ma problemu, jak w przypadku samej manipulacji kodu bajtowego, to tylko pisanie do nowego pliku jar za pośrednictwem JarOutputStream. Ktoś wie, jak rozwiązać ten problem?

+1

Która metoda rzuca ten wyjątek? Czy mógłbyś opublikować cały ślad stosu? – ShyJ

Odpowiedz

8

Problematyczny linia to:

JarEntry je = new JarEntry(jarEntry); 

ponieważ będzie ona również skopiować skompresowany rozmiar.

Jeśli nie dbają o zachowanie innych dziedzin niż nazwy, należy użyć this constructor i dostarczyć tylko nazwę pliku, jak to:

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

Sprężone rozmiar zostanie automatycznie obliczony.

+0

W 100% dziękuję –

4

w ten sposób nie będzie kopiować Atrybuty Słoika i inne meta informacje. Problem jest spowodowany modyfikacją pliku jar/zip po jego początkowym upakowaniu.

Można to zrobić:

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

Spowoduje to wielkość wpisu być przeliczone i dostaniesz skopiowane wszystkie inne atrybuty z oryginalnego jarEntry