| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.multidex; |
| |
| import com.android.dx.cf.direct.DirectClassFile; |
| import com.android.dx.cf.direct.StdAttributeFactory; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| import java.util.zip.ZipException; |
| import java.util.zip.ZipFile; |
| |
| class Path { |
| |
| static ClassPathElement getClassPathElement(File file) |
| throws ZipException, IOException { |
| if (file.isDirectory()) { |
| return new FolderPathElement(file); |
| } else if (file.isFile()) { |
| return new ArchivePathElement(new ZipFile(file)); |
| } else if (file.exists()) { |
| throw new IOException("\"" + file.getPath() + |
| "\" is not a directory neither a zip file"); |
| } else { |
| throw new FileNotFoundException("File \"" + file.getPath() + "\" not found"); |
| } |
| } |
| |
| List<ClassPathElement> elements = new ArrayList<ClassPathElement>(); |
| private final String definition; |
| private final ByteArrayOutputStream baos = new ByteArrayOutputStream(40 * 1024); |
| private final byte[] readBuffer = new byte[20 * 1024]; |
| |
| Path(String definition) throws IOException { |
| this.definition = definition; |
| for (String filePath : definition.split(Pattern.quote(File.pathSeparator))) { |
| try { |
| addElement(getClassPathElement(new File(filePath))); |
| } catch (IOException e) { |
| throw new IOException("Wrong classpath: " + e.getMessage(), e); |
| } |
| } |
| } |
| |
| private static byte[] readStream(InputStream in, ByteArrayOutputStream baos, byte[] readBuffer) |
| throws IOException { |
| try { |
| for (;;) { |
| int amt = in.read(readBuffer); |
| if (amt < 0) { |
| break; |
| } |
| |
| baos.write(readBuffer, 0, amt); |
| } |
| } finally { |
| in.close(); |
| } |
| return baos.toByteArray(); |
| } |
| |
| @Override |
| public String toString() { |
| return definition; |
| } |
| |
| Iterable<ClassPathElement> getElements() { |
| return elements; |
| } |
| |
| private void addElement(ClassPathElement element) { |
| assert element != null; |
| elements.add(element); |
| } |
| |
| synchronized DirectClassFile getClass(String path) throws FileNotFoundException { |
| DirectClassFile classFile = null; |
| for (ClassPathElement element : elements) { |
| try { |
| InputStream in = element.open(path); |
| try { |
| byte[] bytes = readStream(in, baos, readBuffer); |
| baos.reset(); |
| classFile = new DirectClassFile(bytes, path, false); |
| classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); |
| break; |
| } finally { |
| in.close(); |
| } |
| } catch (IOException e) { |
| // search next element |
| } |
| } |
| if (classFile == null) { |
| throw new FileNotFoundException("File \"" + path + "\" not found"); |
| } |
| return classFile; |
| } |
| } |