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:
codestation 2011-01-17 06:15:19 +00:00
parent 5452659d0c
commit fce2d43421
17 changed files with 739 additions and 185 deletions

View file

@ -1,8 +1,11 @@
# translation_file, data_install_file, offset in the data install file where translation_file is found # 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 0017,0011,00204000
0043,0011,00310800
0045,0011,00316000
0046,0011,0031A800
0047,0011,0031F000
0098,NONE,FFFFFFFF 0098,NONE,FFFFFFFF
0222,0013,00143000
2813,0031,00280800 2813,0031,00280800
2814,0031,00284800 2814,0031,00284800
2816,0031,002AE000 2816,0031,002AE000
@ -20,3 +23,4 @@
3985,0032,00369000 3985,0032,00369000
3986,0033,00000000 3986,0033,00000000
3987,0033,00001000 3987,0033,00001000
3992,0033,000CC000

4
manifest.txt Normal file
View file

@ -0,0 +1,4 @@
Manifest-Version: 1.0
Sealed: true
Main-Class: base.Mhtrans

View file

@ -17,73 +17,6 @@
package base; package base;
import java.io.EOFException; public interface Decoder {
import java.io.IOException;
import java.io.RandomAccessFile;
public abstract class Decoder {
public abstract void extract(String filename); 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");
}
} }

View file

@ -17,108 +17,6 @@
package base; package base;
import java.io.EOFException; public interface Encoder {
import java.io.IOException; public abstract void compile(String filelist);
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);
}
} }

95
src/base/EndianFixer.java Normal file
View 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
View 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
View 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);
}
}
}

View file

