Compare commits

..

No commits in common. "master" and "0.13.1" have entirely different histories.

210 changed files with 796 additions and 5648 deletions

View file

@ -1,6 +1,5 @@
[main] [main]
host = https://www.transifex.com host = https://www.transifex.com
lang_map = he: iw, zh_CN: zh-rCN, zh_TW: zh-rTW, es_MX: es-rMX, pt_BR: pt-rBR, nb_NO: nb-rNO
[unipatcher.strings_xml] [unipatcher.strings_xml]
file_filter = app/src/main/res/values-<lang>/strings.xml file_filter = app/src/main/res/values-<lang>/strings.xml

View file

@ -8,30 +8,28 @@ UniPatcher is a ROM patcher for Android that supports IPS, IPS32, UPS, BPS, APS
### Additional features: ### Additional features:
* Creating XDelta3 patches
* Fix checksum in Sega Mega Drive ROMs * Fix checksum in Sega Mega Drive ROMs
* Add/Delete SMC header in Super Nintendo ROMs * Add/Delete SMC header in Super Nintendo ROMs
### Screenshots: ### Screenshots:
<img src="/google-play/screenshot_1.png" width="350"> <img src="/google-play/screenshot_2.png" width="350"> <img src="/google-play/screenshot_1.png" width="350">
<img src="/google-play/screenshot_2.png" width="350">
### Install UniPatcher: ### Install UniPatcher:
[<img src="/google-play/badges/google-play.png" alt="Get it on Google Play" width="220">](https://play.google.com/store/apps/details?id=org.emunix.unipatcher) [<img src="/google-play/badges/f-droid.png" alt="Get it on F-Droid" width="220">](https://f-droid.org/app/org.emunix.unipatcher) [<img src="https://play.google.com/intl/de_de/badges/images/generic/en_badge_web_generic.png" width="192">](https://play.google.com/store/apps/details?id=org.emunix.unipatcher)
[<img src="/google-play/badges/amazon.png" alt="Get it on Amazon" width="220">](http://www.amazon.com/gp/mas/dl/android?p=org.emunix.unipatcher) [<img src="/google-play/badges/slideme.png" alt="Get it on SlideMe" width="220">](http://slideme.org/application/unipatcher)
[... or get a Release APK here on GitHub](https://github.com/btimofeev/UniPatcher/releases) [... or get a Release APK here on GitHub](https://github.com/btimofeev/UniPatcher/releases)
### Contribute: ### How to contribute to UniPatcher:
#### Report a bug or suggest features #### Report a bug or suggest a new feature
These are discussed on the GitHub [Issue Tracker](https://github.com/btimofeev/UniPatcher/issues). Bugs and new features are being discussed on the GitHub [Issue Tracker](https://github.com/btimofeev/UniPatcher/issues).
#### Translations #### Help with translations
Help translate UniPatcher into another language on the [Transifex project page](https://www.transifex.com/unipatcher/unipatcher/). If you want to translate UniPatcher into another language, you can visit the [Transifex project page](https://www.transifex.com/unipatcher/unipatcher/).
### License ### License
UniPatcher is licensed under the GPL version 3. You can find the license text in the COPYING file. UniPatcher is licensed under the GPL version 3. You can find the license text in the COPYING file.

View file

@ -1,8 +1,13 @@
def versionMajor = 0
def versionMinor = 13
def versionPatch = 1
def versionBuild = 0
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 27 compileSdkVersion 25
buildToolsVersion '27.0.1' buildToolsVersion '25.0.2'
signingConfigs { signingConfigs {
release release
@ -11,17 +16,13 @@ android {
defaultConfig { defaultConfig {
applicationId "org.emunix.unipatcher" applicationId "org.emunix.unipatcher"
minSdkVersion 14 minSdkVersion 14
targetSdkVersion 27 targetSdkVersion 25
versionCode 150000 versionCode versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
versionName "0.15" versionName "${versionMajor}.${versionMinor}.${versionPatch}"
vectorDrawables.useSupportLibrary = true
ndk {
abiFilters 'armeabi-v7a', 'x86'
}
externalNativeBuild { externalNativeBuild {
cmake { cmake {
cppFlags "" cppFlags ""
arguments "-DANDROID_PLATFORM=android-14", "-DCMAKE_BUILD_TYPE=Release" arguments "-DANDROID_PLATFORM=android-14"
} }
} }
} }
@ -35,8 +36,6 @@ android {
} }
} }
flavorDimensions "default"
productFlavors { productFlavors {
free { free {
buildConfigField "String", "RATE_URL", "\"https://github.com/btimofeev/UniPatcher\"" buildConfigField "String", "RATE_URL", "\"https://github.com/btimofeev/UniPatcher\""
@ -66,21 +65,11 @@ android {
} }
} }
sourceSets{
amazon.java.srcDir 'src/free/java'
slideme.java.srcDir 'src/free/java'
}
externalNativeBuild { externalNativeBuild {
cmake { cmake {
path "CMakeLists.txt" path "CMakeLists.txt"
} }
} }
lintOptions {
disable 'MissingTranslation'
}
} }
def Properties props = new Properties() def Properties props = new Properties()
@ -109,18 +98,21 @@ if (propFile.canRead()) {
dependencies { dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.12.0' testCompile 'org.mockito:mockito-core:2.2.28'
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:27.0.2' compile 'com.android.support:support-v4:25.1.0'
compile 'com.android.support:appcompat-v7:27.0.2' compile 'com.android.support:appcompat-v7:25.1.0'
compile 'com.android.support:cardview-v7:27.0.2' compile 'com.android.support:cardview-v7:25.1.0'
compile 'com.android.support:preference-v14:27.0.2' compile 'com.android.support:preference-v14:25.1.0'
compile 'com.android.support:recyclerview-v7:27.0.2' compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.android.support:design:27.0.2' compile 'com.android.support:design:25.1.0'
compile 'com.android.support:support-v13:27.0.2' // used in material-dialogs compile 'com.google.firebase:firebase-core:10.0.1'
compile 'com.google.firebase:firebase-crash:10.0.1'
compile 'commons-io:commons-io:2.5' compile 'commons-io:commons-io:2.5'
compile 'org.sufficientlysecure:donations:2.5' compile 'org.sufficientlysecure:donations:2.5'
compile 'org.sufficientlysecure:html-textview:3.5' compile 'org.sufficientlysecure:html-textview:3.0'
compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.1' compile 'org.commonjava.googlecode.markdown4j:markdown4j:2.2-cj-1.1'
compile 'com.afollestad.material-dialogs:core:0.9.6.0' compile 'com.afollestad.material-dialogs:core:0.9.2.3'
} }
apply plugin: 'com.google.gms.google-services'

53
app/google-services.json Normal file
View file

@ -0,0 +1,53 @@
{
"project_info": {
"project_number": "32713218397",
"firebase_url": "https://unipatcher-897b3.firebaseio.com",
"project_id": "unipatcher-897b3",
"storage_bucket": "unipatcher-897b3.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:32713218397:android:4b0afdca1aa174e1",
"android_client_info": {
"package_name": "org.emunix.unipatcher"
}
},
"oauth_client": [
{
"client_id": "32713218397-h8ptc6lelg9l871v10pgq11ni8ejaavg.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "org.emunix.unipatcher",
"certificate_hash": "C31CB23D974F426B38D7AF0848A6F1066FCF1FD9"
}
},
{
"client_id": "32713218397-bhgevevp6i5coukhnkti1g9cecnujuav.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD_8JprF21wL7wpRV7JymLzlbHR-jUBZKI"
}
],
"services": {
"analytics_service": {
"status": 2,
"analytics_property": {
"tracking_id": "UA-77394676-1"
}
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}

View file

@ -0,0 +1,72 @@
/*
Copyright (c) 2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher.ui.activity;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import org.emunix.unipatcher.BuildConfig;
import org.emunix.unipatcher.R;
import org.sufficientlysecure.donations.DonationsFragment;
public class DonateActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_donate);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
try {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} catch (NullPointerException e) {
/* empty */
}
getSupportActionBar().setTitle(R.string.donate_activity_title);
DonationsFragment fragment = (DonationsFragment) getSupportFragmentManager().findFragmentByTag("donationsFragment");
if (fragment == null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
fragment = DonationsFragment.newInstance(BuildConfig.DEBUG,
false, null, null, null,
true, BuildConfig.PAYPAL_USER, BuildConfig.PAYPAL_CURRENCY_CODE, getString(R.string.donation),
false, null, null,
true, BuildConfig.BITCOIN_ADDRESS);
ft.replace(R.id.donate_fragment, fragment, "donationsFragment");
ft.commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View file

@ -6,11 +6,12 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application <application
android:name=".UniPatcher"
android:allowBackup="false" android:allowBackup="false"
android:extractNativeLibs="true" android:extractNativeLibs="false"
android:fullBackupContent="false" android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@ -42,7 +43,6 @@
<data android:pathPattern="/.*\\.dps"/> <data android:pathPattern="/.*\\.dps"/>
<data android:pathPattern="/.*\\.xdelta"/> <data android:pathPattern="/.*\\.xdelta"/>
<data android:pathPattern="/.*\\.xdelta3"/> <data android:pathPattern="/.*\\.xdelta3"/>
<data android:pathPattern="/.*\\.xd"/>
<data android:pathPattern="/.*\\.vcdiff"/> <data android:pathPattern="/.*\\.vcdiff"/>
<data android:host="*"/> <data android:host="*"/>
</intent-filter> </intent-filter>
@ -69,6 +69,10 @@
android:name=".WorkerService" android:name=".WorkerService"
android:exported="false"/> android:exported="false"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
</application> </application>
</manifest> </manifest>

View file

@ -2,7 +2,7 @@
This file based on encode_decode_test.c from XDelta3 sources. This file based on encode_decode_test.c from XDelta3 sources.
Copyright (C) 2007 Ralf Junker Copyright (C) 2007 Ralf Junker
Copyright (C) 2016-2017 Boris Timofeev Copyright (C) 2016 Boris Timofeev
This file is part of UniPatcher. This file is part of UniPatcher.
@ -30,21 +30,18 @@ along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
#include "xdelta3/xdelta3/xdelta3.h" #include "xdelta3/xdelta3/xdelta3.h"
#include "xdelta3/xdelta3/xdelta3.c" #include "xdelta3/xdelta3/xdelta3.c"
int code(int encode, FILE *in, FILE *src, FILE *out, int ignoreChecksum); int apply(FILE *patch, FILE *in, FILE *out);
const int ERR_UNABLE_OPEN_PATCH = -5001; const int ERR_UNABLE_OPEN_PATCH = -5001;
const int ERR_UNABLE_OPEN_ROM = -5002; const int ERR_UNABLE_OPEN_ROM = -5002;
const int ERR_UNABLE_OPEN_OUTPUT = -5003; const int ERR_UNABLE_OPEN_OUTPUT = -5003;
const int ERR_UNABLE_OPEN_SOURCE = -5004;
const int ERR_UNABLE_OPEN_MODIFIED = -5005;
const int ERR_WRONG_CHECKSUM = -5010; const int ERR_WRONG_CHECKSUM = -5010;
int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env, int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
jobject this, jobject this,
jstring patchPath, jstring patchPath,
jstring romPath, jstring romPath,
jstring outputPath, jstring outputPath) {
jboolean ignoreChecksum) {
int ret = 0; int ret = 0;
const char *patchName = (*env)->GetStringUTFChars(env, patchPath, NULL); const char *patchName = (*env)->GetStringUTFChars(env, patchPath, NULL);
const char *romName = (*env)->GetStringUTFChars(env, romPath, NULL); const char *romName = (*env)->GetStringUTFChars(env, romPath, NULL);
@ -73,7 +70,7 @@ int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
return ERR_UNABLE_OPEN_OUTPUT; return ERR_UNABLE_OPEN_OUTPUT;
} }
ret = code(0, patchFile, romFile, outputFile, (int)ignoreChecksum); ret = apply(patchFile, romFile, outputFile);
fclose(patchFile); fclose(patchFile);
fclose(romFile); fclose(romFile);
@ -81,50 +78,8 @@ int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
return ret; return ret;
} }
int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3create(JNIEnv *env, int apply(FILE *patch, FILE *in, FILE *out) {
jobject this, int BUFFER_SIZE = 32768;
jstring patchPath,
jstring sourcePath,
jstring modifiedPath) {
int ret = 0;
const char *patchName = (*env)->GetStringUTFChars(env, patchPath, NULL);
const char *sourceName = (*env)->GetStringUTFChars(env, sourcePath, NULL);
const char *modifiedName = (*env)->GetStringUTFChars(env, modifiedPath, NULL);
FILE *patchFile = fopen(patchName, "wb");
FILE *sourceFile = fopen(sourceName, "rb");
FILE *modifiedFile = fopen(modifiedName, "rb");
(*env)->ReleaseStringUTFChars(env, patchPath, patchName);
(*env)->ReleaseStringUTFChars(env, sourcePath, sourceName);
(*env)->ReleaseStringUTFChars(env, modifiedPath, modifiedName);
if (!patchFile) {
return ERR_UNABLE_OPEN_PATCH;
}
if (!sourceFile) {
fclose(patchFile);
return ERR_UNABLE_OPEN_SOURCE;
}
if (!modifiedFile) {
fclose(patchFile);
fclose(sourceFile);
return ERR_UNABLE_OPEN_MODIFIED;
}
ret = code(1, modifiedFile, sourceFile, patchFile, 0);
fclose(patchFile);
fclose(sourceFile);
fclose(modifiedFile);
return ret;
}
int code(int encode, FILE *in, FILE *src, FILE *out, int ignoreChecksum) {
int BUFFER_SIZE = 0x1000;
int r, ret; int r, ret;
xd3_stream stream; xd3_stream stream;
@ -138,36 +93,31 @@ int code(int encode, FILE *in, FILE *src, FILE *out, int ignoreChecksum) {
xd3_init_config(&config, 0); xd3_init_config(&config, 0);
config.winsize = BUFFER_SIZE; config.winsize = BUFFER_SIZE;
if (ignoreChecksum) {
config.flags |= XD3_ADLER32_NOVER;
}
xd3_config_stream(&stream, &config); xd3_config_stream(&stream, &config);
source.blksize = BUFFER_SIZE; source.blksize = BUFFER_SIZE;
source.curblk = malloc(source.blksize); source.curblk = malloc(source.blksize);
/* Load 1st block of stream. */ /* Load 1st block of stream. */
r = fseek(src, 0, SEEK_SET); r = fseek(in, 0, SEEK_SET);
if (r) if (r)
return r; return r;
source.onblk = fread((void *) source.curblk, 1, source.blksize, src); source.onblk = fread((void *) source.curblk, 1, source.blksize, in);
source.curblkno = 0; source.curblkno = 0;
xd3_set_source(&stream, &source); xd3_set_source(&stream, &source);
Input_Buf = malloc(BUFFER_SIZE); Input_Buf = malloc(BUFFER_SIZE);
fseek(in, 0, SEEK_SET); fseek(patch, 0, SEEK_SET);
do { do {
Input_Buf_Read = fread(Input_Buf, 1, BUFFER_SIZE, in); Input_Buf_Read = fread(Input_Buf, 1, BUFFER_SIZE, patch);
if (Input_Buf_Read < BUFFER_SIZE) { if (Input_Buf_Read < BUFFER_SIZE) {
xd3_set_flags(&stream, XD3_FLUSH | stream.flags); xd3_set_flags(&stream, XD3_FLUSH | stream.flags);
} }
xd3_avail_input(&stream, Input_Buf, Input_Buf_Read); xd3_avail_input(&stream, Input_Buf, Input_Buf_Read);
process: process:
if (encode)
ret = xd3_encode_input(&stream);
else
ret = xd3_decode_input(&stream); ret = xd3_decode_input(&stream);
switch (ret) { switch (ret) {
@ -182,10 +132,10 @@ process:
goto process; goto process;
case XD3_GETSRCBLK: case XD3_GETSRCBLK:
r = fseek(src, source.blksize * source.getblkno, SEEK_SET); r = fseek(in, source.blksize * source.getblkno, SEEK_SET);
if (r) if (r)
return r; return r;
source.onblk = fread((void *) source.curblk, 1, source.blksize, src); source.onblk = fread((void *) source.curblk, 1, source.blksize, in);
source.curblkno = source.getblkno; source.curblkno = source.getblkno;
goto process; goto process;

View file

@ -1,35 +0,0 @@
/*
Copyright (c) 2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher;
public class Action {
public static final int SELECT_ROM_FILE = 1;
public static final int SELECT_PATCH_FILE = 2;
public static final int SELECT_SOURCE_FILE = 3;
public static final int SELECT_MODIFIED_FILE = 4;
public static final int SELECT_HEADER_FILE = 5;
public static final int APPLY_PATCH = 101;
public static final int CREATE_PATCH = 102;
public static final int SMD_FIX_CHECKSUM = 103;
public static final int SNES_ADD_SMC_HEADER = 104;
public static final int SNES_DELETE_SMC_HEADER = 105;
}

View file

@ -0,0 +1,37 @@
/*
Copyright (C) 2013-2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher;
public class Globals {
private static String cmdArgument = null;
public static String getCmdArgument() {
return cmdArgument;
}
public static void setCmdArgument(String cmdArgument) {
Globals.cmdArgument = cmdArgument;
}
public static final int ACTION_PATCHING = 1;
public static final int ACTION_SMD_FIX_CHECKSUM = 2;
public static final int ACTION_SNES_ADD_SMC_HEADER = 3;
public static final int ACTION_SNES_DELETE_SMC_HEADER = 4;
}

View file

@ -69,33 +69,4 @@ public class Settings {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("output_directory", ""); return prefs.getString("output_directory", "");
} }
public static boolean getIgnoreChecksum(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("ignore_checksum", false);
}
public static void setPatchingSuccessful(Context context, Boolean isSuccessful) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("patching_successful", isSuccessful);
editor.apply();
}
public static boolean getPatchingSuccessful(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("patching_successful", false);
}
public static void setDontShowDonateSnackbarCount(Context context, int count) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("dont_show_donate_snackbar", count);
editor.apply();
}
public static int getDontShowDonateSnackbarCount(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getInt("dont_show_donate_snackbar", 0);
}
} }

View file

@ -1,57 +0,0 @@
/*
Copyright (c) 2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
public class UniPatcher extends Application {
private static String appArgument = null;
public static final String NOTIFICATION_CHANNEL_ID = "notifications";
@Override
public void onCreate() {
super.onCreate();
initNotificationChannel();
}
public static String getAppArgument() {
return appArgument;
}
public static void setAppArgument(String appArgument) {
UniPatcher.appArgument = appArgument;
}
public void initNotificationChannel() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return;
}
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
getString(R.string.notification_channel_name),
NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
}

View file

@ -22,7 +22,6 @@ package org.emunix.unipatcher;
import android.Manifest; import android.Manifest;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
@ -49,14 +48,6 @@ public class Utils {
private static final int BUFFER_SIZE = 10240; // 10 Kb private static final int BUFFER_SIZE = 10240; // 10 Kb
public static void startForegroundService(Context context, Intent intent) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(intent);
} else {
context.startForegroundService(intent);
}
}
public static String getAppVersion(Context context) { public static String getAppVersion(Context context) {
String versionName = "N/A"; String versionName = "N/A";
try { try {
@ -161,7 +152,7 @@ public class Utils {
public static boolean isPatch(File file) { public static boolean isPatch(File file) {
String[] patches = String[] patches =
{"ips", "ups", "bps", "aps", "ppf", "dps", "ebp", "xdelta", "xdelta3", "xd", "vcdiff"}; {"ips", "ups", "bps", "aps", "ppf", "dps", "ebp", "xdelta", "xdelta3", "vcdiff"};
String ext = FilenameUtils.getExtension(file.getName()).toLowerCase(Locale.getDefault()); String ext = FilenameUtils.getExtension(file.getName()).toLowerCase(Locale.getDefault());
for (String patch : patches) { for (String patch : patches) {
if (ext.equals(patch)) return true; if (ext.equals(patch)) return true;

View file

@ -24,7 +24,6 @@ import android.app.Notification;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
import android.os.Build;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
@ -44,7 +43,6 @@ import org.emunix.unipatcher.tools.RomException;
import org.emunix.unipatcher.tools.SmdFixChecksum; import org.emunix.unipatcher.tools.SmdFixChecksum;
import org.emunix.unipatcher.tools.SnesSmcHeader; import org.emunix.unipatcher.tools.SnesSmcHeader;
import org.emunix.unipatcher.ui.activity.MainActivity; import org.emunix.unipatcher.ui.activity.MainActivity;
import org.emunix.unipatcher.ui.notify.CreatePatchNotify;
import org.emunix.unipatcher.ui.notify.Notify; import org.emunix.unipatcher.ui.notify.Notify;
import org.emunix.unipatcher.ui.notify.PatchingNotify; import org.emunix.unipatcher.ui.notify.PatchingNotify;
import org.emunix.unipatcher.ui.notify.SmdFixChecksumNotify; import org.emunix.unipatcher.ui.notify.SmdFixChecksumNotify;
@ -76,19 +74,16 @@ public class WorkerService extends IntentService {
try { try {
int action = intent.getIntExtra("action", 0); int action = intent.getIntExtra("action", 0);
switch (action) { switch (action) {
case Action.APPLY_PATCH: case Globals.ACTION_PATCHING:
actionPatching(intent); actionPatching(intent);
break; break;
case Action.CREATE_PATCH: case Globals.ACTION_SMD_FIX_CHECKSUM:
actionCreatePatch(intent);
break;
case Action.SMD_FIX_CHECKSUM:
actionSmdFixChecksum(intent); actionSmdFixChecksum(intent);
break; break;
case Action.SNES_ADD_SMC_HEADER: case Globals.ACTION_SNES_ADD_SMC_HEADER:
actionSnesAddSmcHeader(intent); actionSnesAddSmcHeader(intent);
break; break;
case Action.SNES_DELETE_SMC_HEADER: case Globals.ACTION_SNES_DELETE_SMC_HEADER:
actionSnesDeleteSmcHeader(intent); actionSnesDeleteSmcHeader(intent);
break; break;
} }
@ -146,88 +141,31 @@ public class WorkerService extends IntentService {
patcher = new EBP(this, patchFile, romFile, outputFile); patcher = new EBP(this, patchFile, romFile, outputFile);
else if ("dps".equals(ext)) else if ("dps".equals(ext))
patcher = new DPS(this, patchFile, romFile, outputFile); patcher = new DPS(this, patchFile, romFile, outputFile);
else if ("xdelta".equals(ext) || "xdelta3".equals(ext) || "xd".equals(ext) || "vcdiff".equals(ext)) else if ("xdelta".equals(ext) || "xdelta3".equals(ext) || "vcdiff".equals(ext))
patcher = new XDelta(this, patchFile, romFile, outputFile); patcher = new XDelta(this, patchFile, romFile, outputFile);
else else
errorMsg = getString(R.string.notify_error_unknown_patch_format); errorMsg = getString(R.string.notify_error_unknown_patch_format);
Notify notify = new PatchingNotify(this, outputFile.getName());
if (errorMsg != null) { if (errorMsg != null) {
showErrorNotification(errorMsg); notify.showResult(errorMsg);
return; return;
} }
Notify notify = new PatchingNotify(this, outputFile.getName());
startForeground(notify.getID(), notify.getNotifyBuilder().build()); startForeground(notify.getID(), notify.getNotifyBuilder().build());
try { try {
if ("ppf".equals(ext)) if ("ppf".equals(ext))
Utils.copyFile(this, romFile, outputFile); Utils.copyFile(this, romFile, outputFile);
patcher.apply(Settings.getIgnoreChecksum(this)); patcher.apply();
Settings.setPatchingSuccessful(this, true);
} catch (PatchException | IOException e) { } catch (PatchException | IOException e) {
if (Utils.getFreeSpace(outputFile.getParentFile()) == 0) { if (Utils.getFreeSpace(outputFile.getParentFile()) == 0) {
errorMsg = getString(R.string.notify_error_not_enough_space); errorMsg = getString(R.string.notify_error_not_enough_space);
} else { } else {
errorMsg = e.getMessage(); errorMsg = e.getMessage();
} }
if (outputFile.isFile()) {
FileUtils.deleteQuietly(outputFile); FileUtils.deleteQuietly(outputFile);
}
} finally {
stopForeground(true);
}
notify.showResult(errorMsg);
}
private void actionCreatePatch(Intent intent) {
String errorMsg = null;
File sourceFile = new File(intent.getStringExtra("sourcePath"));
File modifiedFile = new File(intent.getStringExtra("modifiedPath"));
File patchFile = new File(intent.getStringExtra("patchPath"));
if (!fileExists(sourceFile) || !fileExists(modifiedFile))
return;
// create output dir
try {
if (!patchFile.getParentFile().exists()) {
FileUtils.forceMkdirParent(patchFile);
}
} catch (IOException | SecurityException e) {
String text = getString(R.string.notify_error_unable_to_create_directory, patchFile.getParent());
showErrorNotification(text);
return;
}
// check access to output dir
try {
if (!patchFile.getParentFile().canWrite()) {
String text = getString(R.string.notify_error_unable_to_write_to_directory, patchFile.getParent());
showErrorNotification(text);
return;
}
} catch (SecurityException e) {
String text = getString(R.string.notify_error_unable_to_write_to_directory, patchFile.getParent());
showErrorNotification(text);
return;
}
XDelta patcher = new XDelta(this, patchFile, sourceFile, modifiedFile);
Notify notify = new CreatePatchNotify(this, patchFile.getName());
startForeground(notify.getID(), notify.getNotifyBuilder().build());
try {
patcher.create();
Settings.setPatchingSuccessful(this, true);
} catch (PatchException | IOException e) {
if (Utils.getFreeSpace(patchFile.getParentFile()) == 0) {
errorMsg = getString(R.string.notify_error_not_enough_space);
} else {
errorMsg = e.getMessage();
}
FileUtils.deleteQuietly(patchFile);
} finally { } finally {
stopForeground(true); stopForeground(true);
} }
@ -326,21 +264,15 @@ public class WorkerService extends IntentService {
private void showErrorNotification(String text) { private void showErrorNotification(String text) {
Intent notificationIntent = new Intent(this, MainActivity.class); Intent notificationIntent = new Intent(this, MainActivity.class);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notify = new NotificationCompat.Builder(this, UniPatcher.NOTIFICATION_CHANNEL_ID) Notification notify = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.notify_error)) .setContentTitle(getString(R.string.notify_error))
.setContentText(text) .setContentText(text)
.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp) .setSmallIcon(R.drawable.ic_stat_patching)
.setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT)) .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT))
.setAutoCancel(true) .setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle() .setStyle(new NotificationCompat.BigTextStyle()
.bigText(text)) .bigText(text))
.build(); .build();
nm.notify(0, notify);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
nm.notify(32768, notify);
} else {
startForeground(32768, notify);
stopForeground(STOP_FOREGROUND_DETACH);
}
} }
} }

View file

@ -43,7 +43,7 @@ public class APS extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
Patcher aps = null; Patcher aps = null;
switch (checkAPS(patchFile)) { switch (checkAPS(patchFile)) {
case APS_N64_PATCH: case APS_N64_PATCH:
@ -56,7 +56,7 @@ public class APS extends Patcher {
throw new PatchException(context.getString(R.string.notify_error_not_aps_patch)); throw new PatchException(context.getString(R.string.notify_error_not_aps_patch));
} }
aps.apply(ignoreChecksum); aps.apply();
} }
public int checkAPS(File file) throws PatchException, IOException { public int checkAPS(File file) throws PatchException, IOException {

View file

@ -77,7 +77,7 @@ public class APS_GBA extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
long fileSize1, fileSize2, bytesLeft, offset; long fileSize1, fileSize2, bytesLeft, offset;
int crc, patchCrc1, patchCrc2, pCount, oCount; int crc, patchCrc1, patchCrc2, pCount, oCount;
boolean isOriginal = false; boolean isOriginal = false;
@ -138,7 +138,6 @@ public class APS_GBA extends Patcher {
} else if (crc == patchCrc2) { } else if (crc == patchCrc2) {
isModified = true; isModified = true;
} else { } else {
if (!ignoreChecksum)
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
} }
if (isOriginal && isModified) if (isOriginal && isModified)
@ -154,7 +153,7 @@ public class APS_GBA extends Patcher {
if (isOriginal) { if (isOriginal) {
Utils.truncateFile(outputFile, fileSize2); Utils.truncateFile(outputFile, fileSize2);
} else if (isModified) { } else {
Utils.truncateFile(outputFile, fileSize1); Utils.truncateFile(outputFile, fileSize1);
} }
} }

View file

@ -47,7 +47,7 @@ public class APS_N64 extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
BufferedInputStream romStream = null; BufferedInputStream romStream = null;
BufferedInputStream patchStream = null; BufferedInputStream patchStream = null;
BufferedOutputStream outputStream = null; BufferedOutputStream outputStream = null;
@ -96,10 +96,8 @@ public class APS_N64 extends Patcher {
int country = patchStream.read(); int country = patchStream.read();
byte[] crc = new byte[8]; byte[] crc = new byte[8];
patchStream.read(crc); patchStream.read(crc);
if (!ignoreChecksum) {
if (!validateROM(endianness, cardID, country, crc)) if (!validateROM(endianness, cardID, country, crc))
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
}
// skip bytes for future expansion // skip bytes for future expansion
byte[] skip = new byte[5]; byte[] skip = new byte[5];
patchStream.read(skip); patchStream.read(skip);

View file

@ -50,7 +50,7 @@ public class BPS extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
if (patchFile.length() < 19) { if (patchFile.length() < 19) {
throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); throw new PatchException(context.getString(R.string.notify_error_patch_corrupted));
@ -68,12 +68,10 @@ public class BPS extends Patcher {
if (bpsCrc.getPatchFileCRC() != bpsCrc.getRealPatchCRC()) if (bpsCrc.getPatchFileCRC() != bpsCrc.getRealPatchCRC())
throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); throw new PatchException(context.getString(R.string.notify_error_patch_corrupted));
if (!ignoreChecksum) {
long realRomCrc = FileUtils.checksumCRC32(romFile); long realRomCrc = FileUtils.checksumCRC32(romFile);
if (realRomCrc != bpsCrc.getInputFileCRC()) { if (realRomCrc != bpsCrc.getInputFileCRC()) {
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
} }
}
patch = new RandomAccessFile(patchFile, "r").getChannel(); patch = new RandomAccessFile(patchFile, "r").getChannel();
patch.position(4); // skip magic patch.position(4); // skip magic
@ -135,12 +133,10 @@ public class BPS extends Patcher {
IOUtils.closeQuietly(output); IOUtils.closeQuietly(output);
} }
if(!ignoreChecksum) {
long realOutCrc = FileUtils.checksumCRC32(outputFile); long realOutCrc = FileUtils.checksumCRC32(outputFile);
if (realOutCrc != bpsCrc.getOutputFileCRC()) if (realOutCrc != bpsCrc.getOutputFileCRC())
throw new PatchException(context.getString(R.string.notify_error_wrong_checksum_after_patching)); throw new PatchException(context.getString(R.string.notify_error_wrong_checksum_after_patching));
} }
}
// decode pointer // decode pointer
private long decode(FileChannel fc) throws IOException { private long decode(FileChannel fc) throws IOException {

View file

@ -42,7 +42,7 @@ public class DPS extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
if (patchFile.length() < MIN_SIZE_PATCH) { if (patchFile.length() < MIN_SIZE_PATCH) {
throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); throw new PatchException(context.getString(R.string.notify_error_patch_corrupted));
@ -63,11 +63,9 @@ public class DPS extends Patcher {
throw new PatchException(context.getString(R.string.notify_error_not_dps_patch)); throw new PatchException(context.getString(R.string.notify_error_not_dps_patch));
// verify rom // verify rom
if (!ignoreChecksum) {
long romSize = getUInt(buffer, 194); long romSize = getUInt(buffer, 194);
if (romSize != romFile.length()) if (romSize != romFile.length())
throw new IOException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new IOException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
}
romStream = new RandomAccessFile(romFile, "r"); romStream = new RandomAccessFile(romFile, "r");
outputStream = new RandomAccessFile(outputFile, "rw"); outputStream = new RandomAccessFile(outputFile, "rw");

View file

@ -68,12 +68,12 @@ public class EBP extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
File cleanRom = File.createTempFile("rom", null, context.getCacheDir()); File cleanRom = File.createTempFile("rom", null, context.getCacheDir());
File ipsPatch = File.createTempFile("patch", null, context.getCacheDir()); File ipsPatch = File.createTempFile("patch", null, context.getCacheDir());
try { try {
Utils.copyFile(context, romFile, cleanRom); Utils.copyFile(context, romFile, cleanRom);
prepareCleanRom(cleanRom, ignoreChecksum); prepareCleanRom(cleanRom);
EBPtoIPS(patchFile, ipsPatch); EBPtoIPS(patchFile, ipsPatch);
@ -85,7 +85,7 @@ public class EBP extends Patcher {
} }
} }
private void prepareCleanRom(File file, boolean ignoreChecksum) throws IOException, PatchException { private void prepareCleanRom(File file) throws IOException, PatchException {
// delete smc header // delete smc header
SnesSmcHeader smc = new SnesSmcHeader(); SnesSmcHeader smc = new SnesSmcHeader();
try { try {
@ -95,10 +95,8 @@ public class EBP extends Patcher {
} }
// check rom size and remove unused expanded space // check rom size and remove unused expanded space
if (!ignoreChecksum) {
if (file.length() < EB_CLEAN_ROM_SIZE) if (file.length() < EB_CLEAN_ROM_SIZE)
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
}
if (file.length() > EB_CLEAN_ROM_SIZE && checkExpanded(file)) if (file.length() > EB_CLEAN_ROM_SIZE && checkExpanded(file))
removeExpanded(file); removeExpanded(file);

View file

@ -50,10 +50,6 @@ public class IPS extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException {
apply();
}
public void apply() throws PatchException, IOException { public void apply() throws PatchException, IOException {
BufferedInputStream romStream = null; BufferedInputStream romStream = null;
BufferedInputStream patchStream = null; BufferedInputStream patchStream = null;

View file

@ -68,7 +68,7 @@ public class PPF extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
if (patchFile.length() < 61) { if (patchFile.length() < 61) {
throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); throw new PatchException(context.getString(R.string.notify_error_patch_corrupted));
} }
@ -78,10 +78,10 @@ public class PPF extends Patcher {
applyPPF1(); applyPPF1();
break; break;
case 2: case 2:
applyPPF2(ignoreChecksum); applyPPF2();
break; break;
case 3: case 3:
applyPPF3(ignoreChecksum); applyPPF3();
break; break;
default: default:
throw new PatchException(context.getString(R.string.notify_error_not_ppf_patch)); throw new PatchException(context.getString(R.string.notify_error_not_ppf_patch));
@ -112,18 +112,16 @@ public class PPF extends Patcher {
} }
} }
private void applyPPF2(boolean ignoreChecksum) throws IOException, PatchException { private void applyPPF2() throws IOException, PatchException {
try { try {
patchStream = new RandomAccessFile(patchFile, "r"); patchStream = new RandomAccessFile(patchFile, "r");
// Check size of ROM // Check size of ROM
patchStream.seek(56); patchStream.seek(56);
long romSize = readLittleEndianInt(patchStream); long romSize = readLittleEndianInt(patchStream);
if (!ignoreChecksum) {
if (romSize != romFile.length()) { if (romSize != romFile.length()) {
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
} }
}
outputStream = new RandomAccessFile(outputFile, "rw"); outputStream = new RandomAccessFile(outputFile, "rw");
@ -133,10 +131,8 @@ public class PPF extends Patcher {
outputStream.seek(0x9320); outputStream.seek(0x9320);
patchStream.read(patchBinaryBlock, 0, 1024); patchStream.read(patchBinaryBlock, 0, 1024);
outputStream.read(romBinaryBlock, 0, 1024); outputStream.read(romBinaryBlock, 0, 1024);
if (!ignoreChecksum) {
if (!Arrays.equals(patchBinaryBlock, romBinaryBlock)) if (!Arrays.equals(patchBinaryBlock, romBinaryBlock))
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
}
// Calculate end of patch data // Calculate end of patch data
long dataEnd = patchFile.length(); long dataEnd = patchFile.length();
@ -164,7 +160,7 @@ public class PPF extends Patcher {
} }
} }
private void applyPPF3(boolean ignoreChecksum) throws IOException, PatchException { private void applyPPF3() throws IOException, PatchException {
try { try {
patchStream = new RandomAccessFile(patchFile, "r"); patchStream = new RandomAccessFile(patchFile, "r");
outputStream = new RandomAccessFile(outputFile, "rw"); outputStream = new RandomAccessFile(outputFile, "rw");
@ -186,11 +182,9 @@ public class PPF extends Patcher {
} }
patchStream.read(patchBinaryBlock, 0, 1024); patchStream.read(patchBinaryBlock, 0, 1024);
outputStream.read(romBinaryBlock, 0, 1024); outputStream.read(romBinaryBlock, 0, 1024);
if (!ignoreChecksum) {
if (!Arrays.equals(patchBinaryBlock, romBinaryBlock)) if (!Arrays.equals(patchBinaryBlock, romBinaryBlock))
throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new PatchException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
} }
}
// Calculate end of patch data // Calculate end of patch data
long dataEnd = patchFile.length(); long dataEnd = patchFile.length();

View file

@ -37,5 +37,5 @@ public abstract class Patcher {
outputFile = output; outputFile = output;
} }
public abstract void apply(boolean ignoreChecksum) throws PatchException, IOException; public abstract void apply() throws PatchException, IOException;
} }

View file

@ -44,7 +44,7 @@ public class UPS extends Patcher {
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
if (patchFile.length() < 18) { if (patchFile.length() < 18) {
throw new PatchException(context.getString(R.string.notify_error_patch_corrupted)); throw new PatchException(context.getString(R.string.notify_error_patch_corrupted));
@ -90,10 +90,8 @@ public class UPS extends Patcher {
ySize = tmp; ySize = tmp;
upsCrc.swapInOut(); upsCrc.swapInOut();
} else { } else {
if (!ignoreChecksum) {
throw new IOException(context.getString(R.string.notify_error_rom_not_compatible_with_patch)); throw new IOException(context.getString(R.string.notify_error_rom_not_compatible_with_patch));
} }
}
romStream = new BufferedInputStream(new FileInputStream(romFile)); romStream = new BufferedInputStream(new FileInputStream(romFile));
outputStream = new BufferedOutputStream(new FileOutputStream(outputFile)); outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));
@ -127,12 +125,10 @@ public class UPS extends Patcher {
IOUtils.closeQuietly(outputStream); IOUtils.closeQuietly(outputStream);
} }
if (!ignoreChecksum) {
long realOutCrc = FileUtils.checksumCRC32(outputFile); long realOutCrc = FileUtils.checksumCRC32(outputFile);
if (realOutCrc != upsCrc.getOutputFileCRC()) if (realOutCrc != upsCrc.getOutputFileCRC())
throw new PatchException(context.getString(R.string.notify_error_wrong_checksum_after_patching)); throw new PatchException(context.getString(R.string.notify_error_wrong_checksum_after_patching));
} }
}
// decode pointer // decode pointer
private Pair decode(BufferedInputStream stream) throws PatchException, IOException { private Pair decode(BufferedInputStream stream) throws PatchException, IOException {

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2016-2017 Boris Timofeev Copyright (C) 2016 Boris Timofeev
This file is part of UniPatcher. This file is part of UniPatcher.
@ -35,20 +35,17 @@ public class XDelta extends Patcher {
private static final int ERR_UNABLE_OPEN_PATCH = -5001; private static final int ERR_UNABLE_OPEN_PATCH = -5001;
private static final int ERR_UNABLE_OPEN_ROM = -5002; private static final int ERR_UNABLE_OPEN_ROM = -5002;
private static final int ERR_UNABLE_OPEN_OUTPUT = -5003; private static final int ERR_UNABLE_OPEN_OUTPUT = -5003;
private static final int ERR_UNABLE_OPEN_SOURCE = -5004;
private static final int ERR_UNABLE_OPEN_MODIFIED = -5005;
private static final int ERR_WRONG_CHECKSUM = -5010; private static final int ERR_WRONG_CHECKSUM = -5010;
private static final int ERR_INVALID_INPUT = -17712; private static final int ERR_INVALID_INPUT = -17712;
public static native int xdelta3apply(String patchPath, String romPath, String outputPath, boolean ignoreChecksum); public static native int xdelta3apply(String patchPath, String romPath, String outputPath);
public static native int xdelta3create(String patchPath, String sourcePath, String modifiedPath);
public XDelta(Context context, File patch, File rom, File output) { public XDelta(Context context, File patch, File rom, File output) {
super(context, patch, rom, output); super(context, patch, rom, output);
} }
@Override @Override
public void apply(boolean ignoreChecksum) throws PatchException, IOException { public void apply() throws PatchException, IOException {
if (checkXDelta1(patchFile)) if (checkXDelta1(patchFile))
throw new PatchException(context.getString(R.string.notify_error_xdelta1_unsupported)); throw new PatchException(context.getString(R.string.notify_error_xdelta1_unsupported));
@ -58,7 +55,7 @@ public class XDelta extends Patcher {
throw new PatchException(context.getString(R.string.notify_error_failed_load_lib_xdelta3)); throw new PatchException(context.getString(R.string.notify_error_failed_load_lib_xdelta3));
} }
int ret = xdelta3apply(patchFile.getPath(), romFile.getPath(), outputFile.getPath(), ignoreChecksum); int ret = xdelta3apply(patchFile.getPath(), romFile.getPath(), outputFile.getPath());
switch (ret) { switch (ret) {
case NO_ERROR: case NO_ERROR:
@ -81,32 +78,6 @@ public class XDelta extends Patcher {
} }
} }
public void create() throws PatchException, IOException {
try {
System.loadLibrary("xdelta3");
} catch (UnsatisfiedLinkError e) {
throw new PatchException(context.getString(R.string.notify_error_failed_load_lib_xdelta3));
}
int ret = xdelta3create(patchFile.getPath(), romFile.getPath(), outputFile.getPath());
switch (ret) {
case NO_ERROR:
return;
case ERR_UNABLE_OPEN_PATCH:
throw new PatchException(context.getString(R.string.notify_error_unable_open_file)
.concat(" ").concat(patchFile.getName()));
case ERR_UNABLE_OPEN_SOURCE:
throw new PatchException(context.getString(R.string.notify_error_unable_open_file)
.concat(" ").concat(romFile.getName()));
case ERR_UNABLE_OPEN_MODIFIED:
throw new PatchException(context.getString(R.string.notify_error_unable_open_file)
.concat(" ").concat(outputFile.getName()));
default:
throw new PatchException(context.getString(R.string.notify_error_unknown));
}
}
public boolean checkXDelta1(File file) throws IOException { public boolean checkXDelta1(File file) throws IOException {
String[] MAGIC_XDELTA1 = {"%XDELTA%", "%XDZ000%", "%XDZ001%", String[] MAGIC_XDELTA1 = {"%XDELTA%", "%XDZ000%", "%XDZ001%",
"%XDZ002%", "%XDZ003%", "%XDZ004%"}; "%XDZ002%", "%XDZ003%", "%XDZ004%"};

View file

@ -29,7 +29,6 @@ import android.os.Environment;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
@ -64,7 +63,6 @@ public class FilePickerActivity extends AppCompatActivity implements FilePickerA
private RecyclerView list; private RecyclerView list;
private FilePickerAdapter listAdapter; private FilePickerAdapter listAdapter;
private TextView permissionErrorText; private TextView permissionErrorText;
private CardView card;
private TextView crc32; private TextView crc32;
private TextView md5; private TextView md5;
@ -106,7 +104,6 @@ public class FilePickerActivity extends AppCompatActivity implements FilePickerA
permissionErrorText = (TextView) findViewById(R.id.empty_view); permissionErrorText = (TextView) findViewById(R.id.empty_view);
list = (RecyclerView) findViewById(R.id.list); list = (RecyclerView) findViewById(R.id.list);
card = (CardView) findViewById(R.id.card);
try { try {
list.setHasFixedSize(true); list.setHasFixedSize(true);
} catch (NullPointerException e) {/* TODO log */} } catch (NullPointerException e) {/* TODO log */}
@ -204,7 +201,7 @@ public class FilePickerActivity extends AppCompatActivity implements FilePickerA
if (currentDir.getParent() != null && currentDir.getParentFile().canRead()) { if (currentDir.getParent() != null && currentDir.getParentFile().canRead()) {
entry = new FileEntry(); entry = new FileEntry();
entry.setIcon(R.drawable.folder_upload); entry.setIcon(R.drawable.ic_folder_upload_grey600_24dp);
entry.setName(".."); entry.setName("..");
fileList.add(entry); fileList.add(entry);
} }
@ -214,15 +211,15 @@ public class FilePickerActivity extends AppCompatActivity implements FilePickerA
continue; continue;
if (file.isDirectory()) { if (file.isDirectory()) {
entry = new FileEntry(); entry = new FileEntry();
entry.setIcon(R.drawable.folder); entry.setIcon(R.drawable.ic_folder_grey600_24dp);
entry.setName(file.getName()); entry.setName(file.getName());
fileList.add(entry); fileList.add(entry);
} else { } else {
entry = new FileEntry(); entry = new FileEntry();
if (Utils.isPatch(file)) { if (Utils.isPatch(file)) {
entry.setIcon(R.drawable.healing); entry.setIcon(R.drawable.ic_healing_grey600_24dp);
} else { } else {
entry.setIcon(R.drawable.file); entry.setIcon(R.drawable.ic_insert_drive_file_grey600_24dp);
} }
entry.setName(file.getName()); entry.setName(file.getName());
fileList.add(entry); fileList.add(entry);
@ -277,11 +274,11 @@ public class FilePickerActivity extends AppCompatActivity implements FilePickerA
private void showPermissionError(boolean on) { private void showPermissionError(boolean on) {
if (on) { if (on) {
card.setVisibility(View.GONE); list.setVisibility(View.GONE);
permissionErrorText.setVisibility(View.VISIBLE); permissionErrorText.setVisibility(View.VISIBLE);
} else { } else {
permissionErrorText.setVisibility(View.GONE); permissionErrorText.setVisibility(View.GONE);
card.setVisibility(View.VISIBLE); list.setVisibility(View.VISIBLE);
} }
} }

View file

@ -25,7 +25,6 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
@ -36,27 +35,29 @@ import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceManager;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import com.google.firebase.analytics.FirebaseAnalytics;
import org.emunix.unipatcher.BuildConfig; import org.emunix.unipatcher.BuildConfig;
import org.emunix.unipatcher.Globals;
import org.emunix.unipatcher.R; import org.emunix.unipatcher.R;
import org.emunix.unipatcher.Settings;
import org.emunix.unipatcher.UniPatcher;
import org.emunix.unipatcher.ui.fragment.ActionFragment; import org.emunix.unipatcher.ui.fragment.ActionFragment;
import org.emunix.unipatcher.ui.fragment.CreatePatchFragment;
import org.emunix.unipatcher.ui.fragment.PatchingFragment; import org.emunix.unipatcher.ui.fragment.PatchingFragment;
import org.emunix.unipatcher.ui.fragment.SmdFixChecksumFragment; import org.emunix.unipatcher.ui.fragment.SmdFixChecksumFragment;
import org.emunix.unipatcher.ui.fragment.SnesSmcHeaderFragment; import org.emunix.unipatcher.ui.fragment.SnesSmcHeaderFragment;
import java.util.Random;
import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_AUTO; import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_AUTO;
import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_NO; import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_NO;
import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_YES; import static android.support.v7.app.AppCompatDelegate.MODE_NIGHT_YES;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener { implements NavigationView.OnNavigationItemSelectedListener {
private static final String LOG_TAG = "org.emunix.unipatcher";
private FirebaseAnalytics firebaseAnalytics;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -64,6 +65,10 @@ public class MainActivity extends AppCompatActivity
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
firebaseAnalytics = FirebaseAnalytics.getInstance(this);
if (BuildConfig.DEBUG)
firebaseAnalytics.setAnalyticsCollectionEnabled(false);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -82,6 +87,8 @@ public class MainActivity extends AppCompatActivity
if (fragment != null) { if (fragment != null) {
boolean ret = fragment.runAction(); boolean ret = fragment.runAction();
} }
//Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
// .setAction("Action", null).show();
} }
}); });
@ -93,7 +100,6 @@ public class MainActivity extends AppCompatActivity
} }
parseArgument(); parseArgument();
showDonateSnackbar();
} }
private void setTheme() { private void setTheme() {
@ -118,12 +124,10 @@ public class MainActivity extends AppCompatActivity
if (id == R.id.nav_apply_patch) { if (id == R.id.nav_apply_patch) {
selectDrawerItem(0); selectDrawerItem(0);
} else if (id == R.id.nav_create_patch) {
selectDrawerItem(1);
} else if (id == R.id.nav_smd_fix_checksum) { } else if (id == R.id.nav_smd_fix_checksum) {
selectDrawerItem(2); selectDrawerItem(1);
} else if (id == R.id.nav_snes_add_del_smc_header) { } else if (id == R.id.nav_snes_add_del_smc_header) {
selectDrawerItem(3); selectDrawerItem(2);
} }
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
@ -135,7 +139,8 @@ public class MainActivity extends AppCompatActivity
} else if (id == R.id.nav_rate) { } else if (id == R.id.nav_rate) {
rateApp(); rateApp();
} else if (id == R.id.nav_donate) { } else if (id == R.id.nav_donate) {
showDonateActivity(); Intent donateIntent = new Intent(this, DonateActivity.class);
startActivity(donateIntent);
} else if (id == R.id.nav_share) { } else if (id == R.id.nav_share) {
shareApp(); shareApp();
} else if (id == R.id.nav_help) { } else if (id == R.id.nav_help) {
@ -151,12 +156,9 @@ public class MainActivity extends AppCompatActivity
Fragment fragment; Fragment fragment;
switch (position) { switch (position) {
case 1: case 1:
fragment = new CreatePatchFragment();
break;
case 2:
fragment = new SmdFixChecksumFragment(); fragment = new SmdFixChecksumFragment();
break; break;
case 3: case 2:
fragment = new SnesSmcHeaderFragment(); fragment = new SnesSmcHeaderFragment();
break; break;
default: default:
@ -171,51 +173,13 @@ public class MainActivity extends AppCompatActivity
private void parseArgument() { private void parseArgument() {
try { try {
String arg = getIntent().getData().getPath(); String arg = getIntent().getData().getPath();
UniPatcher.setAppArgument(arg); Globals.setCmdArgument(arg);
Log.d(LOG_TAG, "Cmd argument: " + arg);
} catch (NullPointerException e) { } catch (NullPointerException e) {
// The application is not opened from the file manager Log.e(LOG_TAG, "NullPointerException in argument fetching");
} }
} }
private void showDonateSnackbar() {
// don't show snackbar if the user did not patch the file successfully
if (!Settings.getPatchingSuccessful(this))
return;
// don't show snackbar some time if the user swiped off it before
int count = Settings.getDontShowDonateSnackbarCount(this);
if (count != 0) {
Settings.setDontShowDonateSnackbarCount(this, --count);
return;
}
// don't show snackbar each time you open the application
if (new Random().nextInt(6) != 0)
return;
Snackbar.make(findViewById(R.id.content_frame), R.string.main_activity_donate_snackbar_text, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.main_activity_donate_snackbar_button, new View.OnClickListener() {
@Override
public void onClick(View v) {
showDonateActivity();
}
})
.addCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
if (event == Snackbar.Callback.DISMISS_EVENT_SWIPE) {
Settings.setDontShowDonateSnackbarCount(getApplicationContext(), 30);
}
}
}
).show();
}
private void showDonateActivity() {
Intent donateIntent = new Intent(this, DonateActivity.class);
startActivity(donateIntent);
}
private void shareApp() { private void shareApp() {
Intent shareIntent = new Intent(Intent.ACTION_SEND); Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain"); shareIntent.setType("text/plain");

View file

@ -1,259 +0,0 @@
/*
Copyright (c) 2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher.ui.fragment;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.commons.io.FilenameUtils;
import org.emunix.unipatcher.Action;
import org.emunix.unipatcher.R;
import org.emunix.unipatcher.Settings;
import org.emunix.unipatcher.Utils;
import org.emunix.unipatcher.WorkerService;
import org.emunix.unipatcher.ui.activity.FilePickerActivity;
import java.io.File;
public class CreatePatchFragment extends ActionFragment implements View.OnClickListener {
private static final String LOG_TAG = "org.emunix.unipatcher";
private TextView sourceNameTextView;
private TextView modifiedNameTextView;
private TextView patchNameTextView;
private String sourcePath = null;
private String modifiedPath = null;
private String patchPath = null;
public CreatePatchFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_patch_fragment, container, false);
sourceNameTextView = (TextView) view.findViewById(R.id.sourceFileNameTextView);
modifiedNameTextView = (TextView) view.findViewById(R.id.modifiedFileNameTextView);
patchNameTextView = (TextView) view.findViewById(R.id.patchFileNameTextView);
CardView sourceCardView = (CardView) view.findViewById(R.id.sourceFileCardView);
sourceCardView.setOnClickListener(this);
CardView modifiedCardView = (CardView) view.findViewById(R.id.modifiedFileCardView);
modifiedCardView.setOnClickListener(this);
CardView patchCardView = (CardView) view.findViewById(R.id.patchFileCardView);
patchCardView.setOnClickListener(this);
restoreState(savedInstanceState);
setFonts(view);
// Set action bar title
getActivity().setTitle(R.string.nav_create_patch);
return view;
}
private void setFonts(View view) {
TextView sourceLabel = (TextView) view.findViewById(R.id.sourceFileLabel);
TextView modifiedLabel = (TextView) view.findViewById(R.id.modifiedFileLabel);
TextView patchLabel = (TextView) view.findViewById(R.id.patchFileLabel);
Typeface roboto_light = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Roboto-Light.ttf");
sourceLabel.setTypeface(roboto_light);
modifiedLabel.setTypeface(roboto_light);
patchLabel.setTypeface(roboto_light);
sourceNameTextView.setTypeface(roboto_light);
modifiedNameTextView.setTypeface(roboto_light);
patchNameTextView.setTypeface(roboto_light);
}
private void restoreState(Bundle savedInstanceState) {
if (savedInstanceState != null) {
sourcePath = savedInstanceState.getString("sourcePath");
modifiedPath = savedInstanceState.getString("modifiedPath");
patchPath = savedInstanceState.getString("patchPath");
if (sourcePath != null)
sourceNameTextView.setText(new File(sourcePath).getName());
if (modifiedPath != null)
modifiedNameTextView.setText(new File(modifiedPath).getName());
if (patchPath != null)
patchNameTextView.setText(new File(patchPath).getName());
}
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putString("sourcePath", sourcePath);
savedInstanceState.putString("modifiedPath", modifiedPath);
savedInstanceState.putString("patchPath", patchPath);
}
@Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), FilePickerActivity.class);
switch (view.getId()) {
case R.id.sourceFileCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_source_file));
intent.putExtra("directory", Settings.getRomDir(getActivity()));
startActivityForResult(intent, Action.SELECT_SOURCE_FILE);
break;
case R.id.modifiedFileCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_modified_file));
intent.putExtra("directory", Settings.getRomDir(getActivity()));
startActivityForResult(intent, Action.SELECT_MODIFIED_FILE);
break;
case R.id.patchFileCardView:
renamePatchFile();
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(LOG_TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (resultCode == Activity.RESULT_OK) {
String path = data.getStringExtra("path");
File fpath = new File(path);
switch (requestCode) {
case Action.SELECT_SOURCE_FILE:
sourcePath = path;
sourceNameTextView.setVisibility(View.VISIBLE);
sourceNameTextView.setText(fpath.getName());
Settings.setLastRomDir(getActivity(), fpath.getParent());
break;
case Action.SELECT_MODIFIED_FILE:
modifiedPath = path;
modifiedNameTextView.setVisibility(View.VISIBLE);
modifiedNameTextView.setText(fpath.getName());
Settings.setLastRomDir(getActivity(), fpath.getParent());
patchPath = makeOutputPath(path);
patchNameTextView.setText(new File(patchPath).getName());
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private String makeOutputPath(String fullname) {
String dir = Settings.getOutputDir(getActivity());
if (dir.equals("")) { // get ROM directory
dir = FilenameUtils.getFullPath(fullname);
}
String baseName = FilenameUtils.getBaseName(fullname);
return FilenameUtils.concat(dir, baseName.concat(".xdelta"));
}
public boolean runAction() {
if (sourcePath == null & modifiedPath == null) {
Toast.makeText(getActivity(), getString(R.string.create_patch_fragment_toast_source_and_modified_not_selected), Toast.LENGTH_LONG).show();
return false;
} else if (sourcePath == null) {
Toast.makeText(getActivity(), getString(R.string.create_patch_fragment_toast_source_not_selected), Toast.LENGTH_LONG).show();
return false;
} else if (modifiedPath == null) {
Toast.makeText(getActivity(), getString(R.string.create_patch_fragment_toast_modified_not_selected), Toast.LENGTH_LONG).show();
return false;
}
Intent intent = new Intent(getActivity(), WorkerService.class);
intent.putExtra("action", Action.CREATE_PATCH);
intent.putExtra("sourcePath", sourcePath);
intent.putExtra("modifiedPath", modifiedPath);
intent.putExtra("patchPath", patchPath);
Utils.startForegroundService(getActivity(), intent);
Toast.makeText(getActivity(), R.string.toast_create_patch_started_check_notify, Toast.LENGTH_SHORT).show();
return true;
}
private void renamePatchFile() {
if (modifiedPath == null) {
Toast.makeText(getActivity(), getString(R.string.create_patch_fragment_toast_modified_not_selected), Toast.LENGTH_LONG).show();
return;
}
AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
dialog.setTitle(R.string.dialog_rename_title);
final EditText input = new EditText(getActivity());
input.setText(patchNameTextView.getText());
// add left and right margins to EditText.
FrameLayout container = new FrameLayout(getActivity());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int dp_24 = Utils.dpToPx(getActivity(), 24);
params.setMargins(dp_24, 0, dp_24, 0);
input.setLayoutParams(params);
container.addView(input);
dialog.setView(container);
dialog.setPositiveButton(R.string.dialog_rename_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String newName = input.getText().toString();
if (newName.equals("")) {
Toast.makeText(getActivity(), R.string.dialog_rename_error_empty_name, Toast.LENGTH_LONG).show();
return;
}
if (newName.contains("/")) {
newName = newName.replaceAll("/", "_");
Toast.makeText(getActivity(), R.string.dialog_rename_error_invalid_chars, Toast.LENGTH_LONG).show();
}
String newPath = new File(patchPath).getParent().concat(File.separator).concat(newName);
if (FilenameUtils.equals(newPath, sourcePath) || FilenameUtils.equals(newPath, modifiedPath)) {
Toast.makeText(getActivity(), R.string.dialog_rename_error_same_name, Toast.LENGTH_LONG).show();
return;
}
patchNameTextView.setText(newName);
patchPath = newPath;
}
});
dialog.setNegativeButton(R.string.dialog_rename_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
dialog.show();
}
}

View file

@ -36,10 +36,9 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.emunix.unipatcher.Action; import org.emunix.unipatcher.Globals;
import org.emunix.unipatcher.R; import org.emunix.unipatcher.R;
import org.emunix.unipatcher.Settings; import org.emunix.unipatcher.Settings;
import org.emunix.unipatcher.UniPatcher;
import org.emunix.unipatcher.Utils; import org.emunix.unipatcher.Utils;
import org.emunix.unipatcher.WorkerService; import org.emunix.unipatcher.WorkerService;
import org.emunix.unipatcher.ui.activity.FilePickerActivity; import org.emunix.unipatcher.ui.activity.FilePickerActivity;
@ -50,6 +49,8 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
private static final String LOG_TAG = "org.emunix.unipatcher"; private static final String LOG_TAG = "org.emunix.unipatcher";
private static final int SELECT_ROM_FILE = 1;
private static final int SELECT_PATCH_FILE = 2;
private TextView romNameTextView; private TextView romNameTextView;
private TextView patchNameTextView; private TextView patchNameTextView;
private TextView outputNameTextView; private TextView outputNameTextView;
@ -96,7 +97,7 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
} }
private void parseArgument() { private void parseArgument() {
patchPath = UniPatcher.getAppArgument(); patchPath = Globals.getCmdArgument();
if (patchPath != null) { if (patchPath != null) {
patchNameTextView.setText(new File(patchPath).getName()); patchNameTextView.setText(new File(patchPath).getName());
} }
@ -146,12 +147,12 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
case R.id.patchCardView: case R.id.patchCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_patch)); intent.putExtra("title", getString(R.string.file_picker_activity_title_select_patch));
intent.putExtra("directory", Settings.getPatchDir(getActivity())); intent.putExtra("directory", Settings.getPatchDir(getActivity()));
startActivityForResult(intent, Action.SELECT_PATCH_FILE); startActivityForResult(intent, SELECT_PATCH_FILE);
break; break;
case R.id.romCardView: case R.id.romCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom)); intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom));
intent.putExtra("directory", Settings.getRomDir(getActivity())); intent.putExtra("directory", Settings.getRomDir(getActivity()));
startActivityForResult(intent, Action.SELECT_ROM_FILE); startActivityForResult(intent, SELECT_ROM_FILE);
break; break;
case R.id.outputCardView: case R.id.outputCardView:
renameOutputRom(); renameOutputRom();
@ -171,7 +172,7 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
} }
switch (requestCode) { switch (requestCode) {
case Action.SELECT_ROM_FILE: case SELECT_ROM_FILE:
romPath = path; romPath = path;
romNameTextView.setVisibility(View.VISIBLE); romNameTextView.setVisibility(View.VISIBLE);
romNameTextView.setText(fpath.getName()); romNameTextView.setText(fpath.getName());
@ -179,7 +180,7 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
outputPath = makeOutputPath(path); outputPath = makeOutputPath(path);
outputNameTextView.setText(new File(outputPath).getName()); outputNameTextView.setText(new File(outputPath).getName());
break; break;
case Action.SELECT_PATCH_FILE: case SELECT_PATCH_FILE:
patchPath = path; patchPath = path;
patchNameTextView.setVisibility(View.VISIBLE); patchNameTextView.setVisibility(View.VISIBLE);
patchNameTextView.setText(fpath.getName()); patchNameTextView.setText(fpath.getName());
@ -213,11 +214,11 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
} }
Intent intent = new Intent(getActivity(), WorkerService.class); Intent intent = new Intent(getActivity(), WorkerService.class);
intent.putExtra("action", Action.APPLY_PATCH); intent.putExtra("action", Globals.ACTION_PATCHING);
intent.putExtra("romPath", romPath); intent.putExtra("romPath", romPath);
intent.putExtra("patchPath", patchPath); intent.putExtra("patchPath", patchPath);
intent.putExtra("outputPath", outputPath); intent.putExtra("outputPath", outputPath);
Utils.startForegroundService(getActivity(), intent); getActivity().startService(intent);
Toast.makeText(getActivity(), R.string.toast_patching_started_check_notify, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), R.string.toast_patching_started_check_notify, Toast.LENGTH_SHORT).show();
return true; return true;
@ -247,10 +248,6 @@ public class PatchingFragment extends ActionFragment implements View.OnClickList
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
String newName = input.getText().toString(); String newName = input.getText().toString();
if (newName.equals("")) {
Toast.makeText(getActivity(), R.string.dialog_rename_error_empty_name, Toast.LENGTH_LONG).show();
return;
}
if (newName.contains("/")) { if (newName.contains("/")) {
newName = newName.replaceAll("/", "_"); newName = newName.replaceAll("/", "_");
Toast.makeText(getActivity(), R.string.dialog_rename_error_invalid_chars, Toast.LENGTH_LONG).show(); Toast.makeText(getActivity(), R.string.dialog_rename_error_invalid_chars, Toast.LENGTH_LONG).show();

View file

@ -31,7 +31,7 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.emunix.unipatcher.Action; import org.emunix.unipatcher.Globals;
import org.emunix.unipatcher.R; import org.emunix.unipatcher.R;
import org.emunix.unipatcher.Settings; import org.emunix.unipatcher.Settings;
import org.emunix.unipatcher.Utils; import org.emunix.unipatcher.Utils;
@ -43,6 +43,7 @@ import java.io.File;
public class SmdFixChecksumFragment extends ActionFragment implements View.OnClickListener { public class SmdFixChecksumFragment extends ActionFragment implements View.OnClickListener {
private static final String LOG_TAG = "org.emunix.unipatcher"; private static final String LOG_TAG = "org.emunix.unipatcher";
private static final int SELECT_ROM_FILE = 1;
private TextView romNameTextView; private TextView romNameTextView;
private TextView fixChecksumInfoTextview; private TextView fixChecksumInfoTextview;
@ -107,7 +108,7 @@ public class SmdFixChecksumFragment extends ActionFragment implements View.OnCli
case R.id.romCardView: case R.id.romCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom)); intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom));
intent.putExtra("directory", Settings.getRomDir(getActivity())); intent.putExtra("directory", Settings.getRomDir(getActivity()));
startActivityForResult(intent, Action.SELECT_ROM_FILE); startActivityForResult(intent, SELECT_ROM_FILE);
break; break;
} }
} }
@ -123,7 +124,7 @@ public class SmdFixChecksumFragment extends ActionFragment implements View.OnCli
} }
switch (requestCode) { switch (requestCode) {
case Action.SELECT_ROM_FILE: case SELECT_ROM_FILE:
romPath = path; romPath = path;
romNameTextView.setVisibility(View.VISIBLE); romNameTextView.setVisibility(View.VISIBLE);
romNameTextView.setText(new File(path).getName()); romNameTextView.setText(new File(path).getName());
@ -141,9 +142,9 @@ public class SmdFixChecksumFragment extends ActionFragment implements View.OnCli
} }
Intent intent = new Intent(getActivity(), WorkerService.class); Intent intent = new Intent(getActivity(), WorkerService.class);
intent.putExtra("action", Globals.ACTION_SMD_FIX_CHECKSUM);
intent.putExtra("romPath", romPath); intent.putExtra("romPath", romPath);
intent.putExtra("action", Action.SMD_FIX_CHECKSUM); getActivity().startService(intent);
Utils.startForegroundService(getActivity(), intent);
Toast.makeText(getActivity(), R.string.notify_smd_fix_checksum_started_check_notify, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), R.string.notify_smd_fix_checksum_started_check_notify, Toast.LENGTH_SHORT).show();
return true; return true;

View file

@ -31,7 +31,7 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.emunix.unipatcher.Action; import org.emunix.unipatcher.Globals;
import org.emunix.unipatcher.R; import org.emunix.unipatcher.R;
import org.emunix.unipatcher.Settings; import org.emunix.unipatcher.Settings;
import org.emunix.unipatcher.Utils; import org.emunix.unipatcher.Utils;
@ -43,6 +43,8 @@ import java.io.File;
public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClickListener { public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClickListener {
private static final String LOG_TAG = "org.emunix.unipatcher"; private static final String LOG_TAG = "org.emunix.unipatcher";
private static final int SELECT_ROM_FILE = 1;
private static final int SELECT_HEADER_FILE = 2;
private TextView romNameTextView; private TextView romNameTextView;
private TextView headerNameTextView; private TextView headerNameTextView;
@ -102,10 +104,10 @@ public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClic
romPath = savedInstanceState.getString("romPath"); romPath = savedInstanceState.getString("romPath");
headerPath = savedInstanceState.getString("headerPath"); headerPath = savedInstanceState.getString("headerPath");
action = savedInstanceState.getInt("action"); action = savedInstanceState.getInt("action");
if (action == Action.SNES_ADD_SMC_HEADER) { if (action == Globals.ACTION_SNES_ADD_SMC_HEADER) {
headerInfoTextView.setText(R.string.snes_smc_header_will_be_added); headerInfoTextView.setText(R.string.snes_smc_header_will_be_added);
headerCardView.setVisibility(View.VISIBLE); headerCardView.setVisibility(View.VISIBLE);
} else if (action == Action.SNES_DELETE_SMC_HEADER) { } else if (action == Globals.ACTION_SNES_DELETE_SMC_HEADER) {
headerInfoTextView.setText(R.string.snes_smc_header_will_be_removed); headerInfoTextView.setText(R.string.snes_smc_header_will_be_removed);
headerCardView.setVisibility(View.GONE); headerCardView.setVisibility(View.GONE);
} }
@ -131,11 +133,11 @@ public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClic
case R.id.romCardView: case R.id.romCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom)); intent.putExtra("title", getString(R.string.file_picker_activity_title_select_rom));
intent.putExtra("directory", Settings.getRomDir(getActivity())); intent.putExtra("directory", Settings.getRomDir(getActivity()));
startActivityForResult(intent, Action.SELECT_ROM_FILE); startActivityForResult(intent, SELECT_ROM_FILE);
break; break;
case R.id.headerCardView: case R.id.headerCardView:
intent.putExtra("title", getString(R.string.file_picker_activity_title_select_header)); intent.putExtra("title", getString(R.string.file_picker_activity_title_select_header));
startActivityForResult(intent, Action.SELECT_HEADER_FILE); startActivityForResult(intent, SELECT_HEADER_FILE);
break; break;
} }
} }
@ -151,25 +153,25 @@ public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClic
} }
switch (requestCode) { switch (requestCode) {
case Action.SELECT_ROM_FILE: case SELECT_ROM_FILE:
romPath = path; romPath = path;
romNameTextView.setVisibility(View.VISIBLE); romNameTextView.setVisibility(View.VISIBLE);
romNameTextView.setText(new File(path).getName()); romNameTextView.setText(new File(path).getName());
Settings.setLastRomDir(getActivity(), new File(path).getParent()); Settings.setLastRomDir(getActivity(), new File(path).getParent());
SnesSmcHeader checker = new SnesSmcHeader(); SnesSmcHeader checker = new SnesSmcHeader();
if (checker.isHasSmcHeader(new File(path))) { if (checker.isHasSmcHeader(new File(path))) {
action = Action.SNES_DELETE_SMC_HEADER; action = Globals.ACTION_SNES_DELETE_SMC_HEADER;
headerCardView.setVisibility(View.GONE); headerCardView.setVisibility(View.GONE);
headerInfoTextView.setText(R.string.snes_smc_header_will_be_removed); headerInfoTextView.setText(R.string.snes_smc_header_will_be_removed);
} else { } else {
action = Action.SNES_ADD_SMC_HEADER; action = Globals.ACTION_SNES_ADD_SMC_HEADER;
headerCardView.setVisibility(View.VISIBLE); headerCardView.setVisibility(View.VISIBLE);
headerInfoTextView.setText(R.string.snes_smc_header_will_be_added); headerInfoTextView.setText(R.string.snes_smc_header_will_be_added);
} }
headerPath = null; headerPath = null;
headerNameTextView.setText(R.string.main_activity_tap_to_select); headerNameTextView.setText(R.string.main_activity_tap_to_select);
break; break;
case Action.SELECT_HEADER_FILE: case SELECT_HEADER_FILE:
headerPath = path; headerPath = path;
headerNameTextView.setText(new File(path).getName()); headerNameTextView.setText(new File(path).getName());
break; break;
@ -188,9 +190,9 @@ public class SnesSmcHeaderFragment extends ActionFragment implements View.OnClic
intent.putExtra("action", action); intent.putExtra("action", action);
intent.putExtra("romPath", romPath); intent.putExtra("romPath", romPath);
intent.putExtra("headerPath", headerPath); intent.putExtra("headerPath", headerPath);
Utils.startForegroundService(getActivity(), intent); getActivity().startService(intent);
if (action == Action.SNES_ADD_SMC_HEADER) { if (action == Globals.ACTION_SNES_ADD_SMC_HEADER) {
Toast.makeText(getActivity(), R.string.notify_snes_add_smc_header_stared_check_noify, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), R.string.notify_snes_add_smc_header_stared_check_noify, Toast.LENGTH_SHORT).show();
} else { } else {
Toast.makeText(getActivity(), R.string.notify_snes_delete_smc_header_stared_check_noify, Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), R.string.notify_snes_delete_smc_header_stared_check_noify, Toast.LENGTH_SHORT).show();

View file

@ -1,57 +0,0 @@
/*
Copyright (c) 2017 Boris Timofeev
This file is part of UniPatcher.
UniPatcher is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UniPatcher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
*/
package org.emunix.unipatcher.ui.notify;
import android.content.Context;
import android.support.v4.app.NotificationCompat;
import org.emunix.unipatcher.R;
public class CreatePatchNotify extends Notify {
public CreatePatchNotify(Context c, String text) {
super(c);
notifyBuilder.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp);
notifyBuilder.setContentTitle(context.getString(R.string.notify_creating_patch));
notifyBuilder.setContentText(text);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));
setSticked(true);
setProgress(true);
}
@Override
public void setCompleted() {
setProgress(false);
setSticked(false);
notifyBuilder.setTicker(context.getText(R.string.notify_create_patch_complete));
notifyBuilder.setContentTitle(context.getText(R.string.notify_create_patch_complete));
}
@Override
public void setFailed(String message) {
setProgress(false);
setSticked(false);
notifyBuilder.setTicker(context.getText(R.string.notify_error));
notifyBuilder.setContentTitle(context.getString(R.string.notify_error));
notifyBuilder.setContentText(message);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(message));
}
}

