Add oat support in DexFileFactory
diff --git a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
index b6cc157..24bf0b9 100644
--- a/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
+++ b/baksmali/src/main/java/org/jf/baksmali/baksmaliOptions.java
@@ -36,6 +36,7 @@
 import org.jf.dexlib2.analysis.InlineMethodResolver;
 import org.jf.dexlib2.util.SyntheticAccessorResolver;
 
+import javax.annotation.Nullable;
 import java.io.File;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -54,7 +55,7 @@
 
     public int apiLevel = 15;
     public String outputDirectory = "out";
-    public String dexEntry = "classes.dex";
+    @Nullable public String dexEntry = null;
     public List<String> bootClassPathDirs = Lists.newArrayList();
 
     public List<String> bootClassPathEntries = Lists.newArrayList();
diff --git a/baksmali/src/main/java/org/jf/baksmali/main.java b/baksmali/src/main/java/org/jf/baksmali/main.java
index 71598fa..e11dc20 100644
--- a/baksmali/src/main/java/org/jf/baksmali/main.java
+++ b/baksmali/src/main/java/org/jf/baksmali/main.java
@@ -31,9 +31,11 @@
 import com.google.common.collect.Lists;
 import org.apache.commons.cli.*;
 import org.jf.dexlib2.DexFileFactory;
+import org.jf.dexlib2.DexFileFactory.MultipleDexFilesException;
 import org.jf.dexlib2.analysis.InlineMethodResolver;
 import org.jf.dexlib2.dexbacked.DexBackedDexFile;
 import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
+import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
 import org.jf.util.ConsoleUtil;
 import org.jf.util.SmaliHelpFormatter;
 
@@ -256,10 +258,20 @@
         }
 
         //Read in and parse the dex file
-        DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry,
-                options.apiLevel, options.experimental);
+        DexBackedDexFile dexFile = null;
+        try {
+            dexFile = DexFileFactory.loadDexFile(dexFileFile, options.dexEntry, options.apiLevel, options.experimental);
+        } catch (MultipleDexFilesException ex) {
+            System.err.println(String.format("%s contains multiple dex files. You must specify which one to " +
+                    "disassemble with the -e option", dexFileFile.getName()));
+            System.err.println("Valid entries include:");
+            for (OatDexFile oatDexFile: ex.oatFile.getDexFiles()) {
+                System.err.println(oatDexFile.filename);
+            }
+            System.exit(1);
+        }
 
-        if (dexFile.isOdexFile()) {
+        if (dexFile.hasOdexOpcodes()) {
             if (!options.deodex) {
                 System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
                 System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
@@ -547,8 +559,7 @@
                     "/system/framework/services.jar",
                     "/system/framework/apache-xml.jar",
                     "/system/framework/filterfw.jar");
-
-        } else {
+        } else if (apiLevel < 21) {
             // this is correct as of api 17/4.2.2
             return Lists.newArrayList(
                     "/system/framework/core.jar",
@@ -561,6 +572,22 @@
                     "/system/framework/android.policy.jar",
                     "/system/framework/services.jar",
                     "/system/framework/apache-xml.jar");
+        } else { // api >= 21
+            // TODO: verify, add new ones?
+            return Lists.newArrayList(
+                    "/system/framework/core-libart.jar",
+                    "/system/framework/conscrypt.jar",
+                    "/system/framework/okhttp.jar",
+                    "/system/framework/core-junit.jar",
+                    "/system/framework/bouncycastle.jar",
+                    "/system/framework/ext.jar",
+                    "/system/framework/framework.jar",
+                    "/system/framework/telephony-common.jar",
+                    "/system/framework/voip-common.jar",
+                    "/system/framework/ims-common.jar",
+                    "/system/framework/mms-common.jar",
+                    "/system/framework/android.policy.jar",
+                    "/system/framework/apache-xml.jar");
         }
     }
 }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
index fb433bb..60488ba 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/DexFileFactory.java
@@ -31,51 +31,56 @@
 
 package org.jf.dexlib2;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.io.ByteStreams;
 import org.jf.dexlib2.dexbacked.DexBackedDexFile;
 import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
+import org.jf.dexlib2.dexbacked.OatFile;
+import org.jf.dexlib2.dexbacked.OatFile.NotAnOatFileException;
+import org.jf.dexlib2.dexbacked.OatFile.OatDexFile;
 import org.jf.dexlib2.iface.DexFile;
 import org.jf.dexlib2.writer.pool.DexPool;
 import org.jf.util.ExceptionWithContext;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.io.*;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 public final class DexFileFactory {
     @Nonnull
-    public static DexBackedDexFile loadDexFile(String path, int api)
-            throws IOException {
+    public static DexBackedDexFile loadDexFile(@Nonnull String path, int api) throws IOException {
         return loadDexFile(path, api, false);
     }
 
     @Nonnull
-    public static DexBackedDexFile loadDexFile(String path, int api, boolean experimental)
+    public static DexBackedDexFile loadDexFile(@Nonnull String path, int api, boolean experimental)
             throws IOException {
         return loadDexFile(new File(path), "classes.dex", Opcodes.forApi(api, experimental));
     }
 
     @Nonnull
-    public static DexBackedDexFile loadDexFile(File dexFile, int api) throws IOException {
+    public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api) throws IOException {
         return loadDexFile(dexFile, api, false);
     }
 
     @Nonnull
-    public static DexBackedDexFile loadDexFile(File dexFile, int api, boolean experimental)
+    public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, int api, boolean experimental)
             throws IOException {
-        return loadDexFile(dexFile, "classes.dex", Opcodes.forApi(api, experimental));
+        return loadDexFile(dexFile, null, Opcodes.forApi(api, experimental));
     }
 
     @Nonnull
-    public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry, int api,
+    public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry, int api,
             boolean experimental) throws IOException {
         return loadDexFile(dexFile, dexEntry, Opcodes.forApi(api, experimental));
     }
 
     @Nonnull
-    public static DexBackedDexFile loadDexFile(File dexFile, String dexEntry,
-            @Nonnull Opcodes opcodes) throws IOException {
+    public static DexBackedDexFile loadDexFile(@Nonnull File dexFile, @Nullable String dexEntry,
+                                               @Nonnull Opcodes opcodes) throws IOException {
         ZipFile zipFile = null;
         boolean isZipFile = false;
         try {
@@ -83,16 +88,18 @@
             // if we get here, it's safe to assume we have a zip file
             isZipFile = true;
 
-            ZipEntry zipEntry = zipFile.getEntry(dexEntry);
+            String zipEntryName = MoreObjects.firstNonNull(dexEntry, "classes.dex");
+            ZipEntry zipEntry = zipFile.getEntry(zipEntryName);
             if (zipEntry == null) {
-                throw new NoClassesDexException("zip file %s does not contain a classes.dex file", dexFile.getName());
+                throw new DexFileNotFound("zip file %s does not contain a %s file", dexFile.getName(), zipEntryName);
             }
             long fileLength = zipEntry.getSize();
             if (fileLength < 40) {
-                throw new ExceptionWithContext(
-                        "The " + dexEntry + " file in %s is too small to be a valid dex file", dexFile.getName());
+                throw new ExceptionWithContext("The %s file in %s is too small to be a valid dex file",
+                        zipEntryName, dexFile.getName());
             } else if (fileLength > Integer.MAX_VALUE) {
-                throw new ExceptionWithContext("The " + dexEntry + " file in %s is too large to read in", dexFile.getName());
+                throw new ExceptionWithContext("The %s file in %s is too large to read in",
+                        zipEntryName, dexFile.getName());
             }
             byte[] dexBytes = new byte[(int)fileLength];
             ByteStreams.readFully(zipFile.getInputStream(zipEntry), dexBytes);
@@ -127,30 +134,93 @@
             } catch (DexBackedOdexFile.NotAnOdexFile ex) {
                 // just eat it
             }
+
+            OatFile oatFile = null;
+            try {
+                oatFile = OatFile.fromInputStream(inputStream);
+            } catch (NotAnOatFileException ex) {
+                // just eat it
+            }
+
+            if (oatFile != null) {
+                if (oatFile.isSupportedVersion() == OatFile.UNSUPPORTED) {
+                    throw new UnsupportedOatVersionException(oatFile);
+                }
+
+                List<OatDexFile> oatDexFiles = oatFile.getDexFiles();
+
+                if (oatDexFiles.size() == 0) {
+                    throw new DexFileNotFound("Oat file %s contains no dex files", dexFile.getName());
+                }
+
+                if (dexEntry == null) {
+                    if (oatDexFiles.size() > 1) {
+                        throw new MultipleDexFilesException(oatFile);
+                    }
+                    return oatDexFiles.get(0);
+                } else {
+                    // first check for an exact match
+                    for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
+                        if (oatDexFile.filename.equals(dexEntry)) {
+                            return oatDexFile;
+                        }
+                    }
+
+                    if (!dexEntry.contains("/")) {
+                        for (OatDexFile oatDexFile : oatFile.getDexFiles()) {
+                            File oatEntryFile = new File(oatDexFile.filename);
+                            if (oatEntryFile.getName().equals(dexEntry)) {
+                                return oatDexFile;
+                            }
+                        }
+                    }
+
+                    throw new DexFileNotFound("oat file %s does not contain a dex file named %s",
+                            dexFile.getName(), dexEntry);
+                }
+            }
         } finally {
             inputStream.close();
         }
 
