|
|
|
@ -32,8 +32,8 @@ import java.util.*; |
|
|
|
|
* but only the simple methods take default values into account. The reason for |
|
|
|
|
* this behavior is that default values cannot be removed -- they would reappear |
|
|
|
|
* after a serialization cycle. If a tag has repeated values, setXXX(tag, value) |
|
|
|
|
* will overwrite all of them and getXXX(tag) will throw an exception. |
|
|
|
|
* |
|
|
|
|
* will overwrite all of them and getXXX(tag) will throw an exception. |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
public class ProtoBuf { |
|
|
|
@ -46,12 +46,12 @@ public class ProtoBuf { |
|
|
|
|
private static final String MSG_UNSUPPORTED = "Unsupp.Type"; |
|
|
|
|
|
|
|
|
|
// names copied from //net/proto2/internal/wire_format.cc
|
|
|
|
|
private static final int WIRETYPE_END_GROUP = 4; |
|
|
|
|
private static final int WIRETYPE_FIXED32 = 5; |
|
|
|
|
private static final int WIRETYPE_FIXED64 = 1; |
|
|
|
|
private static final int WIRETYPE_LENGTH_DELIMITED = 2; |
|
|
|
|
private static final int WIRETYPE_START_GROUP = 3; |
|
|
|
|
private static final int WIRETYPE_VARINT = 0; |
|
|
|
|
static final int WIRETYPE_END_GROUP = 4; |
|
|
|
|
static final int WIRETYPE_FIXED32 = 5; |
|
|
|
|
static final int WIRETYPE_FIXED64 = 1; |
|
|
|
|
static final int WIRETYPE_LENGTH_DELIMITED = 2; |
|
|
|
|
static final int WIRETYPE_START_GROUP = 3; |
|
|
|
|
static final int WIRETYPE_VARINT = 0; |
|
|
|
|
|
|
|
|
|
/** Maximum number of bytes for VARINT wire format (64 bit, 7 bit/byte) */ |
|
|
|
|
private static final int VARINT_MAX_BYTES = 10; |
|
|
|
@ -62,7 +62,7 @@ public class ProtoBuf { |
|
|
|
|
new Long(10), new Long(11), new Long(12), new Long(13), new Long(14), |
|
|
|
|
new Long(15)}; |
|
|
|
|
|
|
|
|
|
private final ProtoBufType msgType; |
|
|
|
|
private ProtoBufType msgType; |
|
|
|
|
private final Vector values = new Vector(); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -123,6 +123,20 @@ public class ProtoBuf { |
|
|
|
|
insertLong(tag, getCount(tag), value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Appends the given (repeated) tag with the given float value. |
|
|
|
|
*/ |
|
|
|
|
public void addFloat(int tag, float value) { |
|
|
|
|
insertFloat(tag, getCount(tag), value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Appends the given (repeated) tag with the given double value. |
|
|
|
|
*/ |
|
|
|
|
public void addDouble(int tag, double value) { |
|
|
|
|
insertDouble(tag, getCount(tag), value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Appends the given (repeated) tag with the given group or message value. |
|
|
|
|
*/ |
|
|
|
@ -196,6 +210,34 @@ public class ProtoBuf { |
|
|
|
|
return ((Long) getObject(tag, index, ProtoBufType.TYPE_INT64)).longValue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the float value for the given tag. |
|
|
|
|
*/ |
|
|
|
|
public float getFloat(int tag) { |
|
|
|
|
return Float.intBitsToFloat(getInt(tag)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the float value for the given repeated tag at the given index. |
|
|
|
|
*/ |
|
|
|
|
public float getFloat(int tag, int index) { |
|
|
|
|
return Float.intBitsToFloat(getInt(tag, index)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the double value for the given tag. |
|
|
|
|
*/ |
|
|
|
|
public double getDouble(int tag) { |
|
|
|
|
return Double.longBitsToDouble(getLong(tag)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the double value for the given repeated tag at the given index. |
|
|
|
|
*/ |
|
|
|
|
public double getDouble(int tag, int index) { |
|
|
|
|
return Double.longBitsToDouble(getLong(tag, index)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the group or nested message for the given tag. |
|
|
|
|
*/ |
|
|
|
@ -234,6 +276,20 @@ public class ProtoBuf { |
|
|
|
|
return msgType; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the type definition of this protocol buffer. Used internally in |
|
|
|
|
* ProtoBufUtil for incremental reading. |
|
|
|
|
* |
|
|
|
|
* @param type the new type |
|
|
|
|
*/ |
|
|
|
|
void setType(ProtoBufType type) { |
|
|
|
|
if (values.size() != 0 || |
|
|
|
|
(msgType != null && type != null && type != msgType)) { |
|
|
|
|
throw new IllegalArgumentException(); |
|
|
|
|
} |
|
|
|
|
this.msgType = type; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Convenience method for determining whether a tag has a value. Note: in |
|
|
|
|
* contrast to getCount(tag) > 0, this method takes the default value |
|
|
|
@ -652,6 +708,20 @@ public class ProtoBuf { |
|
|
|
|
? SMALL_NUMBERS[(int) value] : new Long(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the given tag to the given double value. |
|
|
|
|
*/ |
|
|
|
|
public void setDouble(int tag, double value) { |
|
|
|
|
setLong(tag, Double.doubleToLongBits(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the given tag to the given float value. |
|
|
|
|
*/ |
|
|
|
|
public void setFloat(int tag, float value) { |
|
|
|
|
setInt(tag, Float.floatToIntBits(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Sets the given tag to the given Group or nested Message. |
|
|
|
|
*/ |
|
|
|
@ -695,6 +765,20 @@ public class ProtoBuf { |
|
|
|
|
? SMALL_NUMBERS[(int) value] : new Long(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Inserts the given float value for the given tag at the given index. |
|
|
|
|
*/ |
|
|
|
|
public void insertFloat(int tag, int index, float value) { |
|
|
|
|
insertInt(tag, index, Float.floatToIntBits(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Inserts the given double value for the given tag at the given index. |
|
|
|
|
*/ |
|
|
|
|
public void insertDouble(int tag, int index, double value) { |
|
|
|
|
insertLong(tag, index, Double.doubleToLongBits(value)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Inserts the given group or message for the given tag at the given index. |
|
|
|
|
*/ |
|
|
|
@ -739,6 +823,8 @@ public class ProtoBuf { |
|
|
|
|
case ProtoBufType.TYPE_UINT64: |
|
|
|
|
case ProtoBufType.TYPE_SINT32: |
|
|
|
|
case ProtoBufType.TYPE_SINT64: |
|
|
|
|
case ProtoBufType.TYPE_FLOAT: |
|
|
|
|
case ProtoBufType.TYPE_DOUBLE: |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} else if (object instanceof byte[]){ |
|
|
|
@ -748,7 +834,6 @@ public class ProtoBuf { |
|
|
|
|
case ProtoBufType.TYPE_MESSAGE: |
|
|
|
|
case ProtoBufType.TYPE_TEXT: |
|
|
|
|
case ProtoBufType.TYPE_BYTES: |
|
|
|
|
case ProtoBufType.TYPE_STRING: |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} else if (object instanceof ProtoBuf) { |
|
|
|
@ -1079,21 +1164,21 @@ public class ProtoBuf { |
|
|
|
|
/** |
|
|
|
|
* Encodes the given string to UTF-8 in the given buffer or calculates |
|
|
|
|
* the space needed if the buffer is null. |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* @param s the string to be UTF-8 encoded |
|
|
|
|
* @param buf byte array to write to |
|
|
|
|
* @return new buffer position after writing (which equals the required size |
|
|
|
|
* @return new buffer position after writing (which equals the required size |
|
|
|
|
* if pos is 0) |
|
|
|
|
*/ |
|
|
|
|
static int encodeUtf8(String s, byte[] buf, int pos){ |
|
|
|
|
int len = s.length(); |
|
|
|
|
for (int i = 0; i < len; i++){ |
|
|
|
|
int code = s.charAt(i); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// surrogate 0xd800 .. 0xdfff?
|
|
|
|
|
if (code >= 0x0d800 && code <= 0x0dfff && i + 1 < len){ |
|
|
|
|
int codeLo = s.charAt(i + 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 0xfc00 is the surrogate id mask (first six bit of 16 set)
|
|
|
|
|
// 0x03ff is the surrogate data mask (remaining 10 bit)
|
|
|
|
|
// check if actually a surrogate pair (d800 ^ dc00 == 0400)
|
|
|
|
@ -1138,35 +1223,35 @@ public class ProtoBuf { |
|
|
|
|
buf[pos + 2] = (byte) ((0x80 | ((code >> 6) & 0x3F))); |
|
|
|
|
buf[pos + 3] = (byte) ((0x80 | (code & 0x3F))); |
|
|
|
|
} |
|
|
|
|
pos += 4; |
|
|
|
|
pos += 4; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return pos; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Decodes an array of UTF-8 bytes to a Java string (UTF-16). The tolerant |
|
|
|
|
* flag determines what to do in case of illegal or unsupported sequences. |
|
|
|
|
* |
|
|
|
|
* @param data input byte array containing UTF-8 data |
|
|
|
|
* Decodes an array of UTF-8 bytes to a Java string (UTF-16). The tolerant |
|
|
|
|
* flag determines what to do in case of illegal or unsupported sequences. |
|
|
|
|
* |
|
|
|
|
* @param data input byte array containing UTF-8 data |
|
|
|
|
* @param start decoding start position in byte array |
|
|
|
|
* @param end decoding end position in byte array |
|
|
|
|
* @param tolerant if true, an IllegalArgumentException is thrown for illegal |
|
|
|
|
* @param tolerant if true, an IllegalArgumentException is thrown for illegal |
|
|
|
|
* UTF-8 codes |
|
|
|
|
* @return the string containing the UTF-8 decoding result |
|
|
|
|
*/ |
|
|
|
|
static String decodeUtf8(byte[] data, int start, int end, |
|
|
|
|
static String decodeUtf8(byte[] data, int start, int end, |
|
|
|
|
boolean tolerant){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StringBuffer sb = new StringBuffer(end - start); |
|
|
|
|
int pos = start; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (pos < end){ |
|
|
|
|
int b = data[pos++] & 0x0ff; |
|
|
|
|
if (b <= 0x7f){ |
|
|
|
|
sb.append((char) b); |
|
|
|
|
} else if (b >= 0xf5){ // byte sequence too long
|
|
|
|
|
} else if (b >= 0xf5){ // byte sequence too long
|
|
|
|
|
if (!tolerant){ |
|
|
|
|
throw new IllegalArgumentException("Invalid UTF8"); |
|
|
|
|
} |
|
|
|
@ -1174,16 +1259,16 @@ public class ProtoBuf { |
|
|
|
|
} else { |
|
|
|
|
int border = 0xe0; |
|
|
|
|
int count = 1; |
|
|
|
|
int minCode = 128; |
|
|
|
|
int minCode = 128; |
|
|
|
|
int mask = 0x01f; |
|
|
|
|
while (b >= border){ |
|
|
|
|
border = (border >> 1) | 0x80; |
|
|
|
|
minCode = minCode << (count == 1 ? 4 : 5); |
|
|
|
|
minCode = minCode << (count == 1 ? 4 : 5); |
|
|
|
|
count++; |
|
|
|
|
mask = mask >> 1; |
|
|
|
|
} |
|
|
|
|
int code = b & mask; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < count; i++){ |
|
|
|
|
code = code << 6; |
|
|
|
|
if (pos >= end){ |
|
|
|
@ -1198,7 +1283,7 @@ public class ProtoBuf { |
|
|
|
|
code |= (data[pos++] & 0x3f); // six bit
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// illegal code or surrogate code
|
|
|
|
|
if (!tolerant && code < minCode || (code >= 0xd800 && code <= 0xdfff)){ |
|
|
|
|
throw new IllegalArgumentException("Invalid UTF8"); |
|
|
|
|