diff --git a/src/java/org/lwjgl/util/XPMFile.java b/src/java/org/lwjgl/util/XPMFile.java
index fb5b5a14..acb89508 100644
--- a/src/java/org/lwjgl/util/XPMFile.java
+++ b/src/java/org/lwjgl/util/XPMFile.java
@@ -1,12 +1,13 @@
package org.lwjgl.util;
+
import java.io.BufferedOutputStream;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.StringTokenizer;
@@ -15,169 +16,209 @@ import java.util.StringTokenizer;
*
* NOTE: This simple XPM reader does not support extensions nor hotspots
*
+ *
* @author Brian Matzon
+ * @author Jos Hirth
* @version $Revision$
*/
public class XPMFile {
/** Array of bytes (RGBA) */
- private byte bytes[] = null;
+ private byte bytes[] = null;
- /** Height of image */
- private int height = 0;
+ private final static int WIDTH = 0;
- /** Width of image */
- private int width = 0;
+ private final static int HEIGHT = 1;
- /*
- * Private constructor, use load(String filename)
+ private final static int NUMBER_OF_COLORS = 2;
+
+ private final static int CHARACTERS_PER_PIXEL = 3;
+
+ private static int[] format = new int[4];
+
+ /*
+ * Private constructor, use load(String filename)
*/
- private XPMFile() { }
-
+ private XPMFile() {
+ }
+
/**
- * Loads the XPM file
+ * Loads the XPM file
*
- * @param file path to file
- * @return XPMFile loaded, or exception
- * @throws IOException If any IO exceptions occurs while reading file
+ * @param file
+ * path to file
+ * @return XPMFile loaded, or exception
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
*/
public static XPMFile load(String file) throws IOException {
return load(new FileInputStream(new File(file)));
}
-
+
/**
- * Loads the XPM file
+ * Loads the XPM file
*
- * @param is InputStream to read file from
- * @return XPMFile loaded, or exception
- * @throws IOException If any IO exceptions occurs while reading file
+ * @param is
+ * InputStream to read file from
+ * @return XPMFile loaded, or exception
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
*/
public static XPMFile load(InputStream is) throws IOException {
XPMFile xFile = new XPMFile();
xFile.readImage(is);
return xFile;
- }
+ }
- /**
- * @return the height of the image.
+ /**
+ * @return the height of the image.
*/
public int getHeight() {
- return height;
+ return format[HEIGHT];
}
- /**
- * @return the width of the image.
+ /**
+ * @return the width of the image.
*/
public int getWidth() {
- return width;
+ return format[WIDTH];
}
- /**
- * @return The data of the image.
+ /**
+ * @return The data of the image.
*/
public byte[] getBytes() {
return bytes;
}
- /**
- * Read the image from the specified file.
+ /**
+ * Read the image from the specified file.
*
- * @throws IOException If any IO exceptions occurs while reading file
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
*/
private void readImage(InputStream is) throws IOException {
try {
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ LineNumberReader reader = new LineNumberReader(
+ new InputStreamReader(is));
HashMap colors = new HashMap();
-
- String comment = br.readLine();
- String typedef = br.readLine();
- int[] format = parseFormat(br.readLine());
-
+
+ format = parseFormat(nextLineOfInterest(reader));
+
// setup color mapping
- for (int i = 0; i < format[2]; i++) {
- Object[] colorDefinition = parseColor(br.readLine());
+ for (int i = 0; i < format[NUMBER_OF_COLORS]; i++) {
+ Object[] colorDefinition = parseColor(nextLineOfInterest(reader));
colors.put(colorDefinition[0], colorDefinition[1]);
}
-
+
// read actual image (convert to RGBA)
- bytes = new byte[format[0] * format[1] * 4];
- for (int i = 0; i < format[1]; i++) {
- parseImageLine(br.readLine(), format, colors, i);
+ bytes = new byte[format[WIDTH] * format[HEIGHT] * 4];
+ for (int i = 0; i < format[HEIGHT]; i++) {
+ parseImageLine(nextLineOfInterest(reader), format, colors, i);
}
} catch (Exception e) {
+ e.printStackTrace();
throw new IllegalArgumentException("Unable to parse XPM File");
}
}
+ /**
+ * Finds the next interesting line of text.
+ *
+ * @param reader
+ * The LineNumberReader to read from
+ * @return The next interesting String (with stripped quotes)
+ * @throws IOException
+ * If any IO exceptions occurs while reading file
+ */
+ private String nextLineOfInterest(LineNumberReader reader)
+ throws IOException {
+ String ret;
+ do {
+ ret = reader.readLine();
+ } while (!ret.startsWith("\""));
+ // lacks sanity check
+ return ret.substring(1, ret.lastIndexOf('\"'));
+ }
+
/**
* Parses the format of the xpm file given a format string
- *
- * @param format String to parse
+ *
+ * @param format
+ * String to parse
* @return Array specifying width, height, colors, characters per pixel
*/
private int[] parseFormat(String format) {
-
// format should look like this:
- // "16 16 122 2",
-
- // nuke first and last " and last ,
- format = format.substring(1, format.length() - 2);
+ // 16 16 122 2
// tokenize it
StringTokenizer st = new StringTokenizer(format);
- return new int[] {
- Integer.parseInt(st.nextToken()), /* width */
- Integer.parseInt(st.nextToken()), /* height */
- Integer.parseInt(st.nextToken()), /* colors */
- Integer.parseInt(st.nextToken()) /* chars per pixel */
+ return new int[] { Integer.parseInt(st.nextToken()), /* width */
+ Integer.parseInt(st.nextToken()), /* height */
+ Integer.parseInt(st.nextToken()), /* colors */
+ Integer.parseInt(st.nextToken()) /* chars per pixel */
};
}
/**
* Given a line defining a color/pixel, parses this into an array containing
* a key and a color
- * @param line Line to parse
+ *
+ * @param line
+ * Line to parse
* @return Array containing a key (String) and a color (Integer)
*/
private Object[] parseColor(String line) {
- // line should look like this
- // "# c #0A0A0A",
-
- // nuke first and last "
- line = line.substring(1, line.length() - 2);
+ // line should look like this:
+ // # c #0A0A0A
- String key = line.substring(0, 2);
- String type = line.substring(3, 4);
- String color = line.substring(6);
+ // NOTE: will break if the color is something like "black" or "gray50"
+ // etc (instead of #rrggbb).
+
+ String key = line.substring(0, format[CHARACTERS_PER_PIXEL]);
+ // since we always assume color as type we dont need to read it
+ // String type = line.substring(format[CHARACTERS_PER_PIXEL] + 1,
+ // format[CHARACTERS_PER_PIXEL] + 2);
+ String color = line.substring(format[CHARACTERS_PER_PIXEL] + 4);
// we always assume type is color, and supplied as #
- return new Object[] { key, new Integer(Integer.parseInt(color, 16))};
+ return new Object[] { key, new Integer(Integer.parseInt(color, 16)) };
}
/**
* Parses an Image line into its byte values
- * @param line Line of chars to parse
- * @param format Format to expext it in
- * @param colors Colors to lookup
- * @param index current index into lines, we've reached
+ *
+ * @param line
+ * Line of chars to parse
+ * @param format
+ * Format to expext it in
+ * @param colors
+ * Colors to lookup
+ * @param index
+ * current index into lines, we've reached
*/
- private void parseImageLine(String line, int[] format, HashMap colors, int index) {
+ private void parseImageLine(String line, int[] format, HashMap colors,
+ int index) {
// offset for next line
- int offset = index * 4 * format[0];
+ int offset = index * 4 * format[WIDTH];
- // nuke first "
- line = line.substring(1, line.length());
-
- // read format[3] characters format[0] times, each iteration is one color
- for (int i = 0; i < format[0]; i++) {
- String key = line.substring(i * 2, (i * 2 + 2));
+ // read characters times,
+ // each iteration equals one pixel
+ for (int i = 0; i < format[WIDTH]; i++) {
+ String key = line
+ .substring(
+ i * format[CHARACTERS_PER_PIXEL],
+ (i * format[CHARACTERS_PER_PIXEL] + format[CHARACTERS_PER_PIXEL]));
Integer color = (Integer) colors.get(key);
- bytes[offset + (i * 4) ] = (byte) ((color.intValue() & 0x00ff0000) >> 16);
- bytes[offset + ((i * 4) + 1)] = (byte) ((color.intValue() & 0x0000ff00) >> 8);
- bytes[offset + ((i * 4) + 2)] = (byte) ((color.intValue() & 0x000000ff) >> 0); // looks better :)
- bytes[offset + ((i * 4) + 3)] = (byte) 0xff; // always 0xff alpha
+ bytes[offset + (i * 4)] = (byte) ((color.intValue() & 0x00ff0000) >> 16);
+ bytes[offset + ((i * 4) + 1)] = (byte) ((color.intValue() & 0x0000ff00) >> 8);
+ bytes[offset + ((i * 4) + 2)] = (byte) ((color.intValue() & 0x000000ff) >> 0); // looks
+ // better
+ // :)
+ bytes[offset + ((i * 4) + 3)] = (byte) 0xff; // always 0xff alpha
}
}
@@ -192,16 +233,16 @@ public class XPMFile {
try {
String out = args[0].substring(0, args[0].indexOf(".")) + ".raw";
XPMFile file = XPMFile.load(args[0]);
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(out)));
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(new File(out)));
bos.write(file.getBytes());
bos.close();
- //showResult(file.getBytes());
+ // showResult(file.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
-
/*
private static void showResult(byte[] bytes) {
final BufferedImage i = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
@@ -232,4 +273,4 @@ public class XPMFile {
frame.setSize(100, 100);
frame.setVisible(true);
}*/
-}
+}
\ No newline at end of file