/**
 *  Copyright (C) 2019 Ryszard Wiśniewski <brut.alll@gmail.com>
 *  Copyright (C) 2019 Connor Tumbleson <connor.tumbleson@gmail.com>
 *
 *  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 brut.androlib.src;

import brut.androlib.AndrolibException;
import org.jf.baksmali.Baksmali;
import org.jf.baksmali.BaksmaliOptions;
import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
import org.jf.dexlib2.dexbacked.DexBackedOdexFile;
import org.jf.dexlib2.analysis.InlineMethodResolver;

import java.io.File;
import java.io.IOException;

/**
 * @author Ryszard Wiśniewski <brut.alll@gmail.com>
 */
public class SmaliDecoder {

    public static void decode(File apkFile, File outDir, String dexName, boolean bakdeb, int api)
            throws AndrolibException {
        new SmaliDecoder(apkFile, outDir, dexName, bakdeb, api).decode();
    }

    private SmaliDecoder(File apkFile, File outDir, String dexName, boolean bakdeb, int api) {
        mApkFile = apkFile;
        mOutDir  = outDir;
        mDexFile = dexName;
        mBakDeb  = bakdeb;
        mApi     = api;
    }

    private void decode() throws AndrolibException {
        try {
            final BaksmaliOptions options = new BaksmaliOptions();

            // options
            options.deodex = false;
            options.implicitReferences = false;
            options.parameterRegisters = true;
            options.localsDirective = true;
            options.sequentialLabels = true;
            options.debugInfo = mBakDeb;
            options.codeOffsets = false;
            options.accessorComments = false;
            options.registerInfo = 0;
            options.inlineResolver = null;

            // set jobs automatically
            int jobs = Runtime.getRuntime().availableProcessors();
            if (jobs > 6) {
                jobs = 6;
            }

            // create the dex
            DexBackedDexFile dexFile = DexFileFactory.loadDexEntry(mApkFile, mDexFile, true, Opcodes.forApi(mApi));

            if (dexFile.isOdexFile()) {
                throw new AndrolibException("Warning: You are disassembling an odex file without deodexing it.");
            }

            if (dexFile instanceof DexBackedOdexFile) {
                options.inlineResolver =
                        InlineMethodResolver.createInlineMethodResolver(((DexBackedOdexFile)dexFile).getOdexVersion());
            }

            Baksmali.disassembleDexFile(dexFile, mOutDir, jobs, options);
        } catch (IOException ex) {
            throw new AndrolibException(ex);
        }
    }

    private final File mApkFile;
    private final File mOutDir;
    private final String mDexFile;
    private final boolean mBakDeb;
    private final int mApi;
}

@@ -1065,16 +1065,63 @@
 esolver;
+%0Aimport org.jf.dexlib2.iface.MultiDexContainer;
 %0A%0Aimport
@@ -2495,19 +2495,25 @@
 ate the 
-dex
+container
 %0A       
@@ -2517,16 +2517,44 @@
         
+MultiDexContainer%3C? extends 
 DexBacke
@@ -2565,16 +2565,19 @@
 File
- dexFile
+%3E container
  = D
@@ -2601,13 +2601,17 @@
 dDex
-Entry
+Container
 (mAp
@@ -2621,82 +2621,786 @@
 le, 
-mDexFile, true, Opcodes.forApi(mApi));%0A%0A            if (dexFile.isOdexFile
+Opcodes.forApi(mApi));%0A            MultiDexContainer.DexEntry%3C? extends DexBackedDexFile%3E dexEntry;%0A            DexBackedDexFile dexFile;%0A%0A            // If we have 1 item, ignore the passed file. Pull the DexFile we need.%0A            if (container.getDexEntryNames().size() == 1) %7B%0A                dexEntry = container.getEntry(container.getDexEntryNames().get(0));%0A            %7D else %7B%0A                dexEntry = container.getEntry(mDexFile);%0A            %7D%0A%0A            // Double check the passed param exists%0A            if (dexEntry == null) %7B%0A                dexEntry = container.getEntry(container.getDexEntryNames().get(0));%0A            %7D%0A%0A            assert dexEntry != null;%0A            dexFile = dexEntry.getDexFile();%0A%0A            if (dexFile.supportsOptimizedOpcodes
 ()) 

use MultiDexContainer instead of DexBackedDexFile