View file

@ -24,7 +24,6 @@ import android.content.Intent;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat; import android.support.v4.app.NotificationManagerCompat;
import org.emunix.unipatcher.UniPatcher;
import org.emunix.unipatcher.ui.activity.MainActivity; import org.emunix.unipatcher.ui.activity.MainActivity;
public abstract class Notify { public abstract class Notify {
@ -41,8 +40,9 @@ public abstract class Notify {
Intent notificationIntent = new Intent(context, MainActivity.class); Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
notifyBuilder = new NotificationCompat.Builder(context, UniPatcher.NOTIFICATION_CHANNEL_ID); notifyBuilder = new NotificationCompat.Builder(context);
notifyBuilder.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT)); notifyBuilder.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT));
//notifyMng = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
notifyMng = NotificationManagerCompat.from(context); notifyMng = NotificationManagerCompat.from(context);
} }

View file

@ -28,7 +28,7 @@ public class PatchingNotify extends Notify {
public PatchingNotify(Context c, String text) { public PatchingNotify(Context c, String text) {
super(c); super(c);
notifyBuilder.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp); notifyBuilder.setSmallIcon(R.drawable.ic_stat_patching);
notifyBuilder.setContentTitle(context.getString(R.string.notify_applying_patch)); notifyBuilder.setContentTitle(context.getString(R.string.notify_applying_patch));
notifyBuilder.setContentText(text); notifyBuilder.setContentText(text);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)); notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));

