<commit_before>package parser.apk;

import com.googlecode.dex2jar.reader.DexFileReader;
import org.apache.commons.io.IOUtils;
import parser.axml.ManifestInfo;
import parser.axml.Parser;
import parser.dex.DexClass;
import parser.dex.DexFileAdapter;
import parser.elf.Elf;
import parser.utils.CertTool;
import parser.utils.FileTypesDetector;
import parser.utils.HashTool;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/**
 * apk package information, classes, methods, various....
 * <p/>
 * <p/>
 * ex:
 * <p>
 * APK apk = new APK("test.apk");
 * apk.getCertificateInfos();
 * </p>
 */
public class APK {
    HashMap<String, String> certificateInfos;
    private List<DexClass> dexClasses = new ArrayList<>();
    @SuppressWarnings("UnusedDeclaration")
    private String absolutePath;
    private String dexMd5 = null;
    private String fileName = "";
    private ManifestInfo manifestInfo;
    private DexFileReader dexFileReader;
    private String dexSHA256;
    private ArrayList<String> subFileHash256List;
    private HashMap<String, ElfData> elfDataHashMap;
    private HashMap<String, APK> subApkDataMap;
    private HashMap<String, String> subFileHash256Map;
    private HashMap<String, String> subAPKHash256Map;
    private HashMap<String, String> metaDatas;

    public APK(InputStream inputStream) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(inputStream);
        bis.mark(bis.available());
        certificateInfos = CertTool.getCertificateInfos(bis);
        bis.reset();

        int size;
        byte[] buffer = new byte[2048];
        ZipInputStream zipInputStream = new ZipInputStream(bis);
        ZipEntry entry;
        ByteArrayOutputStream byteArrayOutputStream;
        InputStream amInputStream = null;
        byte[] arscBytes = null;
        byte[] axmlBytes = null;


        while ((entry = zipInputStream.getNextEntry()) != null) {
            if (entry.getName().equals("classes.dex")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                byte[] bytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();

                dexFileReader = new DexFileReader(byteArrayOutputStream.toByteArray());
                dexMd5 = HashTool.getSHA256(bytes);
                continue;
            }

            if (entry.getName().equals("AndroidManifest.xml")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                axmlBytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
//                amInputStream = new ByteArrayInputStream(bytes);
                continue;
            }

            if (entry.getName().contains(".arsc")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                arscBytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
            }

        }

        if (axmlBytes != null) {
            System.out.println(axmlBytes.toString());
            Parser parser = new Parser(axmlBytes, arscBytes);
            manifestInfo = parser.getManifestInfo();
        }

//        if (amInputStream != null) {
//            final ManifestParser mp = new ManifestParser();
//            manifestInfo = mp.parse(amInputStream, arscBytes);
//        }

