mirror of
https://github.com/codestation/mhtools
synced 2024-12-05 01:19:28 +00:00
Major code refactoring: moved read/write functions in their own
class (EndianFixed), converted Decoder/Encoder classes into interfaces. Added support for extract/rebuild TMH containers. Added jar manifest.
This commit is contained in:
parent
5452659d0c
commit
fce2d43421
17 changed files with 739 additions and 185 deletions
|
@ -1,8 +1,11 @@
|
|||
# translation_file, data_install_file, offset in the data install file where translation_file is found
|
||||
# Note: if you add files that doesn't exist in the data install just follow the
|
||||
# format of the 0098
|
||||
0017,0011,00204000
|
||||
0043,0011,00310800
|
||||
0045,0011,00316000
|
||||
0046,0011,0031A800
|
||||
0047,0011,0031F000
|
||||
0098,NONE,FFFFFFFF
|
||||
0222,0013,00143000
|
||||
2813,0031,00280800
|
||||
2814,0031,00284800
|
||||
2816,0031,002AE000
|
||||
|
@ -20,3 +23,4 @@
|
|||
3985,0032,00369000
|
||||
3986,0033,00000000
|
||||
3987,0033,00001000
|
||||
3992,0033,000CC000
|
||||
|
|
4
manifest.txt
Normal file
4
manifest.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
Manifest-Version: 1.0
|
||||
Sealed: true
|
||||
Main-Class: base.Mhtrans
|
||||
|
|
@ -17,73 +17,6 @@
|
|||
|
||||
package base;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class Decoder {
|
||||
|
||||
public interface 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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,108 +17,6 @@
|
|||
|
||||
package base;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class Encoder {
|
||||
|
||||
public interface 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);
|
||||
}
|
||||
}
|
||||
|
|
95
src/base/EndianFixer.java
Normal file
95
src/base/EndianFixer.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
/* MHTRANS v1.0
|
||||
Copyright (C) 2011 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.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public abstract class EndianFixer {
|
||||
|
||||
protected int readInt(InputStream 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 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 readShort(InputStream file) throws IOException, EOFException {
|
||||
int ch1 = file.read();
|
||||
int ch2 = file.read();
|
||||
if ((ch1 | ch2) < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (ch2 << 8) + (ch1 << 0);
|
||||
}
|
||||
|
||||
protected void writeShort(OutputStream file, int value) throws IOException {
|
||||
int ch1 = (byte) (value >>> 8);
|
||||
int ch2 = (byte) value;
|
||||
file.write(ch2);
|
||||
file.write(ch1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(OutputStream 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
53
src/base/HelperDec.java
Normal file
53
src/base/HelperDec.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* MHTRANS v1.0
|
||||
Copyright (C) 2011 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 HelperDec extends EndianFixer {
|
||||
/**
|
||||
* 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
|
||||
while (file.readByte() == 0) {
|
||||
;
|
||||
}
|
||||
file.seek(file.getFilePointer() - 1);
|
||||
} catch (EOFException e) {
|
||||
return null;
|
||||
}
|
||||
return new String(buffer, 0, counter, "UTF-8");
|
||||
}
|
||||
}
|
71
src/base/HelperEnc.java
Normal file
71
src/base/HelperEnc.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
/* MHTRANS v1.0
|
||||
Copyright (C) 2011 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 HelperEnc extends EndianFixer {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,9 +28,11 @@ import crypt.Encrypter;
|
|||
import dec.ExtractPluginA;
|
||||
import dec.ExtractPluginB;
|
||||
import dec.ExtractPluginC;
|
||||
import dec.ExtractPluginD;
|
||||
import enc.RebuildPluginA;
|
||||
import enc.RebuildPluginB;
|
||||
import enc.RebuildPluginC;
|
||||
import enc.RebuildPluginD;
|
||||
|
||||
public class Mhtrans {
|
||||
|
||||
|
@ -54,6 +56,9 @@ public class Mhtrans {
|
|||
case 3:
|
||||
dec = new ExtractPluginC();
|
||||
break;
|
||||
case 5:
|
||||
dec = new ExtractPluginD();
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unknown decoder: " + decoder);
|
||||
System.exit(1);
|
||||
|
@ -62,11 +67,14 @@ public class Mhtrans {
|
|||
}
|
||||
|
||||
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);
|
||||
if(type < 5) {
|
||||
String str = checkFile(filename + "/filelist.txt");
|
||||
if (str == null) {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case 1:
|
||||
enc = new RebuildPluginA();
|
||||
|
@ -80,6 +88,9 @@ public class Mhtrans {
|
|||
case 3:
|
||||
enc = new RebuildPluginC();
|
||||
break;
|
||||
case 5:
|
||||
enc = new RebuildPluginD();
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unknown encoder: " + encoder);
|
||||
System.exit(1);
|
||||
|
|
|
@ -24,13 +24,14 @@ import java.io.PrintStream;
|
|||
import java.io.RandomAccessFile;
|
||||
|
||||
import base.Decoder;
|
||||
import base.HelperDec;
|
||||
|
||||
/**
|
||||
* ExtractPluginA v1.0 - 0016//0017/475x.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginA extends Decoder {
|
||||
public class ExtractPluginA extends HelperDec implements Decoder {
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
|
|
|
@ -29,13 +29,14 @@ import java.io.RandomAccessFile;
|
|||
import java.util.Vector;
|
||||
|
||||
import base.Decoder;
|
||||
import base.HelperDec;
|
||||
|
||||
/**
|
||||
* ExtractPluginB v1.0 - 53xx.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginB extends Decoder {
|
||||
public class ExtractPluginB extends HelperDec implements Decoder {
|
||||
|
||||
private int mhp3_skip_bytes;
|
||||
|
||||
|
|
|
@ -25,13 +25,14 @@ import java.io.RandomAccessFile;
|
|||
import java.util.Vector;
|
||||
|
||||
import base.Decoder;
|
||||
import base.HelperDec;
|
||||
|
||||
/**
|
||||
* MHP2GDEC v1.0 - 537x.bin language table extractor
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginC extends Decoder {
|
||||
public class ExtractPluginC extends HelperDec implements Decoder {
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
|
|
91
src/dec/ExtractPluginD.java
Normal file
91
src/dec/ExtractPluginD.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* MHP2GDEC v1.0 - MH TMH image extractor
|
||||
Copyright (C) 2011 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 img.Gim;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import base.Decoder;
|
||||
import base.EndianFixer;
|
||||
|
||||
/**
|
||||
* ExtractPluginD v1.0
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class ExtractPluginD extends EndianFixer implements Decoder {
|
||||
|
||||
@Override
|
||||
public void extract(String filename) {
|
||||
try {
|
||||
FileInputStream file = new FileInputStream(filename);
|
||||
byte header_id[] = new byte[8];
|
||||
file.read(header_id);
|
||||
int header_gim_count = readInt(file);
|
||||
file.skip(4);
|
||||
//file.readInt(); //32 bit padding
|
||||
for(int i = 0; i < header_gim_count; i++) {
|
||||
Gim gim = new Gim();
|
||||
gim.load(file);
|
||||
int buffered_type = BufferedImage.TYPE_INT_ARGB;
|
||||
BufferedImage bi = new BufferedImage(gim.getWidth(), gim.getHeight(), buffered_type);
|
||||
bi.setRGB(0, 0, gim.getWidth(), gim.getHeight(), gim.getRGBarray(), 0, gim.getWidth());
|
||||
String directory = filename.split("\\.")[0];
|
||||
new File(directory).mkdir();
|
||||
String fileformat;
|
||||
String format;
|
||||
if(gim.getDataType() == Gim.GIM_TYPE_PALETTE)
|
||||
format = "palette";
|
||||
else if(gim.getDataType() == Gim.GIM_TYPE_PIXELS)
|
||||
format = "pixels";
|
||||
else
|
||||
format = "image";
|
||||
String palette;
|
||||
if(gim.getPaletteType() == Gim.RGBA8888) {
|
||||
palette = "RGBA8888";
|
||||
} else {
|
||||
palette = "RGBA5551";
|
||||
}
|
||||
if(gim.isSupported()) {
|
||||
fileformat = "png";
|
||||
String fileout = String.format(directory + "/%03d", i) + "_" + format + "_" + palette + "." + fileformat;
|
||||
System.out.println("Extracting " + fileout);
|
||||
File out = new File(fileout);
|
||||
out.delete();
|
||||
ImageIO.write(bi,fileformat, out);
|
||||
} else {
|
||||
fileformat = "gim";
|
||||
String fileout = String.format(directory + "/%03d", i) + "_" + format + "_" + palette + "." + fileformat;
|
||||
FileOutputStream out = new FileOutputStream(fileout);
|
||||
gim.write(out);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
System.out.println("Finished!");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,13 +26,14 @@ import java.io.RandomAccessFile;
|
|||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
import base.HelperEnc;
|
||||
|
||||
/**
|
||||
* RebuildPluginA v2.0 - 0016/475x.bin language table rebuilder
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class RebuildPluginA extends Encoder {
|
||||
public class RebuildPluginA extends HelperEnc implements Encoder {
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
|
|
|
@ -32,13 +32,14 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
import base.HelperEnc;
|
||||
|
||||
/**
|
||||
* RebuildPluginB v1.0 - 53xx.bin language table rebuilder
|
||||
*
|
||||
* @author codestation
|
||||
*/
|
||||
public class RebuildPluginB extends Encoder {
|
||||
public class RebuildPluginB extends HelperEnc implements Encoder {
|
||||
|
||||
private int encoder = 0;
|
||||
|
||||
|
|
|
@ -26,13 +26,14 @@ import java.io.RandomAccessFile;
|
|||
import java.util.Vector;
|
||||
|
||||
import base.Encoder;
|
||||
import base.HelperEnc;
|
||||
|
||||
/**
|
||||
* RebuildPluginC v1.0 - 537x.bin language table rebuilder
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class RebuildPluginC extends Encoder {
|
||||
public class RebuildPluginC extends HelperEnc implements Encoder {
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
|
@ -121,7 +122,6 @@ public class RebuildPluginC extends Encoder {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param in
|
||||
|
|
105
src/enc/RebuildPluginD.java
Normal file
105
src/enc/RebuildPluginD.java
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* MHP2GENC v1.0 - TMH image 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 img.Gim;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import base.Encoder;
|
||||
import base.EndianFixer;
|
||||
|
||||
/**
|
||||
* RebuildPluginD v1.0
|
||||
*
|
||||
* @author Codestation
|
||||
*/
|
||||
public class RebuildPluginD extends EndianFixer implements Encoder {
|
||||
|
||||
private byte id[] = {0x2e, 0x54, 0x4d, 0x48, 0x30, 0x2e, 0x31, 0x34};
|
||||
|
||||
@Override
|
||||
public void compile(String filepath) {
|
||||
try {
|
||||
File dir = new File(filepath);
|
||||
if(!dir.isDirectory()) {
|
||||
System.err.println("Isn't a directory: " + filepath);
|
||||
return;
|
||||
}
|
||||
File files[] = dir.listFiles();
|
||||
Arrays.sort(files, new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(File o1, File o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
});
|
||||
if(files.length > 0) {
|
||||
FileOutputStream out = new FileOutputStream(dir.getName() + ".bin");
|
||||
out.write(id);
|
||||
writeInt(out, files.length);
|
||||
writeInt(out, 0);
|
||||
for(File file : files) {
|
||||
System.out.println("Processing " + file.getName());
|
||||
Gim gim = new Gim();
|
||||
if(file.getName().endsWith(".gim")) {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
gim.load(in);
|
||||
in.close();
|
||||
} else {
|
||||
BufferedImage img = ImageIO.read(file);
|
||||
int[] rgbArray = new int[img.getWidth() * img.getHeight()];
|
||||
img.getRGB(0, 0, img.getWidth(), img.getHeight(), rgbArray, 0, img.getWidth());
|
||||
int type;
|
||||
if(file.getName().contains("palette"))
|
||||
type = Gim.GIM_TYPE_PALETTE;
|
||||
else if(file.getName().contains("pixels"))
|
||||
type = Gim.GIM_TYPE_PIXELS;
|
||||
else
|
||||
type = 0;
|
||||
int depth;
|
||||
if(file.getName().contains("RGBA8888"))
|
||||
depth = Gim.RGBA8888;
|
||||
else if(file.getName().contains("RGBA5551"))
|
||||
depth = Gim.RGBA5551;
|
||||
else
|
||||
depth = 0;
|
||||
gim.setRGBarray(img.getWidth(), img.getHeight(), rgbArray, type, depth);
|
||||
}
|
||||
gim.write(out);
|
||||
}
|
||||
out.close();
|
||||
} else {
|
||||
System.err.println("Empty directory\n");
|
||||
}
|
||||
System.out.println("Finished!");
|
||||
} catch (FileNotFoundException e) {
|
||||
System.out.println(e.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
284
src/img/Gim.java
Normal file
284
src/img/Gim.java
Normal file
|
@ -0,0 +1,284 @@
|
|||
package img;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import base.EndianFixer;
|
||||
|
||||
public class Gim extends EndianFixer {
|
||||
|
||||
public static final int RGBA8888 = 3;
|
||||
public static final int RGBA5551 = 1;
|
||||
public static final int GIM_TYPE_PIXELS = 4;
|
||||
public static final int GIM_TYPE_PALETTE = 5;
|
||||
public static final int HEADER_SIZE = 16;
|
||||
public static final int BPP32_BYTE = 4;
|
||||
public static final int BPP16_BYTE = 2;
|
||||
public static final int BPP32 = 32;
|
||||
public static final int BPP16 = 16;
|
||||
|
||||
private int size;
|
||||
private int flags[] = new int[3];
|
||||
private int data_size;
|
||||
private int data_flags;
|
||||
private int data_type;
|
||||
private int width;
|
||||
private int height;
|
||||
private byte imagedata[];
|
||||
private int palette_size;
|
||||
private int palette_flags;
|
||||
private int palette_type;
|
||||
private int palette_count;
|
||||
private byte palettedata[];
|
||||
private int palettedata_count = 0;
|
||||
private boolean loaded = false;
|
||||
|
||||
public void load(InputStream in) throws EOFException, IOException {
|
||||
size = readInt(in);
|
||||
flags[0] = readInt(in);
|
||||
flags[1] = readInt(in);
|
||||
flags[2] = readInt(in);
|
||||
data_size = readInt(in);
|
||||
data_flags = readInt(in);
|
||||
data_type = readInt(in);
|
||||
width = readShort(in);
|
||||
height = readShort(in);
|
||||
imagedata = new byte[data_size - 16];
|
||||
in.read(imagedata);
|
||||
palette_size = readInt(in);
|
||||
palette_flags = readInt(in);
|
||||
palette_type = readInt(in);
|
||||
palette_count = readInt(in);
|
||||
int palette_datasize = palette_count * (palette_type == RGBA8888 ? 4 : 2);
|
||||
palettedata = new byte[palette_datasize];
|
||||
in.read(palettedata);
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
public boolean setRGBarray(int width, int height, int rgb[], int data_type, int palette_type) {
|
||||
flags[0] = 0;
|
||||
flags[1] = 1;
|
||||
flags[2] = 1;
|
||||
data_size = HEADER_SIZE;
|
||||
data_flags = 1;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
palette_size = HEADER_SIZE;
|
||||
this.palette_type = palette_type;
|
||||
palette_flags = 2;
|
||||
this.data_type = data_type;
|
||||
if(data_type == GIM_TYPE_PIXELS) {
|
||||
int palettesize = 16 * (palette_type == RGBA8888 ? 4 : 2);
|
||||
palettedata = new byte[palettesize];
|
||||
data_size += (width / 2) * height;
|
||||
imagedata = new byte[data_size - HEADER_SIZE];
|
||||
palette_count = fill_to_palette(rgb);
|
||||
palette_count = 16;
|
||||
palette_size += palettesize;
|
||||
size = data_size + palette_size + HEADER_SIZE;
|
||||
} else if(data_type == GIM_TYPE_PALETTE) {
|
||||
int palettesize = 256 * (palette_type == RGBA8888 ? 4 : 2);
|
||||
palettedata = new byte[palettesize];
|
||||
data_size += width * height;
|
||||
imagedata = new byte[data_size - HEADER_SIZE];
|
||||
palette_count = fill_to_palette(rgb);
|
||||
palette_count = 256;
|
||||
palette_size += palettesize;
|
||||
size = data_size + palette_size + HEADER_SIZE;
|
||||
} else {
|
||||
loaded = false;
|
||||
return false;
|
||||
}
|
||||
loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int[]getRGBarray() {
|
||||
if(!loaded)
|
||||
return null;
|
||||
int dsx = width;
|
||||
int dsy = height;
|
||||
int mod = (data_type == GIM_TYPE_PALETTE ? BPP16 : BPP32);
|
||||
int colorsize = palette_type == RGBA8888 ? BPP32_BYTE : BPP16_BYTE;
|
||||
dsx /= mod;
|
||||
dsy /= 8;
|
||||
int counter = 0;
|
||||
int bitmapbuffer[] = new int[width * height];
|
||||
boolean flip = false;
|
||||
for (int sy = 0; sy < dsy; sy++) {
|
||||
for (int sx = 0; sx < dsx; sx++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < mod; x++) {
|
||||
int pos = (int)(imagedata[counter] & 0xFF);
|
||||
if(data_type == GIM_TYPE_PIXELS) {
|
||||
if(flip)
|
||||
pos = pos >> 4;
|
||||
else
|
||||
pos = pos & 0xF;
|
||||
}
|
||||
int off = (((sy * 8) + y) * width + ((sx * mod) + x));
|
||||
int rgb = get_color(pos * colorsize);
|
||||
bitmapbuffer[off] = rgb;
|
||||
if(data_type == GIM_TYPE_PIXELS) {
|
||||
if(flip) {
|
||||
counter++;
|
||||
flip = false;
|
||||
} else {
|
||||
flip = true;
|
||||
}
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmapbuffer;
|
||||
}
|
||||
|
||||
public boolean write(OutputStream out)throws IOException {
|
||||
if(!loaded)
|
||||
return false;
|
||||
writeInt(out, size);
|
||||
writeInt(out, flags[0]);
|
||||
writeInt(out, flags[1]);
|
||||
writeInt(out, flags[2]);
|
||||
writeInt(out, data_size);
|
||||
writeInt(out, data_flags);
|
||||
writeInt(out, data_type);
|
||||
writeShort(out, width);
|
||||
writeShort(out, height);
|
||||
out.write(imagedata);
|
||||
writeInt(out, palette_size);
|
||||
writeInt(out, palette_flags);
|
||||
writeInt(out, palette_type);
|
||||
writeInt(out, palette_count);
|
||||
out.write(palettedata);
|
||||
return true;
|
||||
}
|
||||
|
||||
private int fill_to_palette(int rgb[]) {
|
||||
int mod = (data_type == GIM_TYPE_PALETTE ? BPP16 : BPP32);
|
||||
int dsx = width / mod;
|
||||
int dsy = height / 8;
|
||||
boolean flip = false;
|
||||
int counter = 0;
|
||||
palettedata_count = 0;
|
||||
for (int sy = 0; sy < dsy; sy++) {
|
||||
for (int sx = 0; sx < dsx; sx++) {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < mod; x++) {
|
||||
int off = (((sy * 8) + y) * width + ((sx * mod) + x));
|
||||
if(data_type == GIM_TYPE_PALETTE && palettedata_count > 256 ||
|
||||
data_type == GIM_TYPE_PIXELS && palettedata_count > 16) {
|
||||
return 0;
|
||||
}
|
||||
int color = rgb[off];
|
||||
int index = set_unique_color(color);
|
||||
if(data_type == GIM_TYPE_PIXELS) {
|
||||
if(flip) {
|
||||
imagedata[counter] |= (byte) (index << 4);
|
||||
counter++;
|
||||
flip = false;
|
||||
} else {
|
||||
imagedata[counter] = (byte) (index & 0xF);
|
||||
flip = true;
|
||||
}
|
||||
} else {
|
||||
imagedata[counter] = (byte) index;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return palette_count;
|
||||
}
|
||||
|
||||
private void set_color(int color, int offset) {
|
||||
int A = (color >> 24) & 0xFF;
|
||||
int R = (color >> 16) & 0xFF;
|
||||
int G = (color >> 8) & 0xFF;
|
||||
int B = color & 0xFF;
|
||||
if(palette_type == RGBA8888) {
|
||||
palettedata[offset + 2] = (byte) B;
|
||||
palettedata[offset + 1] = (byte) G;
|
||||
palettedata[offset + 0] = (byte) R;
|
||||
palettedata[offset + 3] = (byte) A;
|
||||
} else {
|
||||
A = A == 0 ? 0 : 1;
|
||||
R = R >> 3;
|
||||
G = G >> 3;
|
||||
B = B >> 3;
|
||||
color = R;
|
||||
color |= G << 5;
|
||||
color |= B << 10;
|
||||
color |= A << 15;
|
||||
palettedata[offset+1] = (byte) (color >> 8 & 0xFF);
|
||||
palettedata[offset+0] = (byte) (color & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
private int set_unique_color(int color) {
|
||||
int i = 0;
|
||||
while(i < palettedata_count) {
|
||||
if(color == get_color(i * (palette_type == RGBA8888 ? 4 : 2))) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
set_color(color, i * (palette_type == RGBA8888 ? 4 : 2));
|
||||
palettedata_count = i + 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
private int get_color(int offset) {
|
||||
int A, R, G, B;
|
||||
if(palette_type == RGBA8888) {
|
||||
B = (int)palettedata[offset + 2] & 0xFF;
|
||||
G = (int)palettedata[offset + 1] & 0xFF;
|
||||
R = (int)palettedata[offset + 0] & 0xFF;
|
||||
A = (int)palettedata[offset + 3] & 0xFF;
|
||||
} else {
|
||||
int color = (((int)(palettedata[offset+1]) << 8) & 0xFF00);
|
||||
color |=((int)(palettedata[offset]) & 0xFF);
|
||||
R = color & 0x1F;
|
||||
G = (color >> 5) & 0x1F;
|
||||
B = (color >> 10) & 0x1F;
|
||||
A = (color >> 15) & 0x1;
|
||||
R = (R << 3) | (R >> 2);
|
||||
G = (G << 3) | (G >> 2);
|
||||
B = (B << 3) | (B >> 2);
|
||||
A = A == 0 ? 0 : 255;
|
||||
}
|
||||
int res = ((A << 24) + (R << 16) + (G << 8) + B);
|
||||
return res;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public int getDataType() {
|
||||
return data_type;
|
||||
}
|
||||
|
||||
public int getPaletteType() {
|
||||
return palette_type;
|
||||
}
|
||||
|
||||
public int getPaletteCount() {
|
||||
return palette_count;
|
||||
}
|
||||
|
||||
public boolean isSupported() {
|
||||
return (data_type == GIM_TYPE_PIXELS && palette_count <=16) ||
|
||||
(data_type == GIM_TYPE_PALETTE && palette_count <= 256);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue