Support creating XDelta3 patches
This commit is contained in:
parent
a7228702fe
commit
7dad097c6f
35 changed files with 701 additions and 26 deletions
|
@ -8,6 +8,7 @@ UniPatcher is a ROM patcher for Android that supports IPS, IPS32, UPS, BPS, APS
|
|||
|
||||
### Additional features:
|
||||
|
||||
* Creating XDelta3 patches
|
||||
* Fix checksum in Sega Mega Drive ROMs
|
||||
* Add/Delete SMC header in Super Nintendo ROMs
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
This file based on encode_decode_test.c from XDelta3 sources.
|
||||
|
||||
Copyright (C) 2007 Ralf Junker
|
||||
Copyright (C) 2016 Boris Timofeev
|
||||
Copyright (C) 2016-2017 Boris Timofeev
|
||||
|
||||
This file is part of UniPatcher.
|
||||
|
||||
|
@ -30,11 +30,13 @@ along with UniPatcher. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "xdelta3/xdelta3/xdelta3.h"
|
||||
#include "xdelta3/xdelta3/xdelta3.c"
|
||||
|
||||
int apply(FILE *patch, FILE *in, FILE *out, int ignoreChecksum);
|
||||
int code(int encode, FILE *in, FILE *src, FILE *out, int ignoreChecksum);
|
||||
|
||||
const int ERR_UNABLE_OPEN_PATCH = -5001;
|
||||
const int ERR_UNABLE_OPEN_ROM = -5002;
|
||||
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;
|
||||
|
||||
int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
|
||||
|
@ -71,7 +73,7 @@ int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
|
|||
return ERR_UNABLE_OPEN_OUTPUT;
|
||||
}
|
||||
|
||||
ret = apply(patchFile, romFile, outputFile, (int)ignoreChecksum);
|
||||
ret = code(0, patchFile, romFile, outputFile, (int)ignoreChecksum);
|
||||
|
||||
fclose(patchFile);
|
||||
fclose(romFile);
|
||||
|
@ -79,8 +81,50 @@ int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3apply(JNIEnv *env,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int apply(FILE *patch, FILE *in, FILE *out, int ignoreChecksum) {
|
||||
int BUFFER_SIZE = 32768;
|
||||
int Java_org_emunix_unipatcher_patcher_XDelta_xdelta3create(JNIEnv *env,
|
||||
jobject this,
|
||||
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;
|
||||
xd3_stream stream;
|
||||
|
@ -103,26 +147,28 @@ int apply(FILE *patch, FILE *in, FILE *out, int ignoreChecksum) {
|
|||
source.curblk = malloc(source.blksize);
|
||||
|
||||
/* Load 1st block of stream. */
|
||||
r = fseek(in, 0, SEEK_SET);
|
||||
r = fseek(src, 0, SEEK_SET);
|
||||
if (r)
|
||||
return r;
|
||||
source.onblk = fread((void *) source.curblk, 1, source.blksize, in);
|
||||
source.onblk = fread((void *) source.curblk, 1, source.blksize, src);
|
||||
source.curblkno = 0;
|
||||
xd3_set_source(&stream, &source);
|
||||
|
||||
Input_Buf = malloc(BUFFER_SIZE);
|
||||
|
||||
fseek(patch, 0, SEEK_SET);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
do {
|
||||
Input_Buf_Read = fread(Input_Buf, 1, BUFFER_SIZE, patch);
|
||||
Input_Buf_Read = fread(Input_Buf, 1, BUFFER_SIZE, in);
|
||||
if (Input_Buf_Read < BUFFER_SIZE) {
|
||||
xd3_set_flags(&stream, XD3_FLUSH | stream.flags);
|
||||
}
|
||||
xd3_avail_input(&stream, Input_Buf, Input_Buf_Read);
|
||||
|
||||
process:
|
||||
|
||||
ret = xd3_decode_input(&stream);
|
||||
process:
|
||||
if (encode)
|
||||
ret = xd3_encode_input(&stream);
|
||||
else
|
||||
ret = xd3_decode_input(&stream);
|
||||
|
||||
switch (ret) {
|
||||
case XD3_INPUT:
|
||||
|
@ -136,10 +182,10 @@ int apply(FILE *patch, FILE *in, FILE *out, int ignoreChecksum) {
|
|||
goto process;
|
||||
|
||||
case XD3_GETSRCBLK:
|
||||
r = fseek(in, source.blksize * source.getblkno, SEEK_SET);
|
||||
r = fseek(src, source.blksize * source.getblkno, SEEK_SET);
|
||||
if (r)
|
||||
return r;
|
||||
source.onblk = fread((void *) source.curblk, 1, source.blksize, in);
|
||||
source.onblk = fread((void *) source.curblk, 1, source.blksize, src);
|
||||
source.curblkno = source.getblkno;
|
||||
goto process;
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ public class Globals {
|
|||
}
|
||||
|
||||
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;
|
||||
public static final int ACTION_CREATE_PATCH = 2;
|
||||
public static final int ACTION_SMD_FIX_CHECKSUM = 3;
|
||||
public static final int ACTION_SNES_ADD_SMC_HEADER = 4;
|
||||
public static final int ACTION_SNES_DELETE_SMC_HEADER = 5;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.emunix.unipatcher.tools.RomException;
|
|||
import org.emunix.unipatcher.tools.SmdFixChecksum;
|
||||
import org.emunix.unipatcher.tools.SnesSmcHeader;
|
||||
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.PatchingNotify;
|
||||
import org.emunix.unipatcher.ui.notify.SmdFixChecksumNotify;
|
||||
|
@ -77,6 +78,9 @@ public class WorkerService extends IntentService {
|
|||
case Globals.ACTION_PATCHING:
|
||||
actionPatching(intent);
|
||||
break;
|
||||
case Globals.ACTION_CREATE_PATCH:
|
||||
actionCreatePatch(intent);
|
||||
break;
|
||||
case Globals.ACTION_SMD_FIX_CHECKSUM:
|
||||
actionSmdFixChecksum(intent);
|
||||
break;
|
||||
|
@ -172,6 +176,60 @@ public class WorkerService extends IntentService {
|
|||
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();
|
||||
} 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 {
|
||||
stopForeground(true);
|
||||
}
|
||||
notify.showResult(errorMsg);
|
||||
}
|
||||
|
||||
private void actionSmdFixChecksum(Intent intent) {
|
||||
String errorMsg = null;
|
||||
File romFile = new File(intent.getStringExtra("romPath"));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2016 Boris Timofeev
|
||||
Copyright (C) 2016-2017 Boris Timofeev
|
||||
|
||||
This file is part of UniPatcher.
|
||||
|
||||
|
@ -35,10 +35,13 @@ public class XDelta extends Patcher {
|
|||
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_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_INVALID_INPUT = -17712;
|
||||
|
||||
public static native int xdelta3apply(String patchPath, String romPath, String outputPath, boolean ignoreChecksum);
|
||||
public static native int xdelta3create(String patchPath, String sourcePath, String modifiedPath);
|
||||
|
||||
public XDelta(Context context, File patch, File rom, File output) {
|
||||
super(context, patch, rom, output);
|
||||
|
@ -78,6 +81,32 @@ 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 {
|
||||
String[] MAGIC_XDELTA1 = {"%XDELTA%", "%XDZ000%", "%XDZ001%",
|
||||
"%XDZ002%", "%XDZ003%", "%XDZ004%"};
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.emunix.unipatcher.BuildConfig;
|
|||
import org.emunix.unipatcher.Globals;
|
||||
import org.emunix.unipatcher.R;
|
||||
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.SmdFixChecksumFragment;
|
||||
import org.emunix.unipatcher.ui.fragment.SnesSmcHeaderFragment;
|
||||
|
@ -116,10 +117,12 @@ public class MainActivity extends AppCompatActivity
|
|||
|
||||
if (id == R.id.nav_apply_patch) {
|
||||
selectDrawerItem(0);
|
||||
} else if (id == R.id.nav_smd_fix_checksum) {
|
||||
} else if (id == R.id.nav_create_patch) {
|
||||
selectDrawerItem(1);
|
||||
} else if (id == R.id.nav_snes_add_del_smc_header) {
|
||||
} else if (id == R.id.nav_smd_fix_checksum) {
|
||||
selectDrawerItem(2);
|
||||
} else if (id == R.id.nav_snes_add_del_smc_header) {
|
||||
selectDrawerItem(3);
|
||||
}
|
||||
|
||||
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
|
@ -148,9 +151,12 @@ public class MainActivity extends AppCompatActivity
|
|||
Fragment fragment;
|
||||
switch (position) {
|
||||
case 1:
|
||||
fragment = new SmdFixChecksumFragment();
|
||||
fragment = new CreatePatchFragment();
|
||||
break;
|
||||
case 2:
|
||||
fragment = new SmdFixChecksumFragment();
|
||||
break;
|
||||
case 3:
|
||||
fragment = new SnesSmcHeaderFragment();
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
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.Globals;
|
||||
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 static final int SELECT_SOURCE_FILE = 1;
|
||||
private static final int SELECT_MODIFIED_FILE = 2;
|
||||
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, 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, 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 SELECT_SOURCE_FILE:
|
||||
sourcePath = path;
|
||||
sourceNameTextView.setVisibility(View.VISIBLE);
|
||||
sourceNameTextView.setText(fpath.getName());
|
||||
Settings.setLastRomDir(getActivity(), fpath.getParent());
|
||||
break;
|
||||
case 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", Globals.ACTION_CREATE_PATCH);
|
||||
intent.putExtra("sourcePath", sourcePath);
|
||||
intent.putExtra("modifiedPath", modifiedPath);
|
||||
intent.putExtra("patchPath", patchPath);
|
||||
getActivity().startService(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.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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
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_stat_patching);
|
||||
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));
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable-hdpi/ic_plus_box_grey600_24dp.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_plus_box_grey600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 434 B |
BIN
app/src/main/res/drawable-mdpi/ic_plus_box_grey600_24dp.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_plus_box_grey600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 262 B |
BIN
app/src/main/res/drawable-xhdpi/ic_plus_box_grey600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_plus_box_grey600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 396 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_plus_box_grey600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_plus_box_grey600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 575 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_plus_box_grey600_24dp.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_plus_box_grey600_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 686 B |
131
app/src/main/res/layout/create_patch_fragment.xml
Normal file
131
app/src/main/res/layout/create_patch_fragment.xml
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentTop="true">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/CardsHolder">
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:id="@+id/sourceFileCardView"
|
||||
style="@style/Card.Clickable">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/card_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sourceFileLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/create_patch_fragment_source_file"
|
||||
android:textColor="@color/colorCardHeaderText"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/card_line_height"
|
||||
android:layout_marginBottom="@dimen/card_line_margin"
|
||||
android:layout_marginTop="@dimen/card_line_margin"
|
||||
android:background="@color/colorCardLine"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sourceFileNameTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_folder_grey600_24dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/main_activity_tap_to_select"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:id="@+id/modifiedFileCardView"
|
||||
style="@style/Card.Clickable">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/card_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/modifiedFileLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/create_patch_fragment_modified_file"
|
||||
android:textColor="@color/colorCardHeaderText"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/card_line_height"
|
||||
android:layout_marginBottom="@dimen/card_line_margin"
|
||||
android:layout_marginTop="@dimen/card_line_margin"
|
||||
android:background="@color/colorCardLine"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/modifiedFileNameTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_folder_grey600_24dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/main_activity_tap_to_select"
|
||||
android:textSize="20sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
<android.support.v7.widget.CardView
|
||||
android:id="@+id/patchFileCardView"
|
||||
style="@style/Card.Clickable">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/card_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/patchFileLabel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/create_patch_fragment_patch_file"
|
||||
android:textColor="@color/colorCardHeaderText"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/card_line_height"
|
||||
android:layout_marginBottom="@dimen/card_line_margin"
|
||||
android:layout_marginTop="@dimen/card_line_margin"
|
||||
android:background="@color/colorCardLine"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/patchFileNameTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableLeft="@drawable/ic_edit_grey600_24dp"
|
||||
android:drawablePadding="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/main_activity_tap_to_rename"
|
||||
android:textSize="20sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -8,6 +8,10 @@
|
|||
android:id="@+id/nav_apply_patch"
|
||||
android:icon="@drawable/ic_healing_grey600_24dp"
|
||||
android:title="@string/nav_apply_patch"/>
|
||||
<item
|
||||
android:id="@+id/nav_create_patch"
|
||||
android:icon="@drawable/ic_plus_box_grey600_24dp"
|
||||
android:title="@string/nav_create_patch"/>
|
||||
<item
|
||||
android:id="@+id/nav_smd_fix_checksum"
|
||||
android:icon="@drawable/ic_fingerprint_grey600_24dp"
|
||||
|
|
|
@ -2,6 +2,7 @@ UniPatcher è un patcher che supporta i tipi di patch IPS, IPS32, UPS, BPS, APS
|
|||
|
||||
Funzioni aggiuntive:
|
||||
|
||||
- Creating XDelta3 patches
|
||||
- Risolvi checksum nei ROM del Sega Mega Drive
|
||||
- Aggiungi/Elimina intestazione SMC nei ROM del Super Nintendo
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ Forse c'è un bug nel mio programma. Ti prego di contattarmi alla [e-mail](mailt
|
|||
|
||||
Si. UniPatcher può:
|
||||
|
||||
- create XDelta3 patches.
|
||||
- Risolvere checksum per un gioco Sega Mega Drive / Sega Genesis.
|
||||
- aggiungere o rimuovere l'intestazione SMC per un gioco Super Nintendo.
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ UniPatcher jest programem do łatkowania ROM-ów. Wsparcie dla typów łatek: IP
|
|||
|
||||
Dodatkowe funkcje:
|
||||
|
||||
- Creating XDelta3 patches
|
||||
- Napraw sumę kontrolną dla ROM-ów Sega Mega Drive
|
||||
- Dodaj/Usuń nagłówek dla Super Nintendo
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ Może jest to bug w moim programie. Proszę skontaktuj się ze mną przez [e-mai
|
|||
|
||||
Tak. UniPatcher może:
|
||||
|
||||
- create XDelta3 patches.
|
||||
- naprawiać sumę kontrolną w grach z konsol Sega Mega Drive/Sega Genesis
|
||||
- Dodawać bądź usuwać nagłówek SMC dla gier z konsoli Super Nintendo Entertaiment System (SNES).
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ UniPatcher это ROM патчер поддерживающий патчи в ф
|
|||
|
||||
Дополнительные функции:
|
||||
|
||||
- Создание патчей в формате XDelta3
|
||||
- Исправление контрольной суммы для игр Sega Mega Drive
|
||||
- Добавление или удалениие SMC заголовка для игр Super Nintendo
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ ECM это формат сжатия данных созданный специ
|
|||
|
||||
Да. Приложение может:
|
||||
|
||||
- создавать патчи в формате XDelta3.
|
||||
- исправлять контрольную сумму для игр Sega Mega Drive.
|
||||
- добавлять или удалять SMC заголовки для игр Super Nintendo.
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ UniPatcher це ROM патчер який підтримує патчі у фо
|
|||
|
||||
Додаткові функції:
|
||||
|
||||
- Creating XDelta3 patches
|
||||
- Виправлення контрольної суми для ігор Sega Mega Drive
|
||||
- Додавання або видаляння SMC заголовку для ігор Super Nintendo
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ ECM це формат стискання даних створений спец
|
|||
|
||||
Так. Додаток може:
|
||||
|
||||
- create XDelta3 patches.
|
||||
- виправляти контрольну суму для ігор Sega Mega Drive.
|
||||
- додавати або видаляти SMC назви для ігор Super Nintendo.
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ UniPatcher is a ROM patcher that supports IPS, IPS32, UPS, BPS, APS (GBA), APS (
|
|||
|
||||
Additional features:
|
||||
|
||||
- Creating XDelta3 patches
|
||||
- Fix checksum in Sega Mega Drive ROMs
|
||||
- Add/Delete SMC header in Super Nintendo ROMs
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ Maybe it's a bug in my program. Please contact me at [e-mail](mailto:mashin87@gm
|
|||
|
||||
Yes. UniPatcher can:
|
||||
|
||||
- create XDelta3 patches.
|
||||
- fix checksum for a Sega Mega Drive / Sega Genesis games.
|
||||
- add or remove SMC header for a Super Nintendo games.
|
||||
|
||||
|
|
|
@ -21,9 +21,17 @@
|
|||
<string name="dialog_rename_title">Rinomina</string>
|
||||
<string name="dialog_rename_ok">OK</string>
|
||||
<string name="dialog_rename_cancel">Cancella</string>
|
||||
<string name="dialog_rename_error_same_name">I nomi di input e output della ROM dovrebbero essere differenti</string>
|
||||
<string name="dialog_rename_error_same_name">The input and output file names must be different</string>
|
||||
<string name="dialog_rename_error_invalid_chars">Simbolo non valido /</string>
|
||||
|
||||
<!-- Create patch fragment -->
|
||||
<string name="create_patch_fragment_source_file">Source file</string>
|
||||
<string name="create_patch_fragment_modified_file">Modified file</string>
|
||||
<string name="create_patch_fragment_patch_file">Patch file</string>
|
||||
<string name="create_patch_fragment_toast_source_and_modified_not_selected">The source and modified files is not selected</string>
|
||||
<string name="create_patch_fragment_toast_source_not_selected">The source file is not selected</string>
|
||||
<string name="create_patch_fragment_toast_modified_not_selected">The modified file is not selected</string>
|
||||
|
||||
<!-- Info for SNES SMC header -->
|
||||
<string name="snes_smc_header_help">Questa caratteristica è solo per le ROM Super Nintendo.\\n\\nlf la ROM contiene l\'intestazione SMC - che verrà rimossa. Altrimenti, verrà aggiunta.\\n\\nAttenzione: questa funzione non crea un backup.</string>
|
||||
<string name="snes_smc_header_will_be_removed">Questa ROM ha l\'intestazione SMC. Verrà rimossa.</string>
|
||||
|
@ -36,6 +44,8 @@
|
|||
<string name="file_picker_activity_title">Seleziona file</string>
|
||||
<string name="file_picker_activity_title_select_rom">Seleziona il file ROM</string>
|
||||
<string name="file_picker_activity_title_select_patch">Seleziona il file di patch</string>
|
||||
<string name="file_picker_activity_title_select_source_file">Select the source file</string>
|
||||
<string name="file_picker_activity_title_select_modified_file">Select the modified file</string>
|
||||
<string name="file_picker_activity_title_select_header">Scegli il file di intestazione</string>
|
||||
<string name="file_picker_activity_error_unable_read_dir">Impossibile leggere la cartella %1$s</string>
|
||||
|
||||
|
@ -54,7 +64,10 @@
|
|||
<!-- Notifications -->
|
||||
<string name="notify_applying_patch">Applicando la patch</string>
|
||||
<string name="notify_patching_complete">Patch completato</string>
|
||||
<string name="notify_creating_patch">Creating patch</string>
|
||||
<string name="notify_create_patch_complete">Patch creation completed</string>
|
||||
<string name="toast_patching_started_check_notify">Patching iniziato. Controlla l\'area di notifica</string>
|
||||
<string name="toast_create_patch_started_check_notify">Creating patch started. Check the notification area</string>
|
||||
|
||||
<string name="notify_error">Errore</string>
|
||||
<string name="notify_error_could_not_copy_file">Non si può copiare il file</string>
|
||||
|
@ -138,6 +151,7 @@
|
|||
|
||||
<!-- Navigation list -->
|
||||
<string name="nav_apply_patch">Applica patch</string>
|
||||
<string name="nav_create_patch">Create patch</string>
|
||||
<string name="nav_smd_fix_checksum">Risolvi checksum (SMD)</string>
|
||||
<string name="nav_snes_add_del_smc_header">Aggiungi/Cancella intestazione SMC (SNES)</string>
|
||||
<string name="nav_settings">Impostazioni</string>
|
||||
|
|
|
@ -21,9 +21,17 @@
|
|||
<string name="dialog_rename_title">Zmień Nazwę</string>
|
||||
<string name="dialog_rename_ok">OK</string>
|
||||
<string name="dialog_rename_cancel">Anuluj</string>
|
||||
<string name="dialog_rename_error_same_name">Wejściowe i wyjściowe nazwy ROM-ów muszą być różne</string>
|
||||
<string name="dialog_rename_error_same_name">The input and output file names must be different</string>
|
||||
<string name="dialog_rename_error_invalid_chars">Niewłaściwy symbol /</string>
|
||||
|
||||
<!-- Create patch fragment -->
|
||||
<string name="create_patch_fragment_source_file">Source file</string>
|
||||
<string name="create_patch_fragment_modified_file">Modified file</string>
|
||||
<string name="create_patch_fragment_patch_file">Patch file</string>
|
||||
<string name="create_patch_fragment_toast_source_and_modified_not_selected">The source and modified files is not selected</string>
|
||||
<string name="create_patch_fragment_toast_source_not_selected">The source file is not selected</string>
|
||||
<string name="create_patch_fragment_toast_modified_not_selected">The modified file is not selected</string>
|
||||
|
||||
<!-- Info for SNES SMC header -->
|
||||
<string name="snes_smc_header_help">Ta opcja jest tylko dla ROM-ów Super Nintendo.\n\nJeżeli ROM zawiera nagłówek SMC - zostanie on usunięty. Inaczej zostanie on dodany.\n\nUwaga: ta funkcja nie tworzy kopii zapasowej.</string>
|
||||
<string name="snes_smc_header_will_be_removed">Ten ROM zawiera nagłówek SMC. Zostanie on usunięty.</string>
|
||||
|
@ -36,6 +44,8 @@
|
|||
<string name="file_picker_activity_title">Wybierz plik</string>
|
||||
<string name="file_picker_activity_title_select_rom">Wybierz plik ROM</string>
|
||||
<string name="file_picker_activity_title_select_patch">Wybier plik Łatki</string>
|
||||
<string name="file_picker_activity_title_select_source_file">Select the source file</string>
|
||||
<string name="file_picker_activity_title_select_modified_file">Select the modified file</string>
|
||||
<string name="file_picker_activity_title_select_header">Wybierz plik nagłówka</string>
|
||||
<string name="file_picker_activity_error_unable_read_dir">Błędna ścieżka %1$s</string>
|
||||
|
||||
|
@ -54,7 +64,10 @@
|
|||
<!-- Notifications -->
|
||||
<string name="notify_applying_patch">Stosowanie łatki</string>
|
||||
<string name="notify_patching_complete">Łatkowanie ukończone</string>
|
||||
<string name="notify_creating_patch">Creating patch</string>
|
||||
<string name="notify_create_patch_complete">Patch creation completed</string>
|
||||
<string name="toast_patching_started_check_notify">Łatkowanie rozpoczęte. Sprawdzaj pasek powiadomień.</string>
|
||||
<string name="toast_create_patch_started_check_notify">Creating patch started. Check the notification area</string>
|
||||
|
||||
<string name="notify_error">Błąd</string>
|
||||
<string name="notify_error_could_not_copy_file">Nie można skopiować pliku</string>
|
||||
|
@ -138,6 +151,7 @@
|
|||
|
||||
<!-- Navigation list -->
|
||||
<string name="nav_apply_patch">Zastosuj łatkę</string>
|
||||
<string name="nav_create_patch">Create patch</string>
|
||||
<string name="nav_smd_fix_checksum">Napraw sumę kontrolną (SMD)</string>
|
||||
<string name="nav_snes_add_del_smc_header">Dodaj/Usuń nagłówek SMC (SNES)</string>
|
||||
<string name="nav_settings">Ustawienia</string>
|
||||
|
|
|
@ -21,9 +21,17 @@
|
|||
<string name="dialog_rename_title">Переименовать</string>
|
||||
<string name="dialog_rename_ok">Переименовать</string>
|
||||
<string name="dialog_rename_cancel">Отмена</string>
|
||||
<string name="dialog_rename_error_same_name">Имена ROM файлов должны отличаться</string>
|
||||
<string name="dialog_rename_error_same_name">Имена файлов должны отличаться</string>
|
||||
<string name="dialog_rename_error_invalid_chars">Некорректный символ /</string>
|
||||
|
||||
<!-- Create patch fragment -->
|
||||
<string name="create_patch_fragment_source_file">Исходный файл</string>
|
||||
<string name="create_patch_fragment_modified_file">Изменённый файл</string>
|
||||
<string name="create_patch_fragment_patch_file">Патч</string>
|
||||
<string name="create_patch_fragment_toast_source_and_modified_not_selected">Сначала выберите исходный и изменённый файлы</string>
|
||||
<string name="create_patch_fragment_toast_source_not_selected">Сначала выберите исходный файл</string>
|
||||
<string name="create_patch_fragment_toast_modified_not_selected">Сначала выберите изменённый файл</string>
|
||||
|
||||
<!-- Info for SNES SMC header -->
|
||||
<string name="snes_smc_header_help">Эта функция только для ROM\'ов Super Nintendo.\n\nЕсли ROM содержит SMC заголовок - он будет удалён. Иначе он будет добавлен.\n\nПредупреждение: эта функция не создаёт резервную копию.</string>
|
||||
<string name="snes_smc_header_will_be_removed">У этого ROM\'а есть SMC заголовок. Он будет удалён.</string>
|
||||
|
@ -36,6 +44,8 @@
|
|||
<string name="file_picker_activity_title">Выберите файл</string>
|
||||
<string name="file_picker_activity_title_select_rom">Выберите ROM файл</string>
|
||||
<string name="file_picker_activity_title_select_patch">Выберите патч</string>
|
||||
<string name="file_picker_activity_title_select_source_file">Выберите исходный файл</string>
|
||||
<string name="file_picker_activity_title_select_modified_file">Выберите изменённый файл</string>
|
||||
<string name="file_picker_activity_title_select_header">Выберите файл заголовка</string>
|
||||
<string name="file_picker_activity_error_unable_read_dir">Не удалось открыть директорию %1$s</string>
|
||||
|
||||
|
@ -54,7 +64,10 @@
|
|||
<!-- Notifications -->
|
||||
<string name="notify_applying_patch">Применяю патч</string>
|
||||
<string name="notify_patching_complete">Применение патча завершено</string>
|
||||
<string name="notify_creating_patch">Создаю патч</string>
|
||||
<string name="notify_create_patch_complete">Создание патча завершено</string>
|
||||
<string name="toast_patching_started_check_notify">Применяю патч. Проверьте область уведомлений</string>
|
||||
<string name="toast_create_patch_started_check_notify">Создаю патч. Проверьте область уведомлений</string>
|
||||
|
||||
<string name="notify_error">Ошибка</string>
|
||||
<string name="notify_error_could_not_copy_file">Не удалось скопировать файл</string>
|
||||
|
@ -138,6 +151,7 @@
|
|||
|
||||
<!-- Navigation list -->
|
||||
<string name="nav_apply_patch">Применить патч</string>
|
||||
<string name="nav_create_patch">Создать патч</string>
|
||||
<string name="nav_smd_fix_checksum">Испр. контр. сумму (SMD)</string>
|
||||
<string name="nav_snes_add_del_smc_header">SMC заголовок (SNES)</string>
|
||||
<string name="nav_settings">Настройки</string>
|
||||
|
|
|
@ -21,9 +21,17 @@
|
|||
<string name="dialog_rename_title">Перейменувати</string>
|
||||
<string name="dialog_rename_ok">OK</string>
|
||||
<string name="dialog_rename_cancel">Скасувати</string>
|
||||
<string name="dialog_rename_error_same_name">Назви вхідного та вихідного ROM\'у не повинні відрізнятись</string>
|
||||
<string name="dialog_rename_error_same_name">The input and output file names must be different</string>
|
||||
<string name="dialog_rename_error_invalid_chars">Недійсний символ /</string>
|
||||
|
||||
<!-- Create patch fragment -->
|
||||
<string name="create_patch_fragment_source_file">Source file</string>
|
||||
<string name="create_patch_fragment_modified_file">Modified file</string>
|
||||
<string name="create_patch_fragment_patch_file">Patch file</string>
|
||||
<string name="create_patch_fragment_toast_source_and_modified_not_selected">The source and modified files is not selected</string>
|
||||
<string name="create_patch_fragment_toast_source_not_selected">The source file is not selected</string>
|
||||
<string name="create_patch_fragment_toast_modified_not_selected">The modified file is not selected</string>
|
||||
|
||||
<!-- Info for SNES SMC header -->
|
||||
<string name="snes_smc_header_help">Ця функція доступна тільки для Super Nintendo ROM\'ів.\n\nIf ROM містить SMC заголовок - його буде перезаписано. При його відсутності, він буде доданий.\n\nУвага: ця функція не створює резервної копії.</string>
|
||||
<string name="snes_smc_header_will_be_removed">Цей ROM має SMC заголовок. Його буде перезаписано.</string>
|
||||
|
@ -36,6 +44,8 @@
|
|||
<string name="file_picker_activity_title">Обрати файл</string>
|
||||
<string name="file_picker_activity_title_select_rom">Обрати ROM файл</string>
|
||||
<string name="file_picker_activity_title_select_patch">Обрати Патч файл</string>
|
||||
<string name="file_picker_activity_title_select_source_file">Select the source file</string>
|
||||
<string name="file_picker_activity_title_select_modified_file">Select the modified file</string>
|
||||
<string name="file_picker_activity_title_select_header">Обрати файл заголовок</string>
|
||||
<string name="file_picker_activity_error_unable_read_dir">Неможливо прочитати папку %1$s</string>
|
||||
|
||||
|
@ -54,7 +64,10 @@
|
|||
<!-- Notifications -->
|
||||
<string name="notify_applying_patch">Застосування патчу</string>
|
||||
<string name="notify_patching_complete">Патчинг завершено</string>
|
||||
<string name="notify_creating_patch">Creating patch</string>
|
||||
<string name="notify_create_patch_complete">Patch creation completed</string>
|
||||
<string name="toast_patching_started_check_notify">Патчинг почався. Перевірте область повідомлень</string>
|
||||
<string name="toast_create_patch_started_check_notify">Creating patch started. Check the notification area</string>
|
||||
|
||||
<string name="notify_error">Помилка</string>
|
||||
<string name="notify_error_could_not_copy_file">Не вдалося скопіювати файл</string>
|
||||
|
@ -138,6 +151,7 @@
|
|||
|
||||
<!-- Navigation list -->
|
||||
<string name="nav_apply_patch">Застосувати Патч</string>
|
||||
<string name="nav_create_patch">Create patch</string>
|
||||
<string name="nav_smd_fix_checksum">Виправити контрольну суму (SMD)</string>
|
||||
<string name="nav_snes_add_del_smc_header">Додати/Видалити SMC заголовок (SNES)</string>
|
||||
<string name="nav_settings">Налаштування</string>
|
||||
|
|
|
@ -21,9 +21,17 @@
|
|||
<string name="dialog_rename_title">Rename</string>
|
||||
<string name="dialog_rename_ok">OK</string>
|
||||
<string name="dialog_rename_cancel">Cancel</string>
|
||||
<string name="dialog_rename_error_same_name">The input and output ROM names must be different</string>
|
||||
<string name="dialog_rename_error_same_name">The input and output file names must be different</string>
|
||||
<string name="dialog_rename_error_invalid_chars">Invalid symbol /</string>
|
||||
|
||||
<!-- Create patch fragment -->
|
||||
<string name="create_patch_fragment_source_file">Source file</string>
|
||||
<string name="create_patch_fragment_modified_file">Modified file</string>
|
||||
<string name="create_patch_fragment_patch_file">Patch file</string>
|
||||
<string name="create_patch_fragment_toast_source_and_modified_not_selected">The source and modified files is not selected</string>
|
||||
<string name="create_patch_fragment_toast_source_not_selected">The source file is not selected</string>
|
||||
<string name="create_patch_fragment_toast_modified_not_selected">The modified file is not selected</string>
|
||||
|
||||
<!-- Info for SNES SMC header -->
|
||||
<string name="snes_smc_header_help">This feature is only for Super Nintendo ROMs.\n\nIf the ROM contains the SMC header - it will be removed. Otherwise, it will be added.\n\nWarning: this function does not create a backup.</string>
|
||||
<string name="snes_smc_header_will_be_removed">This ROM has the SMC header. It will be removed.</string>
|
||||
|
@ -36,6 +44,8 @@
|
|||
<string name="file_picker_activity_title">Select file</string>
|
||||
<string name="file_picker_activity_title_select_rom">Select the ROM file</string>
|
||||
<string name="file_picker_activity_title_select_patch">Select the patch file</string>
|
||||
<string name="file_picker_activity_title_select_source_file">Select the source file</string>
|
||||
<string name="file_picker_activity_title_select_modified_file">Select the modified file</string>
|
||||
<string name="file_picker_activity_title_select_header">Select the header file</string>
|
||||
<string name="file_picker_activity_error_unable_read_dir">Unable to read directory %1$s</string>
|
||||
|
||||
|
@ -54,7 +64,10 @@
|
|||
<!-- Notifications -->
|
||||
<string name="notify_applying_patch">Applying patch</string>
|
||||
<string name="notify_patching_complete">Patching complete</string>
|
||||
<string name="notify_creating_patch">Creating patch</string>
|
||||
<string name="notify_create_patch_complete">Patch creation completed</string>
|
||||
<string name="toast_patching_started_check_notify">Patching started. Check the notification area</string>
|
||||
<string name="toast_create_patch_started_check_notify">Creating patch started. Check the notification area</string>
|
||||
|
||||
<string name="notify_error">Error</string>
|
||||
<string name="notify_error_could_not_copy_file">Could not copy file</string>
|
||||
|
@ -138,6 +151,7 @@
|
|||
|
||||
<!-- Navigation list -->
|
||||
<string name="nav_apply_patch">Apply patch</string>
|
||||
<string name="nav_create_patch">Create patch</string>
|
||||
<string name="nav_smd_fix_checksum">Fix checksum (SMD)</string>
|
||||
<string name="nav_snes_add_del_smc_header">Add/Del SMC header (SNES)</string>
|
||||
<string name="nav_settings">Settings</string>
|
||||
|
|
|
@ -8,6 +8,7 @@ Utility to apply patches to game rom.
|
|||
|
||||
<b>Features:</b>
|
||||
• Supported formats of patches: IPS, IPS32, UPS, BPS, APS (GBA), APS (N64), PPF, DPS, EBP, XDelta 3
|
||||
• Creating XDelta patches
|
||||
• Fix checksum in Sega Mega Drive ROMs
|
||||
• Add/Delete SMC header in Super Nintendo ROMs
|
||||
• No ads
|
||||
|
|
|
@ -8,6 +8,7 @@ Utilità per applicare le patch alle ROM dei giochi.
|
|||
|
||||
<b>Features:</b>
|
||||
• Supported formats of patches: IPS, IPS32, UPS, BPS, APS (GBA), APS (N64), PPF, DPS, EBP, XDelta 3
|
||||
• Creating XDelta patches
|
||||
• Risolvi checksum nei ROM del Sega Mega Drive
|
||||
• Aggiungi/Elimina intestazione SMC nei ROM del Super Nintendo
|
||||
• No ads
|
||||
|
|
|
@ -8,6 +8,7 @@ Narzędzie do aplikowania łatek do ROM-ów
|
|||
|
||||
<b>Features:</b>
|
||||
• Supported formats of patches: IPS, IPS32, UPS, BPS, APS (GBA), APS (N64), PPF, DPS, EBP, XDelta 3
|
||||
• Creating XDelta patches
|
||||
• Napraw sumę kontrolną dla ROM-ów Segs Mega Drive
|
||||
• Dodaj/Usuń nagłówek SMC dla ROM-ów Super Nintendo
|
||||
• No ads
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<b>Особенности:</b>
|
||||
• Поддержка множества форматов патчей: IPS, IPS32, UPS, BPS, APS (GBA), APS (N64), PPF, DPS, EBP, XDelta 3
|
||||
• Создание патчей в формате XDelta
|
||||
• Исправление контрольной суммы для игр Sega Mega Drive
|
||||
• Удаление/добавление SMC заголовка для игр Super Nintendo
|
||||
• Не имеет рекламы
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<b>Features:</b>
|
||||
• Supported formats of patches: IPS, IPS32, UPS, BPS, APS (GBA), APS (N64), PPF, DPS, EBP, XDelta 3
|
||||
• Creating XDelta patches
|
||||
• Виправлення контрольної суми для ігор Sega Mega Drive
|
||||
• Додавання або Видаляння SMC заголовку для ігор Super Nintendo
|
||||
• No ads
|
||||
|
|
Loading…
Add table
Reference in a new issue