mirror of
https://github.com/codestation/mhtools
synced 2024-11-10 05:44:17 +00:00
first commit
This commit is contained in:
commit
a4848cb2d4
15 changed files with 1717 additions and 0 deletions
6
.classpath
Normal file
6
.classpath
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/index.bin
|
||||
/.settings
|
17
.project
Normal file
17
.project
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>mhtrans</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
88
src/base/Decoder.java
Normal file
88
src/base/Decoder.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G xxxx.bin language table extractor
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package base;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class Decoder {
|
||||
|
||||
public abstract void extract(String filename);
|
||||
|
||||
/**
|
||||
* The "readInt" function of java reads in BigEndian mode but we need
|
||||
* LittleEndian so i made a custom function for that
|
||||
*
|
||||
* @param file
|
||||
* @return 8 byte integer in LittleEndian mode
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected int readInt(RandomAccessFile file) throws IOException, EOFException {
|
||||
int ch1 = file.read();
|
||||
int ch2 = file.read();
|
||||
int ch3 = file.read();
|
||||
int ch4 = file.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some hex-edited files have some extra zeros at the end of the strings so
|
||||
* its better to skip them
|
||||
*
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected void advanceNext(RandomAccessFile file) throws IOException {
|
||||
while (file.readByte() == 0) {
|
||||
;
|
||||
}
|
||||
file.seek(file.getFilePointer() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "readUTF8" function of java expects a different format of the string
|
||||
* so i have to make a custom one
|
||||
*
|
||||
* @param file
|
||||
* @return string extracted from file
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected String readString(RandomAccessFile file) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
byte data = 0;
|
||||
int counter = 0;
|
||||
try {
|
||||
do {
|
||||
data = file.readByte();
|
||||
buffer[counter++] = data;
|
||||
} while (data != 0);
|
||||
// checks if the string is a edited one
|
||||
advanceNext(file);
|
||||
} catch (EOFException e) {
|
||||
return null;
|
||||
}
|
||||
return new String(buffer, 0, counter, "UTF-8");
|
||||
}
|
||||
}
|
122
src/base/Encoder.java
Normal file
122
src/base/Encoder.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G xxxx.bin language table rebuilder
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package base;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class Encoder {
|
||||
|
||||
public abstract void compile(String filelist);
|
||||
|
||||
/**
|
||||
* The "readUTF8" function of java expects a different format of the string
|
||||
* so i have to make a custom one.
|
||||
*
|
||||
* @param file
|
||||
* @return string extracted from file
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected String readString(RandomAccessFile file) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
byte data = 0;
|
||||
boolean eol = false;
|
||||
int counter = 0;
|
||||
try {
|
||||
while (!eol) {
|
||||
switch (data = file.readByte()) {
|
||||
case '\n':
|
||||
eol = true;
|
||||
break;
|
||||
case '\r':
|
||||
eol = true;
|
||||
long cur = file.getFilePointer();
|
||||
if (file.readByte() != '\n') {
|
||||
file.seek(cur);
|
||||
eol = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
buffer[counter++] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
return null;
|
||||
}
|
||||
return new String(buffer, 0, counter, "UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file have the unicode BOM mark and skip it (thanks notepad
|
||||
* grr..)
|
||||
*
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected void checkUnicodeBOM(RandomAccessFile file) throws IOException {
|
||||
int a = file.readByte();
|
||||
int b = file.readByte();
|
||||
int c = file.readByte();
|
||||
if (a != -17 || b != -69 || c != -65) {
|
||||
file.seek(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The "writeInt" function of java writes in BigEndian mode but we need
|
||||
* LittleEndian so i made a custom function for that
|
||||
*
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* if any error occur while writing
|
||||
*/
|
||||
protected void writeInt(RandomAccessFile file, int value) throws IOException {
|
||||
int ch1 = (byte) (value >>> 24);
|
||||
int ch2 = (byte) (value >>> 16);
|
||||
int ch3 = (byte) (value >>> 8);
|
||||
int ch4 = (byte) value;
|
||||
file.write(ch4);
|
||||
file.write(ch3);
|
||||
file.write(ch2);
|
||||
file.write(ch1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "readInt" function of java reads in BigEndian mode but we need
|
||||
* LittleEndian so i made a custom function for that
|
||||
*
|
||||
* @param file
|
||||
* @return 8 byte integer in LittleEndian mode
|
||||
* @throws IOException
|
||||
* if any error occur while reading
|
||||
*/
|
||||
protected int readInt(RandomAccessFile file) throws IOException, EOFException {
|
||||
int ch1 = file.read();
|
||||
int ch2 = file.read();
|
||||
int ch3 = file.read();
|
||||
int ch4 = file.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
|
||||
}
|
||||
}
|
184
src/base/Mhtrans.java
Normal file
184
src/base/Mhtrans.java
Normal file
|
@ -0,0 +1,184 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G xxxx.bin language table extractor/rebuilder/encrypter/decrypter
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package base;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import crypt.Decrypter;
|
||||
import crypt.Encrypter;
|
||||
import dec.ExtractPluginA;
|
||||
import dec.ExtractPluginB;
|
||||
import dec.ExtractPluginC;
|
||||
import enc.RebuildPluginA;
|
||||
import enc.RebuildPluginB;
|
||||
import enc.RebuildPluginC;
|
||||
|
||||
public class Mhtrans {
|
||||
|
||||
public static void extract(String filename, String decoder) {
|
||||
// (00[1-2][0-9]|47[0-9][0-9])\\..* decoder A
|
||||
// 53[0-9][0-9]\\..* decoder B
|
||||
// 54[0-9][0-9]\\..* decoder C
|
||||
|
||||
Decoder dec = null;
|
||||
int type = Integer.parseInt(decoder);
|
||||
switch(type) {
|
||||
case 1:
|
||||
dec = new ExtractPluginA();
|
||||
break;
|
||||
case 2:
|
||||
dec = new ExtractPluginB(false);
|
||||
break;
|
||||
case 4:
|
||||
dec = new ExtractPluginB(true);
|
||||
break;
|
||||
case 3:
|
||||
dec = new ExtractPluginC();
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unknown decoder: " + decoder);
|
||||
System.exit(1);
|
||||
}
|
||||
dec.extract(filename);
|
||||
}
|
||||
|
||||
public static void rebuild(String filename, String encoder) {
|
||||
String str = checkFile(filename + "/filelist.txt");
|
||||
Encoder enc = null;
|
||||
if (str == null)
|
||||
System.exit(1);
|
||||
int type = Integer.parseInt(encoder);
|
||||
switch(type) {
|
||||
case 1:
|
||||
enc = new RebuildPluginA();
|
||||
break;
|
||||
case 2:
|
||||
enc = new RebuildPluginB(0);
|
||||
break;
|
||||
case 4:
|
||||
enc = new RebuildPluginB(type);
|
||||
break;
|
||||
case 3:
|
||||
enc = new RebuildPluginC();
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unknown encoder: " + encoder);
|
||||
System.exit(1);
|
||||
}
|
||||
enc.compile(filename);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("mhtrans v2.0 - MHP2G/MHFU/MHP3 xxxx.bin language table extractor/rebuilder");
|
||||
System.out.println();
|
||||
if (args.length < 2) {
|
||||
System.err.println("Usage: java -jar mhtrans.jar --extract <path to xxxx.bin> <decoder number>");
|
||||
System.err.println(" java -jar mhtrans.jar --rebuild <path to project folder> <encoder number>");
|
||||
System.err.println(" java -jar mhtrans.jar --decrypt <path to xxxx.bin>");
|
||||
System.err.println(" java -jar mhtrans.jar --encrypt <path to xxxx.bin>");
|
||||
System.err.println(" java -jar mhtrans.jar --dec-ext <path to xxxx.bin> <decoder number>");
|
||||
System.err.println(" java -jar mhtrans.jar --reb-enc <path to project folder> <encoder number>");
|
||||
System.err.println(" java -jar mhtrans.jar --gen-index <data.bin>");
|
||||
System.err.println(" java -jar mhtrans.jar --dec-all <data.bin> <path to output folder>");
|
||||
//System.err.println(" java MHP2GTRANS --dec-single <data.bin> <path of xxxx.bin>");
|
||||
//System.err.println(" java MHP2GTRANS --insert <path of xxxx.bin> <data.bin>");
|
||||
System.exit(1);
|
||||
} else {
|
||||
if (args[0].equals("--extract")) {
|
||||
if(args.length < 3) {
|
||||
System.err.println("Decoder number missing. Aborting");
|
||||
System.exit(1);
|
||||
}
|
||||
extract(args[1], args[2]);
|
||||
} else if (args[0].equals("--rebuild")) {
|
||||
if(args.length < 3) {
|
||||
System.err.println("Decoder number missing. Aborting");
|
||||
System.exit(1);
|
||||
}
|
||||
rebuild(args[1], args[2]);
|
||||
} else if (args[0].equals("--decrypt")) {
|
||||
new Decrypter().decrypt(args[1], args[1] + ".dec");
|
||||
} else if (args[0].equals("--encrypt")) {
|
||||
String filename = new File(args[1]).getName();
|
||||
new Encrypter().encrypt(args[1], filename + ".enc");
|
||||
} else if (args[0].equals("--dec-ext")) {
|
||||
if(args.length < 3) {
|
||||
System.err.println("Decoder number missing. Aborting");
|
||||
System.exit(1);
|
||||
}
|
||||
new Decrypter().decrypt(args[1], args[1] + ".dec");
|
||||
new File(args[1]).renameTo(new File(args[1] + ".tmp"));
|
||||
new File(args[1] + ".dec").renameTo(new File(args[1]));
|
||||
extract(args[1], args[2]);
|
||||
new File(args[1]).delete();
|
||||
new File(args[1] + ".tmp").renameTo(new File(args[1]));
|
||||
} else if (args[0].equals("--reb-enc")) {
|
||||
if(args.length < 3) {
|
||||
System.err.println("Decoder number missing. Aborting");
|
||||
System.exit(1);
|
||||
}
|
||||
rebuild(args[1], args[2]);
|
||||
String filename = new File(args[1]).getName();
|
||||
new Encrypter().encrypt(filename + ".bin.out", filename + ".bin.enc");
|
||||
System.out.println("Moving to " + filename + ".bin.enc");
|
||||
new File(filename + ".bin.out").delete();
|
||||
} else if(args[0].equals("--gen-index")) {
|
||||
new Decrypter().decrypt_index(args[1], null);
|
||||
} else if(args[0].equals("--dec-all")) {
|
||||
if(args.length < 3) {
|
||||
System.err.println("Output folder missing. Aborting");
|
||||
System.exit(1);
|
||||
}
|
||||
new Decrypter().decrypt_whole(args[1], args[2]);
|
||||
// } else if(args[0].equals("--dec-single")) {
|
||||
// if(args.length < 3) {
|
||||
// System.err.println("Output xxxx.bin missing. Aborting");
|
||||
// System.exit(1);
|
||||
// }
|
||||
//
|
||||
// } else if(args[0].equals("--insert")) {
|
||||
// if(args.length < 3) {
|
||||
// System.err.println("Path of data.bin missing. Aborting");
|
||||
// System.exit(1);
|
||||
// }
|
||||
} else {
|
||||
System.err.println("Unknown parameter: " + args[0]);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String checkFile(String filename) {
|
||||
try {
|
||||
BufferedReader file = new BufferedReader(new FileReader(filename));
|
||||
String name = file.readLine().split(" ")[0];
|
||||
file.close();
|
||||
return name;
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println(e.toString());
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
146
src/crypt/DecryptTable.java
Normal file
146
src/crypt/DecryptTable.java
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* MHP2GDEC v1.0 - MH data.bin/xxxx.bin encrypter/decrypter
|
||||
Copyright (C) 2008 codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package crypt;
|
||||
|
||||
//import java.io.EOFException;
|
||||
import java.io.EOFException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class DecryptTable {
|
||||
|
||||
protected final byte decrypt_table[] = { (byte) 0xCB, (byte) 0x96,
|
||||
(byte) 0x85, (byte) 0xA6, (byte) 0x5F, (byte) 0x3E, (byte) 0xAB,
|
||||
(byte) 0x03, (byte) 0x50, (byte) 0xB7, (byte) 0x9C, (byte) 0x5C,
|
||||
(byte) 0xB2, (byte) 0x40, (byte) 0xEF, (byte) 0xF6, (byte) 0xFF,
|
||||
(byte) 0x61, (byte) 0x15, (byte) 0x29, (byte) 0xA2, (byte) 0xF1,
|
||||
(byte) 0xEC, (byte) 0x52, (byte) 0x35, (byte) 0x28, (byte) 0xD9,
|
||||
(byte) 0x68, (byte) 0x24, (byte) 0x36, (byte) 0xC4, (byte) 0x74,
|
||||
(byte) 0x26, (byte) 0xE2, (byte) 0xD5, (byte) 0x8C, (byte) 0x47,
|
||||
(byte) 0x4D, (byte) 0x2C, (byte) 0xFA, (byte) 0x86, (byte) 0x66,
|
||||
(byte) 0xC1, (byte) 0x4F, (byte) 0x0B, (byte) 0x81, (byte) 0x5B,
|
||||
(byte) 0x1B, (byte) 0xC0, (byte) 0x0A, (byte) 0xFD, (byte) 0x17,
|
||||
(byte) 0xA4, (byte) 0xA9, (byte) 0x6D, (byte) 0x63, (byte) 0xAD,
|
||||
(byte) 0xF3, (byte) 0xF4, (byte) 0x6E, (byte) 0x8D, (byte) 0x89,
|
||||
(byte) 0x14, (byte) 0xDD, (byte) 0x59, (byte) 0x87, (byte) 0x4A,
|
||||
(byte) 0x30, (byte) 0xCE, (byte) 0xFE, (byte) 0x3F, (byte) 0x7E,
|
||||
(byte) 0x06, (byte) 0x49, (byte) 0xA5, (byte) 0x04, (byte) 0x5E,
|
||||
(byte) 0xD0, (byte) 0xDE, (byte) 0xE8, (byte) 0x0F, (byte) 0xD4,
|
||||
(byte) 0x13, (byte) 0x1F, (byte) 0xBA, (byte) 0xB9, (byte) 0x69,
|
||||
(byte) 0x71, (byte) 0x3D, (byte) 0xE4, (byte) 0xDC, (byte) 0x58,
|
||||
(byte) 0x90, (byte) 0x34, (byte) 0x3A, (byte) 0x3C, (byte) 0xCA,
|
||||
(byte) 0x10, (byte) 0x76, (byte) 0xC7, (byte) 0xC8, (byte) 0x45,
|
||||
(byte) 0x33, (byte) 0xC3, (byte) 0x92, (byte) 0x1D, (byte) 0x2B,
|
||||
(byte) 0x1C, (byte) 0x8F, (byte) 0x6F, (byte) 0x05, (byte) 0x07,
|
||||
(byte) 0x38, (byte) 0x57, (byte) 0x51, (byte) 0xD6, (byte) 0xDA,
|
||||
(byte) 0x2D, (byte) 0xB3, (byte) 0xC6, (byte) 0x2E, (byte) 0x64,
|
||||
(byte) 0x32, (byte) 0x1E, (byte) 0x43, (byte) 0xB1, (byte) 0x5D,
|
||||
(byte) 0xE1, (byte) 0xBB, (byte) 0x8E, (byte) 0x9D, (byte) 0x72,
|
||||
(byte) 0x77, (byte) 0xF2, (byte) 0x27, (byte) 0xC9, (byte) 0x7F,
|
||||
(byte) 0x9E, (byte) 0xAA, (byte) 0x6A, (byte) 0x2F, (byte) 0x6C,
|
||||
(byte) 0xF9, (byte) 0x48, (byte) 0xE7, (byte) 0xA0, (byte) 0x09,
|
||||
(byte) 0x56, (byte) 0xB8, (byte) 0xBD, (byte) 0x20, (byte) 0x41,
|
||||
(byte) 0xCD, (byte) 0x95, (byte) 0x80, (byte) 0xD7, (byte) 0x23,
|
||||
(byte) 0x0C, (byte) 0x42, (byte) 0xE5, (byte) 0xAE, (byte) 0x8B,
|
||||
(byte) 0x7D, (byte) 0xBC, (byte) 0x54, (byte) 0x39, (byte) 0xBF,
|
||||
(byte) 0x65, (byte) 0x01, (byte) 0x88, (byte) 0xE0, (byte) 0x7B,
|
||||
(byte) 0xB6, (byte) 0x16, (byte) 0x18, (byte) 0x4B, (byte) 0xCC,
|
||||
(byte) 0x22, (byte) 0x5A, (byte) 0xB5, (byte) 0xEB, (byte) 0xFC,
|
||||
(byte) 0xF8, (byte) 0x9B, (byte) 0x4E, (byte) 0xE6, (byte) 0xA8,
|
||||
(byte) 0xBE, (byte) 0x67, (byte) 0x73, (byte) 0x97, (byte) 0x94,
|
||||
(byte) 0x00, (byte) 0x62, (byte) 0xB4, (byte) 0xD2, (byte) 0x21,
|
||||
(byte) 0x25, (byte) 0x11, (byte) 0x82, (byte) 0xDB, (byte) 0x93,
|
||||
(byte) 0x02, (byte) 0x84, (byte) 0x7C, (byte) 0xD3, (byte) 0xB0,
|
||||
(byte) 0xA3, (byte) 0x91, (byte) 0xA7, (byte) 0xF7, (byte) 0x55,
|
||||
(byte) 0x70, (byte) 0x7A, (byte) 0x08, (byte) 0x75, (byte) 0x8A,
|
||||
(byte) 0x53, (byte) 0x79, (byte) 0xFB, (byte) 0x9F, (byte) 0x46,
|
||||
(byte) 0xF5, (byte) 0x83, (byte) 0xD8, (byte) 0x0E, (byte) 0xE9,
|
||||
(byte) 0xED, (byte) 0x12, (byte) 0xD1, (byte) 0xDF, (byte) 0xF0,
|
||||
(byte) 0x37, (byte) 0x2A, (byte) 0x44, (byte) 0x19, (byte) 0x9A,
|
||||
(byte) 0x31, (byte) 0xCF, (byte) 0xA1, (byte) 0xAF, (byte) 0xE3,
|
||||
(byte) 0x3B, (byte) 0x1A, (byte) 0x4C, (byte) 0x78, (byte) 0xC2,
|
||||
(byte) 0x60, (byte) 0xEE, (byte) 0x98, (byte) 0x6B, (byte) 0x0D,
|
||||
(byte) 0x99, (byte) 0xEA, (byte) 0xC5, (byte) 0xAC };
|
||||
|
||||
private long lower_offset;
|
||||
private long upper_offset;
|
||||
|
||||
protected void initSeed(long seed) {
|
||||
lower_offset = seed & 0xFFFF;
|
||||
upper_offset = seed >> 0x10 & 0xFFFF;
|
||||
if (lower_offset == 0) {
|
||||
lower_offset = 0x7F8D;
|
||||
}
|
||||
if (upper_offset == 0) {
|
||||
upper_offset = 0x2345;
|
||||
}
|
||||
}
|
||||
|
||||
protected long getBeta() {
|
||||
lower_offset = (lower_offset * 0x7F8D) % 0xFFF1;
|
||||
upper_offset = (upper_offset * 0x2345) % 0xFFD9;
|
||||
return lower_offset + (upper_offset << 0x10);
|
||||
}
|
||||
|
||||
protected void set_table_value(byte table[], int pos, long value) {
|
||||
table[pos] = (byte) value;
|
||||
table[pos+1] = (byte) (value >> 8);
|
||||
table[pos+2] = (byte) (value >> 16);
|
||||
table[pos+3] = (byte) (value >> 24);
|
||||
}
|
||||
|
||||
protected long get_table_value(byte table[], int pos) {
|
||||
return (table[pos] & 0xFF)
|
||||
+ ((long) (table[pos+1] & 0xFF) << 8)
|
||||
+ ((long) (table[pos+2] & 0xFF) << 16)
|
||||
+ ((long) (table[pos+3] & 0xFF) << 24);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can't use the RandomAccessFile readInt func as we need the bytes
|
||||
* in reverse order
|
||||
*/
|
||||
private int readInt(RandomAccessFile file) throws IOException, EOFException {
|
||||
int ch1 = file.read();
|
||||
int ch2 = file.read();
|
||||
int ch3 = file.read();
|
||||
int ch4 = file.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
|
||||
}
|
||||
|
||||
protected int getOffset(int value) throws EOFException, FileNotFoundException, IOException {
|
||||
int res = -1;
|
||||
if (value == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
RandomAccessFile table = new RandomAccessFile("index.bin", "r");
|
||||
table.seek(value * 4 - 4);
|
||||
res = readInt(table);
|
||||
table.close();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
protected int extractNumber(String filename) {
|
||||
return Integer.parseInt(filename.substring(filename.indexOf(".") - 4, filename.indexOf(".")));
|
||||
}
|
||||
}
|
160
src/crypt/Decrypter.java
Normal file
160
src/crypt/Decrypter.java
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* MHP2GDEC v1.0 - MH data.bin/xxxx.bin decrypter
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package crypt;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class Decrypter extends DecryptTable {
|
||||
|
||||
public void decrypt_index(String in, ByteArrayOutputStream index_buffer) {
|
||||
try {
|
||||
RandomAccessFile filein = new RandomAccessFile(in, "r");
|
||||
RandomAccessFile fileout = new RandomAccessFile("index.bin", "rw");
|
||||
fileout.setLength(0);
|
||||
byte[] buffer = new byte[4];
|
||||
System.out.println("Decrypting index...");
|
||||
initSeed(0);
|
||||
boolean table_end = false;
|
||||
boolean end_flag = false;
|
||||
int i = 0;
|
||||
while(!table_end) {
|
||||
filein.read(buffer);
|
||||
buffer[0] = decrypt_table[buffer[0] & 0xFF];
|
||||
buffer[1] = decrypt_table[buffer[1] & 0xFF];
|
||||
buffer[2] = decrypt_table[buffer[2] & 0xFF];
|
||||
buffer[3] = decrypt_table[buffer[3] & 0xFF];
|
||||
long beta = getBeta();
|
||||
long alpha = get_table_value(buffer, 0);
|
||||
long gamma = alpha ^ beta;
|
||||
|
||||
if(gamma > 0xFF) {
|
||||
end_flag = true;
|
||||
} else if(end_flag) {
|
||||
table_end = true;
|
||||
continue;
|
||||
}
|
||||
set_table_value(buffer, 0, gamma);
|
||||
fileout.write(buffer);
|
||||
if(index_buffer != null)
|
||||
index_buffer.write(buffer);
|
||||
i += 4;
|
||||
}
|
||||
fileout.close();
|
||||
System.out.println("Index size: " + i + " bytes");
|
||||
System.out.println("File count: " + i / 4);
|
||||
}catch(FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void decrypt_whole(String in, String out) {
|
||||
ByteArrayOutputStream index_buffer = new ByteArrayOutputStream();
|
||||
decrypt_index(in, index_buffer);
|
||||
RandomAccessFile filein;
|
||||
try {
|
||||
filein = new RandomAccessFile(in, "r");
|
||||
byte index_table[] = index_buffer.toByteArray();
|
||||
int files_count = index_table.length / 4;
|
||||
new File(out).mkdir();
|
||||
boolean create_subdirectory = true;
|
||||
int last_subdirectory = 0;
|
||||
long last_offset = 0;
|
||||
for(int i = 0; i < files_count; i++) {
|
||||
if(create_subdirectory) {
|
||||
last_subdirectory = i / 1000;
|
||||
new File(out + "/0" + Integer.toString(last_subdirectory)).mkdir();
|
||||
create_subdirectory = false;
|
||||
} else {
|
||||
if(last_subdirectory < i / 1000) {
|
||||
create_subdirectory = true;
|
||||
}
|
||||
}
|
||||
long offset = last_offset;
|
||||
last_offset = get_table_value(index_table, i * 4);
|
||||
long file_length = (get_table_value(index_table, i * 4) - offset) << 11;
|
||||
String fileout = out +
|
||||
"/0" + Integer.toString(last_subdirectory) +
|
||||
"/" + String.format("%04d.bin", i);
|
||||
System.out.print("Decrypting " + fileout + "(" + file_length + " bytes/offset: " + (offset << 11) + ") ... ");
|
||||
decrypt_internal(filein, offset, file_length, fileout, false);
|
||||
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void decrypt_internal(RandomAccessFile filein, long pos, long size, String out, boolean single) {
|
||||
try {
|
||||
if(!single)
|
||||
filein.seek(pos << 11);
|
||||
RandomAccessFile fileout = new RandomAccessFile(out, "rw");
|
||||
byte buffer[] = new byte[1024];
|
||||
fileout.setLength(0);
|
||||
initSeed(pos);
|
||||
while (size > 0) {
|
||||
int read = filein.read(buffer);
|
||||
size -= read;
|
||||
for(int i = 0; i < read; i += 4) {
|
||||
buffer[i] = decrypt_table[buffer[i] & 0xFF];
|
||||
buffer[i+1] = decrypt_table[buffer[i+1] & 0xFF];
|
||||
buffer[i+2] = decrypt_table[buffer[i+2] & 0xFF];
|
||||
buffer[i+3] = decrypt_table[buffer[i+3] & 0xFF];
|
||||
long alpha = get_table_value(buffer, i);
|
||||
long beta = getBeta();
|
||||
long gamma = alpha ^ beta;
|
||||
set_table_value(buffer, i, gamma);
|
||||
}
|
||||
fileout.write(buffer);
|
||||
}
|
||||
fileout.close();
|
||||
System.out.println("Finished!");
|
||||
}catch(FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void decrypt(String in, String out) {
|
||||
RandomAccessFile filein = null;
|
||||
try {
|
||||
filein = new RandomAccessFile(in, "r");
|
||||
System.out.print("Decrypting " + out + " ... ");
|
||||
decrypt_internal(filein, getOffset(extractNumber(in)), filein.length(), out, true);
|
||||
|
||||
}catch(FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if(filein != null)
|
||||
try {
|
||||
filein.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
src/crypt/Encrypter.java
Normal file
62
src/crypt/Encrypter.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G data.bin/xxxx.bin encrypter
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package crypt;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class Encrypter extends DecryptTable {
|
||||
|
||||
private byte []encrypt_table;
|
||||
|
||||
public Encrypter() {
|
||||
encrypt_table = new byte[256];
|
||||
for(int i = 0;i < 256; i++) {
|
||||
encrypt_table[decrypt_table[i] & 0xFF] = (byte)i;
|
||||
}
|
||||
}
|
||||
|
||||
public void encrypt(String in, String out) {
|
||||
try {
|
||||
RandomAccessFile filein = new RandomAccessFile(in, "r");
|
||||
RandomAccessFile fileout = new RandomAccessFile(out, "rw");
|
||||
initSeed(getOffset(extractNumber(in)));
|
||||
byte[] buffer = new byte[4];
|
||||
System.out.println("Encrypting " + in);
|
||||
while (filein.read(buffer) >= 0) {
|
||||
long gamma = get_table_value(buffer, 0);
|
||||
long beta = getBeta();
|
||||
long alpha = beta ^ gamma;
|
||||
set_table_value(buffer, 0, alpha);
|
||||
buffer[0] = encrypt_table[buffer[0] & 0xFF];
|
||||
buffer[1] = encrypt_table[buffer[1] & 0xFF];
|
||||
buffer[2] = encrypt_table[buffer[2] & 0xFF];
|
||||
buffer[3] = encrypt_table[buffer[3] & 0xFF];
|
||||
fileout.write(buffer);
|
||||
}
|
||||
filein.close();
|
||||
fileout.close();
|
||||
System.out.println("Finished!");
|
||||
}catch(FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
120
src/dec/ExtractPluginA.java
Normal file
120
src/dec/ExtractPluginA.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G 0016/0017/475x.bin language table extractor
|
||||
Copyright (C) 2008-2010 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package dec;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import base.Decoder;
|
||||
|
||||
/**
|
||||
* ExtractPluginA v1.0 - 0016//0017/475x.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginA extends Decoder {
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
int tables_count;
|
||||
byte[] paddingData;
|
||||
int[] table_offset;
|
||||
int offset;
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile(filename, "r");
|
||||
// reading of number of main tables
|
||||
tables_count = readInt(file);
|
||||
// skipping 4 bytes of unknown data
|
||||
file.skipBytes(4);
|
||||
table_offset = new int[tables_count];
|
||||
// read the location of each table
|
||||
for (int i = 0; i < tables_count; i++) {
|
||||
table_offset[i] = readInt(file);
|
||||
}
|
||||
String directory = filename.split("\\.")[0];
|
||||
new File(directory).mkdir();
|
||||
// create the list of string tables used in the rebuild
|
||||
PrintStream filelist = new PrintStream(new FileOutputStream(new File(directory + "/filelist.txt")), true, "UTF-8");
|
||||
// save the name and size of the file
|
||||
filelist.println(filename + " " + file.length());
|
||||
for (int j = 0; j < tables_count; j++) {
|
||||
if(table_offset[j] == -1) {
|
||||
//System.out.println("Creating " + directory + "/string_table_" + j + ".txt (empty)");
|
||||
System.out.println("Can't create " + directory + "/string_table_" + j + ".txt (null table), skipping.");
|
||||
File f = new File(directory + "/string_table_" + j + ".txt");
|
||||
f.delete();
|
||||
//f.createNewFile();
|
||||
filelist.println("string_table_" + j + ".txt");
|
||||
continue;
|
||||
}
|
||||
file.seek(table_offset[j]);
|
||||
System.out.println("Creating " + directory + "/string_table_" + j + ".txt");
|
||||
PrintStream stringout = new PrintStream(new FileOutputStream(new File(directory + "/string_table_" + j + ".txt")), true, "UTF-8");
|
||||
filelist.println("string_table_" + j + ".txt");
|
||||
int offsetCounter = 0;
|
||||
// just skip the offset section (not needed)
|
||||
while (true) {
|
||||
offset = readInt(file);
|
||||
if (offset == -1) {
|
||||
break;
|
||||
}
|
||||
offsetCounter++;
|
||||
}
|
||||
int stringCounter = 0;
|
||||
while (stringCounter < offsetCounter) {
|
||||
String str = readString(file);
|
||||
if (str.length() == 1 && str.charAt(0) == 0) {
|
||||
// some offsets points to empty strings, so i put this
|
||||
// string to make
|
||||
// sure that it will created at the moment of repack
|
||||
stringout.println("<EMPTY STRING>");
|
||||
} else {
|
||||
str = str.substring(0, str.length() - 1);
|
||||
// need one string per line, so better replace the
|
||||
// newlines
|
||||
stringout.println(str.replaceAll("\n", "<NEWLINE>"));
|
||||
}
|
||||
stringCounter++;
|
||||
}
|
||||
// skip the end-byte mark
|
||||
file.skipBytes(1);
|
||||
stringout.close();
|
||||
}
|
||||
file.seek(file.getFilePointer() - 1);
|
||||
// calculate the size of the ending padding data and make a file of
|
||||
// it
|
||||
int size = (int) (file.length() - file.getFilePointer());
|
||||
paddingData = new byte[size];
|
||||
file.read(paddingData, 0, size);
|
||||
System.out.println("Creating " + directory + "/enddata.bin");
|
||||
RandomAccessFile end = new RandomAccessFile(directory + "/enddata.bin", "rw");
|
||||
filelist.println("enddata.bin");
|
||||
end.write(paddingData, 0, size);
|
||||
end.setLength(end.getFilePointer());
|
||||
end.close();
|
||||
file.close();
|
||||
filelist.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
147
src/dec/ExtractPluginB.java
Normal file
147
src/dec/ExtractPluginB.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G 53xx.bin language table extractor
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package dec;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Vector;
|
||||
|
||||
import base.Decoder;
|
||||
|
||||
/**
|
||||
* ExtractPluginB v1.0 - 53xx.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginB extends Decoder {
|
||||
|
||||
private int mhp3_skip_bytes;
|
||||
public ExtractPluginB(boolean newdec) {
|
||||
mhp3_skip_bytes = newdec ? 4 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
byte[] unknownData;
|
||||
Vector<Integer> table_offset;
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile(filename, "r");
|
||||
table_offset = new Vector<Integer>();
|
||||
int pointer;
|
||||
while (true) {
|
||||
pointer = readInt(file);
|
||||
if (pointer == 0) {
|
||||
break;
|
||||
}
|
||||
table_offset.add(pointer);
|
||||
}
|
||||
String directory = filename.split("\\.")[0];
|
||||
new File(directory).mkdir();
|
||||
PrintStream filelist = new PrintStream(new FileOutputStream(new File(directory + "/filelist.txt")), true, "UTF-8");
|
||||
filelist.println(filename + " " + file.length());
|
||||
for (int j = 0; j < table_offset.size(); j++) {
|
||||
file.seek(table_offset.get(j));
|
||||
System.out.println("Creating " + directory + "/string_table_" + j + ".txt");
|
||||
PrintStream stringout = new PrintStream(new FileOutputStream(new File(directory + "/string_table_" + j + ".txt")), true, "UTF-8");
|
||||
filelist.println("string_table_" + j + ".txt");
|
||||
// int unknown0 = readInt(file);
|
||||
// int payment = readInt(file);
|
||||
// int reward = readInt(file);
|
||||
// int decrease = readInt(file);
|
||||
// int unknown_fixed = readInt(file);
|
||||
file.skipBytes(20 + mhp3_skip_bytes);
|
||||
int offset_table_pointer = readInt(file);
|
||||
// int unknown1 = readInt(file);
|
||||
// int unknown2 = readInt(file);
|
||||
// int unknown3 = readInt(file);
|
||||
// int unknown4 = readInt(file);
|
||||
// int unknown5 = readInt(file);
|
||||
// int unknown6 = readInt(file);
|
||||
// int unknown7 = readInt(file);
|
||||
file.seek(offset_table_pointer);
|
||||
int string_table_pointers = readInt(file);
|
||||
for (long i = string_table_pointers; i < offset_table_pointer; i += 4) {
|
||||
file.seek(i);
|
||||
int current_string = readInt(file);
|
||||
file.seek(current_string);
|
||||
String str = readString(file);
|
||||
if (str.length() == 1 && str.charAt(0) == 0) {
|
||||
// some offsets points to empty strings, so i put this
|
||||
// string to make
|
||||
// sure that it will created at the moment of re-pack
|
||||
stringout.println("<EMPTY STRING>");
|
||||
} else {
|
||||
str = str.substring(0, str.length() - 1);
|
||||
// need one string per line, so better replace the
|
||||
// newlines
|
||||
stringout.println(str.replaceAll("\n", "<NEWLINE>"));
|
||||
}
|
||||
}
|
||||
stringout.close();
|
||||
file.seek(offset_table_pointer + 7 * 4);
|
||||
}
|
||||
// calculate the size of the ending unknown data and make a file of
|
||||
// it
|
||||
int size = (int) (file.length() - file.getFilePointer());
|
||||
unknownData = new byte[size];
|
||||
file.read(unknownData, 0, size);
|
||||
System.out.println("Creating " + directory + "/enddata.bin");
|
||||
RandomAccessFile end = new RandomAccessFile(directory + "/enddata.bin", "rw");
|
||||
filelist.println("enddata.bin");
|
||||
end.write(unknownData, 0, size);
|
||||
end.setLength(end.getFilePointer());
|
||||
end.close();
|
||||
file.close();
|
||||
filelist.close();
|
||||
System.out.println("Copying " + filename + " to " + directory + "/" + filename + " (needed for rebuild)");
|
||||
copyfile(filename, directory + "/" + filename);
|
||||
System.out.println("Finished!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyfile(String srFile, String dtFile) {
|
||||
try {
|
||||
File f1 = new File(srFile);
|
||||
File f2 = new File(dtFile);
|
||||
InputStream in = new FileInputStream(f1);
|
||||
OutputStream out = new FileOutputStream(f2);
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (FileNotFoundException ex) {
|
||||
System.out.println(ex.getMessage() + " in the specified directory.");
|
||||
System.exit(0);
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
117
src/dec/ExtractPluginC.java
Normal file
117
src/dec/ExtractPluginC.java
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* MHP2GDEC v1.0 - MHP2G 537x.bin language table extractor
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package dec;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Vector;
|
||||
|
||||
import base.Decoder;
|
||||
|
||||
/**
|
||||
* MHP2GDEC v1.0 - 537x.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginC extends Decoder {
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
Vector<Integer> offset_tables = new Vector<Integer>();
|
||||
Vector<Integer> unknown_values = new Vector<Integer>();
|
||||
try {
|
||||
RandomAccessFile file = new RandomAccessFile(filename, "r");
|
||||
while (true) {
|
||||
int unknown = readInt(file);
|
||||
int offset = readInt(file);
|
||||
if (unknown == -1 && offset == -1) {
|
||||
break;
|
||||
}
|
||||
unknown_values.add(unknown);
|
||||
offset_tables.add(offset);
|
||||
|
||||
}
|
||||
String directory = filename.split("\\.")[0];
|
||||
new File(directory).mkdir();
|
||||
// create the list of string tables used in the rebuild
|
||||
PrintStream filelist = new PrintStream(new FileOutputStream(new File(directory + "/filelist.txt")), true, "UTF-8");
|
||||
// save the name and size of the file
|
||||
filelist.println(filename + " " + file.length());
|
||||
int string_table_end = 0;
|
||||
;
|
||||
for (int j = 0; j < offset_tables.size(); j++) {
|
||||
file.seek(offset_tables.get(j));
|
||||
System.out.println("Creating " + directory + "/string_table_" + j + ".txt");
|
||||
PrintStream stringout = new PrintStream(new FileOutputStream(new File(directory + "/string_table_" + j + ".txt")), true, "UTF-8");
|
||||
filelist.println(unknown_values.get(j) + ",string_table_" + j + ".txt");
|
||||
int offset_table_start = (int) file.getFilePointer();
|
||||
int string_table_start = 0;
|
||||
boolean first = false;
|
||||
while (true) {
|
||||
int unknown = readInt(file);
|
||||
int offset = readInt(file);
|
||||
if (!first) {
|
||||
first = true;
|
||||
string_table_start = offset + offset_table_start;
|
||||
}
|
||||
int actual_offset = (int) file.getFilePointer();
|
||||
file.seek(offset + offset_table_start);
|
||||
String str = readString(file);
|
||||
string_table_end = (int) file.getFilePointer();
|
||||
file.seek(actual_offset);
|
||||
if (str.length() == 1 && str.charAt(0) == 0) {
|
||||
// some offsets points to empty strings, so i put this
|
||||
// string to make
|
||||
// sure that it will created at the moment of re-pack
|
||||
stringout.println(unknown + ",<EMPTY STRING>");
|
||||
} else {
|
||||
str = str.substring(0, str.length() - 1);
|
||||
// need one string per line, so better replace the
|
||||
// newlines
|
||||
stringout.println(unknown + ","
|
||||
+ str.replaceAll("\n", "<NEWLINE>"));
|
||||
}
|
||||
if (file.getFilePointer() >= string_table_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
stringout.close();
|
||||
}
|
||||
file.seek(string_table_end);
|
||||
// calculate the size of the ending unknown data and make a file of
|
||||
// it
|
||||
int size = (int) (file.length() - file.getFilePointer());
|
||||
byte[] unknownData = new byte[size];
|
||||
file.read(unknownData, 0, size);
|
||||
file.close();
|
||||
System.out.println("Creating " + directory + "/enddata.bin");
|
||||
RandomAccessFile end = new RandomAccessFile(directory + "/enddata.bin", "rw");
|
||||
filelist.println("enddata.bin");
|
||||
filelist.close();
|
||||
end.write(unknownData, 0, size);
|
||||
end.setLength(end.getFilePointer());
|
||||
end.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
194
src/enc/RebuildPluginA.java
Normal file
194
src/enc/RebuildPluginA.java
Normal file
|
@ -0,0 +1,194 @@
|
|||
/* MHP2GENC v1.0 - MHP 0016/475x/0017.bin language table rebuilder
|
||||
Copyright (C) 2008-2010 codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package enc;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
|
||||
/**
|
||||
* RebuildPluginA v2.0 - 0016/475x.bin language table rebuilder
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class RebuildPluginA extends Encoder {
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
try {
|
||||
BufferedReader files = new BufferedReader(new FileReader(filepath + "/filelist.txt"));
|
||||
String file = files.readLine();
|
||||
// retrieve the filename and size
|
||||
String filename = file.split(" ")[0];
|
||||
long size = Integer.parseInt(file.split(" ")[1]);
|
||||
// now make a list with the string tables files
|
||||
Vector<String> filenames = new Vector<String>();
|
||||
while ((file = files.readLine()) != null) {
|
||||
filenames.add(file);
|
||||
}
|
||||
files.close();
|
||||
RandomAccessFile out = new RandomAccessFile(filename + ".out", "rw");
|
||||
out.setLength(0);
|
||||
// write the first value (number of tables)
|
||||
writeInt(out, filenames.size() - 1);
|
||||
int offset = 0;
|
||||
offset += 8;
|
||||
// write the second value (unknown...or maybe offset to tables
|
||||
// offsets?)
|
||||
writeInt(out, offset);
|
||||
offset += (filenames.size() - 1) * 4;
|
||||
// write the first table offset (fixed value)
|
||||
writeInt(out, offset);
|
||||
long table_offset = out.getFilePointer();
|
||||
// first write empty offset values (we don't know the values...yet)
|
||||
for (int i = 1; i < filenames.size() - 1; i++) {
|
||||
writeInt(out, 0);
|
||||
}
|
||||
for (int i = 0; i < filenames.size() - 1; i++) {
|
||||
// now start to create each offset table / string table
|
||||
try {
|
||||
createStringTable(filepath, filenames.get(i), out);
|
||||
// write the end-table mark
|
||||
out.writeByte(0);
|
||||
if (i < filenames.size() - 2) {
|
||||
long current = out.getFilePointer();
|
||||
out.seek(table_offset);
|
||||
// now we know the value of the next table, so write above
|
||||
// in the main offset table
|
||||
writeInt(out, (int) current);
|
||||
out.seek(current);
|
||||
table_offset += 4;
|
||||
}
|
||||
}catch(FileNotFoundException e) {
|
||||
// New in MHP3: null tables
|
||||
System.out.println(filenames.get(i) + " not found, assuming null table pointer.");
|
||||
if (i < filenames.size() - 2) {
|
||||
long current = out.getFilePointer();
|
||||
out.seek(table_offset - 4);
|
||||
int last_offset = readInt(out);
|
||||
out.seek(table_offset - 4);
|
||||
writeInt(out, -1);
|
||||
out.seek(table_offset);
|
||||
writeInt(out, last_offset);
|
||||
out.seek(current);
|
||||
table_offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we need to know the size of the enddata, so open it now
|
||||
System.out.println("Reading " + filenames.lastElement());
|
||||
RandomAccessFile enddata = new RandomAccessFile(filepath + "/" + filenames.lastElement(), "rw");
|
||||
|
||||
long enddataSize = enddata.length();
|
||||
|
||||
// some checks to make sure that the file size of xxxx.bin is
|
||||
// correct
|
||||
if (out.getFilePointer() > size - enddataSize) {
|
||||
System.out.println("File too big (by " + (out.getFilePointer() - (size - enddataSize))+ " bytes), please reduce some strings :(");
|
||||
} else if (out.getFilePointer() < size - enddataSize) {
|
||||
System.out.println("File too small (by " + ((size - enddataSize) - out.getFilePointer())+ " bytes), filling with 0x00 (this is OK) :D");
|
||||
while (out.getFilePointer() < size - enddataSize) {
|
||||
out.writeByte(0);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Perfect size of file :O");
|
||||
}
|
||||
// now append the padding data at the end of file
|
||||
int data;
|
||||
while ((data = enddata.read()) != -1) {
|
||||
out.write((byte) data);
|
||||
}
|
||||
enddata.close();
|
||||
out.setLength(out.getFilePointer());
|
||||
out.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println(e.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param in
|
||||
* filename of text file
|
||||
* @param out
|
||||
* file to write the table
|
||||
* @throws FileNotFoundException
|
||||
* if the file is not found
|
||||
* @throws IOException
|
||||
* if any error occur while reading/writing
|
||||
*/
|
||||
public void createStringTable(String directory, String in, RandomAccessFile out) throws FileNotFoundException, IOException {
|
||||
System.out.println("Reading " + directory + "/" + in);
|
||||
RandomAccessFile file = new RandomAccessFile(directory + "/" + in, "r");
|
||||
if(file.length() == 0) {
|
||||
// new in MHP3: empty tables
|
||||
writeInt(out, -1);
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
checkUnicodeBOM(file); // thanks notepad :/ (who the hell uses notepad?)
|
||||
Vector<String> stringTable = new Vector<String>();
|
||||
try {
|
||||
while (true) {
|
||||
// read all strings of file
|
||||
String str = readString(file);
|
||||
if (str == null) {
|
||||
break;
|
||||
}
|
||||
// remove the labels and put the original data
|
||||
str = str.replaceAll("<NEWLINE>", "\n");
|
||||
str = str.replaceAll("<EMPTY STRING>", "\0");
|
||||
stringTable.add(str);
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
file.close();
|
||||
}
|
||||
int offset = stringTable.size() * 4;
|
||||
offset += 4;
|
||||
// now calculate the offsets using the length in bytes of the strings
|
||||
for (int i = 0; i < stringTable.size(); i++) {
|
||||
writeInt(out, offset);
|
||||
if (stringTable.elementAt(i).getBytes("UTF-8").length == 1 && stringTable.elementAt(i).charAt(0) == '\0') {
|
||||
offset++;
|
||||
} else {
|
||||
offset += stringTable.elementAt(i).getBytes("UTF-8").length + 1;
|
||||
}
|
||||
}
|
||||
// end of offset table mark
|
||||
writeInt(out, -1);
|
||||
// now write the zero terminated string in the file
|
||||
for (int i = 0; i < stringTable.size(); i++) {
|
||||
String str = stringTable.elementAt(i);
|
||||
if (str.equals("\0")) {
|
||||
out.writeByte(0);
|
||||
} else {
|
||||
out.write(str.getBytes("UTF-8"));
|
||||
out.writeByte(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
176
src/enc/RebuildPluginB.java
Normal file
176
src/enc/RebuildPluginB.java
Normal file
|
@ -0,0 +1,176 @@
|
|||
/* MHP2GENC v1.0 - MHP2G 53xx.bin language table rebuilder
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package enc;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
|
||||
/**
|
||||
* RebuildPluginB v1.0 - 53xx.bin language table rebuilder
|
||||
*
|
||||
* @author codestation
|
||||
*/
|
||||
public class RebuildPluginB extends Encoder {
|
||||
|
||||
private int encoder = 0;
|
||||
public RebuildPluginB(int type) {
|
||||
encoder = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
try {
|
||||
BufferedReader files = new BufferedReader(new FileReader(filepath + "/filelist.txt"));
|
||||
String file = files.readLine();
|
||||
// retrieve the filename and size
|
||||
String filename = file.split(" ")[0];
|
||||
// long size = Integer.parseInt(file.split(" ")[1]);
|
||||
// now make a list with the string tables files
|
||||
Vector<String> filenames = new Vector<String>();
|
||||
while ((file = files.readLine()) != null) {
|
||||
filenames.add(file);
|
||||
}
|
||||
files.close();
|
||||
copyfile(filepath + "/" + filename, filename + ".out");
|
||||
RandomAccessFile out = new RandomAccessFile(filename + ".out", "rw");
|
||||
Vector<Integer> table_offset = new Vector<Integer>();
|
||||
int pointer;
|
||||
while (true) {
|
||||
pointer = readInt(out);
|
||||
if (pointer == 0) {
|
||||
break;
|
||||
}
|
||||
table_offset.add(pointer);
|
||||
}
|
||||
for (int i = 0; i < table_offset.size(); i++) {
|
||||
patchStringTable(filepath, filenames.get(i), out, table_offset.get(i));
|
||||
}
|
||||
out.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println(e.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void patchStringTable(String directory, String in, RandomAccessFile out, int starting_offset) throws FileNotFoundException, IOException {
|
||||
System.out.println("Reading " + directory + "/" + in);
|
||||
RandomAccessFile file = new RandomAccessFile(directory + "/" + in, "r");
|
||||
checkUnicodeBOM(file); // thanks notepad :/ (die notepad, die)
|
||||
Vector<String> stringTable = new Vector<String>();
|
||||
try {
|
||||
while (true) {
|
||||
// read all strings of file
|
||||
String str = readString(file);
|
||||
if (str == null) {
|
||||
break;
|
||||
}
|
||||
// remove the labels and put the original data
|
||||
str = str.replaceAll("<NEWLINE>", "\n");
|
||||
str = str.replaceAll("<EMPTY STRING>", "\0");
|
||||
stringTable.add(str);
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
}
|
||||
file.close();
|
||||
out.seek(starting_offset);
|
||||
out.skipBytes(20 + encoder);
|
||||
int offset_table_pointer = readInt(out);
|
||||
int string_start = (int) out.getFilePointer() + 28;
|
||||
out.seek(offset_table_pointer);
|
||||
int string_table_pointers = readInt(out);
|
||||
int diff = string_table_pointers - string_start - calculateTotalSize(stringTable);
|
||||
if (diff < 0) {
|
||||
System.err.println(in + " is too big, please remove at least " + -diff + " bytes. Skipped");
|
||||
return;
|
||||
}
|
||||
out.seek(string_table_pointers);
|
||||
int starting_string = readInt(out);
|
||||
out.seek(starting_string);
|
||||
long orig_table_pointer = string_table_pointers;
|
||||
for (String str : stringTable) {
|
||||
out.write(str.getBytes("UTF-8"));
|
||||
out.writeByte(0);
|
||||
out.writeByte(0);
|
||||
while (out.getFilePointer() % 4 != 0) {
|
||||
out.writeByte(0);
|
||||
}
|
||||
int tmp = (int) out.getFilePointer();
|
||||
out.seek(string_table_pointers);
|
||||
writeInt(out, starting_string);
|
||||
string_table_pointers += 4;
|
||||
starting_string = tmp;
|
||||
out.seek(tmp);
|
||||
}
|
||||
long current_offset = out.getFilePointer();
|
||||
while (current_offset < orig_table_pointer) {
|
||||
out.writeByte(0);
|
||||
current_offset++;
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateTotalSize(Vector<String> st) throws UnsupportedEncodingException {
|
||||
int total = 0;
|
||||
for (String str : st) {
|
||||
int len = str.getBytes("UTF-8").length;
|
||||
|
||||
if (len == 1 && str.charAt(0) == 0) {
|
||||
total++;
|
||||
} else {
|
||||
total += len + 1;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private void copyfile(String srFile, String dtFile) {
|
||||
try {
|
||||
File f1 = new File(srFile);
|
||||
File f2 = new File(dtFile);
|
||||
InputStream in = new FileInputStream(f1);
|
||||
OutputStream out = new FileOutputStream(f2);
|
||||
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (FileNotFoundException ex) {
|
||||
System.out.println(ex.getMessage() + " in the specified directory.");
|
||||
System.exit(0);
|
||||
} catch (IOException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
176
src/enc/RebuildPluginC.java
Normal file
176
src/enc/RebuildPluginC.java
Normal file
|
@ -0,0 +1,176 @@
|
|||
/* MHP2GENC v1.0 - MHP2G 537x.bin language table rebuilder
|
||||
Copyright (C) 2008 Codestation
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package enc;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.EOFException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
|
||||
/**
|
||||
* RebuildPluginC v1.0 - 537x.bin language table rebuilder
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class RebuildPluginC extends Encoder {
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
try {
|
||||
BufferedReader files = new BufferedReader(new FileReader(filepath + "/filelist.txt"));
|
||||
String string_file = files.readLine();
|
||||
// retrieve the filename and size
|
||||
String filename = string_file.split(" ")[0];
|
||||
long size = Integer.parseInt(string_file.split(" ")[1]);
|
||||
// now make a list with the string tables files
|
||||
Vector<String> filenames = new Vector<String>();
|
||||
Vector<Integer> unknown = new Vector<Integer>();
|
||||
while ((string_file = files.readLine()) != null) {
|
||||
if (string_file.equals("enddata.bin")) {
|
||||
filenames.add(string_file);
|
||||
} else {
|
||||
filenames.add(string_file.split(",")[1]);
|
||||
unknown.add(Integer.parseInt(string_file.split(",")[0]));
|
||||
}
|
||||
}
|
||||
files.close();
|
||||
RandomAccessFile out = new RandomAccessFile(filename + ".out", "rw");
|
||||
writeInt(out, unknown.get(0));
|
||||
writeInt(out, (unknown.size() + 1) * 8);
|
||||
for (int i = 1; i < unknown.size(); i++) {
|
||||
writeInt(out, unknown.get(i));
|
||||
writeInt(out, 0);
|
||||
}
|
||||
writeInt(out, -1);
|
||||
writeInt(out, -1);
|
||||
int table_offset = 12;
|
||||
for (int i = 0; i < filenames.size() - 1; i++) {
|
||||
// now start to create each offset table / string table
|
||||
createStringTable(filepath, filenames.get(i), out);
|
||||
// write the end-table mark
|
||||
out.writeByte(0);
|
||||
if (i < filenames.size() - 2) {
|
||||
long current = out.getFilePointer();
|
||||
out.seek(table_offset);
|
||||
// now we know the value of the next table, so write above
|
||||
// in the main
|
||||
// offset table
|
||||
writeInt(out, (int) current);
|
||||
out.seek(current);
|
||||
table_offset += 8;
|
||||
out.seek(current);
|
||||
}
|
||||
}
|
||||
out.writeByte(0);
|
||||
// we need to know the size of the enddata, so open it now
|
||||
System.out.println("Reading " + filenames.lastElement());
|
||||
RandomAccessFile enddata = new RandomAccessFile(filepath + "/" + filenames.lastElement(), "rw");
|
||||
|
||||
long enddataSize = enddata.length();
|
||||
|
||||
// some checks to make sure that the file size of xxxx.bin is
|
||||
// correct
|
||||
if (out.getFilePointer() > size - enddataSize) {
|
||||
System.out.println("File too big (by " + (out.getFilePointer() - (size - enddataSize))+ " bytes), please reduce some strings :(");
|
||||
} else if (out.getFilePointer() < size - enddataSize) {
|
||||
System.out.println("File too small (by " + ((size - enddataSize) - out.getFilePointer())+ " bytes), filling with 0x00 (this is OK) :D");
|
||||
while (out.getFilePointer() < size - enddataSize) {
|
||||
out.writeByte(0);
|
||||
}
|
||||
} else {
|
||||
System.out.println("Perfect size of file :O");
|
||||
}
|
||||
// now append the unknown data at the end of file
|
||||
int data;
|
||||
while ((data = enddata.read()) != -1) {
|
||||
out.write((byte) data);
|
||||
}
|
||||
enddata.close();
|
||||
out.setLength(out.getFilePointer());
|
||||
out.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println(e.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param in
|
||||
* filename of text file
|
||||
* @param out
|
||||
* file to write the table
|
||||
* @throws FileNotFoundException
|
||||
* if the file is not found
|
||||
* @throws IOException
|
||||
* if any error occur while reading/writing
|
||||
*/
|
||||
private void createStringTable(String directory, String in, RandomAccessFile out) throws FileNotFoundException, IOException {
|
||||
System.out.println("Reading " + directory + "/" + in);
|
||||
RandomAccessFile file = new RandomAccessFile(directory + "/" + in, "r");
|
||||
checkUnicodeBOM(file); // thanks notepad :/ (*sigh*)
|
||||
Vector<String> stringTable = new Vector<String>();
|
||||
Vector<Integer> unknownTable = new Vector<Integer>();
|
||||
try {
|
||||
while (true) {
|
||||
// read all strings of file
|
||||
String str = readString(file);
|
||||
if (str == null) {
|
||||
break;
|
||||
}
|
||||
// remove the labels and put the original data
|
||||
unknownTable.add(Integer.parseInt(str.split(",")[0]));
|
||||
str = str.substring(str.indexOf(",") + 1);
|
||||
str = str.replaceAll("<NEWLINE>", "\n");
|
||||
str = str.replaceAll("<EMPTY STRING>", "\0");
|
||||
stringTable.add(str);
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
}
|
||||
file.close();
|
||||
int offset = stringTable.size() * 8;
|
||||
// now calculate the offsets using the length in bytes of the strings
|
||||
for (int i = 0; i < stringTable.size(); i++) {
|
||||
writeInt(out, unknownTable.get(i));
|
||||
writeInt(out, offset);
|
||||
if (stringTable.elementAt(i).getBytes("UTF-8").length == 1
|
||||
&& stringTable.elementAt(i).charAt(0) == '\0') {
|
||||
offset++;
|
||||
} else {
|
||||
offset += stringTable.elementAt(i).getBytes("UTF-8").length + 1;
|
||||
}
|
||||
}
|
||||
// now write the zero terminated string in the file
|
||||
for (int i = 0; i < stringTable.size(); i++) {
|
||||
String str = stringTable.elementAt(i);
|
||||
if (str.equals("\0")) {
|
||||
out.writeByte(0);
|
||||
} else {
|
||||
out.write(str.getBytes("UTF-8"));
|
||||
out.writeByte(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue