1adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul/* 2adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * Copyright (C) 2010 The Android Open Source Project 3adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * 4adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License"); 5adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * you may not use this file except in compliance with the License. 6adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * You may obtain a copy of the License at 7adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * 8adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * http://www.apache.org/licenses/LICENSE-2.0 9adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * 10adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * Unless required by applicable law or agreed to in writing, software 11adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS, 12adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * See the License for the specific language governing permissions and 14adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * limitations under the License. 15adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul */ 16adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 17adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulpackage com.android.dexgen.util; 18adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 19adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.BufferedInputStream; 20adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.BufferedOutputStream; 21adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.File; 22adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.FileInputStream; 23adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.FileOutputStream; 24adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.io.IOException; 25adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.util.jar.Attributes; 26adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.util.jar.JarEntry; 27adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.util.jar.JarOutputStream; 28adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulimport java.util.jar.Manifest; 29adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 30adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul/** 31adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * Helper class used to encapsulate generated .dex file into .jar 32adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * so that it fits {@code DexClassLoader} constructor. 33adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul */ 34adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgulpublic class DexJarMaker { 35adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 36adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul /** indicates name of the dex file added to jar */ 37adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul public static final String DEX_FILE_NAME_IN_JAR = "classes" + PathHolder.DEX_FILE_EXTENSION; 38adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 39adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul /** {@code non-null;} storage for all the paths related to current dex file */ 40adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul private final PathHolder pathHolder; 41adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 42adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul public DexJarMaker(PathHolder pathHolder) { 43adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul this.pathHolder = pathHolder; 44adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 45adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 46adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul /** Packs previously added files into a single jar archive. */ 47adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul public void create() throws DexClassLoadingException { 48adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul Manifest manifest = new Manifest(); 49adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); 50adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul JarOutputStream target = null; 51adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul try { 52adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul target = new JarOutputStream( 53adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul new BufferedOutputStream(new FileOutputStream(pathHolder.getJarFilePath())), 54adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul manifest); 55adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul add(new File(pathHolder.getDexFilePath()), target); 56adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 57adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } catch (IOException e) { 58adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul throw new DexClassLoadingException(e); 59adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 60adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul finally { 61adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul try { 62adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul if (target != null) { 63adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul target.close(); 64adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 65adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } catch(IOException e) { 66adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul // Ignoring deliberately in order to keep the original exception clear. 67adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 68adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 69adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 70adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 71adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul /** 72adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * Adds indicated file to the requested archive. 73adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * 74adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * @param source {@code non-null;} dex file to add 75adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * @param target {@code non-null;} target jar archive 76adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul * @throws IOException 77adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul */ 78adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul private void add(File source, JarOutputStream target) throws IOException { 79adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 80adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul if (!source.isFile()) { 81adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul throw new IllegalArgumentException("Wrong source dex file provided"); 82adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 83adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 84adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul BufferedInputStream in = new BufferedInputStream(new FileInputStream(source)); 85adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul JarEntry entry = new JarEntry(DEX_FILE_NAME_IN_JAR); 86adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul entry.setTime(source.lastModified()); 87adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul target.putNextEntry(entry); 88adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul 89adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul int curr = -1; 90adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul while ((curr = in.read()) != -1) { 91adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul target.write(curr); 92adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 93adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul target.closeEntry(); 94adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul } 95adcf37c5226629ed9cb5e73ee7627e0a45764cabPiotr Gurgul}