com.xperia64.rompatcher.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.xperia64.rompatcher.MainActivity.java

Source

/*******************************************************************************
 * This file is part of ROM Patcher.
 * 
 * Copyright (c) 2014 xperia64.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *    Paul Kratt - main MultiPatch application for Mac OSX
 *    byuu - UPS and BPS patchers
 *    Neil Corlett - IPS patcher
 *    Daniel Ekstr'm - PPF patcher
 *    Josh MacDonald - XDelta
 *    Colin Percival - BSDiff
 *    xperia64 - port to Android and IPS32 support
 ******************************************************************************/
package com.xperia64.rompatcher;

import com.google.common.io.Files;
import com.xperia64.rompatcher.R;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;

import com.xperia64.rompatcher.javapatchers.APSGBAPatcher;
import com.xperia64.rompatcher.javapatchers.nsmbe.ROM;
import com.xperia64.rompatcher.javapatchers.nsmbe.dsfilesystem.NitroROMFilesystem;
import com.xperia64.rompatcher.javapatchers.nsmbe.patcher.RealPatch;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Locale;

import android.text.InputFilter;
import android.text.TextUtils;
import android.util.Log;
import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
//import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
//import android.net.Uri;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import android.text.Spanned;

public class MainActivity extends Activity {

    public static native int apsN64PatchRom(String romPath, String patchPath);

    public static native int ipsPatchRom(String romPath, String patchPath);

    public static native int ips32PatchRom(String romPath, String patchPath);

    public static native int upsPatchRom(String romPath, String patchPath, String outputFile, int jignoreChecksum);

    public static native int xdelta1PatchRom(String romPath, String patchPath, String outputFile);

    public static native int ecmPatchRom(String romPath, String outFile, int bkup);

    public static native int dpsPatchRom(String romPath, String patchPath, String outFile);

    public static native int xdelta3PatchRom(String romPath, String patchPath, String outputFile);

    public static native int bsdiffPatchRom(String romPath, String patchPath, String outputFile);

    public static native int bpsPatchRom(String romPath, String patchPath, String outputFile, int jignoreChecksum);

    public static native int ppfPatchRom(String romPath, String patchPath, int jignoreChecksum);

    public static native int asmPatchRom(String romPath, String patchPath);

    public static native int dldiPatchRom(String romPath, String patchPath);

    public static native int xpcPatchRom(String romPath, String patchPath, String outputFile);

    public static native int asarPatchRom(String romPath, String patchPath, int jignoreChecksum);

    Context staticThis;
    CheckBox c;// = (CheckBox) findViewById(R.id.backupCheckbox);
    CheckBox d;// = (CheckBox) findViewById(R.id.altNameCheckbox);
    CheckBox r;// = (CheckBox) findViewById(R.id.ignoreCRC);
    CheckBox e;// = (CheckBox) findViewById(R.id.fileExtCheckbox);
    EditText ed;// = (EditText) findViewById(R.id.txtOutFile);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        staticThis = MainActivity.this;

        setContentView(R.layout.main);
        // Load native libraries
        try {
            System.loadLibrary("apsn64patcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab apspatcher!");
        }
        try {
            System.loadLibrary("ipspatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ipspatcher!");
        }
        try {
            System.loadLibrary("ipspatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ipspatcher!");
        }
        try {
            System.loadLibrary("upspatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab upspatcher!");
        }
        try {
            System.loadLibrary("xdelta3patcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab xdelta3patcher!");
        }
        try {
            System.loadLibrary("bpspatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab bpspatcher!");
        }
        try {
            System.loadLibrary("bzip2");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab bzip2!");
        }
        try {
            System.loadLibrary("bsdiffpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab bsdiffpatcher!");
        }
        try {
            System.loadLibrary("ppfpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ppfpatcher!");
        }
        try {
            System.loadLibrary("ips32patcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ips32patcher!");
        }
        try {
            System.loadLibrary("glib-2.0");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab glib-2.0!");
        }
        try {
            System.loadLibrary("gmodule-2.0");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab gmodule-2.0!");
        }
        try {
            System.loadLibrary("edsio");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab edsio!");
        }
        try {
            System.loadLibrary("xdelta1patcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ips32patcher!");
        }
        try {
            System.loadLibrary("ips32patcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ips32patcher!");
        }
        try {
            System.loadLibrary("ecmpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab ecmpatcher!");
        }
        try {
            System.loadLibrary("dpspatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab dpspatcher!");
        }
        try {
            System.loadLibrary("dldipatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab dldipatcher!");
        }
        try {
            System.loadLibrary("xpcpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab xpcpatcher!");
        }
        try {
            System.loadLibrary("asarpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab asarpatcher!");
        }
        try {
            System.loadLibrary("asmpatcher");
        } catch (UnsatisfiedLinkError e) {
            Log.e("Bad:", "Cannot grab asmpatcher!");
        }
        c = (CheckBox) findViewById(R.id.backupCheckbox);
        d = (CheckBox) findViewById(R.id.altNameCheckbox);
        r = (CheckBox) findViewById(R.id.ignoreCRC);
        e = (CheckBox) findViewById(R.id.fileExtCheckbox);
        ed = (EditText) findViewById(R.id.txtOutFile);

