1*055d4590SKeyi Gui /* 2*055d4590SKeyi Gui * Copyright (C) 2014 The Android Open Source Project 3*055d4590SKeyi Gui * 4*055d4590SKeyi Gui * Licensed under the Apache License, Version 2.0 (the "License"); 5*055d4590SKeyi Gui * you may not use this file except in compliance with the License. 6*055d4590SKeyi Gui * You may obtain a copy of the License at 7*055d4590SKeyi Gui * 8*055d4590SKeyi Gui * http://www.apache.org/licenses/LICENSE-2.0 9*055d4590SKeyi Gui * 10*055d4590SKeyi Gui * Unless required by applicable law or agreed to in writing, software 11*055d4590SKeyi Gui * distributed under the License is distributed on an "AS IS" BASIS, 12*055d4590SKeyi Gui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*055d4590SKeyi Gui * See the License for the specific language governing permissions and 14*055d4590SKeyi Gui * limitations under the License. 15*055d4590SKeyi Gui */ 16*055d4590SKeyi Gui 17*055d4590SKeyi Gui package com.android.multidex; 18*055d4590SKeyi Gui 19*055d4590SKeyi Gui import com.android.dx.cf.direct.DirectClassFile; 20*055d4590SKeyi Gui import com.android.dx.cf.direct.StdAttributeFactory; 21*055d4590SKeyi Gui import java.io.ByteArrayOutputStream; 22*055d4590SKeyi Gui import java.io.File; 23*055d4590SKeyi Gui import java.io.FileNotFoundException; 24*055d4590SKeyi Gui import java.io.IOException; 25*055d4590SKeyi Gui import java.io.InputStream; 26*055d4590SKeyi Gui import java.util.ArrayList; 27*055d4590SKeyi Gui import java.util.List; 28*055d4590SKeyi Gui import java.util.regex.Pattern; 29*055d4590SKeyi Gui import java.util.zip.ZipException; 30*055d4590SKeyi Gui import java.util.zip.ZipFile; 31*055d4590SKeyi Gui 32*055d4590SKeyi Gui class Path { 33*055d4590SKeyi Gui getClassPathElement(File file)34*055d4590SKeyi Gui static ClassPathElement getClassPathElement(File file) 35*055d4590SKeyi Gui throws ZipException, IOException { 36*055d4590SKeyi Gui if (file.isDirectory()) { 37*055d4590SKeyi Gui return new FolderPathElement(file); 38*055d4590SKeyi Gui } else if (file.isFile()) { 39*055d4590SKeyi Gui return new ArchivePathElement(new ZipFile(file)); 40*055d4590SKeyi Gui } else if (file.exists()) { 41*055d4590SKeyi Gui throw new IOException("\"" + file.getPath() + 42*055d4590SKeyi Gui "\" is not a directory neither a zip file"); 43*055d4590SKeyi Gui } else { 44*055d4590SKeyi Gui throw new FileNotFoundException("File \"" + file.getPath() + "\" not found"); 45*055d4590SKeyi Gui } 46*055d4590SKeyi Gui } 47*055d4590SKeyi Gui 48*055d4590SKeyi Gui List<ClassPathElement> elements = new ArrayList<ClassPathElement>(); 49*055d4590SKeyi Gui private final String definition; 50*055d4590SKeyi Gui private final ByteArrayOutputStream baos = new ByteArrayOutputStream(40 * 1024); 51*055d4590SKeyi Gui private final byte[] readBuffer = new byte[20 * 1024]; 52*055d4590SKeyi Gui Path(String definition)53*055d4590SKeyi Gui Path(String definition) throws IOException { 54*055d4590SKeyi Gui this.definition = definition; 55*055d4590SKeyi Gui for (String filePath : definition.split(Pattern.quote(File.pathSeparator))) { 56*055d4590SKeyi Gui try { 57*055d4590SKeyi Gui addElement(getClassPathElement(new File(filePath))); 58*055d4590SKeyi Gui } catch (IOException e) { 59*055d4590SKeyi Gui throw new IOException("Wrong classpath: " + e.getMessage(), e); 60*055d4590SKeyi Gui } 61*055d4590SKeyi Gui } 62*055d4590SKeyi Gui } 63*055d4590SKeyi Gui readStream(InputStream in, ByteArrayOutputStream baos, byte[] readBuffer)64*055d4590SKeyi Gui private static byte[] readStream(InputStream in, ByteArrayOutputStream baos, byte[] readBuffer) 65*055d4590SKeyi Gui throws IOException { 66*055d4590SKeyi Gui try { 67*055d4590SKeyi Gui for (;;) { 68*055d4590SKeyi Gui int amt = in.read(readBuffer); 69*055d4590SKeyi Gui if (amt < 0) { 70*055d4590SKeyi Gui break; 71*055d4590SKeyi Gui } 72*055d4590SKeyi Gui 73*055d4590SKeyi Gui baos.write(readBuffer, 0, amt); 74*055d4590SKeyi Gui } 75*055d4590SKeyi Gui } finally { 76*055d4590SKeyi Gui in.close(); 77*055d4590SKeyi Gui } 78*055d4590SKeyi Gui return baos.toByteArray(); 79*055d4590SKeyi Gui } 80*055d4590SKeyi Gui 81*055d4590SKeyi Gui @Override toString()82*055d4590SKeyi Gui public String toString() { 83*055d4590SKeyi Gui return definition; 84*055d4590SKeyi Gui } 85*055d4590SKeyi Gui getElements()86*055d4590SKeyi Gui Iterable<ClassPathElement> getElements() { 87*055d4590SKeyi Gui return elements; 88*055d4590SKeyi Gui } 89*055d4590SKeyi Gui addElement(ClassPathElement element)90*055d4590SKeyi Gui private void addElement(ClassPathElement element) { 91*055d4590SKeyi Gui assert element != null; 92*055d4590SKeyi Gui elements.add(element); 93*055d4590SKeyi Gui } 94*055d4590SKeyi Gui getClass(String path)95*055d4590SKeyi Gui synchronized DirectClassFile getClass(String path) throws FileNotFoundException { 96*055d4590SKeyi Gui DirectClassFile classFile = null; 97*055d4590SKeyi Gui for (ClassPathElement element : elements) { 98*055d4590SKeyi Gui try { 99*055d4590SKeyi Gui InputStream in = element.open(path); 100*055d4590SKeyi Gui try { 101*055d4590SKeyi Gui byte[] bytes = readStream(in, baos, readBuffer); 102*055d4590SKeyi Gui baos.reset(); 103*055d4590SKeyi Gui classFile = new DirectClassFile(bytes, path, false); 104*055d4590SKeyi Gui classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); 105*055d4590SKeyi Gui break; 106*055d4590SKeyi Gui } finally { 107*055d4590SKeyi Gui in.close(); 108*055d4590SKeyi Gui } 109*055d4590SKeyi Gui } catch (IOException e) { 110*055d4590SKeyi Gui // search next element 111*055d4590SKeyi Gui } 112*055d4590SKeyi Gui } 113*055d4590SKeyi Gui if (classFile == null) { 114*055d4590SKeyi Gui throw new FileNotFoundException("File \"" + path + "\" not found"); 115*055d4590SKeyi Gui } 116*055d4590SKeyi Gui return classFile; 117*055d4590SKeyi Gui } 118*055d4590SKeyi Gui } 119