2012-11-17 14 views
5

Sto utilizzando una libreria bytecode nota come ASM per modificare i file di classe, quindi voglio scrivere ogni file di classe in un file jar anziché in una cartella piena di file di classe. Faccio questo eseguendo questo codice:Dimensione ingresso non valida Dimensione compressa

Il mio problema si verifica quando uno ZipException è un tiro per non essere la dimensione prevista, vale a dire

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; 
    } 
} 

} 

Il ClassReader, ClassWriter (ogni parte della biblioteca), e FieldAdapter (fatta da solo) basta altare il codice, e per ottenere i byte dell'intera classe uso cw.toByteArray(). Non c'è alcun problema per quanto riguarda la manipolazione bytecode stessa, è solo la scrittura in un nuovo file jar attraverso un JarOutputStream. Qualcuno sa come risolvere questo problema?

+1

Quale metodo genera questa eccezione? Potresti postare l'intera traccia dello stack? – ShyJ

risposta

8

La linea problematica è questo:

JarEntry je = new JarEntry(jarEntry); 

come sarà anche copiare la dimensione compressa.

A meno che non si preoccupano di conservare gli altri campi di nome, si dovrebbe usare this constructor e fornire solo il nome del file, come questo:

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

La dimensione compressa verrà poi calcolato automaticamente.

+0

Ha lavorato al 100% grazie –

4

in questo modo non copierà gli attributi Jar e altre metamodifiche. Il problema si verifica quando il file jar/zip viene modificato dopo che è stato inizialmente confezionato.

Si può fare questo:

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

Questo farà sì che la dimensione della voce di essere ricalcolato e avrai copiato tutti gli altri attributi rispetto all'originale JarEntry

Problemi correlati