        zipInputStream.close();
        bis.close();
        inputStream.close();
    }


    /**
     * @param filePath  文件路径
     * @param parseAXML 是否解析 AndroidManifest.xml
     * @param parseDex  是否解析 Dex
     * @param parseCert 是否解析证书
     * @throws IOException
     */
    public APK(String filePath, boolean parseAXML, boolean parseDex, boolean parseCert)
            throws IOException {


        File file = new File(filePath);

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();


        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }


        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        zipFile.close();

        if (parseAXML) {
            // 解析清单信息

            Parser parser = new Parser(file);
            manifestInfo = parser.getManifestInfo();

            if (manifestInfo == null) {
                throw new FileNotFoundException("No AndroidManifest.xml");
            }
        }

        if (parseDex) {
            initDexFileReader(file);
        }

        if (parseCert) {
            certificateInfos = CertTool.getCertificateInfos(file);
        }

    }

    /**
     * @param file      文件
     * @param parseAXML 是否解析 AndroidManifest.xml
     * @param parseDex  是否解析 Dex
     * @param parseCert 是否解析证书
     * @throws IOException
     */
    public APK(File file, boolean parseAXML, boolean parseDex, boolean parseCert)
            throws IOException {

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }

        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        zipFile.close();

        if (parseAXML) {
            Parser parser = new Parser(file);
            manifestInfo = parser.getManifestInfo();
            if (manifestInfo == null) {
                throw new FileNotFoundException("No AndroidManifest.xml");
            }
        }

        if (parseDex) {
            initDexFileReader(file);
        }

        if (parseCert) {
            certificateInfos = CertTool.getCertificateInfos(file);
        }

    }


    /**
     * 构造函数
     *
     * @param filePath 文件路径
     * @throws IOException
     */
    public APK(String filePath)
            throws Exception {

        File file = new File(filePath);

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        if (!FileTypesDetector.isAPK(file)) {
            throw new Exception("IT IS NOT A APK FILE.");
        }


        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getMD5(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
            dexSHA256 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        initSubFileList(zipFile);
        zipFile.close();

        initDexFileReader(file);

        // 解析清单信息
        Parser parser = new Parser(file);
        manifestInfo = parser.getManifestInfo();

        if (manifestInfo == null) {
            throw new Exception("No AndroidManifest.xml");
        }


        certificateInfos = CertTool.getCertificateInfos(file);
    }

    /**
     * 构造函数
     *
     * @param file 文件
     * @throws IOException
     */
    public APK(File file) throws IOException {

        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");

        if (zipEntry != null) {
            dexMd5 = HashTool.getMD5(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
            dexSHA256 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        initSubFileList(zipFile);
        zipFile.close();


        Parser parser = new Parser(file);
        manifestInfo = parser.getManifestInfo();

        initDexFileReader(file);
        certificateInfos = CertTool.getCertificateInfos(file);
    }

    public HashMap<String, APK> getSubApkDataMap() {
        return subApkDataMap;
    }

    public HashMap<String, String> getSubAPKHash256Map() {
        return subAPKHash256Map;
    }

    public HashMap<String, ElfData> getElfDataHashMap() {
        return elfDataHashMap;
    }


    private void initSubFileList(ZipFile zipFile) {
        subFileHash256List = new ArrayList<>();
        subFileHash256Map = new HashMap<>();
        subAPKHash256Map = new HashMap<>();
//        elfHashMap = new HashMap<>();
//        elfStringsMap = new HashMap<>();
        elfDataHashMap = new HashMap<>();
        subApkDataMap = new HashMap<>();

        ZipEntry zipEntry;
        Enumeration enumeration = zipFile.entries();
        while (enumeration.hasMoreElements()) {
            zipEntry = (ZipEntry) enumeration.nextElement();
            String name = zipEntry.getName();

            try {

                String fileType = FileTypesDetector.getType(zipFile.getInputStream(zipEntry));
                if (fileType.contains("ELF")) {
                    String hash = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
                    Elf elf = new Elf(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
                    List<String> strings = elf.loadStrings();

                    elfDataHashMap.put(name, new ElfData(hash, strings));
                    continue;
                }

                String hash = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
                if (fileType.contains("APK") || fileType.contains("ZIP")
                        && FileTypesDetector.isAPK(zipFile.getInputStream(zipEntry))) {
                    System.out.println(zipEntry.getName());
                    APK apk = new APK(zipFile.getInputStream(zipEntry));

                    subAPKHash256Map.put(name, hash);
                    subApkDataMap.put(name, apk);
                    continue;
//                    }
                }


                subFileHash256Map.put(name, hash);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void initDexFileReader(File file) throws IOException {<commit_msg>elf parser has bug.<commit_after>package parser.apk;

import com.googlecode.dex2jar.reader.DexFileReader;
import org.apache.commons.io.IOUtils;
import parser.axml.ManifestInfo;
import parser.axml.Parser;
import parser.dex.DexClass;
import parser.dex.DexFileAdapter;
import parser.utils.CertTool;
import parser.utils.FileTypesDetector;
import parser.utils.HashTool;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/**
 * apk package information, classes, methods, various....
 * <p/>
 * <p/>
 * ex:
 * <p>
 * APK apk = new APK("test.apk");
 * apk.getCertificateInfos();
 * </p>
 */
public class APK {
    HashMap<String, String> certificateInfos;
    private List<DexClass> dexClasses = new ArrayList<>();
    @SuppressWarnings("UnusedDeclaration")
    private String absolutePath;
    private String dexMd5 = null;
    private String fileName = "";
    private ManifestInfo manifestInfo;
    private DexFileReader dexFileReader;
    private String dexSHA256;
    private ArrayList<String> subFileHash256List;
    private HashMap<String, ElfData> elfDataHashMap;
    private HashMap<String, APK> subApkDataMap;
    private HashMap<String, String> subFileHash256Map;
    private HashMap<String, String> subAPKHash256Map;
    private HashMap<String, String> metaDatas;

    public APK(InputStream inputStream) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(inputStream);
        bis.mark(bis.available());
        certificateInfos = CertTool.getCertificateInfos(bis);
        bis.reset();

        int size;
        byte[] buffer = new byte[2048];
        ZipInputStream zipInputStream = new ZipInputStream(bis);
        ZipEntry entry;
        ByteArrayOutputStream byteArrayOutputStream;
        InputStream amInputStream = null;
        byte[] arscBytes = null;
        byte[] axmlBytes = null;


        while ((entry = zipInputStream.getNextEntry()) != null) {
            if (entry.getName().equals("classes.dex")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                byte[] bytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();

                dexFileReader = new DexFileReader(byteArrayOutputStream.toByteArray());
                dexMd5 = HashTool.getSHA256(bytes);
                continue;
            }

            if (entry.getName().equals("AndroidManifest.xml")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                axmlBytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
//                amInputStream = new ByteArrayInputStream(bytes);
                continue;
            }

            if (entry.getName().contains(".arsc")) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                while ((size = zipInputStream.read(buffer, 0, buffer.length)) != -1) {
                    byteArrayOutputStream.write(buffer, 0, size);
                }
                arscBytes = byteArrayOutputStream.toByteArray();
                byteArrayOutputStream.close();
            }

        }

        if (axmlBytes != null) {
            System.out.println(axmlBytes.toString());
            Parser parser = new Parser(axmlBytes, arscBytes);
            manifestInfo = parser.getManifestInfo();
        }

//        if (amInputStream != null) {
//            final ManifestParser mp = new ManifestParser();
//            manifestInfo = mp.parse(amInputStream, arscBytes);
//        }

        zipInputStream.close();
        bis.close();
        inputStream.close();
    }


    /**
     * @param filePath  文件路径
     * @param parseAXML 是否解析 AndroidManifest.xml
     * @param parseDex  是否解析 Dex
     * @param parseCert 是否解析证书
     * @throws IOException
     */
    public APK(String filePath, boolean parseAXML, boolean parseDex, boolean parseCert)
            throws IOException {


        File file = new File(filePath);

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();


        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }


        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        zipFile.close();

        if (parseAXML) {
            // 解析清单信息

            Parser parser = new Parser(file);
            manifestInfo = parser.getManifestInfo();

            if (manifestInfo == null) {
                throw new FileNotFoundException("No AndroidManifest.xml");
            }
        }

        if (parseDex) {
            initDexFileReader(file);
        }

        if (parseCert) {
            certificateInfos = CertTool.getCertificateInfos(file);
        }

    }

    /**
     * @param file      文件
     * @param parseAXML 是否解析 AndroidManifest.xml
     * @param parseDex  是否解析 Dex
     * @param parseCert 是否解析证书
     * @throws IOException
     */
    public APK(File file, boolean parseAXML, boolean parseDex, boolean parseCert)
            throws IOException {

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }

        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        zipFile.close();

        if (parseAXML) {
            Parser parser = new Parser(file);
            manifestInfo = parser.getManifestInfo();
            if (manifestInfo == null) {
                throw new FileNotFoundException("No AndroidManifest.xml");
            }
        }

        if (parseDex) {
            initDexFileReader(file);
        }

        if (parseCert) {
            certificateInfos = CertTool.getCertificateInfos(file);
        }

    }


    /**
     * 构造函数
     *
     * @param filePath 文件路径
     * @throws IOException
     */
    public APK(String filePath)
            throws Exception {

        File file = new File(filePath);

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        if (!FileTypesDetector.isAPK(file)) {
            throw new Exception("IT IS NOT A APK FILE.");
        }


        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");
        if (zipEntry != null) {
            dexMd5 = HashTool.getMD5(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
            dexSHA256 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        initSubFileList(zipFile);
        zipFile.close();

        initDexFileReader(file);

        // 解析清单信息
        Parser parser = new Parser(file);
        manifestInfo = parser.getManifestInfo();

        if (manifestInfo == null) {
            throw new Exception("No AndroidManifest.xml");
        }


        certificateInfos = CertTool.getCertificateInfos(file);
    }

    /**
     * 构造函数
     *
     * @param file 文件
     * @throws IOException
     */
    public APK(File file) throws IOException {

        if (!FileTypesDetector.isAPK(file)) {
            throw new IOException("IT IS NOT A APK FILE.");
        }

        absolutePath = file.getAbsolutePath();
        fileName = file.getName();

        ZipFile zipFile = new ZipFile(file);
        ZipEntry zipEntry = zipFile.getEntry("classes.dex");

        if (zipEntry != null) {
            dexMd5 = HashTool.getMD5(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
            dexSHA256 = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
        }
        initSubFileList(zipFile);
        zipFile.close();


        Parser parser = new Parser(file);
        manifestInfo = parser.getManifestInfo();

        initDexFileReader(file);
        certificateInfos = CertTool.getCertificateInfos(file);
    }

    public HashMap<String, APK> getSubApkDataMap() {
        return subApkDataMap;
    }

    public HashMap<String, String> getSubAPKHash256Map() {
        return subAPKHash256Map;
    }

    public HashMap<String, ElfData> getElfDataHashMap() {
        return elfDataHashMap;
    }


    private void initSubFileList(ZipFile zipFile) {
        subFileHash256List = new ArrayList<>();
        subFileHash256Map = new HashMap<>();
        subAPKHash256Map = new HashMap<>();
        elfDataHashMap = new HashMap<>();
        subApkDataMap = new HashMap<>();

        ZipEntry zipEntry;
        Enumeration enumeration = zipFile.entries();
        while (enumeration.hasMoreElements()) {
            zipEntry = (ZipEntry) enumeration.nextElement();
            String name = zipEntry.getName();

            try {


                String fileType = FileTypesDetector.getType(zipFile.getInputStream(zipEntry));
                // FIXME elf got some bug.
//                if (fileType.contains("ELF")) {
//                    String hash = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
//                    Elf elf = new Elf(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
//                    List<String> strings = elf.loadStrings();
//
//                    elfDataHashMap.put(name, new ElfData(hash, strings));
//                    continue;
//                }

                String hash = HashTool.getSHA256(IOUtils.toByteArray(zipFile.getInputStream(zipEntry)));
                if (fileType.contains("APK") || fileType.contains("ZIP")
                        && FileTypesDetector.isAPK(zipFile.getInputStream(zipEntry))) {
                    System.out.println(zipEntry.getName());
                    APK apk = new APK(zipFile.getInputStream(zipEntry));

                    subAPKHash256Map.put(name, hash);
                    subApkDataMap.put(name, apk);
                    continue;
                }


                subFileHash256Map.put(name, hash);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void initDexFileReader(File file) throws IOException {
{'fraction_non_alphanumeric': 0.1060929240471112, 'fraction_numerical': 0.0076045627376425855, 'mean_word_length': 2.119323112525311, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 26}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1442757', 'n_tokens_mistral': 6172, 'n_tokens_neox': 5899, 'n_words': 1208}