Some updates and changes to support some work on https://issues.apache.org/jira/browse/AMQ-3467

Cleanup some code in the DataByteArrayOutputStream and fix an issue in the readUTF 
code that code result in a UTFDataFormatException to be thrown for no reason.

Adds some tests for those classes as well.

git-svn-id: https://svn.apache.org/repos/asf/activemq/trunk@1172600 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Timothy A. Bish 2011-09-19 12:46:38 +00:00
parent a36e618f71
commit 199c6838d4
5 changed files with 252 additions and 103 deletions

View File

@ -32,6 +32,8 @@ public final class DataByteArrayInputStream extends InputStream implements DataI
private int offset; private int offset;
private int length; private int length;
private byte[] work;
/** /**
* Creates a <code>StoreByteArrayInputStream</code>. * Creates a <code>StoreByteArrayInputStream</code>.
* *
@ -42,6 +44,7 @@ public final class DataByteArrayInputStream extends InputStream implements DataI
this.pos = 0; this.pos = 0;
this.offset = 0; this.offset = 0;
this.length = buf.length; this.length = buf.length;
this.work = new byte[8];
} }
/** /**
@ -54,6 +57,7 @@ public final class DataByteArrayInputStream extends InputStream implements DataI
this.offset = sequence.getOffset(); this.offset = sequence.getOffset();
this.pos = this.offset; this.pos = this.offset;
this.length = sequence.length; this.length = sequence.length;
this.work = new byte[8];
} }
/** /**
@ -204,34 +208,35 @@ public final class DataByteArrayInputStream extends InputStream implements DataI
} }
public short readShort() { public short readShort() {
int ch1 = read(); this.read(work, 0, 2);
int ch2 = read(); return (short) (((work[0] & 0xff) << 8) | (work[1] & 0xff));
return (short)((ch1 << 8) + (ch2 << 0));
} }
public int readUnsignedShort() { public int readUnsignedShort() {
int ch1 = read(); this.read(work, 0, 2);
int ch2 = read(); return (int) (((work[0] & 0xff) << 8) | (work[1] & 0xff));
return (ch1 << 8) + (ch2 << 0);
} }
public char readChar() { public char readChar() {
int ch1 = read(); this.read(work, 0, 2);
int ch2 = read(); return (char) (((work[0] & 0xff) << 8) | (work[1] & 0xff));
return (char)((ch1 << 8) + (ch2 << 0));
} }
public int readInt() { public int readInt() {
int ch1 = read(); this.read(work, 0, 4);
int ch2 = read(); return ((work[0] & 0xff) << 24) | ((work[1] & 0xff) << 16) |
int ch3 = read(); ((work[2] & 0xff) << 8) | (work[3] & 0xff);
int ch4 = read();
return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0);
} }
public long readLong() { public long readLong() {
long rc = ((long)buf[pos++] << 56) + ((long)(buf[pos++] & 255) << 48) + ((long)(buf[pos++] & 255) << 40) + ((long)(buf[pos++] & 255) << 32); this.read(work, 0, 8);
return rc + ((long)(buf[pos++] & 255) << 24) + ((buf[pos++] & 255) << 16) + ((buf[pos++] & 255) << 8) + ((buf[pos++] & 255) << 0);
int i1 = ((work[0] & 0xff) << 24) | ((work[1] & 0xff) << 16) |
((work[2] & 0xff) << 8) | (work[3] & 0xff);
int i2 = ((work[4] & 0xff) << 24) | ((work[5] & 0xff) << 16) |
((work[6] & 0xff) << 8) | (work[7] & 0xff);
return ((i1 & 0xffffffffL) << 32) | (i2 & 0xffffffffL);
} }
public float readFloat() throws IOException { public float readFloat() throws IOException {
@ -262,59 +267,32 @@ public final class DataByteArrayInputStream extends InputStream implements DataI
public String readUTF() throws IOException { public String readUTF() throws IOException {
int length = readUnsignedShort(); int length = readUnsignedShort();
int endPos = pos + length;
int count = 0, a;
char[] characters = new char[length]; char[] characters = new char[length];
int c; while (pos < endPos) {
int c2; if ((characters[count] = (char) buf[pos++]) < '\u0080')
int c3; count++;
int count = 0; else if (((a = characters[count]) & 0xE0) == 0xC0) {
int total = pos + length; if (pos >= endPos) {
while (pos < total) {
c = (int)buf[pos] & 0xff;
if (c > 127) {
break;
}
pos++;
characters[count++] = (char)c;
}
while (pos < total) {
c = (int)buf[pos] & 0xff;
switch (c >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
pos++;
characters[count++] = (char)c;
break;
case 12:
case 13:
pos += 2;
if (pos > length) {
throw new UTFDataFormatException("bad string"); throw new UTFDataFormatException("bad string");
} }
c2 = (int)buf[pos - 1]; int b = buf[pos++];
if ((c2 & 0xC0) != 0x80) { if ((b & 0xC0) != 0x80) {
throw new UTFDataFormatException("bad string"); throw new UTFDataFormatException("bad string");
} }
characters[count++] = (char)(((c & 0x1F) << 6) | (c2 & 0x3F)); characters[count++] = (char) (((a & 0x1F) << 6) | (b & 0x3F));
break; } else if ((a & 0xf0) == 0xe0) {
case 14: if (pos + 1 >= endPos) {
pos += 3;
if (pos > length) {
throw new UTFDataFormatException("bad string"); throw new UTFDataFormatException("bad string");
} }
c2 = (int)buf[pos - 2]; int b = buf[pos++];
c3 = (int)buf[pos - 1]; int c = buf[pos++];
if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) { if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) {
throw new UTFDataFormatException("bad string"); throw new UTFDataFormatException("bad string");
} }
characters[count++] = (char)(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0)); characters[count++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F));
break; } else {
default:
throw new UTFDataFormatException("bad string"); throw new UTFDataFormatException("bad string");
} }
} }

View File

@ -21,13 +21,15 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UTFDataFormatException; import java.io.UTFDataFormatException;
import org.apache.kahadb.page.PageFile;
/** /**
* Optimized ByteArrayOutputStream * Optimized ByteArrayOutputStream
* *
* *
*/ */
public class DataByteArrayOutputStream extends OutputStream implements DataOutput { public class DataByteArrayOutputStream extends OutputStream implements DataOutput {
private static final int DEFAULT_SIZE = 2048; private static final int DEFAULT_SIZE = PageFile.DEFAULT_PAGE_SIZE;
protected byte buf[]; protected byte buf[];
protected int pos; protected int pos;
@ -233,26 +235,18 @@ public class DataByteArrayOutputStream extends OutputStream implements DataOutpu
} }
ensureEnoughBuffer(pos + encodedsize + 2); ensureEnoughBuffer(pos + encodedsize + 2);
writeShort(encodedsize); writeShort(encodedsize);
int i = 0; for (int i = 0; i < strlen; i++) {
for (i = 0; i < strlen; i++) { int charValue = str.charAt(i);
c = str.charAt(i); if (charValue > 0 && charValue <= 127) {
if (!((c >= 0x0001) && (c <= 0x007F))) { buf[pos++] = (byte) charValue;
break; } else if (charValue <= 2047) {
} buf[pos++] = (byte) (0xc0 | (0x1f & (charValue >> 6)));
buf[pos++] = (byte)c; buf[pos++] = (byte) (0x80 | (0x3f & charValue));
}
for (; i < strlen; i++) {
c = str.charAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
buf[pos++] = (byte)c;
} else if (c > 0x07FF) {
buf[pos++] = (byte)(0xE0 | ((c >> 12) & 0x0F));
buf[pos++] = (byte)(0x80 | ((c >> 6) & 0x3F));
buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F));
} else { } else {
buf[pos++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); buf[pos++] = (byte) (0xe0 | (0x0f & (charValue >> 12)));
buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F)); buf[pos++] = (byte) (0x80 | (0x3f & (charValue >> 6)));
} buf[pos++] = (byte) (0x80 | (0x3f & charValue));
}
} }
onWrite(); onWrite();
} }

View File

@ -28,6 +28,7 @@ import org.apache.kahadb.util.StringMarshaller;
import junit.framework.TestCase; import junit.framework.TestCase;
@SuppressWarnings("rawtypes")
public class PageFileTest extends TestCase { public class PageFileTest extends TestCase {
public void testCRUD() throws IOException { public void testCRUD() throws IOException {

View File

@ -0,0 +1,76 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.kahadb.util;
import junit.framework.TestCase;
public class DataByteArrayInputStreamTest extends TestCase {
/**
* https://issues.apache.org/activemq/browse/AMQ-1911
*/
public void testNonAscii() throws Exception {
doMarshallUnMarshallValidation("meißen");
String accumulator = new String();
int test = 0; // int to get Supplementary chars
while(Character.isDefined(test)) {
String toTest = String.valueOf((char)test);
accumulator += toTest;
doMarshallUnMarshallValidation(toTest);
test++;
}
int massiveThreeByteCharValue = 0x0FFF;
String toTest = String.valueOf((char)massiveThreeByteCharValue);
accumulator += toTest;
doMarshallUnMarshallValidation(String.valueOf((char)massiveThreeByteCharValue));
// Altogether
doMarshallUnMarshallValidation(accumulator);
// the three byte values
char t = '\u0800';
final char max = '\uffff';
accumulator = String.valueOf(t);
while (t < max) {
String val = String.valueOf(t);
accumulator += val;
doMarshallUnMarshallValidation(val);
t++;
}
// Altogether so long as it is not too big
while (accumulator.length() > 20000) {
accumulator = accumulator.substring(20000);
}
doMarshallUnMarshallValidation(accumulator);
}
void doMarshallUnMarshallValidation(String value) throws Exception {
DataByteArrayOutputStream out = new DataByteArrayOutputStream();
out.writeBoolean(true);
out.writeUTF(value);
out.close();
DataByteArrayInputStream in = new DataByteArrayInputStream(out.getData());
in.readBoolean();
String readBack = in.readUTF();
assertEquals(value, readBack);
}
}

View File

@ -0,0 +1,100 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.kahadb.util;
import java.io.IOException;
import junit.framework.TestCase;
public class DataByteArrayOutputStreamTest extends TestCase {
/**
* This test case assumes that an ArrayIndexOutOfBoundsException will be thrown when the buffer fails to resize
* @throws IOException
*/
public void testResize() throws IOException {
int initSize = 64;
DataByteArrayOutputStream out = new DataByteArrayOutputStream();
fillOut(out, initSize);
// Should resized here
out.writeBoolean(true);
fillOut(out, initSize);
// Should resized here
out.writeByte(1);
fillOut(out, initSize);
// Should resized here
out.writeBytes("test");
fillOut(out, initSize);
// Should resized here
out.writeChar('C');
fillOut(out, initSize);
// Should resized here
out.writeChars("test");
fillOut(out, initSize);
// Should resized here
out.writeDouble(3.1416);
fillOut(out, initSize);
// Should resized here
out.writeFloat((float)3.1416);
fillOut(out, initSize);
// Should resized here
out.writeInt(12345);
fillOut(out, initSize);
// Should resized here
out.writeLong(12345);
fillOut(out, initSize);
// Should resized here
out.writeShort(1234);
fillOut(out, initSize);
// Should resized here
out.writeUTF("test");
fillOut(out, initSize);
// Should resized here
out.write(1234);
fillOut(out, initSize);
// Should resized here
out.write(new byte[10], 5, 5);
fillOut(out, initSize);
// Should resized here
out.write(new byte[10]);
}
/**
* This method restarts the stream to the init size, and fills it up with data
* @param out
* @param size
* @throws IOException
*/
public void fillOut(DataByteArrayOutputStream out, int size) throws IOException {
out.restart(size);
out.write(new byte[size]);
}
}