| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 | package com.android.tools.r8.utils; | 
 |  | 
 | import com.android.tools.r8.dex.Constants; | 
 | import com.android.tools.r8.errors.Unreachable; | 
 | import com.android.tools.r8.utils.structural.Ordered; | 
 | import java.util.Optional; | 
 |  | 
 | /** Android dex version */ | 
 | public enum DexVersion implements Ordered<DexVersion> { | 
 |   V35(35, new byte[] {'0', '3', '5'}, Layout.SINGLE_DEX), | 
 |   V37(37, new byte[] {'0', '3', '7'}, Layout.SINGLE_DEX), | 
 |   V38(38, new byte[] {'0', '3', '8'}, Layout.SINGLE_DEX), | 
 |   V39(39, new byte[] {'0', '3', '9'}, Layout.SINGLE_DEX), | 
 |   V40(40, new byte[] {'0', '4', '0'}, Layout.SINGLE_DEX), | 
 |   V41(41, new byte[] {'0', '4', '1'}, Layout.CONTAINER_DEX); | 
 |  | 
 |   public enum Layout { | 
 |     SINGLE_DEX, | 
 |     CONTAINER_DEX; | 
 |  | 
 |     public boolean isContainer() { | 
 |       return this == CONTAINER_DEX; | 
 |     } | 
 |  | 
 |     public int getHeaderSize() { | 
 |       return isContainer() ? Constants.TYPE_HEADER_ITEM_SIZE_V41 : Constants.TYPE_HEADER_ITEM_SIZE; | 
 |     } | 
 |   } | 
 |  | 
 |   private final int dexVersion; | 
 |   private final byte[] dexVersionBytes; | 
 |   private final Layout layout; | 
 |  | 
 |   DexVersion(int dexVersion, byte[] dexVersionBytes, Layout layout) { | 
 |     this.dexVersion = dexVersion; | 
 |     this.dexVersionBytes = dexVersionBytes; | 
 |     this.layout = layout; | 
 |   } | 
 |  | 
 |   public Layout getLayout() { | 
 |     return layout; | 
 |   } | 
 |  | 
 |   public boolean isContainerDex() { | 
 |     return getLayout() == Layout.CONTAINER_DEX; | 
 |   } | 
 |  | 
 |   public int getIntValue() { | 
 |     return dexVersion; | 
 |   } | 
 |  | 
 |   public byte[] getBytes() { | 
 |     return dexVersionBytes; | 
 |   } | 
 |  | 
 |   public boolean matchesApiLevel(AndroidApiLevel androidApiLevel) { | 
 |     return getDexVersion(androidApiLevel).dexVersion >= dexVersion; | 
 |   } | 
 |  | 
 |   public static DexVersion getDexVersion(AndroidApiLevel androidApiLevel) { | 
 |     switch (androidApiLevel) { | 
 |         // ANDROID_PLATFORM is an unknown higher api version we therefore choose the highest known | 
 |         // version. | 
 |       case ANDROID_PLATFORM: | 
 |       case MASTER: | 
 |       case U: | 
 |       case T: | 
 |       case Sv2: | 
 |       case S: | 
 |       case R: | 
 |         // Dex version should have been V40 starting from API level 30, see b/269089718. | 
 |         // return DexVersion.V40; | 
 |       case Q: | 
 |       case P: | 
 |         return DexVersion.V39; | 
 |       case O_MR1: | 
 |       case O: | 
 |         return DexVersion.V38; | 
 |       case N_MR1: | 
 |       case N: | 
 |         return DexVersion.V37; | 
 |       case B: | 
 |       case B_1_1: | 
 |       case C: | 
 |       case D: | 
 |       case E: | 
 |       case E_0_1: | 
 |       case E_MR1: | 
 |       case F: | 
 |       case G: | 
 |       case G_MR1: | 
 |       case H: | 
 |       case H_MR1: | 
 |       case H_MR2: | 
 |       case I: | 
 |       case I_MR1: | 
 |       case J: | 
 |       case J_MR1: | 
 |       case J_MR2: | 
 |       case K: | 
 |       case K_WATCH: | 
 |       case L: | 
 |       case L_MR1: | 
 |       case M: | 
 |         return DexVersion.V35; | 
 |       default: | 
 |         throw new Unreachable("Unsupported api level " + androidApiLevel); | 
 |     } | 
 |   } | 
 |  | 
 |   public static Optional<DexVersion> getDexVersion(int intValue) { | 
 |     switch (intValue) { | 
 |       case 35: | 
 |         return Optional.of(V35); | 
 |       case 37: | 
 |         return Optional.of(V37); | 
 |       case 38: | 
 |         return Optional.of(V38); | 
 |       case 39: | 
 |         return Optional.of(V39); | 
 |       case 40: | 
 |         return Optional.of(V40); | 
 |       case 41: | 
 |         return Optional.of(V41); | 
 |       default: | 
 |         return Optional.empty(); | 
 |     } | 
 |   } | 
 |  | 
 |   public static Optional<DexVersion> getDexVersion(char b0, char b1, char b2) { | 
 |     if (b0 != '0') { | 
 |       return Optional.empty(); | 
 |     } | 
 |     for (DexVersion candidate : DexVersion.values()) { | 
 |       assert candidate.getBytes()[0] == '0'; | 
 |       if (candidate.getBytes()[2] == b2 && candidate.getBytes()[1] == b1) { | 
 |         return Optional.of(candidate); | 
 |       } | 
 |     } | 
 |     return Optional.empty(); | 
 |   } | 
 | } |