View file

@ -28,7 +28,7 @@ public class SmdFixChecksumNotify extends Notify {
public SmdFixChecksumNotify(Context c, String text) { public SmdFixChecksumNotify(Context c, String text) {
super(c); super(c);
notifyBuilder.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp); notifyBuilder.setSmallIcon(R.drawable.ic_stat_patching);
notifyBuilder.setContentTitle(context.getString(R.string.notify_smd_fix_checksum_in_progress)); notifyBuilder.setContentTitle(context.getString(R.string.notify_smd_fix_checksum_in_progress));
notifyBuilder.setContentText(text); notifyBuilder.setContentText(text);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)); notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));

View file

@ -27,7 +27,7 @@ import org.emunix.unipatcher.R;
public class SnesAddSmcHeaderNotify extends Notify { public class SnesAddSmcHeaderNotify extends Notify {
public SnesAddSmcHeaderNotify(Context c, String text) { public SnesAddSmcHeaderNotify(Context c, String text) {
super(c); super(c);
notifyBuilder.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp); notifyBuilder.setSmallIcon(R.drawable.ic_stat_patching);
notifyBuilder.setContentTitle(context.getString(R.string.notify_snes_add_smc_header_in_progress)); notifyBuilder.setContentTitle(context.getString(R.string.notify_snes_add_smc_header_in_progress));
notifyBuilder.setContentText(text); notifyBuilder.setContentText(text);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)); notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));

View file

@ -27,7 +27,7 @@ import org.emunix.unipatcher.R;
public class SnesDeleteSmcHeaderNotify extends Notify { public class SnesDeleteSmcHeaderNotify extends Notify {
public SnesDeleteSmcHeaderNotify(Context c, String text) { public SnesDeleteSmcHeaderNotify(Context c, String text) {
super(c); super(c);
notifyBuilder.setSmallIcon(R.drawable.ic_gamepad_variant_white_24dp); notifyBuilder.setSmallIcon(R.drawable.ic_stat_patching);
notifyBuilder.setContentTitle(context.getString(R.string.notify_snes_delete_smc_header_in_progress)); notifyBuilder.setContentTitle(context.getString(R.string.notify_snes_delete_smc_header_in_progress));
notifyBuilder.setContentText(text); notifyBuilder.setContentText(text);
notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text)); notifyBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Some files were not shown because too many files have changed in this diff Show more