Adding support for UTF8 and Ascii based buffers. This should help make it more clear what type of encoding is being used string stored in a buffer feild.
git-svn-id: https://svn.apache.org/repos/asf/activemq/activemq-protobuf/trunk@746129 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java
new file mode 100644
index 0000000..a7fe78f
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/AsciiBuffer.java
@@ -0,0 +1,75 @@
+package org.apache.activemq.protobuf;
+
+
+final public class AsciiBuffer extends Buffer {
+
+ private int hashCode;
+
+ public AsciiBuffer(Buffer other) {
+ super(other);
+ }
+
+ public AsciiBuffer(byte[] data, int offset, int length) {
+ super(data, offset, length);
+ }
+
+ public AsciiBuffer(byte[] data) {
+ super(data);
+ }
+
+ public AsciiBuffer(String input) {
+ super(encode(input));
+ }
+
+ public AsciiBuffer compact() {
+ if (length != data.length) {
+ return new AsciiBuffer(toByteArray());
+ }
+ return this;
+ }
+
+ public String toString()
+ {
+ return decode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if( obj==this )
+ return true;
+
+ if( obj==null || obj.getClass()!=AsciiBuffer.class )
+ return false;
+
+ return equals((Buffer)obj);
+ }
+
+ @Override
+ public int hashCode() {
+ if( hashCode==0 ) {
+ hashCode = super.hashCode();;
+ }
+ return hashCode;
+ }
+
+ static public byte[] encode(String value)
+ {
+ int size = value.length();
+ byte rc[] = new byte[size];
+ for( int i=0; i < size; i++ ) {
+ rc[i] = (byte)(value.charAt(i)&0xFF);
+ }
+ return rc;
+ }
+ static public String decode(Buffer value)
+ {
+ int size = value.getLength();
+ char rc[] = new char[size];
+ for( int i=0; i < size; i++ ) {
+ rc[i] = (char)(value.byteAt(i) & 0xFF );
+ }
+ return new String(rc);
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java
index 0c350f7..144aa44 100644
--- a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/Buffer.java
@@ -17,25 +17,20 @@
package org.apache.activemq.protobuf;
-import java.io.UnsupportedEncodingException;
+import java.util.List;
-final public class Buffer {
+public class Buffer {
- public byte[] data;
- public int offset;
- public int length;
+ final public byte[] data;
+ final public int offset;
+ final public int length;
- public Buffer() {
+ public Buffer(Buffer other) {
+ this(other.data, other.offset, other.length);
}
-
- public Buffer(String input) {
- this( encode(input) );
- }
-
+
public Buffer(byte data[]) {
- this.data = data;
- this.offset = 0;
- this.length = data.length;
+ this(data, 0, data.length);
}
public Buffer(byte data[], int offset, int length) {
@@ -44,107 +39,143 @@
this.length = length;
}
+ @Deprecated
+ public Buffer(String value) {
+ this(UTF8Buffer.encode(value));
+ }
- public byte[] getData() {
+ public final Buffer slice(int low, int high) {
+ int sz;
+
+ if (high < 0) {
+ sz = length + high;
+ } else {
+ sz = high - low;
+ }
+
+ if (sz < 0) {
+ sz = 0;
+ }
+
+ return new Buffer(data, offset + low, sz);
+ }
+
+ public final byte[] getData() {
return data;
}
- public int getLength() {
+ public final int getLength() {
return length;
}
- public int getOffset() {
+ public final int getOffset() {
return offset;
}
- public void setData(byte[] data) {
- this.data = data;
- }
-
- public void setLength(int length) {
- this.length = length;
- }
-
- public void setOffset(int offset) {
- this.offset = offset;
- }
-
- public void compact() {
+ public Buffer compact() {
if (length != data.length) {
- byte t[] = new byte[length];
- System.arraycopy(data, offset, t, 0, length);
- data = t;
- offset = 0;
+ return new Buffer(toByteArray());
}
+ return this;
}
-
- public byte[] toByteArray() {
+
+ final public byte[] toByteArray() {
if (length != data.length) {
byte t[] = new byte[length];
System.arraycopy(data, offset, t, 0, length);
- data = t;
- offset = 0;
}
return data;
}
- public String toStringUtf8() {
- try {
- return new String(data, offset, length, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
- }
+ public byte byteAt(int i) {
+ return data[offset + i];
}
- public byte byteAt(int i) {
- return data[offset+i];
- }
-
- private static byte[] encode(String input) {
- try {
- return input.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
- }
- }
@Override
public int hashCode() {
- byte []target = new byte[4];
- for(int i=0; i < length; i++) {
- target[i%4] ^= data[offset+i];
+ byte[] target = new byte[4];
+ for (int i = 0; i < length; i++) {
+ target[i % 4] ^= data[offset + i];
}
- return target[0]<<24 | target[1]<<16 | target[2]<<8 | target[3];
+ return target[0] << 24 | target[1] << 16 | target[2] << 8 | target[3];
}
-
+
@Override
public boolean equals(Object obj) {
- if( obj==this )
- return true;
-
- if( obj==null || obj.getClass()!=Buffer.class )
- return false;
-
- return equals((Buffer)obj);
- }
-
- public boolean equals(Buffer obj) {
- if( length != obj.length ) {
+ if (obj == this)
+ return true;
+
+ if (obj == null || obj.getClass() != Buffer.class)
+ return false;
+
+ return equals((Buffer) obj);
+ }
+
+ final public boolean equals(Buffer obj) {
+ if (length != obj.length) {
return false;
}
- for(int i=0; i < length; i++) {
- if( obj.data[obj.offset+i] != data[offset+i] ) {
- return false;
- }
+ for (int i = 0; i < length; i++) {
+ if (obj.data[obj.offset + i] != data[offset + i]) {
+ return false;
+ }
}
return true;
- }
+ }
- public BufferInputStream newInput() {
- return new BufferInputStream(this);
- }
-
- public BufferOutputStream newOutput() {
- return new BufferOutputStream(this);
- }
+ final public BufferInputStream newInput() {
+ return new BufferInputStream(this);
+ }
+
+ final public BufferOutputStream newOutput() {
+ return new BufferOutputStream(this);
+ }
+
+ final public boolean isEmpty() {
+ return length == 0;
+ }
+
+ final public boolean contains(byte value) {
+ return indexOf(value, 0) >= 0;
+ }
+
+ final public int indexOf(byte value, int pos) {
+ for (int i = pos; i < length; i++) {
+ if (data[offset + i] == value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ final public static Buffer join(List<Buffer> items, Buffer seperator) {
+ if (items.isEmpty())
+ return new Buffer(seperator.data, 0, 0);
+
+ int size = 0;
+ for (Buffer item : items) {
+ size += item.length;
+ }
+ size += seperator.length * (items.size() - 1);
+
+ int pos = 0;
+ byte data[] = new byte[size];
+ for (Buffer item : items) {
+ if (pos != 0) {
+ System.arraycopy(seperator.data, seperator.offset, data, pos, seperator.length);
+ pos += seperator.length;
+ }
+ System.arraycopy(item.data, item.offset, data, pos, item.length);
+ pos += item.length;
+ }
+
+ return new Buffer(data, 0, size);
+ }
+
+ @Deprecated
+ public String toStringUtf8() {
+ return UTF8Buffer.decode(this);
+ }
+
}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java
new file mode 100644
index 0000000..1ddb52c
--- /dev/null
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/UTF8Buffer.java
@@ -0,0 +1,75 @@
+package org.apache.activemq.protobuf;
+
+import java.io.UnsupportedEncodingException;
+
+final public class UTF8Buffer extends Buffer {
+
+ int hashCode;
+
+ public UTF8Buffer(Buffer other) {
+ super(other);
+ }
+
+ public UTF8Buffer(byte[] data, int offset, int length) {
+ super(data, offset, length);
+ }
+
+ public UTF8Buffer(byte[] data) {
+ super(data);
+ }
+
+ public UTF8Buffer(String input) {
+ super(encode(input));
+ }
+
+ public UTF8Buffer compact() {
+ if (length != data.length) {
+ return new UTF8Buffer(toByteArray());
+ }
+ return this;
+ }
+
+ public String toString()
+ {
+ return decode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if( obj==this )
+ return true;
+
+ if( obj==null || obj.getClass()!=UTF8Buffer.class )
+ return false;
+
+ return equals((Buffer)obj);
+ }
+
+ @Override
+ public int hashCode() {
+ if( hashCode==0 ) {
+ hashCode = super.hashCode();;
+ }
+ return hashCode;
+ }
+
+ static public byte[] encode(String value)
+ {
+ try {
+ return value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
+ }
+ }
+
+ static public String decode(Buffer buffer)
+ {
+ try {
+ return new String(buffer.getData(), buffer.getOffset(), buffer.getLength(), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("A UnsupportedEncodingException was thrown for teh UTF-8 encoding. (This should never happen)");
+ }
+ }
+
+
+}
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java
index c8485ae..9745f71 100644
--- a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/AltJavaGenerator.java
@@ -1096,14 +1096,18 @@
indent();
p(setter + "(input.readString());");
} else if (field.getType() == FieldDescriptor.BYTES_TYPE) {
- p("case "
- + makeTag(field.getTag(),
- WIRETYPE_LENGTH_DELIMITED) + ":");
+ p("case "+ makeTag(field.getTag(), WIRETYPE_LENGTH_DELIMITED) + ":");
indent();
- p(setter + "(input.readBytes());");
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ p(setter + "(new org.apache.activemq.protobuf.AsciiBuffer(input.readBytes()));");
+ } else if( "UTF8Buffer".equals(override) ) {
+ p(setter + "(new org.apache.activemq.protobuf.UTF8Buffer(input.readBytes()));");
+ } else {
+ p(setter + "(input.readBytes());");
+ }
} else if (field.getType() == FieldDescriptor.BOOL_TYPE) {
- p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)
- + ":");
+ p("case " + makeTag(field.getTag(), WIRETYPE_VARINT)+ ":");
indent();
p(setter + "(input.readBool());");
} else if (field.getType() == FieldDescriptor.DOUBLE_TYPE) {
@@ -1339,7 +1343,7 @@
} else if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
p("byte b[] = new byte[in.readInt()];");
p("in.readFully(b);");
- p("f_"+lname+".add(new org.apache.activemq.protobuf.Buffer(b));");
+ p("f_"+lname+".add(new "+type+"(b));");
} else if (field.getTypeDescriptor().isEnum() ) {
p("f_"+lname+".add(" + type + ".valueOf(in.readShort()));");
} else {
@@ -1394,7 +1398,7 @@
indent();
p("byte b[] = new byte[size];");
p("in.readFully(b);");
- p("f_"+lname+" = new org.apache.activemq.protobuf.Buffer(b);");
+ p("f_"+lname+" = new "+type+"(b);");
p("b_"+lname+" = true;");
unindent();
p("} else {");
@@ -1919,7 +1923,7 @@
if( field.isStringType() ) {
return asJavaString(defaultOption.getValue());
} else if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
- return "new org.apache.activemq.protobuf.Buffer("+asJavaString(defaultOption.getValue())+")";
+ return "new "+javaType(field)+"("+asJavaString(defaultOption.getValue())+")";
} else if( field.isInteger32Type() ) {
int v;
if( field.getType() == FieldDescriptor.UINT32_TYPE ) {
@@ -2123,10 +2127,27 @@
return "java.lang.Float";
}
if( field.getType() == FieldDescriptor.STRING_TYPE ) {
- return "java.lang.String";
+ // TODO: support handling string fields as buffers.
+// String override = getOption(field.getOptions(), "java_override_type", null);
+// if( "AsciiBuffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.AsciiBuffer";
+// } else if( "UTF8Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.UTF8Buffer";
+// } else if( "Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.Buffer";
+// } else {
+ return "java.lang.String";
+// }
}
if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
- return "org.apache.activemq.protobuf.Buffer";
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.AsciiBuffer";
+ } else if( "UTF8Buffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.UTF8Buffer";
+ } else {
+ return "org.apache.activemq.protobuf.Buffer";
+ }
}
if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
return "java.lang.Boolean";
@@ -2150,10 +2171,27 @@
return "float";
}
if( field.getType() == FieldDescriptor.STRING_TYPE ) {
- return "java.lang.String";
+ // TODO: support handling string fields as buffers.
+// String override = getOption(field.getOptions(), "java_override_type", null);
+// if( "AsciiBuffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.AsciiBuffer";
+// } else if( "UTF8Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.UTF8Buffer";
+// } else if( "Buffer".equals(override) ) {
+// return "org.apache.activemq.protobuf.Buffer";
+// } else {
+ return "java.lang.String";
+// }
}
if( field.getType() == FieldDescriptor.BYTES_TYPE ) {
- return "org.apache.activemq.protobuf.Buffer";
+ String override = getOption(field.getOptions(), "java_override_type", null);
+ if( "AsciiBuffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.AsciiBuffer";
+ } else if( "UTF8Buffer".equals(override) ) {
+ return "org.apache.activemq.protobuf.UTF8Buffer";
+ } else {
+ return "org.apache.activemq.protobuf.Buffer";
+ }
}
if( field.getType() == FieldDescriptor.BOOL_TYPE ) {
return "boolean";
diff --git a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/TextFormat.java b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/TextFormat.java
index ea9f68b..f16d4df 100644
--- a/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/TextFormat.java
+++ b/activemq-protobuf/src/main/java/org/apache/activemq/protobuf/compiler/TextFormat.java
@@ -23,6 +23,7 @@
import java.util.regex.Pattern;
import org.apache.activemq.protobuf.Buffer;
+import org.apache.activemq.protobuf.UTF8Buffer;
/**
* Provide ascii text parsing and formatting support for proto2 instances.
@@ -370,7 +371,7 @@
* value. Otherwise, throw a {@link ParseException}.
*/
public String consumeString() throws ParseException {
- return consumeBuffer().toStringUtf8();
+ return new UTF8Buffer(consumeBuffer()).toString();
}
/**
@@ -598,7 +599,7 @@
* individually as a 3-digit octal escape. Yes, it's weird.
*/
static String escapeText(String input) {
- return escapeBytes(new Buffer(input));
+ return escapeBytes(new UTF8Buffer(input));
}
/**
@@ -606,7 +607,7 @@
* Two-digit hex escapes (starting with "\x") are also recognized.
*/
static String unescapeText(String input) throws InvalidEscapeSequence {
- return unescapeBytes(input).toStringUtf8();
+ return new UTF8Buffer(unescapeBytes(input)).toString();
}
/** Is this an octal digit? */