2012-11-17 19 views
5

Sınıf dosyalarını değiştirmek için ASM olarak bilinen bir baytkod kütüphanesi kullanıyorum, her sınıf dosyasını sınıf dosyaları ile dolu bir klasör yerine bir jar dosyasına geri yazmak istiyorum. Bu kodu çalıştırarak bunu:Geçersiz Giriş Sıkıştırılmış Boyutu

bir ZipException yani

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

} 

yapılan ClassReader, ClassWriter (kütüphanesinin her parçası) ve FieldAdapter (beklenen boyutu olmadığı için atmak zaman benim sorun oluşur tek başıma) sadece kodu sunun ve cw.toByteArray() işlevini kullandığım tüm sınıfın baytlarını elde etmek için. Bayt kodu manipülasyonunun kendisi için bir problem yok, sadece JarOutputStream üzerinden yeni bir jar dosyasına yazı yazmak. Bu sorunu çözmek için bilinen herkes?

+1

diğer tüm özelliklerini kopyalanan alırsınız? Tüm yığın izini gönderir misiniz? – ShyJ

cevap

8

sorunlu çizgi şudur: o da sıkıştırılmış boyutu kopyalar olarak

JarEntry je = new JarEntry(jarEntry); 

. Eğer adından başka alanları koruyarak umurumda sürece

, sen this constructor kullanmalı ve bu gibi yalnızca dosya adını verin:

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

sıkıştırılmış boyut otomatik olarak hesaplanacaktır.

+0

Çalıştığı% 100 teşekkür ederim –

4

bu şekilde Jar Attributes ve diğer meta bilgileri kopyalamaz. Sorun, jar/zip dosyasının başlangıçta paketlendikten sonra değiştirilmesinden kaynaklanır.

Bunu yapabilirsin:

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

Bu girişinin boyutunu neden olacaktır yeniden hesaplanması ve yöntem bu istisna atar orijinal jarEntry

İlgili konular