/* * 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 elements = new ArrayList(); 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 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; } }