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