-        throw new ExceptionWithContext("%s is not an apk, dex file or odex file.", dexFile.getPath());
+        throw new ExceptionWithContext("%s is not an apk, dex, odex or oat file.", dexFile.getPath());
     }
 
-    public static void writeDexFile(String path, DexFile dexFile) throws IOException {
+    public static void writeDexFile(@Nonnull String path, @Nonnull DexFile dexFile) throws IOException {
         DexPool.writeTo(path, dexFile);
     }
 
     private DexFileFactory() {}
 
-    public static class NoClassesDexException extends ExceptionWithContext {
-        public NoClassesDexException(Throwable cause) {
+    public static class DexFileNotFound extends ExceptionWithContext {
+        public DexFileNotFound(@Nullable Throwable cause) {
             super(cause);
         }
 
-        public NoClassesDexException(Throwable cause, String message, Object... formatArgs) {
+        public DexFileNotFound(@Nullable Throwable cause, @Nullable String message, Object... formatArgs) {
             super(cause, message, formatArgs);
         }
 
-        public NoClassesDexException(String message, Object... formatArgs) {
+        public DexFileNotFound(@Nullable String message, Object... formatArgs) {
             super(message, formatArgs);
         }
     }
+
+    public static class MultipleDexFilesException extends ExceptionWithContext {
+        @Nonnull public final OatFile oatFile;
+
+        public MultipleDexFilesException(@Nonnull OatFile oatFile) {
+            super("Oat file has multiple dex files.");
+            this.oatFile = oatFile;
+        }
+    }
+
+    public static class UnsupportedOatVersionException extends ExceptionWithContext {
+        @Nonnull public final OatFile oatFile;
+
+        public UnsupportedOatVersionException(@Nonnull OatFile oatFile) {
+            super("Unsupported oat version: %d", oatFile.getOatVersion());
+            this.oatFile = oatFile;
+        }
+    }
 }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
index bd9cfb1..4185da8 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/analysis/ClassPath.java
@@ -39,6 +39,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.jf.dexlib2.DexFileFactory;
+import org.jf.dexlib2.DexFileFactory.DexFileNotFound;
 import org.jf.dexlib2.analysis.reflection.ReflectionClassDef;
 import org.jf.dexlib2.iface.ClassDef;
 import org.jf.dexlib2.iface.DexFile;
@@ -58,6 +59,7 @@
     @Nonnull private final TypeProto unknownClass;
     @Nonnull private HashMap<String, ClassDef> availableClasses = Maps.newHashMap();
     private boolean checkPackagePrivateAccess;
+    public boolean isArt;
 
     /**
      * Creates a new ClassPath instance that can load classes from the given dex files
@@ -82,15 +84,29 @@
      * Creates a new ClassPath instance that can load classes from the given dex files
      *
      * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
-     * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by default
+     * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
+     *                                  default
      */
     public ClassPath(@Nonnull Iterable<DexFile> classPath, boolean checkPackagePrivateAccess) {
+        this(classPath, checkPackagePrivateAccess, false);
+    }
+
+    /**
+     * Creates a new ClassPath instance that can load classes from the given dex files
+     *
+     * @param classPath An iterable of DexFile objects. When loading a class, these dex files will be searched in order
+     * @param checkPackagePrivateAccess Whether checkPackagePrivateAccess is needed, enabled for ONLY early API 17 by
+     *                                  default
+     * @param isArt Whether this is ClassPath is for ART
+     */
+    public ClassPath(@Nonnull Iterable < DexFile > classPath, boolean checkPackagePrivateAccess, boolean isArt) {
         // add fallbacks for certain special classes that must be present
         Iterable<DexFile> dexFiles = Iterables.concat(classPath, Lists.newArrayList(getBasicClasses()));
 
         unknownClass = new UnknownClassProto(this);
         loadedClasses.put(unknownClass.getType(), unknownClass);
         this.checkPackagePrivateAccess = checkPackagePrivateAccess;
+        this.isArt = isArt;
 
         loadPrimitiveType("Z");
         loadPrimitiveType("B");
@@ -223,7 +239,7 @@
                     } else {
                         try {
                             return DexFileFactory.loadDexFile(file, api, experimental);
-                        } catch (DexFileFactory.NoClassesDexException ex) {
+                        } catch (DexFileNotFound ex) {
                             // ignore and continue
                         } catch (Exception ex) {
                             throw ExceptionWithContext.withContext(ex,
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
index 7d06bff..9cf4929 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexBuffer.java
@@ -37,13 +37,19 @@
 
 public class BaseDexBuffer {
     @Nonnull /* package private */ final byte[] buf;
+    /* package private */ final int baseOffset;
 
     public BaseDexBuffer(@Nonnull byte[] buf) {
+        this(buf, 0);
+    }
+    public BaseDexBuffer(@Nonnull byte[] buf, int offset) {
         this.buf = buf;
+        this.baseOffset = offset;
     }
 
     public int readSmallUint(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         int result = (buf[offset] & 0xff) |
                 ((buf[offset+1] & 0xff) << 8) |
                 ((buf[offset+2] & 0xff) << 16) |
@@ -56,6 +62,7 @@
 
     public int readOptionalUint(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         int result = (buf[offset] & 0xff) |
                 ((buf[offset+1] & 0xff) << 8) |
                 ((buf[offset+2] & 0xff) << 16) |
@@ -68,16 +75,18 @@
 
     public int readUshort(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         return (buf[offset] & 0xff) |
                 ((buf[offset+1] & 0xff) << 8);
     }
 
     public int readUbyte(int offset) {
-        return buf[offset] & 0xff;
+        return buf[offset + baseOffset] & 0xff;
     }
 
     public long readLong(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         return (buf[offset] & 0xff) |
                 ((buf[offset+1] & 0xff) << 8) |
                 ((buf[offset+2] & 0xff) << 16) |
@@ -90,6 +99,7 @@
 
     public int readInt(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         return (buf[offset] & 0xff) |
                 ((buf[offset+1] & 0xff) << 8) |
                 ((buf[offset+2] & 0xff) << 16) |
@@ -98,12 +108,13 @@
 
     public int readShort(int offset) {
         byte[] buf = this.buf;
+        offset += baseOffset;
         return (buf[offset] & 0xff) |
                 (buf[offset+1] << 8);
     }
 
     public int readByte(int offset) {
-        return buf[offset];
+        return buf[baseOffset + offset];
     }
 
     @Nonnull
@@ -115,4 +126,8 @@
     protected byte[] getBuf() {
         return buf;
     }
+
+    protected int getBaseOffset() {
+        return baseOffset;
+    }
 }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
index 96645b8..13c0a7b 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/BaseDexReader.java
@@ -49,7 +49,7 @@
     public void setOffset(int offset) { this.offset = offset; }
 
     public int readSleb128() {
-        int end = offset;
+        int end = dexBuf.baseOffset + offset;
         int currentByteValue;
         int result;
         byte[] buf = dexBuf.buf;
@@ -84,7 +84,7 @@
             }
         }
 
-        offset = end;
+        offset = end - dexBuf.baseOffset;
         return result;
     }
 
@@ -93,7 +93,7 @@
     }
 
     private int readUleb128(boolean allowLarge) {
-        int end = offset;
+        int end = dexBuf.baseOffset + offset;
         int currentByteValue;
         int result;
         byte[] buf = dexBuf.buf;
@@ -129,7 +129,7 @@
             }
         }
 
-        offset = end;
+        offset = end - dexBuf.baseOffset;
         return result;
     }
 
@@ -150,7 +150,7 @@
      * @return The unsigned value, reinterpreted as a signed int
      */
     public int readBigUleb128() {
-        int end = offset;
+        int end = dexBuf.baseOffset + offset;
         int currentByteValue;
         int result;
         byte[] buf = dexBuf.buf;
@@ -179,12 +179,12 @@
             }
         }
 
-        offset = end;
+        offset = end - dexBuf.baseOffset;
         return result;
     }
 
     public void skipUleb128() {
-        int end = offset;
+        int end = dexBuf.baseOffset + offset;
         byte currentByteValue;
         byte[] buf = dexBuf.buf;
 
@@ -206,7 +206,7 @@
             }
         }
 
-        offset = end;
+        offset = end - dexBuf.baseOffset;
     }
 
     public int readSmallUint() {
@@ -285,7 +285,7 @@
     public int readByte(int offset) { return dexBuf.readByte(offset); }
 
     public int readSizedInt(int bytes) {
-        int o = offset;
+        int o = dexBuf.baseOffset + offset;
         byte[] buf = dexBuf.buf;
 
         int result;
@@ -311,12 +311,12 @@
             default:
                 throw new ExceptionWithContext("Invalid size %d for sized int at offset 0x%x", bytes, offset);
         }
-        offset = o + bytes;
+        offset = o + bytes - dexBuf.baseOffset;
         return result;
     }
 
     public int readSizedSmallUint(int bytes) {
-        int o = offset;
+        int o = dexBuf.baseOffset + offset;
         byte[] buf = dexBuf.buf;
 
         int result = 0;
@@ -341,12 +341,12 @@
             default:
                 throw new ExceptionWithContext("Invalid size %d for sized uint at offset 0x%x", bytes, offset);
         }
-        offset = o + bytes;
+        offset = o + bytes - dexBuf.baseOffset;
         return result;
     }
 
     public int readSizedRightExtendedInt(int bytes) {
-        int o = offset;
+        int o = dexBuf.baseOffset + offset;
         byte[] buf = dexBuf.buf;
 
         int result;
@@ -373,12 +373,12 @@
                 throw new ExceptionWithContext(
                         "Invalid size %d for sized, right extended int at offset 0x%x", bytes, offset);
         }
-        offset = o + bytes;
+        offset = o + bytes - dexBuf.baseOffset;
         return result;
     }
 
     public long readSizedRightExtendedLong(int bytes) {
-        int o = offset;
+        int o = dexBuf.baseOffset + offset;
         byte[] buf = dexBuf.buf;
 
         long result;
@@ -439,12 +439,12 @@
                 throw new ExceptionWithContext(
                         "Invalid size %d for sized, right extended long at offset 0x%x", bytes, offset);
         }
