TMI-TIFF: Now uses String class instead of byte[], to avoid excessive array concatenation and copying.

This commit is contained in:
Harald Kuhr 2013-01-29 22:26:11 +01:00
parent dd849aeea6
commit e68b3aa9e3

View File

@ -33,7 +33,6 @@ import com.twelvemonkeys.io.enc.Decoder;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Arrays;
/** /**
* LZWDecoder * LZWDecoder
@ -53,8 +52,7 @@ abstract class LZWDecoder implements Decoder {
private final boolean compatibilityMode; private final boolean compatibilityMode;
private final byte[][] table; private final String[] table;
// private final Entry[] tableToo = new Entry[4096 + 1024];
private int tableLength; private int tableLength;
int bitsPerCode; int bitsPerCode;
private int oldCode = CLEAR_CODE; private int oldCode = CLEAR_CODE;
@ -69,16 +67,12 @@ abstract class LZWDecoder implements Decoder {
protected LZWDecoder(final boolean compatibilityMode) { protected LZWDecoder(final boolean compatibilityMode) {
this.compatibilityMode = compatibilityMode; this.compatibilityMode = compatibilityMode;
table = new byte[compatibilityMode ? 4096 + 1024 : 4096][0]; // libTiff adds another 1024 "for compatibility"... table = new String[compatibilityMode ? 4096 + 1024 : 4096]; // libTiff adds another 1024 "for compatibility"...
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
table[i] = new byte[] {(byte) i}; table[i] = new String((byte) i);
} }
// for (int i = 0; i < 256; i++) {
// tableToo[i] = new Entry((byte) i);
// }
//
init(); init();
} }
@ -109,17 +103,17 @@ abstract class LZWDecoder implements Decoder {
break; break;
} }
bufferPos += writeString(table[code], buffer, bufferPos); bufferPos += table[code].writeTo(buffer, bufferPos);
} }
else { else {
if (isInTable(code)) { if (isInTable(code)) {
bufferPos += writeString(table[code], buffer, bufferPos); bufferPos += table[code].writeTo(buffer, bufferPos);
addStringToTable(concatenate(table[oldCode], table[code][0])); addStringToTable(table[oldCode].concatenate(table[code].firstChar));
} }
else { else {
byte[] outString = concatenate(table[oldCode], table[oldCode][0]); String outString = table[oldCode].concatenate(table[oldCode].firstChar);
bufferPos += writeString(outString, buffer, bufferPos); bufferPos += outString.writeTo(buffer, bufferPos);
addStringToTable(outString); addStringToTable(outString);
} }
} }
@ -135,14 +129,7 @@ abstract class LZWDecoder implements Decoder {
return bufferPos; return bufferPos;
} }
private static byte[] concatenate(final byte[] string, final byte firstChar) { private void addStringToTable(final String string) throws IOException {
byte[] result = Arrays.copyOf(string, string.length + 1);
result[string.length] = firstChar;
return result;
}
private void addStringToTable(final byte[] string) throws IOException {
table[tableLength++] = string; table[tableLength++] = string;
if (tableLength > maxCode) { if (tableLength > maxCode) {
@ -153,7 +140,7 @@ abstract class LZWDecoder implements Decoder {
bitsPerCode--; bitsPerCode--;
} }
else { else {
throw new DecodeException(String.format("TIFF LZW with more than %d bits per code encountered (table overflow)", MAX_BITS)); throw new DecodeException(java.lang.String.format("TIFF LZW with more than %d bits per code encountered (table overflow)", MAX_BITS));
} }
} }
@ -168,22 +155,6 @@ abstract class LZWDecoder implements Decoder {
protected abstract int maxCode(); protected abstract int maxCode();
private static int writeString(final byte[] string, final byte[] buffer, final int bufferPos) {
if (string.length == 0) {
return 0;
}
else if (string.length == 1) {
buffer[bufferPos] = string[0];
return 1;
}
else {
System.arraycopy(string, 0, buffer, bufferPos, string.length);
return string.length;
}
}
private boolean isInTable(int code) { private boolean isInTable(int code) {
return code < tableLength; return code < tableLength;
} }
@ -302,22 +273,47 @@ abstract class LZWDecoder implements Decoder {
} }
} }
private class Entry { private static final class String {
final Entry next; final String previous;
final int length; final int length;
final byte value; final byte value;
final byte firstChar; final byte firstChar; // Copied forward for fast access
public Entry(byte code) { public String(final byte code) {
this(code, code, 1, null); this(code, code, 1, null);
} }
public Entry(byte value, byte firstChar, int length, Entry next) { private String(final byte value, final byte firstChar, final int length, final String previous) {
this.length = length;
this.value = value; this.value = value;
this.firstChar = firstChar; this.firstChar = firstChar;
this.next = next; this.length = length;
this.previous = previous;
}
public final String concatenate(final byte firstChar) {
return new String(firstChar, this.firstChar, length + 1, this);
}
public final int writeTo(final byte[] buffer, final int offset) {
if (length == 0) {
return 0;
}
else if (length == 1) {
buffer[offset] = value;
return 1;
}
else {
String e = this;
for (int i = length - 1; i >= 0; i--) {
buffer[offset + i] = e.value;
e = e.previous;
}
return length;
}
} }
} }
} }