        final Button romButton = (Button) findViewById(R.id.romButton);
        romButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Globals.mode = true;
                Intent intent = new Intent(staticThis, FileBrowserActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivityForResult(intent, 1);

            }
        });
        final Button patchButton = (Button) findViewById(R.id.patchButton);
        patchButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Globals.mode = false;
                Intent intent = new Intent(staticThis, FileBrowserActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivityForResult(intent, 1);
            }
        });
        final ImageButton bkHelp = (ImageButton) findViewById(R.id.backupHelp);
        bkHelp.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                AlertDialog dialog = new AlertDialog.Builder(staticThis).create();
                dialog.setTitle(getResources().getString(R.string.bkup_rom));
                dialog.setMessage(getResources().getString(R.string.bkup_rom_desc));
                dialog.setCancelable(true);
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(android.R.string.ok),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int buttonId) {

                            }
                        });
                dialog.show();
            }
        });
        final ImageButton altNameHelp = (ImageButton) findViewById(R.id.outfileHelp);
        altNameHelp.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                AlertDialog dialog = new AlertDialog.Builder(staticThis).create();
                dialog.setTitle(getResources().getString(R.string.rename1));
                dialog.setMessage(getResources().getString(R.string.rename_desc));
                dialog.setCancelable(true);
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(android.R.string.ok),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int buttonId) {

                            }
                        });
                dialog.show();
            }
        });
        final ImageButton chkHelp = (ImageButton) findViewById(R.id.ignoreHelp);
        chkHelp.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                AlertDialog dialog = new AlertDialog.Builder(staticThis).create();
                dialog.setTitle(getResources().getString(R.string.ignoreChks));
                dialog.setMessage(getResources().getString(R.string.ignoreChks_desc));
                dialog.setCancelable(true);
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(android.R.string.ok),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int buttonId) {

                            }
                        });
                dialog.show();
            }
        });

        InputFilter filter = new InputFilter() {
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart,
                    int dend) {
                for (int i = start; i < end; i++) {
                    String IC = "*/*\n*\r*\t*\0*\f*`*?***\\*<*>*|*\"*:*";
                    if (IC.contains("*" + source.charAt(i) + "*")) {
                        return "";
                    }
                }
                return null;
            }
        };
        ed.setFilters(new InputFilter[] { filter });
        c.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (((CheckBox) v).isChecked()) {
                    d.setEnabled(true);
                    if (d.isChecked()) {
                        ed.setEnabled(true);
                        e.setEnabled(true);
                    }
                } else {
                    d.setEnabled(false);
                    ed.setEnabled(false);
                    e.setEnabled(false);
                }
            }
        });
        d.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (((CheckBox) v).isChecked()) {
                    ed.setEnabled(true);
                    e.setEnabled(true);
                } else {
                    e.setEnabled(false);
                    ed.setEnabled(false);
                }
            }
        });
        final Button applyButton = (Button) findViewById(R.id.applyPatch);
        applyButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // Warn about patching archives.
                if (Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".7z")
                        || Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".zip")
                        || Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".rar")) {
                    AlertDialog dialog = new AlertDialog.Builder(staticThis).create();
                    dialog.setTitle(getResources().getString(R.string.warning));
                    dialog.setMessage(getResources().getString(R.string.zip_warning_desc));
                    dialog.setCancelable(false);
                    dialog.setButton(DialogInterface.BUTTON_POSITIVE,
                            getResources().getString(android.R.string.yes), new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int buttonId) {

                                    patchCheck();
                                }
                            });
                    dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
                            getResources().getString(android.R.string.cancel),
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int buttonId) {
                                    Toast t = Toast.makeText(staticThis, getResources().getString(R.string.nopatch),
                                            Toast.LENGTH_SHORT);
                                    t.show();

                                }
                            });
                    dialog.show();
                } else {
                    patchCheck();
                }

            }
        });
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // Uggh.
            requestPermissions();
        }
    }

    final int PERMISSION_REQUEST = 178;
    final int NUM_PERMISSIONS = 2;

    public void requestPermissions() {
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            // Should we show an explanation?
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

                new AlertDialog.Builder(this).setTitle("Permissions")
                        .setMessage(
                                "ROM Patcher needs to be able to:\n" + "Read your storage to read ROMs/patches\n\n"
                                        + "Write to your storage to save patched ROMs\n\n")

                        .setPositiveButton("OK", new OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                actuallyRequestPermissions();

                            }

                        }).setNegativeButton("Cancel", new OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                new AlertDialog.Builder(MainActivity.this).setTitle("Error")
                                        .setMessage("ROM Patcher cannot proceed without these permissions")
                                        .setPositiveButton("OK", new OnClickListener() {

                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                MainActivity.this.finish();
                                            }

                                        }).setCancelable(false).show();

                            }

                        }).setCancelable(false).show();

                // Show an expanation to the user *asynchronously* -- don't block
                // this thread waiting for the user's response! After the user
                // sees the explanation, try again to request the permission.

            } else {

                // No explanation needed, we can request the permission.
                actuallyRequestPermissions();

                // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
                // app-defined int constant. The callback method gets the
                // result of the request.
            }
        } /*else{
            yetAnotherInit();
          }*/
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    public void actuallyRequestPermissions() {
        ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE }, PERMISSION_REQUEST);
    }

    @SuppressLint("NewApi")
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
        case PERMISSION_REQUEST: {
            // If request is cancelled, the result arrays are empty.
            boolean good = true;
            if (permissions.length != NUM_PERMISSIONS || grantResults.length != NUM_PERMISSIONS) {
                good = false;
            }

            for (int i = 0; i < grantResults.length && good; i++) {
                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                    good = false;
                }
            }
            if (!good) {

                // permission denied, boo! Disable the app.
                new AlertDialog.Builder(MainActivity.this).setTitle("Error")
                        .setMessage("ROM Patcher cannot proceed without these permissions")
                        .setPositiveButton("OK", new OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                MainActivity.this.finish();
                            }

                        }).setCancelable(false).show();
            } else {
                if (!Environment.getExternalStorageDirectory().canRead()) {
                    // Buggy emulator? Try restarting the app
                    AlarmManager alm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
                    alm.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, PendingIntent.getActivity(this,
                            237462, new Intent(this, MainActivity.class), Intent.FLAG_ACTIVITY_NEW_TASK));
                    System.exit(0);
                }
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
        }
    }

    private void patchCheck() {
        // Just try to interpret the following if statement. I dare you.
        if (new File(Globals.fileToPatch + ".bak").exists()
                || (Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".ecm") && new File(
                        Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('.'))).exists())
                || new File(Globals.fileToPatch + ".new").exists()
                || (new File(Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('/') + 1)
                        + ed.getText().toString()
                        + ((e.isChecked())
                                ? ((Globals.fileToPatch.lastIndexOf('.') > -1) ? Globals.fileToPatch.substring(
                                        Globals.fileToPatch.lastIndexOf('.'), Globals.fileToPatch.length()) : "")
                                : "")).exists()
                        && d.isChecked() && c.isChecked())) {

            System.out.println("bad");
            AlertDialog dialog2 = new AlertDialog.Builder(staticThis).create();
            dialog2.setTitle(getResources().getString(R.string.warning));
            dialog2.setMessage(getResources().getString(R.string.warning_desc));
            dialog2.setCancelable(false);
            dialog2.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(android.R.string.yes),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int buttonId) {
                            new File(Globals.fileToPatch + ".bak").delete();
                            new File(Globals.fileToPatch + ".new").delete();
                            if (Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".ecm"))
                                new File(Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('.')))
                                        .delete();
                            new File(Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('/') + 1)
                                    + ed.getText().toString()
                                    + ((e.isChecked()) ? ((Globals.fileToPatch.lastIndexOf('.') > -1)
                                            ? Globals.fileToPatch.substring(Globals.fileToPatch.lastIndexOf('.'),
                                                    Globals.fileToPatch.length())
                                            : "") : "")).delete();
                            if (d.isChecked() && c.isChecked() && e.isChecked()
                                    && Globals.fileToPatch.lastIndexOf('.') > -1) {
                                ed.setText(ed.getText() + Globals.fileToPatch.substring(
                                        Globals.fileToPatch.lastIndexOf('.'), Globals.fileToPatch.length()));
                            }
                            patch(c.isChecked(), d.isChecked(), r.isChecked(), ed.getText().toString());
                        }
                    });
            dialog2.setButton(DialogInterface.BUTTON_NEGATIVE, getResources().getString(android.R.string.cancel),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int buttonId) {
                            Toast t = Toast.makeText(staticThis, getResources().getString(R.string.nopatch),
                                    Toast.LENGTH_SHORT);
                            t.show();
                        }
                    });
            dialog2.show();
        } else {
            if (d.isChecked() && c.isChecked() && e.isChecked() && Globals.fileToPatch.lastIndexOf('.') > -1) {
                ed.setText(ed.getText() + Globals.fileToPatch.substring(Globals.fileToPatch.lastIndexOf('.'),
                        Globals.fileToPatch.length()));
            }
            patch(c.isChecked(), d.isChecked(), r.isChecked(), ed.getText().toString());
        }

    }

    private boolean isPackageInstalled(String packagename, Context context) {
        PackageManager pm = context.getPackageManager();
        try {
            pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
            return true;
        } catch (NameNotFoundException e) {
            return false;
        }
    }

    public void patch(final boolean c, final boolean d, final boolean r, final String ed) {
        final ProgressDialog myPd_ring = ProgressDialog.show(MainActivity.this,
                getResources().getString(R.string.wait), getResources().getString(R.string.wait_desc), true);
        myPd_ring.setCancelable(false);
        new Thread(new Runnable() {
            public void run() {
                if (new File(Globals.patchToApply).exists() && new File(Globals.fileToPatch).exists()
                        && !Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".ecm")) {
                    String msg = getResources().getString(R.string.success);
                    if (!new File(Globals.fileToPatch).canWrite()) {
                        Globals.msg = msg = "Can not write to output file. If you are on KitKat or Lollipop, move the file to your internal storage.";
                        return;
                    }
                    if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".ups")) {
                        int e = upsPatchRom(Globals.fileToPatch, Globals.patchToApply, Globals.fileToPatch + ".new",
                                r ? 1 : 0);
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_UPS);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xdelta")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xdelta3")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".vcdiff")) {
                        RandomAccessFile f = null;
                        try {
                            f = new RandomAccessFile(Globals.patchToApply, "r");
                        } catch (FileNotFoundException e1) {
                            e1.printStackTrace();
                            Globals.msg = msg = getResources().getString(R.string.fnf);
                            return;
                        }
                        StringBuilder s = new StringBuilder();
                        try {
                            if (f.length() >= 9) {
                                for (int i = 0; i < 8; i++) {
                                    s.append((char) f.readByte());
                                    f.seek(i + 1);
                                }
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        try {
                            f.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        // Header of xdelta patch determines version
                        if (s.toString().equals("%XDELTA%") || s.toString().equals("%XDZ000%")
                                || s.toString().equals("%XDZ001%") || s.toString().equals("%XDZ002%")
                                || s.toString().equals("%XDZ003%") || s.toString().equals("%XDZ004%")) {
                            int e = xdelta1PatchRom(Globals.fileToPatch, Globals.patchToApply,
                                    Globals.fileToPatch + ".new");
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_XDELTA1);
                            }
                        } else {
                            int e = xdelta3PatchRom(Globals.fileToPatch, Globals.patchToApply,
                                    Globals.fileToPatch + ".new");
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_XDELTA3);
                            }
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".bps")) {
                        int e = bpsPatchRom(Globals.fileToPatch, Globals.patchToApply, Globals.fileToPatch + ".new",
                                r ? 1 : 0);
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_BPS);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".dps")) {
                        int e = dpsPatchRom(Globals.fileToPatch, Globals.patchToApply,
                                Globals.fileToPatch + ".new");
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_DPS);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".bsdiff")) {
                        int e = bsdiffPatchRom(Globals.fileToPatch, Globals.patchToApply,
                                Globals.fileToPatch + ".new");
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_BSDIFF);
                        }

                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".aps")) {
                        File f = new File(Globals.fileToPatch);
                        File f2 = new File(Globals.fileToPatch + ".bak");
                        try {
                            Files.copy(f, f2);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        // Wow.
                        byte[] gbaSig = { 0x41, 0x50, 0x53, 0x31, 0x00 };
                        byte[] n64Sig = { 0x41, 0x50, 0x53, 0x31, 0x30 };
                        byte[] realSig = new byte[5];
                        RandomAccessFile raf = null;
                        System.out.println("APS Patch");
                        try {
                            raf = new RandomAccessFile(Globals.patchToApply, "r");
                        } catch (FileNotFoundException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                            Globals.msg = msg = getResources().getString(R.string.fnf);
                            return;
                        }
                        try {
                            raf.read(realSig);
                            raf.close();
                        } catch (IOException e1) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }

                        if (Arrays.equals(realSig, gbaSig)) {
                            System.out.println("GBA APS");
                            APSGBAPatcher aa = new APSGBAPatcher();
                            aa.crcTableInit();
                            int e = 0;
                            try {
                                e = aa.ApplyPatch(Globals.patchToApply, Globals.fileToPatch, r);
                            } catch (IOException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                                e = -5;
                            }
                            System.out.println("e: " + e);
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_APSGBA);
                            }
                        } else if (Arrays.equals(realSig, n64Sig)) {
                            System.out.println("N64 APS");
                            int e = apsN64PatchRom(Globals.fileToPatch, Globals.patchToApply);
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_APSN64);
                            }
                        } else {
                            msg = parseError(-131, -10000);
                        }

                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".ppf")) {
                        File f = new File(Globals.fileToPatch);
                        File f2 = new File(Globals.fileToPatch + ".bak");
                        try {
                            Files.copy(f, f2);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        int e = ppfPatchRom(Globals.fileToPatch, Globals.patchToApply, r ? 1 : 0);
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_PPF);
                        }

                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".patch")) {
                        int e = xdelta1PatchRom(Globals.fileToPatch, Globals.patchToApply,
                                Globals.fileToPatch + ".new");
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_XDELTA1);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".asm")) {
                        File f = new File(Globals.fileToPatch);
                        File f2 = new File(Globals.fileToPatch + ".bak");
                        try {
                            Files.copy(f, f2);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        int e;
                        if (Globals.asar)
                            e = asarPatchRom(Globals.fileToPatch, Globals.patchToApply, r ? 1 : 0);
                        else
                            e = asmPatchRom(Globals.fileToPatch, Globals.patchToApply);
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_ASM);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".dldi")) {
                        File f = new File(Globals.fileToPatch);
                        File f2 = new File(Globals.fileToPatch + ".bak");
                        try {
                            Files.copy(f, f2);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        int e = dldiPatchRom(Globals.fileToPatch, Globals.patchToApply);
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_DLDI);
                        }
                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xpc")) {
                        int e = xpcPatchRom(Globals.fileToPatch, Globals.patchToApply,
                                Globals.fileToPatch + ".new");
                        if (e != 0) {
                            msg = parseError(e, Globals.TYPE_XPC);
                        }

                    } else if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".nmp")) {

                        String drm = MainActivity.this.getPackageName();
                        System.out.println("Drm is: " + drm);
                        if (drm.equals("com.xperia64.rompatcher.donation")) {
                            if (c) {
                                File f = new File(Globals.fileToPatch);
                                File f2 = new File(Globals.fileToPatch + ".bak");
                                try {
                                    Files.copy(f, f2);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                            NitroROMFilesystem fs;
                            try {
                                fs = new NitroROMFilesystem(Globals.fileToPatch);
                                ROM.load(fs);
                                RealPatch.patch(Globals.patchToApply, new Object());
                                ROM.close();
                            } catch (Exception e1) {
                                // TODO Auto-generated catch block
                                //e1.printStackTrace();
                                Globals.msg = msg = String.format(getResources().getString(R.string.nmpDefault),
                                        e1.getStackTrace()[0].getFileName(), e1.getStackTrace()[0].getLineNumber());
                            }
                            if (c && d && !TextUtils.isEmpty(ed)) {
                                File f = new File(Globals.fileToPatch);
                                File f3 = new File(Globals.fileToPatch + ".bak");
                                File f2 = new File(
                                        Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('/') + 1)
                                                + ed);
                                f.renameTo(f2);
                                f3.renameTo(f);
                            }
                        } else {
                            Globals.msg = msg = getResources().getString(R.string.drmwarning);
                            MainActivity.this.runOnUiThread(new Runnable() {
                                public void run() {
                                    AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
                                    b.setTitle(getResources().getString(R.string.drmwarning));
                                    b.setIcon(
                                            ResourcesCompat.getDrawable(getResources(), R.drawable.icon_pro, null));
                                    b.setMessage(getResources().getString(R.string.drmwarning_desc));
                                    b.setCancelable(false);
                                    b.setNegativeButton(getResources().getString(android.R.string.cancel),
                                            new OnClickListener() {
                                                @Override
                                                public void onClick(DialogInterface arg0, int arg1) {
                                                }
                                            });
                                    b.setPositiveButton(getResources().getString(R.string.nagInfo),
                                            new OnClickListener() {

                                                @Override
                                                public void onClick(DialogInterface arg0, int arg1) {
                                                    try {
                                                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(
                                                                "market://details?id=com.xperia64.rompatcher.donation")));
                                                    } catch (android.content.ActivityNotFoundException anfe) {
                                                        startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(
                                                                "http://play.google.com/store/apps/details?id=com.xperia64.rompatcher.donation")));
                                                    }
                                                }
                                            });
                                    b.create().show();
                                }
                            });
                        }

                    } else {
                        RandomAccessFile f = null;
                        try {
                            f = new RandomAccessFile(Globals.patchToApply, "r");
                        } catch (FileNotFoundException e1) {
                            e1.printStackTrace();
                            Globals.msg = msg = getResources().getString(R.string.fnf);
                            return;
                        }
                        StringBuilder s = new StringBuilder();
                        try {
                            if (f.length() >= 6) {
                                for (int i = 0; i < 5; i++) {
                                    s.append((char) f.readByte());
                                    f.seek(i + 1);
                                }
                            }
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        try {
                            f.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                        int e;
                        // Two variants of IPS, the normal PATCH type, then this weird one called IPS32 with messily hacked in 32 bit offsets
                        if (s.toString().equals("IPS32")) {
                            e = ips32PatchRom(Globals.fileToPatch, Globals.patchToApply);
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_IPS);
                            }
                        } else {
                            e = ipsPatchRom(Globals.fileToPatch, Globals.patchToApply);
                            if (e != 0) {
                                msg = parseError(e, Globals.TYPE_IPS);
                            }
                        }

                    }
                    if (Globals.patchToApply.toLowerCase(Locale.US).endsWith(".ups")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xdelta")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xdelta3")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".vcdiff")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".patch")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".bps")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".bsdiff")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".dps")
                            || Globals.patchToApply.toLowerCase(Locale.US).endsWith(".xpc")) {
                        File oldrom = new File(Globals.fileToPatch);
                        File bkrom = new File(Globals.fileToPatch + ".bak");
                        oldrom.renameTo(bkrom);
                        File newrom = new File(Globals.fileToPatch + ".new");
                        newrom.renameTo(oldrom);
                    }
                    if (!c) {
                        File f = new File(Globals.fileToPatch + ".bak");
                        if (f.exists()) {
                            f.delete();
                        }
                    } else {
                        if (d) {
                            File one = new File(Globals.fileToPatch + ".bak");
                            File two = new File(Globals.fileToPatch);
                            File three = new File(
                                    Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('/') + 1)
                                            + ed);
                            two.renameTo(three);
                            File four = new File(Globals.fileToPatch);
                            one.renameTo(four);
                        }
                    }
                    Globals.msg = msg;
                } else if (Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".ecm")) {
                    int e = 0;
                    String msg = getResources().getString(R.string.success);
                    if (c) {

                        if (d) {
                            e = ecmPatchRom(Globals.fileToPatch,
                                    Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('/')) + ed, 1);
                        } else {
                            //new File(Globals.fileToPatch).renameTo(new File(Globals.fileToPatch+".bak"));
                            e = ecmPatchRom(Globals.fileToPatch,
                                    Globals.fileToPatch.substring(0, Globals.fileToPatch.lastIndexOf('.')), 1);
                        }
                    } else {
                        e = ecmPatchRom(Globals.fileToPatch, "", 0);
                    }
                    if (e != 0) {
                        msg = parseError(e, Globals.TYPE_ECM);
                    }
                    Globals.msg = msg;
                } else {
                    Globals.msg = getResources().getString(R.string.fnf);
                }

            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (Globals.msg.equals("")) {
                        Thread.sleep(25);
                    }
                    ;
                    myPd_ring.dismiss();
                    runOnUiThread(new Runnable() {
                        public void run() {
                            Toast t = Toast.makeText(staticThis, Globals.msg, Toast.LENGTH_SHORT);
                            t.show();
                            Globals.msg = "";
                        }
                    });
                    if (Globals.msg.equals(getResources().getString(R.string.success))) // Don't annoy people who did something wrong even further
                    {
                        final SharedPreferences prefs = PreferenceManager
                                .getDefaultSharedPreferences(MainActivity.this);
                        int x = prefs.getInt("purchaseNag", 5);
                        if (x != -1) {
                            if ((isPackageInstalled("com.xperia64.timidityae", MainActivity.this)
                                    || isPackageInstalled("com.xperia64.rompatcher.donation", MainActivity.this))) {
                                prefs.edit().putInt("purchaseNag", -1);
                            } else {
                                if (x >= 5) {

                                    prefs.edit().putInt("purchaseNag", 0).commit();
                                    /*runOnUiThread(new Runnable() {
                                        public void run() {
                                    AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
                                    b.setTitle("Like ROM Patcher?");
                                    b.setIcon(getResources().getDrawable(R.drawable.icon_pro));
                                    b.setMessage(getResources().getString(R.string.nagMsg));
                                    b.setCancelable(false);
                                    b.setNegativeButton(getResources().getString(android.R.string.cancel), new OnClickListener(){@Override public void onClick(DialogInterface arg0, int arg1) {}});
                                    b.setPositiveButton(getResources().getString(R.string.nagInfo), new OnClickListener(){
                                        
                                      @Override
                                      public void onClick(DialogInterface arg0, int arg1) {
                                         try  {
                                             startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.xperia64.rompatcher.donation")));
                                         } catch (android.content.ActivityNotFoundException anfe) {
                                             startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=com.xperia64.rompatcher.donation")));
                                         }
                                      }
                                       });
                                          b.create().show();
                                           }
                                       }); // end of UIThread*/
                                } else {
                                    prefs.edit().putInt("purchaseNag", x + 1).commit();
                                }
                            }
                        }
                    }

                } catch (Exception e) {
                }
            }
        }).start();
    }

    @Override
    public boolean onKeyDown(int KeyCode, KeyEvent event) {
        if (KeyCode == KeyEvent.KEYCODE_BACK) {
            System.exit(0);
        }
        return true;
    }

    // Error message based on error code.
    public String parseError(int e, int t) {
        switch (t) {
        case Globals.TYPE_UPS:
            switch (e) {
            case -1:
                return getResources().getString(R.string.upsNegativeOne);
            case -2:
                return getResources().getString(R.string.upsNegativeTwo);
            case -3:
                return getResources().getString(R.string.upsNegativeThree);
            case -4:
                return getResources().getString(R.string.upsNegativeFour);
            case -5:
                return getResources().getString(R.string.upsNegativeFive);
            case -6:
                return getResources().getString(R.string.upsNegativeSix);
            case -7:
                return getResources().getString(R.string.upsNegativeSeven);
            default:
                return getResources().getString(R.string.upsDefault) + e;
            }
        case Globals.TYPE_XDELTA3:
            switch (e) {
            case -17710:
                return getResources().getString(R.string.xdelta3NegativeSeventeenThousandSevenHundredTen);
            case -17711:
                return getResources().getString(R.string.xdelta3NegativeSeventeenThousandSevenHundredEleven);
            case -17712:
                return getResources().getString(R.string.xdelta3NegativeSeventeenThousandSevenHundredTwelve);
            default:
                return getResources().getString(R.string.xdelta3Default) + e;
            }
        case Globals.TYPE_XDELTA1:
            switch (e) {
            case 2:
                return getResources().getString(R.string.xdelta1Two);
            case 3:
                return getResources().getString(R.string.xdelta1Three);
            case 4:
                return getResources().getString(R.string.xdelta1Four);
            case 5:
                return getResources().getString(R.string.xdelta1Five);
            case 6:
                return getResources().getString(R.string.xdelta1Six);
            case 7:
                return getResources().getString(R.string.xdelta1Seven);
            case 8:
                return getResources().getString(R.string.xdelta1Eight);
            case 9:
                return getResources().getString(R.string.xdelta1Nine);
            case 10:
                return getResources().getString(R.string.xdelta1Ten);
            case 11:
                return getResources().getString(R.string.xdelta1Eleven);
            case 12:
                return getResources().getString(R.string.xdelta1Twelve);
            case 13:
                return getResources().getString(R.string.xdelta1Thirteen);
            default:
                return getResources().getString(R.string.xdelta1Default) + e;
            }
        case Globals.TYPE_BPS:
            switch (e) {
            case 1:
                return getResources().getString(R.string.bpsOne);
            case -1:
                return getResources().getString(R.string.bpsNegativeOne);
            case -2:
                return getResources().getString(R.string.bpsNegativeTwo);
            case -3:
                return getResources().getString(R.string.bpsNegativeThree);
            case -4:
                return getResources().getString(R.string.bpsNegativeFour);
            case -5:
                return getResources().getString(R.string.bpsNegativeFive);
            case -6:
                return getResources().getString(R.string.bpsNegativeSix);
            case -7:
                return getResources().getString(R.string.bpsNegativeSeven);
            case -8:
                return getResources().getString(R.string.bpsNegativeEight) + e;
            default:
                return getResources().getString(R.string.bpsDefault) + e;
            }
        case Globals.TYPE_BSDIFF:
            switch (e) {
            case 1:
                return getResources().getString(R.string.bsdiffOne);
            case 2:
                return getResources().getString(R.string.bsdiffTwo);
            default:
                return getResources().getString(R.string.bsdiffDefault) + e;
            }
        case Globals.TYPE_PPF:
            switch (e) {
            case 1:
                return getResources().getString(R.string.ppfOne);
            case -1:
                return getResources().getString(R.string.ppfNegativeOne);
            case -2:
                return getResources().getString(R.string.ppfNegativeTwo);
            case -3:
                return getResources().getString(R.string.ppfNegativeThree);
            case -4:
                return getResources().getString(R.string.ppfNegativeFour);
            default:
                return getResources().getString(R.string.ppfDefault) + e;
            }
        case Globals.TYPE_IPS:
            switch (e) {
            case 1:
                return getResources().getString(R.string.ipsOne);
            case -1:
                return getResources().getString(R.string.ipsNegativeOne);
            case -2:
                return getResources().getString(R.string.ipsNegativeTwo);
            case -3:
                return getResources().getString(R.string.ipsNegativeThree);
            case -4:
                return getResources().getString(R.string.ipsNegativeFour);
            case -5:
                return getResources().getString(R.string.ipsNegativeFive);
            case -6:
                return getResources().getString(R.string.ipsNegativeSix);
            case -7:
                return getResources().getString(R.string.ipsNegativeSeven);
            default:
                return getResources().getString(R.string.ipsDefault) + e;
            }
        case Globals.TYPE_IPS32:
            switch (e) {
            case 1:
                return getResources().getString(R.string.ips32One);
            case -1:
                return getResources().getString(R.string.ips32NegativeOne);
            case -2:
                return getResources().getString(R.string.ips32NegativeTwo);
            case -3:
                return getResources().getString(R.string.ips32NegativeThree);
            case -4:
                return getResources().getString(R.string.ips32NegativeFour);
            case -5:
                return getResources().getString(R.string.ips32NegativeFive);
            case -6:
                return getResources().getString(R.string.ips32NegativeSix);
            case -7:
                return getResources().getString(R.string.ips32NegativeSeven);
            default:
                return getResources().getString(R.string.ips32Default) + e;
            }
        case Globals.TYPE_ECM:
            switch (e) {
            case 1:
                return getResources().getString(R.string.ecmOne);
            case 2:
                return getResources().getString(R.string.ecmTwo);
            case 3:
                return getResources().getString(R.string.ecmThree);
            case 4:
                return getResources().getString(R.string.ecmFour);
            case 5:
                return getResources().getString(R.string.ecmFive);
            default:
                return getResources().getString(R.string.ecmDefault) + e;
            }
        case Globals.TYPE_DPS:
            switch (e) {
            case -1:
                return getResources().getString(R.string.dpsNegativeOne);
            case -2:
                return getResources().getString(R.string.dpsNegativeTwo);
            case -3:
                return getResources().getString(R.string.dpsNegativeThree);
            default:
                return getResources().getString(R.string.dpsDefault) + e;
            }
        case Globals.TYPE_ASM:
            switch (e) {
            default:
                return getResources().getString(R.string.asmDefault) + e;
            }
        case Globals.TYPE_DLDI:
            switch (e) {
            default:
                return getResources().getString(R.string.dldiDefault) + e;
            }
        case Globals.TYPE_APSN64:
            switch (e) {
            default:
                return getResources().getString(R.string.apsn64Default) + e;
            }
        case Globals.TYPE_APSGBA:
            switch (e) {
            case -1:
                return getResources().getString(R.string.apsgbaNegativeOne);
            case -2:
                return getResources().getString(R.string.apsgbaNegativeTwo);
            case -3:
                return getResources().getString(R.string.apsgbaNegativeThree);
            case -4:
                return getResources().getString(R.string.apsgbaNegativeFour);
            case -5:
                return getResources().getString(R.string.apsgbaNegativeFive);
            default:
                return getResources().getString(R.string.apsgbaDefault) + e;
            }
        case Globals.TYPE_XPC:
            switch (e) {
            default:
                return getResources().getString(R.string.xpcDefault) + e;
            }
        default:
            return getResources().getString(R.string.errorDefault);
        }
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1) {
            if (resultCode == RESULT_OK) {
                TextView tv1 = (TextView) findViewById(R.id.romText);
                TextView tv2 = (TextView) findViewById(R.id.patchText);
                if (Globals.fileToPatch.lastIndexOf("/") > -1) {
                    tv1.setText(Globals.fileToPatch.substring(Globals.fileToPatch.lastIndexOf("/") + 1));
                }
                if (Globals.fileToPatch.toLowerCase(Locale.US).endsWith(".ecm")) {
                    tv2.setEnabled(false);
                    ((Button) findViewById(R.id.patchButton)).setEnabled(false);
                } else {
                    tv2.setEnabled(true);
                    ((Button) findViewById(R.id.patchButton)).setEnabled(true);
                    if (Globals.patchToApply.lastIndexOf("/") > -1) {
                        tv2.setText(Globals.patchToApply.substring(Globals.patchToApply.lastIndexOf("/") + 1));
                    }
                }
                tv1.postInvalidate();
                tv2.postInvalidate();
            }
        }
    }
}