Add partial support for dex containers (DEX v41).

Accept the new format as long as the container has just one dex file.

(ported from external/smali)

Test: TreeHugger
Change-Id: I307a16172820c7e73066f952f2f1c9ac6c52c0e2
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
index 5809e6d..cbc6db2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/VersionMap.java
@@ -43,22 +43,39 @@
                 return 27;
             case 39:
                 return 28;
+            case 40:
+                return 34;
+            case 41:
+                return 35;
             default:
                 return NO_VERSION;
         }
     }
 
     public static int mapApiToDexVersion(int api) {
-        if (api <= 23) {
+        if (api <= 23) {  // Android M/6
             return 35;
         }
-        if (api <= 25) {
-            return 37;
+        switch (api) {
+            case 24:  // Android N/7
+            case 25:  // Android N/7.1
+                return 37;
+            case 26:  // Android O/8
+            case 27:  // Android O/8.1
+                return 38;
+            case 28:  // Android P/9
+                return 39;
+            case 29:  // Android Q/10
+            case 30:  // Android R/11
+            case 31:  // Android S/12
+            case 32:  // Android S/12.1
+            case 33:  // Android T/13
+            case 34:  // Android U/14
+                return 40;
+            case 35:  // Android V/15
+                return 41;
         }
-        if (api <= 27) {
-            return 38;
-        }
-        return 39;
+        return NO_VERSION;
     }
 
     public static int mapArtVersionToApi(int artVersion) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
index 93d7581..653fb5d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedDexFile.java
@@ -121,6 +121,16 @@
         } else {
             hiddenApiRestrictionsOffset = DexWriter.NO_OFFSET;
         }
+
+        if (dexVersion >= 41) {
+          // Reject non-trivial dex container (i.e. multiples dex files in the same physical file).
+          int container_off = dexBuffer.readSmallUint(HeaderItem.CONTAINER_OFF_OFFSET);
+          int container_size = dexBuffer.readSmallUint(HeaderItem.CONTAINER_SIZE_OFFSET);
+          int file_size = dexBuffer.readSmallUint(HeaderItem.FILE_SIZE_OFFSET);
+          if (container_off != 0 || container_size != file_size) {
+            throw new DexUtil.UnsupportedFile(String.format("Dex container is not supported"));
+          }
+        }
     }
 
     protected DexBackedDexFile(@Nullable Opcodes opcodes, @Nonnull DexBuffer dexBuffer, @Nonnull DexBuffer dataBuffer, int offset, boolean verifyMagic) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
index 61cc0f3..56bb992 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/raw/HeaderItem.java
@@ -87,6 +87,9 @@
     public static final int DATA_SIZE_OFFSET = 104;
     public static final int DATA_START_OFFSET = 108;
 
+    public static final int CONTAINER_SIZE_OFFSET = 112;
+    public static final int CONTAINER_OFF_OFFSET = 116;
+
     @Nonnull private DexBackedDexFile dexFile;
 
     public HeaderItem(@Nonnull DexBackedDexFile dexFile) {