-        offset = o + bytes;
+        offset = o + bytes - dexBuf.baseOffset;
         return result;
     }
 
     public long readSizedLong(int bytes) {
-        int o = offset;
+        int o = dexBuf.baseOffset + offset;
         byte[] buf = dexBuf.buf;
 
         long result;
@@ -505,13 +505,14 @@
                 throw new ExceptionWithContext("Invalid size %d for sized long at offset 0x%x", bytes, offset);
         }
 
-        offset = o + bytes;
+        offset = o + bytes - dexBuf.baseOffset;
         return result;
     }
 
     public String readString(int utf16Length) {
         int[] ret = new int[1];
-        String value = Utf8Utils.utf8BytesWithUtf16LengthToString(dexBuf.buf, offset, utf16Length, ret);
+        String value = Utf8Utils.utf8BytesWithUtf16LengthToString(
+                dexBuf.buf, dexBuf.baseOffset + offset, utf16Length, ret);
         offset += ret[0];
         return value;
     }
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
index 1774096..638fd85 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java
@@ -62,7 +62,7 @@
     private final int classStartOffset;
 
     private DexBackedDexFile(Opcodes opcodes, @Nonnull byte[] buf, int offset, boolean verifyMagic) {
-        super(buf);
+        super(buf, offset);
 
         this.opcodes = opcodes;
 
@@ -121,10 +121,16 @@
         return opcodes;
     }
 
