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}