Path.java revision 893795fc95fdd77d398ebb77a0fe336c45b596cf
1/*
2 * Copyright (C) 2014 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
17package com.android.multidex;
18
19import com.android.dx.cf.direct.DirectClassFile;
20import com.android.dx.cf.direct.StdAttributeFactory;
21
22import java.io.ByteArrayOutputStream;
23import java.io.File;
24import java.io.FileNotFoundException;
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.ArrayList;
28import java.util.List;
29import java.util.regex.Pattern;
30import java.util.zip.ZipException;
31import java.util.zip.ZipFile;
32
33class Path {
34
35    static ClassPathElement getClassPathElement(File file)
36            throws ZipException, IOException {
37        if (file.isDirectory()) {
38            return new FolderPathElement(file);
39        } else if (file.isFile()) {
40            return new ArchivePathElement(new ZipFile(file));
41        } else if (file.exists()) {
42            throw new IOException("\"" + file.getPath() +
43                    "\" is not a directory neither a zip file");
44        } else {
45            throw new FileNotFoundException("File \"" + file.getPath() + "\" not found");
46        }
47    }
48
49    List<ClassPathElement> elements = new ArrayList<ClassPathElement>();
50    private final String definition;
51    private final ByteArrayOutputStream baos = new ByteArrayOutputStream(40 * 1024);
52    private final byte[] readBuffer = new byte[20 * 1024];
53
54    Path(String definition) throws IOException {
55        this.definition = definition;
56        for (String filePath : definition.split(Pattern.quote(File.pathSeparator))) {
57            try {
58                addElement(getClassPathElement(new File(filePath)));
59            } catch (IOException e) {
60                throw new IOException("Wrong classpath: " + e.getMessage(), e);
61            }
62        }
63    }
64
65    private static byte[] readStream(InputStream in, ByteArrayOutputStream baos, byte[] readBuffer)
66            throws IOException {
67        try {
68            for (;;) {
69                int amt = in.read(readBuffer);
70                if (amt < 0) {
71                    break;
72                }
73
74                baos.write(readBuffer, 0, amt);
75            }
76        } finally {
77            in.close();
78        }
79        return baos.toByteArray();
80    }
81
82    @Override
83    public String toString() {
84        return definition;
85    }
86
87    Iterable<ClassPathElement> getElements() {
88      return elements;
89    }
90
91    private void addElement(ClassPathElement element) {
92        assert element != null;
93        elements.add(element);
94    }
95
96    synchronized DirectClassFile getClass(String path) throws FileNotFoundException {
97        DirectClassFile classFile = null;
98        for (ClassPathElement element : elements) {
99            try {
100                InputStream in = element.open(path);
101                try {
102                    byte[] bytes = readStream(in, baos, readBuffer);
103                    baos.reset();
104                    classFile = new DirectClassFile(bytes, path, false);
105                    classFile.setAttributeFactory(StdAttributeFactory.THE_ONE);
106                    break;
107                } finally {
108                    in.close();
109                }
110            } catch (IOException e) {
111                // search next element
112            }
113        }
114        if (classFile == null) {
115            throw new FileNotFoundException("File \"" + path + "\" not found");
116        }
117        return classFile;
118    }
119}