+    // Will only be true for a dalvik-style odex file
     public boolean isOdexFile() {
         return false;
     }
 
+    // Will be true for both a dalvik-style odex file, and an art-style odex file embedded in an oat file
+    public boolean hasOdexOpcodes() {
+        return false;
+    }
+
     @Nonnull
     @Override
     public Set<? extends DexBackedClassDef> getClasses() {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
index 1aa9c1e..12f19db 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedOdexFile.java
@@ -33,7 +33,6 @@
 
 import com.google.common.io.ByteStreams;
 import org.jf.dexlib2.Opcodes;
-import org.jf.dexlib2.dexbacked.raw.HeaderItem;
 import org.jf.dexlib2.dexbacked.raw.OdexHeaderItem;
 import org.jf.dexlib2.dexbacked.util.VariableSizeList;
 
@@ -61,6 +60,10 @@
         return true;
     }
 
+    @Override public boolean hasOdexOpcodes() {
+        return true;
+    }
+
     public List<String> getDependencies() {
         final int dexOffset = OdexHeaderItem.getDexOffset(odexBuf);
         final int dependencyOffset = OdexHeaderItem.getDependenciesOffset(odexBuf) - dexOffset;
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java
index 88ef08c..b5250d0 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/OatFile.java
@@ -124,8 +124,12 @@
         return new OatFile(buf);
     }
 
+    public int getOatVersion() {
+        return oatHeader.getVersion();
+    }
+
     public int isSupportedVersion() {
-        int version = oatHeader.getVersion();
+        int version = getOatVersion();
         if (version < MIN_OAT_VERSION) {
             return UNSUPPORTED;
         }
@@ -187,6 +191,10 @@
             super(opcodes, OatFile.this.buf, offset);
             this.filename = filename;
         }
+
+        @Override public boolean hasOdexOpcodes() {
+            return true;
+        }
     }
 
     private class OatHeader {
diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
index 1fac80b..204a29d 100644
--- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
+++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/RawDexFile.java
@@ -59,7 +59,7 @@
 
     @Nonnull
     public byte[] readByteRange(int start, int length) {
-        return Arrays.copyOfRange(getBuf(), start, start+length);
+        return Arrays.copyOfRange(getBuf(), getBaseOffset() + start, getBaseOffset() + start + length);
     }
 
     public int getMapOffset() {
@@ -94,6 +94,7 @@
     }
 
     public void writeAnnotations(@Nonnull Writer out, @Nonnull AnnotatedBytes annotatedBytes) throws IOException {
+        // TODO: need to pass in the offset
         annotatedBytes.writeAnnotations(out, getBuf());
     }
 }