@ -28,9 +28,11 @@ import crypt.Encrypter;
import dec.ExtractPluginA; import dec.ExtractPluginA;
import dec.ExtractPluginB; import dec.ExtractPluginB;
import dec.ExtractPluginC; import dec.ExtractPluginC;
import dec.ExtractPluginD;
import enc.RebuildPluginA; import enc.RebuildPluginA;
import enc.RebuildPluginB; import enc.RebuildPluginB;
import enc.RebuildPluginC; import enc.RebuildPluginC;
import enc.RebuildPluginD;
public class Mhtrans { public class Mhtrans {
@ -54,6 +56,9 @@ public class Mhtrans {
case 3: case 3:
dec = new ExtractPluginC(); dec = new ExtractPluginC();
break; break;
case 5:
dec = new ExtractPluginD();
break;
default: default:
System.err.println("Unknown decoder: " + decoder); System.err.println("Unknown decoder: " + decoder);
System.exit(1); System.exit(1);
@ -62,11 +67,14 @@ public class Mhtrans {
} }
public static void rebuild(String filename, String encoder) { public static void rebuild(String filename, String encoder) {
String str = checkFile(filename + "/filelist.txt");
Encoder enc = null; Encoder enc = null;
if (str == null)
System.exit(1);
int type = Integer.parseInt(encoder); int type = Integer.parseInt(encoder);
if(type < 5) {
String str = checkFile(filename + "/filelist.txt");
if (str == null) {
System.exit(1);
}
}
switch (type) { switch (type) {
case 1: case 1:
enc = new RebuildPluginA(); enc = new RebuildPluginA();
@ -80,6 +88,9 @@ public class Mhtrans {
case 3: case 3:
enc = new RebuildPluginC(); enc = new RebuildPluginC();
break; break;
case 5:
enc = new RebuildPluginD();
break;
default: default:
System.err.println("Unknown encoder: " + encoder); System.err.println("Unknown encoder: " + encoder);
System.exit(1); System.exit(1);

View file

@ -24,13 +24,14 @@ import java.io.PrintStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import base.Decoder; import base.Decoder;
import base.HelperDec;
/** /**
* ExtractPluginA v1.0 - 0016//0017/475x.bin language table extractor * ExtractPluginA v1.0 - 0016//0017/475x.bin language table extractor
* *
* @author Codestation * @author Codestation
*/ */
public class ExtractPluginA extends Decoder { public class ExtractPluginA extends HelperDec implements Decoder {
@Override @Override
public void extract(String filename) { public void extract(String filename) {

View file

@ -29,13 +29,14 @@ import java.io.RandomAccessFile;
import java.util.Vector; import java.util.Vector;
import base.Decoder; import base.Decoder;
import base.HelperDec;
/** /**
* ExtractPluginB v1.0 - 53xx.bin language table extractor * ExtractPluginB v1.0 - 53xx.bin language table extractor
* *
* @author Codestation * @author Codestation
*/ */
public class ExtractPluginB extends Decoder { public class ExtractPluginB extends HelperDec implements Decoder {
private int mhp3_skip_bytes; private int mhp3_skip_bytes;
@ -48,7 +49,7 @@ public class ExtractPluginB extends Decoder {
byte[] unknownData; byte[] unknownData;
Vector<Integer> table_offset; Vector<Integer> table_offset;
try { try {
RandomAccessFile file = new RandomAccessFile(filename, "r"); RandomAccessFile file = new RandomAccessFile(filename,"r");
table_offset = new Vector<Integer>(); table_offset = new Vector<Integer>();
int pointer; int pointer;
while (true) { while (true) {

View file

@ -25,13 +25,14 @@ import java.io.RandomAccessFile;
import java.util.Vector; import java.util.Vector;
import base.Decoder; import base.Decoder;
import base.HelperDec;
/** /**
* MHP2GDEC v1.0 - 537x.bin language table extractor * MHP2GDEC v1.0 - 537x.bin language table extractor
* *
* @author Codestation * @author Codestation
*/ */
public class ExtractPluginC extends Decoder { public class ExtractPluginC extends HelperDec implements Decoder {
@Override @Override
public void extract(String filename) { public void extract(String filename) {

View 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();
}
}
}

View file

@ -26,13 +26,14 @@ import java.io.RandomAccessFile;
import java.util.Vector; import java.util.Vector;
import base.Encoder; import base.Encoder;
import base.HelperEnc;
/** /**
* RebuildPluginA v2.0 - 0016/475x.bin language table rebuilder * RebuildPluginA v2.0 - 0016/475x.bin language table rebuilder
* *
* @author Codestation * @author Codestation
*/ */
public class RebuildPluginA extends Encoder { public class RebuildPluginA extends HelperEnc implements Encoder {
@Override @Override
public void compile(String filepath) { public void compile(String filepath) {

View file

@ -32,13 +32,14 @@ import java.io.UnsupportedEncodingException;
import java.util.Vector; import java.util.Vector;
import base.Encoder; import base.Encoder;
import base.HelperEnc;
/** /**
* RebuildPluginB v1.0 - 53xx.bin language table rebuilder * RebuildPluginB v1.0 - 53xx.bin language table rebuilder
* *
* @author codestation * @author codestation
*/ */
public class RebuildPluginB extends Encoder { public class RebuildPluginB extends HelperEnc implements Encoder {
private int encoder = 0; private int encoder = 0;

View file

@ -26,13 +26,14 @@ import java.io.RandomAccessFile;
import java.util.Vector; import java.util.Vector;
import base.Encoder; import base.Encoder;
import base.HelperEnc;
/** /**
* RebuildPluginC v1.0 - 537x.bin language table rebuilder * RebuildPluginC v1.0 - 537x.bin language table rebuilder
* *
* @author Codestation * @author Codestation
*/ */
public class RebuildPluginC extends Encoder { public class RebuildPluginC extends HelperEnc implements Encoder {
@Override @Override
public void compile(String filepath) { public void compile(String filepath) {
@ -121,7 +122,6 @@ public class RebuildPluginC extends Encoder {
e.printStackTrace(); e.printStackTrace();
} }
} }
/** /**
* *
* @param in * @param in

105
src/enc/RebuildPluginD.java Normal file
View 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
View 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);
}
}