/* * @(#)ProcessJAR.java 1.15 02/08/21 * * Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved. */ package com.sun.media.customizer; import java.util.*; import java.util.zip.*; import java.io.*; import javax.swing.JProgressBar; import javax.media.PlugInManager; import javax.media.CaptureDeviceManager; import javax.media.CaptureDeviceInfo; import javax.media.cdm.*; /** * The purpose of this class is to do the real customization work: * open the source JMF JAR file, * filter out those plugins not selected by the user, * create the target JAR file and write out all necessary classes. * An object of this class will run on a separate thread. * @version 2.0 * */ public class ProcessJAR extends Thread implements TokenDef { public static final String[] sollibs = { "libCvidPro.so", "libjmcvid.so", "libjmdaud.so", "libjmfCVIDPro.so", "libjmg723.so", "libjmgsm.so", "libjmh261.so", "libjmh263enc.so", "libjmiv32.so", "libjmjpeg.so", "libjmmpa.so", "libjmmpegv.so", "libjmmpx.so", "libjmmpx2.so", "libjmopi.so", "libjmsunray.so", "libjmvh263.so", "libjmxil.so", "libjmxlib.so", "libjsound.so", "soundbank.gm", "sound.jar", }; public static final String[] win32libs = { "jmacm.dll", "jmam.dll", "jmcvid.dll", "jmdaud.dll", "jmdaudc.dll", "jmddraw.dll", "jmg723.dll", "jmgdi.dll", "jmgsm.dll", "jmh261.dll", "jmh263enc.dll", "jmiv32.dll", "jmjpeg.dll", "jmmci.dll", "jmmpa.dll", "jmmpegv.dll", "jmvcm.dll", "jmvfw.dll", "jmvh263.dll", "jsound.dll", "soundbank.gm", "sound.jar", }; public static final Hashtable cdmap; static { cdmap = new Hashtable(); cdmap.put("dsound", "com/sun/media/protocol/dsound/DataSource.class"); cdmap.put("javasound", "com/sun/media/protocol/javasound/DataSource.class"); cdmap.put("vfw", "com/sun/media/protocol/vfw/DataSource.class"); cdmap.put("sunvideo", "com/sun/media/protocol/sunvideo/DataSource.class"); cdmap.put("sunvideoplus", "com/sun/media/protocol/sunvideoplus/DataSource.class"); } String srcJARname; String dstJARname; String workDir; int[] selected; ProgressDiag progressDlg; CusRegistry theRegistry; int release; boolean twojars; public ProcessJAR(String srcJARname, String dstJARname, int[] selected,ProgressDiag progressDlg, CusRegistry theRegistry, int release, boolean twojars) { this.srcJARname = srcJARname; this.dstJARname = dstJARname; this.selected = selected; this.progressDlg = progressDlg; this.theRegistry = theRegistry; this.workDir = this.theRegistry.getWorkDir(); this.release = release; this.twojars = twojars; } /** * run(): * The method of the thread to do the real job: * * Open source JAR file: * Open it for reading * make sure all mediaFormat/Codecs classes are there to pick * display class name/class count/file size while processing * * Process the request by marking necessary MediaFormat/Codec classes * * Create destinaton JAR file: * create the file, abort if any error * for each class from source * if this class is needed, write it to the destination JAR/ZIP file * otherwise ignore it * * When done, enable DONE button of the progress bar * * @Param N/A * @return N/A * */ public void run() { // Assuming 35% for reading, 15% for updating the registry and 50% for writing, can be adjusted if needed. File srcFile, dstFile, dstFile2 = null; long srcfilesize, filesizeSoFar; int classCountSoFar; int progressSoFar = 0; ZipFile srcZF = null; ZipEntry srcZE; FileOutputStream fos, fos2; ZipOutputStream zos = null, zos2 = null; InputStream is = null; double readRate, writeRate; //System.out.println("in ProcessJAR run..."); //System.out.println("srcname = " + srcJARname); //System.out.println("dstname = " + dstJARname); //for ( int i = 0; i < selected.length; i++) //System.out.println(" " + selected[i]); // let dialog thread execute first try { sleep(30); } catch (Exception ex) { } srcFile = new File(srcJARname); // We will use the file size as the base for the initial segment // of the progress bar srcfilesize = srcFile.length(); readRate = 35.0/srcfilesize; // Open the source file as a ZipFile try { srcZF = new ZipFile(srcFile); } catch (ZipException e) { errorMessage(e.getMessage()); return; } catch (IOException e) { errorMessage(e.getMessage()); return; } if ( CustomDB.getSize() == 0 ) CustomDB.buildDB(); else CustomDB.clearAllMarks(); Vector orglist = new Vector(); Enumeration se = srcZF.entries(); String clsname; long entrysize; classCountSoFar = 0; filesizeSoFar = 0; // read classes from source jar while (se.hasMoreElements()) { srcZE = (ZipEntry)se.nextElement(); clsname = srcZE.getName(); if (!(clsname.endsWith(".class") || clsname.endsWith(".gif")) ){ // System.out.println(clsname); continue; } orglist.addElement(srcZE); entrysize = srcZE.getCompressedSize(); classCountSoFar++; filesizeSoFar += entrysize; if ( classCountSoFar % 5 == 0 ) { progressSoFar = (int)(readRate*filesizeSoFar); progressDlg.updateValue(progressSoFar); progressDlg.updateSourceInfo(filesizeSoFar, classCountSoFar); myyield(); } } progressDlg.updateSourceInfo(srcfilesize, classCountSoFar); myyield(); // Finish loading source jar file, start to write target int notwanted = CustomDB.markAllClasses(selected); writeRate = 50.0/(classCountSoFar - notwanted); progressDlg.updateNote(I18N.getResource("ProcessJAR.REGISTRY")); myyield(); updateRegistry(); // Create the destination file if ( !twojars ) { dstFile = new File(dstJARname); try { fos = new FileOutputStream(dstFile); zos = new ZipOutputStream(fos); } catch (IOException e) { try { srcZF.close(); } catch (IOException ex) { } dstFile.delete(); errorMessage(e.getMessage()); return; } } else { dstFile = new File(dstJARname); String pp = dstFile.getParent() + File.separator; String fn = dstFile.getName(); // System.out.println("pp = " + pp); // System.out.println("fn = " + fn); dstFile = new File(pp + "core_" + fn); dstFile2 = new File(pp + "plugin_" + fn); try { fos = new FileOutputStream(dstFile); fos2 = new FileOutputStream(dstFile2); zos = new ZipOutputStream(fos); zos2 = new ZipOutputStream(fos2); } catch (IOException e) { try { srcZF.close(); } catch (IOException ex) { } dstFile.delete(); dstFile2.delete(); errorMessage(e.getMessage()); return; } } classCountSoFar = 0; filesizeSoFar = 0; byte buffer[] = new byte[4096]; // Read/Write buffer int len; DBItem dbentry; progressDlg.updateNote(I18N.getResource("ProcessJAR.WRT")); myyield(); // Traverse all classes from source JAR/ZIp file int NNN = orglist.size(); if ( !twojars ) { for (int nn = 0 ; nn < NNN; nn++ ) { srcZE = (ZipEntry)(orglist.elementAt(nn)); clsname = srcZE.getName(); entrysize = srcZE.getCompressedSize(); if ( (dbentry=(DBItem)CustomDB.get(clsname)) == null || dbentry.isMarked()) { ++classCountSoFar; // filesizeSoFar += entrysize; ZipEntry newZE; String rClsName = "com/sun/media/util/RegistryLib.class"; try { if ( clsname.equals(rClsName)) { String fullName = rClsName.replace('/', File.separatorChar); fullName = workDir + File.separator + fullName; is = new FileInputStream(fullName); } else { is = srcZF.getInputStream(srcZE); } newZE = new ZipEntry(clsname); zos.putNextEntry(newZE); while (true) { if (is.available() == 0) break; len = is.read(buffer); if (len == -1) break; zos.write(buffer, 0, len); } zos.closeEntry(); is.close(); if (clsname.equals("com/sun/media/util/RegistryLib.class")) { System.out.println("Default Registry replaced"); entrysize = newZE.getCompressedSize(); } } catch (IOException e) { try { srcZF.close(); }catch (IOException ex) { } dstFile.delete(); errorMessage(e.getMessage()); return; } filesizeSoFar += entrysize; } if ( classCountSoFar % 5 == 0 ) { progressSoFar = (int)(50 + writeRate * classCountSoFar); progressDlg.updateValue(progressSoFar); progressDlg.updateTargetInfo(filesizeSoFar, classCountSoFar); myyield(); } } // end of for nn // Done try { zos.close(); srcZF.close(); } catch ( IOException ex) { dstFile.delete(); errorMessage(ex.getMessage()); return; } } else { // generate two jars for (int nn = 0 ; nn < NNN; nn++ ) { srcZE = (ZipEntry)(orglist.elementAt(nn)); clsname = srcZE.getName(); entrysize = srcZE.getCompressedSize(); dbentry=(DBItem)CustomDB.get(clsname); if ( dbentry == null ) { // core classes ++classCountSoFar; // filesizeSoFar += entrysize; ZipEntry newZE; try { is = srcZF.getInputStream(srcZE); newZE = new ZipEntry(clsname); zos.putNextEntry(newZE); while (true) { if (is.available() == 0) break; len = is.read(buffer); if (len == -1) break; zos.write(buffer, 0, len); } zos.closeEntry(); is.close(); } catch (IOException e) { try { srcZF.close(); }catch (IOException ex) { } dstFile.delete(); errorMessage(e.getMessage()); return; } } else if ( dbentry.isMarked()) { // plugable classes ++classCountSoFar; // filesizeSoFar += entrysize; ZipEntry newZE; String rClsName = "com/sun/media/util/RegistryLib.class"; try { if ( clsname.equals(rClsName)) { String fullName = rClsName.replace('/', File.separatorChar); fullName = workDir + File.separator + fullName; is = new FileInputStream(fullName); } else { is = srcZF.getInputStream(srcZE); } newZE = new ZipEntry(clsname); zos2.putNextEntry(newZE); while (true) { if (is.available() == 0) break; len = is.read(buffer); if (len == -1) break; zos2.write(buffer, 0, len); } zos2.closeEntry(); is.close(); if (clsname.equals("com/sun/media/util/RegistryLib.class")) { System.out.println("Default Registry replaced"); entrysize = newZE.getCompressedSize(); } } catch (IOException e) { try { srcZF.close(); }catch (IOException ex) { } dstFile2.delete(); errorMessage(e.getMessage()); return; } } filesizeSoFar += entrysize; if ( classCountSoFar % 5 == 0 ) { progressSoFar = (int)(50 + writeRate * classCountSoFar); progressDlg.updateValue(progressSoFar); progressDlg.updateTargetInfo(filesizeSoFar, classCountSoFar); myyield(); } } // Done try { zos.close(); zos2.close(); srcZF.close(); } catch ( IOException ex) { dstFile.delete(); dstFile2.delete(); errorMessage(ex.getMessage()); return; } } // end of else twojars // ?? long dstfilesize = dstFile.length(); if ( twojars ) { dstfilesize += dstFile2.length(); } progressDlg.updateValue(100); progressDlg.updateTargetInfo(dstfilesize, classCountSoFar); progressDlg.enableDone(); // Process native libs if ( release >= 2 ) { System.out.println("***Needed native modules***"); } if ( release == 2 ) { //SPP String libname = null; for (int i = 0; i < sollibs.length; i++) { libname = sollibs[i]; if ( (dbentry=(DBItem)CustomDB.get(libname)) == null || dbentry.isMarked()) { System.out.println(libname); } } System.out.println("libjmutil.so"); } if (release == 3 ) { String libname = null; for (int i = 0; i < win32libs.length; i++) { libname = win32libs[i]; if ( (dbentry=(DBItem)CustomDB.get(libname)) == null || dbentry.isMarked()) { System.out.println(libname); } } System.out.println("jmutil.dll"); } } private void errorMessage(String msg) { progressDlg.sentErr(msg); myyield(); } private void myyield() { try { sleep(15); } catch (Exception ex) { } } private void updateRegistry() { Vector v; Hashtable newDefHash, newFullHash, theHash; boolean b_def, b_full; int len; String pin, newpin; newFullHash = (Hashtable)(theRegistry.getFullRegistry().clone()); if ( newFullHash != null && newFullHash.size() > 0 ) b_full = true; else b_full = false; if ( b_full ) { newDefHash = newFullHash; b_def = false; } else { newDefHash = (Hashtable)(theRegistry.getDefaultRegistry().clone()); if ( newDefHash != null && newDefHash.size() > 0 ) b_def = true; else b_def = false; } // update DEMUX v = PlugInManager.getPlugInList(null, null, PlugInManager.DEMULTIPLEXER); len = v.size(); for (int i = 0; i < len; i++) { pin = (String)v.elementAt(i); pin.trim(); newpin = pin.replace('.', '/') + ".class"; DBItem dbentry = (DBItem)CustomDB.get(newpin); if ( dbentry != null && !dbentry.isMarked()) { if ( b_full) { theRegistry.removePlugIn(newFullHash, pin,PlugInManager.DEMULTIPLEXER); } else if ( b_def) { theRegistry.removePlugIn(newDefHash, pin,PlugInManager.DEMULTIPLEXER); } } } // update CODEC v = PlugInManager.getPlugInList(null, null, PlugInManager.CODEC); len = v.size(); for (int i = 0; i < len; i++) { pin = (String)v.elementAt(i); pin.trim(); newpin = pin.replace('.', '/') + ".class"; DBItem dbentry = (DBItem)CustomDB.get(newpin); if ( dbentry != null && !dbentry.isMarked()) { // PlugInManager.removePlugIn(pin,PlugInManager.CODEC); if ( b_full) { theRegistry.removePlugIn(newFullHash,pin,PlugInManager.CODEC); } else if ( b_def) { theRegistry.removePlugIn(newDefHash,pin,PlugInManager.CODEC); } } } // update MUX v = PlugInManager.getPlugInList(null, null, PlugInManager.MULTIPLEXER); len = v.size(); for (int i = 0; i < len; i++) { pin = (String)v.elementAt(i); pin.trim(); newpin = pin.replace('.', '/') + ".class"; DBItem dbentry = (DBItem)CustomDB.get(newpin); if ( dbentry != null && !dbentry.isMarked()){ // PlugInManager.removePlugIn(pin,PlugInManager.MULTIPLEXER); if ( b_full) { theRegistry.removePlugIn(newFullHash, pin,PlugInManager.MULTIPLEXER); } else if ( b_def) { theRegistry.removePlugIn(newDefHash, pin,PlugInManager.MULTIPLEXER); } } } // update RENDERER v = PlugInManager.getPlugInList(null, null, PlugInManager.RENDERER); len = v.size(); for (int i = 0; i < len; i++) { pin = (String)v.elementAt(i); pin.trim(); newpin = pin.replace('.', '/') + ".class"; DBItem dbentry = (DBItem)CustomDB.get(newpin); if ( dbentry != null && !dbentry.isMarked()){ // PlugInManager.removePlugIn(pin,PlugInManager.RENDERER); if (b_full) { theRegistry.removePlugIn(newFullHash, pin,PlugInManager.RENDERER); } else if (b_def) { theRegistry.removePlugIn(newDefHash, pin,PlugInManager.RENDERER); } } } // update Capture Devices v = CaptureDeviceManager.getDeviceList(null); len = v.size(); String dname = null; for ( int i = 0; i < len; i++){ CaptureDeviceInfo info = (CaptureDeviceInfo)v.elementAt(i); dname = info.getLocator().getProtocol(); if ( !isCDSelected(dname)) { if ( b_full) { theRegistry.removeCaptureD(newFullHash, dname); } else if (b_def) { theRegistry.removeCaptureD(newDefHash, dname); } } } // generate RegistyLib.java if ( b_full ) { writeRegistryLib(newFullHash) ; } else if ( b_def) { writeRegistryLib(newDefHash); } // compile RegistryLib try { String[] cmdarr = new String[4]; cmdarr[0] = theRegistry.getJavacPath() + File.separator + "javac"; cmdarr[1] = "-d"; cmdarr[2] = workDir; cmdarr[3] = workDir + File.separator + "RegistryLib.java"; Process proc = Runtime.getRuntime().exec(cmdarr); proc.waitFor(); } catch (Exception ex) { ex.printStackTrace(); } // save the full registry to disk if (release >= 2 && b_full) theRegistry.saveRegistry(newFullHash); progressDlg.updateValue(42); myyield(); } private boolean isCDSelected(String dname) { DBItem dbentry = null; String pname; // System.out.println("dname = " + dname); pname = (String)(cdmap.get(dname)); dbentry = (DBItem)CustomDB.get(pname); if ( dbentry != null && dbentry.isMarked()) return true; return false; } private void writeRegistryLib(Hashtable newhash) { byte[] properties; int i,j; properties = null; // write the newhash to a ByteOutputStream try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); int tableSize = newhash.size(); oos.writeInt(tableSize); oos.writeInt(theRegistry.versionNumber); for (Enumeration e = newhash.keys(); e.hasMoreElements() ;) { String key = (String) e.nextElement(); Object value = newhash.get(key); oos.writeUTF(key); // write key as UTF chars. oos.writeObject(value); oos.flush(); } oos.close(); properties = bos.toByteArray(); } catch (Exception ex) { ex.printStackTrace(); System.out.println("Sth is wrong when saving the registry"); return; } // write RegistryLib try { String registryname = workDir + File.separator + "RegistryLib.java"; DataOutputStream ds = new DataOutputStream(new FileOutputStream(registryname)); ds.writeBytes("/* Generated by RegistryGen.\n DO NOT EDIT.*/\n\n"); ds.writeBytes("package com.sun.media.util;\n\n"); ds.writeBytes("public abstract class "); ds.writeBytes("RegistryLib"); ds.writeBytes(" {\n\n"); if (properties.length > 0) { ds.writeBytes(" public static byte[] getData(){\n"); ds.writeBytes(" int i;\n"); ds.writeBytes(" byte[] b= new byte["+properties.length+"];\n"); ds.writeBytes(" for (i=0;i<b.length;i++)\n"); // switch back between 255 and 0 ds.writeBytes(" b[i] = (byte)(s.charAt(i)-1);\n"); ds.writeBytes(" return b;\n"); ds.writeBytes(" }\n"); } else { ds.writeBytes(" public static byte[] getData(){\n"); ds.writeBytes(" return null;\n"); ds.writeBytes(" }\n"); } ds.writeBytes(" private static String s = \n "); ds.writeBytes("\""); int len= properties.length; for (j = 0; j < len; j++) { // switch between 255 and 0 since 0 is more common ds.writeBytes( ("\\"+byte2oct((byte)(1+properties[j]))) ); if ((j%16)==15) { ds.writeBytes("\"+\n \"" ); } } ds.writeBytes("\";\n\n" ); ds.writeBytes("}\n"); //trailer ds.close(); } catch (Exception ex) { System.out.println("Sth wrong when writing RegsitryLib"); } } // convert byte to its octal presentation (always 3 characters) private static String byte2oct(byte b) { int i=b&0xff; int dig3=i%8; int dig2=(i/8)%8; int dig1=i/64; return (""+dig1+""+dig2+""+dig3); } }