1ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver/* 2ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * Copyright 2012, Google Inc. 3ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * All rights reserved. 4ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * 5ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * Redistribution and use in source and binary forms, with or without 6ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * modification, are permitted provided that the following conditions are 7ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * met: 8ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * 9ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * * Redistributions of source code must retain the above copyright 10ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * notice, this list of conditions and the following disclaimer. 11ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * * Redistributions in binary form must reproduce the above 12ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * copyright notice, this list of conditions and the following disclaimer 13ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * in the documentation and/or other materials provided with the 14ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * distribution. 15ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * * Neither the name of Google Inc. nor the names of its 16ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * contributors may be used to endorse or promote products derived from 17ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * this software without specific prior written permission. 18ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * 19ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver */ 31ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver 32ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruverpackage org.jf.dexlib2; 33ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver 34ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruverimport com.google.common.io.ByteStreams; 35ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruverimport org.jf.dexlib2.dexbacked.DexBackedDexFile; 36d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruverimport org.jf.dexlib2.dexbacked.DexBackedOdexFile; 37ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruverimport org.jf.dexlib2.iface.DexFile; 380f198bc78bbb18a2eed3b55403ce17c93ea98932Ben Gruverimport org.jf.dexlib2.writer.pool.DexPool; 39ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruverimport org.jf.util.ExceptionWithContext; 40ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver 41ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruverimport javax.annotation.Nonnull; 42d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruverimport java.io.*; 43ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruverimport java.util.zip.ZipEntry; 44ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruverimport java.util.zip.ZipFile; 45ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver 4685b31462241daf1d5d5e7b5e94ca926e46dff971Ben Gruverpublic final class DexFileFactory { 47ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver @Nonnull 4883f77f51aa888998486c0c9ad693047480b060b0Ben Gruver public static DexBackedDexFile loadDexFile(String path, int api) throws IOException { 4983f77f51aa888998486c0c9ad693047480b060b0Ben Gruver return loadDexFile(new File(path), new Opcodes(api)); 50ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver } 51ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver 52ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver @Nonnull 5383f77f51aa888998486c0c9ad693047480b060b0Ben Gruver public static DexBackedDexFile loadDexFile(File dexFile, int api) throws IOException { 5483f77f51aa888998486c0c9ad693047480b060b0Ben Gruver return loadDexFile(dexFile, new Opcodes(api)); 5583f77f51aa888998486c0c9ad693047480b060b0Ben Gruver } 5683f77f51aa888998486c0c9ad693047480b060b0Ben Gruver 5783f77f51aa888998486c0c9ad693047480b060b0Ben Gruver @Nonnull 5883f77f51aa888998486c0c9ad693047480b060b0Ben Gruver public static DexBackedDexFile loadDexFile(File dexFile, @Nonnull Opcodes opcodes) throws IOException { 59ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver ZipFile zipFile = null; 60d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver boolean isZipFile = false; 61ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver try { 62ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver zipFile = new ZipFile(dexFile); 63ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver // if we get here, it's safe to assume we have a zip file 64ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver isZipFile = true; 65ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver 66ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver ZipEntry zipEntry = zipFile.getEntry("classes.dex"); 67ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver if (zipEntry == null) { 684cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver throw new NoClassesDexException("zip file %s does not contain a classes.dex file", dexFile.getName()); 69ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 70ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver long fileLength = zipEntry.getSize(); 71ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver if (fileLength < 40) { 72ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver throw new ExceptionWithContext( 73ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver "The classes.dex file in %s is too small to be a valid dex file", dexFile.getName()); 74ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } else if (fileLength > Integer.MAX_VALUE) { 75ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver throw new ExceptionWithContext("The classes.dex file in %s is too large to read in", dexFile.getName()); 76ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 77d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver byte[] dexBytes = new byte[(int)fileLength]; 78ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver ByteStreams.readFully(zipFile.getInputStream(zipEntry), dexBytes); 7983f77f51aa888998486c0c9ad693047480b060b0Ben Gruver return new DexBackedDexFile(opcodes, dexBytes); 80ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } catch (IOException ex) { 81d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver // don't continue on if we know it's a zip file 82ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver if (isZipFile) { 83ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver throw ex; 84ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 85ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } finally { 86ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver if (zipFile != null) { 87ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver try { 88ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver zipFile.close(); 89ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } catch (IOException ex) { 90ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver // just eat it 91ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 92ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 93ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 94ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver 95d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver InputStream inputStream = new BufferedInputStream(new FileInputStream(dexFile)); 96d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver 97d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver try { 9883f77f51aa888998486c0c9ad693047480b060b0Ben Gruver return DexBackedDexFile.fromInputStream(opcodes, inputStream); 99d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver } catch (DexBackedDexFile.NotADexFile ex) { 100d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver // just eat it 101d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver } 102d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver 103d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver // Note: DexBackedDexFile.fromInputStream will reset inputStream back to the same position, if it fails 104d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver 105d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver try { 10683f77f51aa888998486c0c9ad693047480b060b0Ben Gruver return DexBackedOdexFile.fromInputStream(opcodes, inputStream); 107d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver } catch (DexBackedOdexFile.NotAnOdexFile ex) { 108d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver // just eat it 109ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver } 110ebc11d32160041c61c5fb5be11e3d82853486880Ben Gruver 111d45a6a60921ac27a4f13360a68e02e8f5fc28454Ben Gruver throw new ExceptionWithContext("%s is not an apk, dex file or odex file.", dexFile.getPath()); 112ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver } 11385b31462241daf1d5d5e7b5e94ca926e46dff971Ben Gruver 1144ffbfa2e71ffdf6ecaa8429b19ce29daa28e9fc4Ben Gruver public static void writeDexFile(String path, DexFile dexFile) throws IOException { 1150f198bc78bbb18a2eed3b55403ce17c93ea98932Ben Gruver DexPool.writeTo(path, dexFile); 1164ffbfa2e71ffdf6ecaa8429b19ce29daa28e9fc4Ben Gruver } 1174ffbfa2e71ffdf6ecaa8429b19ce29daa28e9fc4Ben Gruver 11885b31462241daf1d5d5e7b5e94ca926e46dff971Ben Gruver private DexFileFactory() {} 1194cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver 1204cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver public static class NoClassesDexException extends ExceptionWithContext { 1214cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver public NoClassesDexException(Throwable cause) { 1224cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver super(cause); 1234cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver } 1244cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver 1254cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver public NoClassesDexException(Throwable cause, String message, Object... formatArgs) { 1264cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver super(cause, message, formatArgs); 1274cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver } 1284cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver 1294cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver public NoClassesDexException(String message, Object... formatArgs) { 1304cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver super(message, formatArgs); 1314cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver } 1324cf7845ea4d6821b435f134f6e5a73efc2cb0ebcBen Gruver } 133ec47cb62a802276f78d09240be107f635f9d7a26Ben Gruver} 134