2012-11-17 15 views
5

クラスファイルを変更するためにASMと呼ばれるバイトコードライブラリを使用しています。クラスファイルで満たされたフォルダではなく、jarファイルにそれぞれのクラスファイルを書き戻したいと思います。私はこのコードを実行することにより、次の操作を行います。無効なエントリ圧縮されたサイズ

持つZipExceptionはすなわち、

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(ライブラリーの各部分)、およびFieldAdapter(予想されるサイズをされていないために投げているとき、私の問題が発生します自分で)コードを祭壇にし、クラス全体のバイトを得るために私はcw.toByteArray()を使います。バイトコードの操作自体は問題ありません.JarOutputStreamを使って新しいjarファイルに書き込むだけです。この問題を解決する方法を知っている人は誰ですか?それはまた、圧縮サイズがコピーされますよう

JarEntry je = new JarEntry(jarEntry); 

+1

から他のすべての属性をコピーされますよね?スタックトレース全体を投稿できますか? – ShyJ

答えて

8

問題の行はこれです。

あなたが名前以外の分野を維持を気にしないかぎり、this constructorを使用する必要がありますし、このように、ファイル名のみを提供します。

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

圧縮サイズが自動的に計算されます。

+0

働いた100%ありがとう –

4

このようにすると、Jar属性やその他のメタ情報はコピーされません。 この問題は、jarファイルが最初にパッケージ化された後に変更された場合に発生します。あなたがこれを行うことができます

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

をこれは、エントリのサイズが再計算されることになりますと、あなたはメソッドは、この例外をスローオリジナルたJarEntry

関連する問題