Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
P
protobuf
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
protobuf
Commits
778b51ce
Commit
778b51ce
authored
Mar 04, 2009
by
The Android Open Source Project
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
auto import from //depot/cupcake/@135843
parent
a3cc5f17
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
0 additions
and
1716 deletions
+0
-1716
ProtoBuf.java
src/com/google/common/io/protocol/ProtoBuf.java
+0
-1304
ProtoBufType.java
src/com/google/common/io/protocol/ProtoBufType.java
+0
-170
ProtoBufUtil.java
src/com/google/common/io/protocol/ProtoBufUtil.java
+0
-237
package.html
src/com/google/common/io/protocol/package.html
+0
-5
No files found.
src/com/google/common/io/protocol/ProtoBuf.java
deleted
100644 → 0
View file @
a3cc5f17
// Copyright 2007 The Android Open Source Project
// All Rights Reserved.
package
com
.
google
.
common
.
io
.
protocol
;
import
java.io.*
;
import
java.util.*
;
/**
* Protocol buffer message object. Currently, it is assumed that tags ids are
* not large. This could be improved by storing a start offset, reducing the
* assumption to a dense number space.
* <p>
* ProtoBuf instances may or may not reference a ProtoBufType instance,
* representing information from a corresponding .proto file, which defines tag
* data types. The type can only be set in the constructor, it cannot be
* changed later.
* <p>
* If the type is null, the ProtoBuffer should be used only for reading or
* as a local persistent storage buffer. An untyped Protocol Buffer must never
* be sent to a server.
* <p>
* If a ProtoBufType is set, unknown values are read from the stream and
* preserved, but it is not possible to add values for undefined tags using
* this API. Attempts to set undefined tags will result in an exception.
* <p>
* This class provides two different sets of access methods for simple and
* repeated tags. Simple access methods are has(tag), getXXX(tag),
* and setXXX(tag, value). Access methods for repeated tags are getCount(tag),
* getXXX(tag, index), remove(tag, index), insert(tag, index, value) and
* addXXX(tag, value). Note that both sets of methods can be used in both cases,
* 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.
*
*/
public
class
ProtoBuf
{
public
static
final
Boolean
FALSE
=
new
Boolean
(
false
);
public
static
final
Boolean
TRUE
=
new
Boolean
(
true
);
private
static
final
String
MSG_EOF
=
"Unexp.EOF"
;
private
static
final
String
MSG_MISMATCH
=
"Type mismatch"
;
private
static
final
String
MSG_UNSUPPORTED
=
"Unsupp.Type"
;
// names copied from //net/proto2/internal/wire_format.cc
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
;
private
static
Long
[]
SMALL_NUMBERS
=
{
new
Long
(
0
),
new
Long
(
1
),
new
Long
(
2
),
new
Long
(
3
),
new
Long
(
4
),
new
Long
(
5
),
new
Long
(
6
),
new
Long
(
7
),
new
Long
(
8
),
new
Long
(
9
),
new
Long
(
10
),
new
Long
(
11
),
new
Long
(
12
),
new
Long
(
13
),
new
Long
(
14
),
new
Long
(
15
)};
private
ProtoBufType
msgType
;
private
final
Vector
values
=
new
Vector
();
/**
* Wire types picked up on the wire or implied by setters (if no other
* type information is available.
*/
private
final
StringBuffer
wireTypes
=
new
StringBuffer
();
/**
* Creates a protocol message according to the given description. The
* description is required if it is necessary to write the protocol buffer for
* data exchange with other systems relying on the .proto file.
*/
public
ProtoBuf
(
ProtoBufType
type
)
{
this
.
msgType
=
type
;
}
/**
* Clears all data stored in this ProtoBuf.
*/
public
void
clear
()
{
values
.
setSize
(
0
);
wireTypes
.
setLength
(
0
);
}
/**
* Creates a new instance of the group with the given tag.
*/
public
ProtoBuf
createGroup
(
int
tag
)
{
return
new
ProtoBuf
((
ProtoBufType
)
getType
().
getData
(
tag
));
}
/**
* Appends the given (repeated) tag with the given boolean value.
*/
public
void
addBool
(
int
tag
,
boolean
value
){
insertBool
(
tag
,
getCount
(
tag
),
value
);
}
/**
* Appends the given (repeated) tag with the given byte[] value.
*/
public
void
addBytes
(
int
tag
,
byte
[]
value
){
insertBytes
(
tag
,
getCount
(
tag
),
value
);
}
/**
* Appends the given (repeated) tag with the given int value.
*/
public
void
addInt
(
int
tag
,
int
value
){
insertInt
(
tag
,
getCount
(
tag
),
value
);
}
/**
* Appends the given (repeated) tag with the given long value.
*/
public
void
addLong
(
int
tag
,
long
value
){
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.
*/
public
void
addProtoBuf
(
int
tag
,
ProtoBuf
value
){
insertProtoBuf
(
tag
,
getCount
(
tag
),
value
);
}
/**
* Appends the given (repeated) tag with the given String value.
*/
public
void
addString
(
int
tag
,
String
value
){
insertString
(
tag
,
getCount
(
tag
),
value
);
}
/**
* Returns the boolean value for the given tag.
*/
public
boolean
getBool
(
int
tag
)
{
return
((
Boolean
)
getObject
(
tag
,
ProtoBufType
.
TYPE_BOOL
))
.
booleanValue
();
}
/**
* Returns the boolean value for the given repeated tag at the given index.
*/
public
boolean
getBool
(
int
tag
,
int
index
)
{
return
((
Boolean
)
getObject
(
tag
,
index
,
ProtoBufType
.
TYPE_BOOL
))
.
booleanValue
();
}
/**
* Returns the given string tag as byte array.
*/
public
byte
[]
getBytes
(
int
tag
)
{
return
(
byte
[])
getObject
(
tag
,
ProtoBufType
.
TYPE_DATA
);
}
/**
* Returns the given repeated string tag at the given index as byte array.
*/
public
byte
[]
getBytes
(
int
tag
,
int
index
)
{
return
(
byte
[])
getObject
(
tag
,
index
,
ProtoBufType
.
TYPE_DATA
);
}
/**
* Returns the integer value for the given tag.
*/
public
int
getInt
(
int
tag
)
{
return
(
int
)
((
Long
)
getObject
(
tag
,
ProtoBufType
.
TYPE_INT32
)).
longValue
();
}
/**
* Returns the integer value for the given repeated tag at the given index.
*/
public
int
getInt
(
int
tag
,
int
index
)
{
return
(
int
)
((
Long
)
getObject
(
tag
,
index
,
ProtoBufType
.
TYPE_INT32
)).
longValue
();
}
/**
* Returns the long value for the given tag.
*/
public
long
getLong
(
int
tag
)
{
return
((
Long
)
getObject
(
tag
,
ProtoBufType
.
TYPE_INT64
)).
longValue
();
}
/**
* Returns the long value for the given repeated tag at the given index.
*/
public
long
getLong
(
int
tag
,
int
index
)
{
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.
*/
public
ProtoBuf
getProtoBuf
(
int
tag
)
{
return
(
ProtoBuf
)
getObject
(
tag
,
ProtoBufType
.
TYPE_GROUP
);
}
/**
* Returns the group or nested message for the given repeated tag at the given
* index.
*/
public
ProtoBuf
getProtoBuf
(
int
tag
,
int
index
)
{
return
(
ProtoBuf
)
getObject
(
tag
,
index
,
ProtoBufType
.
TYPE_GROUP
);
}
/**
* Returns the string value for a given tag converted to a Java String
* assuming UTF-8 encoding.
*/
public
String
getString
(
int
tag
)
{
return
(
String
)
getObject
(
tag
,
ProtoBufType
.
TYPE_TEXT
);
}
/**
* Returns the string value for a given repeated tag at the given index
* converted to a Java String assuming UTF-8 encoding.
*/
public
String
getString
(
int
tag
,
int
index
)
{
return
(
String
)
getObject
(
tag
,
index
,
ProtoBufType
.
TYPE_TEXT
);
}
/**
* Returns the type definition of this protocol buffer or group -- if set.
*/
public
ProtoBufType
getType
()
{
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
* into account.
*/
public
boolean
has
(
int
tag
){
return
getCount
(
tag
)
>
0
||
getDefault
(
tag
)
!=
null
;
}
/**
* Reads the contents of this ProtocolMessage from the given byte array.
* Currently, this is a shortcut for parse(new ByteArrayInputStream(data)).
* However, this may change in future versions for efficiency reasons.
*
* @param data the byte array the ProtocolMessage is read from
* @throws IOException if an unexpected "End of file" is encountered in
* the byte array
*/
public
ProtoBuf
parse
(
byte
[]
data
)
throws
IOException
{
parse
(
new
ByteArrayInputStream
(
data
),
data
.
length
);
return
this
;
}
/**
* Reads the contents of this ProtocolMessage from the given stream.
*
* @param is the input stream providing the contents
* @return this
* @throws IOException raised if an IO exception occurs in the underlying
* stream or the end of the stream is reached at an unexpected
* position
*/
public
ProtoBuf
parse
(
InputStream
is
)
throws
IOException
{
parse
(
is
,
Integer
.
MAX_VALUE
);
return
this
;
}
/**
* Reads the contents of this ProtocolMessage from the given stream, consuming
* at most the given number of bytes.
*
* @param is the input stream providing the contents
* @param available maximum number of bytes to read
* @return this
* @throws IOException raised if an IO exception occurs in the
* underlying stream or the end of the stream is reached at
* an unexpected position
*/
public
int
parse
(
InputStream
is
,
int
available
)
throws
IOException
{
clear
();
while
(
available
>
0
)
{
long
tagAndType
=
readVarInt
(
is
,
true
/* permits EOF */
);
if
(
tagAndType
==
-
1
){
break
;
}
available
-=
getVarIntSize
(
tagAndType
);
int
wireType
=
((
int
)
tagAndType
)
&
0x07
;
if
(
wireType
==
WIRETYPE_END_GROUP
)
{
break
;
}
int
tag
=
(
int
)
(
tagAndType
>>>
3
);
while
(
wireTypes
.
length
()
<=
tag
){
wireTypes
.
append
((
char
)
ProtoBufType
.
TYPE_UNDEFINED
);
}
wireTypes
.
setCharAt
(
tag
,
(
char
)
wireType
);
// first step: decode tag value
Object
value
;
switch
(
wireType
)
{
case
WIRETYPE_VARINT:
long
v
=
readVarInt
(
is
,
false
);
available
-=
getVarIntSize
(
v
);
if
(
isZigZagEncodedType
(
tag
))
{
v
=
zigZagDecode
(
v
);
}
value
=
(
v
>=
0
&&
v
<
SMALL_NUMBERS
.
length
)
?
SMALL_NUMBERS
[(
int
)
v
]
:
new
Long
(
v
);
break
;
// also used for fixed values
case
WIRETYPE_FIXED32:
case
WIRETYPE_FIXED64:
v
=
0
;
int
shift
=
0
;
int
count
=
(
wireType
==
WIRETYPE_FIXED32
)
?
4
:
8
;
available
-=
count
;
while
(
count
--
>
0
)
{
long
l
=
is
.
read
();
v
|=
l
<<
shift
;
shift
+=
8
;
}
value
=
(
v
>=
0
&&
v
<
SMALL_NUMBERS
.
length
)
?
SMALL_NUMBERS
[(
int
)
v
]
:
new
Long
(
v
);
break
;
case
WIRETYPE_LENGTH_DELIMITED:
int
total
=
(
int
)
readVarInt
(
is
,
false
);
available
-=
getVarIntSize
(
total
);
available
-=
total
;
if
(
getType
(
tag
)
==
ProtoBufType
.
TYPE_MESSAGE
)
{
ProtoBuf
msg
=
new
ProtoBuf
((
ProtoBufType
)
msgType
.
getData
(
tag
));
msg
.
parse
(
is
,
total
);
value
=
msg
;
}
else
{
byte
[]
data
=
new
byte
[
total
];
int
pos
=
0
;
while
(
pos
<
total
)
{
count
=
is
.
read
(
data
,
pos
,
total
-
pos
);
if
(
count
<=
0
)
{
throw
new
IOException
(
MSG_EOF
);
}
pos
+=
count
;
}
value
=
data
;
}
break
;
case
WIRETYPE_START_GROUP:
ProtoBuf
group
=
new
ProtoBuf
(
msgType
==
null
?
null
:
((
ProtoBufType
)
msgType
.
getData
(
tag
)));
available
=
group
.
parse
(
is
,
available
);
value
=
group
;
break
;
default
:
throw
new
RuntimeException
(
MSG_UNSUPPORTED
+
wireType
);
}
insertObject
(
tag
,
getCount
(
tag
),
value
);
}
if
(
available
<
0
){
throw
new
IOException
();
}
return
available
;
}
/**
* Removes the tag value at the given index.
*/
public
void
remove
(
int
tag
,
int
index
){
int
count
=
getCount
(
tag
);
if
(
index
>=
count
){
throw
new
ArrayIndexOutOfBoundsException
();
}
if
(
count
==
1
){
values
.
setElementAt
(
null
,
tag
);
}
else
{
Vector
v
=
(
Vector
)
values
.
elementAt
(
tag
);
v
.
removeElementAt
(
index
);
}
}
/**
* Returns the number of repeated and optional (0..1) values for a given tag.
* Note: Default values are not counted (and in general not considered in
* access methods for repeated tags), but considered for has(tag).
*/
public
int
getCount
(
int
tag
)
{
if
(
tag
>=
values
.
size
()){
return
0
;
}
Object
o
=
values
.
elementAt
(
tag
);
if
(
o
==
null
){
return
0
;
}
return
(
o
instanceof
Vector
)
?
((
Vector
)
o
).
size
()
:
1
;
}
/**
* Returns the tag type of the given tag (one of the ProtoBufType.TYPE_XXX
* constants). If no ProtoBufType is set, the wire type is returned. If no
* wire type is available, the wire type is determined by looking at the
* tag value (making sure the wire type is consistent for all values). If
* no value is set, TYPE_UNDEFINED is returned.
*/
public
int
getType
(
int
tag
){
int
tagType
=
ProtoBufType
.
TYPE_UNDEFINED
;
if
(
msgType
!=
null
){
tagType
=
msgType
.
getType
(
tag
);
}
if
(
tagType
==
ProtoBufType
.
TYPE_UNDEFINED
&&
tag
<
wireTypes
.
length
())
{
tagType
=
wireTypes
.
charAt
(
tag
);
}
if
(
tagType
==
ProtoBufType
.
TYPE_UNDEFINED
&&
getCount
(
tag
)
>
0
)
{
Object
o
=
getObject
(
tag
,
0
,
ProtoBufType
.
TYPE_UNDEFINED
);
tagType
=
(
o
instanceof
Long
)
||
(
o
instanceof
Boolean
)
?
WIRETYPE_VARINT
:
WIRETYPE_LENGTH_DELIMITED
;
}
return
tagType
;
}
/**
* Returns the number of bytes needed to store this protocol buffer
*/
public
int
getDataSize
()
{
int
size
=
0
;
for
(
int
tag
=
0
;
tag
<=
maxTag
();
tag
++)
{
for
(
int
i
=
0
;
i
<
getCount
(
tag
);
i
++)
{
size
+=
getDataSize
(
tag
,
i
);
}
}
return
size
;
}
/**
* Returns the size of the given value
*/
private
int
getDataSize
(
int
tag
,
int
i
)
{
int
tagSize
=
getVarIntSize
(
tag
<<
3
);
switch
(
getWireType
(
tag
)){
case
WIRETYPE_FIXED32:
return
tagSize
+
4
;
case
WIRETYPE_FIXED64:
return
tagSize
+
8
;
case
WIRETYPE_VARINT:
long
value
=
getLong
(
tag
,
i
);
if
(
isZigZagEncodedType
(
tag
))
{
value
=
zigZagEncode
(
value
);
}
return
tagSize
+
getVarIntSize
(
value
);
case
WIRETYPE_START_GROUP:
// take end group into account....
return
tagSize
+
getProtoBuf
(
tag
,
i
).
getDataSize
()
+
tagSize
;
}
// take the object as stored
Object
o
=
getObject
(
tag
,
i
,
ProtoBufType
.
TYPE_UNDEFINED
);
int
contentSize
;
if
(
o
instanceof
byte
[]){
contentSize
=
((
byte
[])
o
).
length
;
}
else
if
(
o
instanceof
String
)
{
contentSize
=
encodeUtf8
((
String
)
o
,
null
,
0
);
}
else
{
contentSize
=
((
ProtoBuf
)
o
).
getDataSize
();
}
return
tagSize
+
getVarIntSize
(
contentSize
)
+
contentSize
;
}
/**
* Returns the number of bytes needed to encode the given value using
* WIRETYPE_VARINT
*/
private
static
int
getVarIntSize
(
long
i
)
{
if
(
i
<
0
)
{
return
10
;
}
int
size
=
1
;
while
(
i
>=
128
)
{
size
++;
i
>>=
7
;
}
return
size
;
}
/**
* Writes this and nested protocol buffers to the given output stream.
*
* @param os target output stream
* @throws IOException thrown if there is an IOException
*/
public
void
outputTo
(
OutputStream
os
)
throws
IOException
{
for
(
int
tag
=
0
;
tag
<=
maxTag
();
tag
++)
{
int
size
=
getCount
(
tag
);
int
wireType
=
getWireType
(
tag
);
// ignore default values
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
writeVarInt
(
os
,
(
tag
<<
3
)
|
wireType
);
switch
(
wireType
)
{
case
WIRETYPE_FIXED32:
case
WIRETYPE_FIXED64:
long
v
=
((
Long
)
getObject
(
tag
,
i
,
ProtoBufType
.
TYPE_INT64
))
.
longValue
();
int
cnt
=
(
wireType
==
WIRETYPE_FIXED32
)
?
4
:
8
;
for
(
int
b
=
0
;
b
<
cnt
;
b
++)
{
os
.
write
((
int
)
(
v
&
0x0ff
));
v
>>=
8
;
}
break
;
case
WIRETYPE_VARINT:
v
=
((
Long
)
getObject
(
tag
,
i
,
ProtoBufType
.
TYPE_INT64
)).
longValue
();
if
(
isZigZagEncodedType
(
tag
))
{
v
=
zigZagEncode
(
v
);
}
writeVarInt
(
os
,
v
);
break
;
case
WIRETYPE_LENGTH_DELIMITED:
Object
o
=
getObject
(
tag
,
i
,
getType
(
tag
)
==
ProtoBufType
.
TYPE_MESSAGE
?
ProtoBufType
.
TYPE_UNDEFINED
:
ProtoBufType
.
TYPE_DATA
);
if
(
o
instanceof
byte
[]){
byte
[]
data
=
(
byte
[])
o
;
writeVarInt
(
os
,
data
.
length
);
os
.
write
(
data
);
}
else
{
ProtoBuf
msg
=
(
ProtoBuf
)
o
;
writeVarInt
(
os
,
msg
.
getDataSize
());
msg
.
outputTo
(
os
);
}
break
;
case
WIRETYPE_START_GROUP:
((
ProtoBuf
)
getObject
(
tag
,
i
,
ProtoBufType
.
TYPE_GROUP
))
.
outputTo
(
os
);
writeVarInt
(
os
,
(
tag
<<
3
)
|
WIRETYPE_END_GROUP
);
break
;
default
:
throw
new
IllegalArgumentException
();
}
}
}
}
/**
* Returns true if the given tag has a signed type that should be ZigZag-
* encoded on the wire.
*
* ZigZag encoding turns a signed number into
* a non-negative number by mapping negative input numbers to positive odd
* numbers in the output space, and positive input numbers to positive even
* numbers in the output space. This is useful because the wire format
* for protocol buffers requires a large number of bytes to encode
* negative integers, while positive integers take up a smaller number
* of bytes proportional to their magnitude.
*/
private
boolean
isZigZagEncodedType
(
int
tag
)
{
int
declaredType
=
getType
(
tag
);
return
declaredType
==
ProtoBufType
.
TYPE_SINT32
||
declaredType
==
ProtoBufType
.
TYPE_SINT64
;
}
/**
* Converts a signed number into a non-negative ZigZag-encoded number.
*/
private
static
long
zigZagEncode
(
long
v
)
{
v
=
((
v
<<
1
)
^
-(
v
>>>
63
));
return
v
;
}
/**
* Converts a non-negative ZigZag-encoded number back into a signed number.
*/
private
static
long
zigZagDecode
(
long
v
)
{
v
=
(
v
>>>
1
)
^
-(
v
&
1
);
return
v
;
}
/**
* Writes this and nested protocol buffers to a byte array.
*
* @throws IOException thrown if there is problem writing the byte array
*/
public
byte
[]
toByteArray
()
throws
IOException
{
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
();
outputTo
(
baos
);
return
baos
.
toByteArray
();
}
/**
* Returns the largest tag id used in this message (to simplify testing).
*/
public
int
maxTag
()
{
return
values
.
size
()
-
1
;
}
/**
* Sets the given tag to the given boolean value.
*/
public
void
setBool
(
int
tag
,
boolean
value
)
{
setObject
(
tag
,
value
?
TRUE
:
FALSE
);
}
/**
* Sets the given tag to the given data bytes.
*/
public
void
setBytes
(
int
tag
,
byte
[]
value
)
{
setObject
(
tag
,
value
);
}
/**
* Sets the given tag to the given integer value.
*/
public
void
setInt
(
int
tag
,
int
value
)
{
setLong
(
tag
,
value
);
}
/**
* Sets the given tag to the given long value.
*/
public
void
setLong
(
int
tag
,
long
value
)
{
setObject
(
tag
,
value
>=
0
&&
value
<
SMALL_NUMBERS
.
length
?
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.
*/
public
void
setProtoBuf
(
int
tag
,
ProtoBuf
pb
)
{
setObject
(
tag
,
pb
);
}
/**
* Sets the given tag to the given String value.
*/
public
void
setString
(
int
tag
,
String
value
)
{
setObject
(
tag
,
value
);
}
/**
* Inserts the given boolean value for the given tag at the given index.
*/
public
void
insertBool
(
int
tag
,
int
index
,
boolean
value
)
{
insertObject
(
tag
,
index
,
value
?
TRUE
:
FALSE
);
}
/**
* Inserts the given byte array value for the given tag at the given index.
*/
public
void
insertBytes
(
int
tag
,
int
index
,
byte
[]
value
)
{
insertObject
(
tag
,
index
,
value
);
}
/**
* Inserts the given int value for the given tag at the given index.
*/
public
void
insertInt
(
int
tag
,
int
index
,
int
value
)
{
insertLong
(
tag
,
index
,
value
);
}
/**
* Inserts the given long value for the given tag at the given index.
*/
public
void
insertLong
(
int
tag
,
int
index
,
long
value
)
{
insertObject
(
tag
,
index
,
value
>=
0
&&
value
<
SMALL_NUMBERS
.
length
?
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.
*/
public
void
insertProtoBuf
(
int
tag
,
int
index
,
ProtoBuf
pb
)
{
insertObject
(
tag
,
index
,
pb
);
}
/**
* Inserts the given string value for the given tag at the given index.
*/
public
void
insertString
(
int
tag
,
int
index
,
String
value
)
{
insertObject
(
tag
,
index
,
value
);
}
// ----------------- private stuff below this line ------------------------
private
void
assertTypeMatch
(
int
tag
,
Object
object
){
int
tagType
=
getType
(
tag
);
if
(
tagType
==
ProtoBufType
.
TYPE_UNDEFINED
&&
msgType
==
null
)
{
return
;
}
if
(
object
instanceof
Boolean
)
{
if
(
tagType
==
ProtoBufType
.
TYPE_BOOL
||
tagType
==
WIRETYPE_VARINT
)
{
return
;
}
}
else
if
(
object
instanceof
Long
)
{
switch
(
tagType
){
case
WIRETYPE_FIXED32:
case
WIRETYPE_FIXED64:
case
WIRETYPE_VARINT:
case
ProtoBufType
.
TYPE_BOOL
:
case
ProtoBufType
.
TYPE_ENUM
:
case
ProtoBufType
.
TYPE_FIXED32
:
case
ProtoBufType
.
TYPE_FIXED64
:
case
ProtoBufType
.
TYPE_INT32
:
case
ProtoBufType
.
TYPE_INT64
:
case
ProtoBufType
.
TYPE_SFIXED32
:
case
ProtoBufType
.
TYPE_SFIXED64
:
case
ProtoBufType
.
TYPE_UINT32
:
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
[]){
switch
(
tagType
){
case
WIRETYPE_LENGTH_DELIMITED:
case
ProtoBufType
.
TYPE_DATA
:
case
ProtoBufType
.
TYPE_MESSAGE
:
case
ProtoBufType
.
TYPE_TEXT
:
case
ProtoBufType
.
TYPE_BYTES
:
return
;
}
}
else
if
(
object
instanceof
ProtoBuf
)
{
switch
(
tagType
){
case
WIRETYPE_LENGTH_DELIMITED:
case
WIRETYPE_START_GROUP:
case
ProtoBufType
.
TYPE_DATA
:
case
ProtoBufType
.
TYPE_GROUP
:
case
ProtoBufType
.
TYPE_MESSAGE
:
if
(
msgType
==
null
||
msgType
.
getData
(
tag
)
==
null
||
((
ProtoBuf
)
object
).
msgType
==
null
||
((
ProtoBuf
)
object
).
msgType
==
msgType
.
getData
(
tag
))
{
return
;
}
}
}
else
if
(
object
instanceof
String
){
switch
(
tagType
){
case
WIRETYPE_LENGTH_DELIMITED:
case
ProtoBufType
.
TYPE_DATA
:
case
ProtoBufType
.
TYPE_TEXT
:
case
ProtoBufType
.
TYPE_STRING
:
return
;
}
}
throw
new
IllegalArgumentException
(
MSG_MISMATCH
+
" type:"
+
msgType
+
" tag:"
+
tag
);
}
/**
* Returns the default value for the given tag.
*/
private
Object
getDefault
(
int
tag
){
switch
(
getType
(
tag
)){
case
ProtoBufType
.
TYPE_UNDEFINED
:
case
ProtoBufType
.
TYPE_GROUP
:
case
ProtoBufType
.
TYPE_MESSAGE
:
return
null
;
default
:
return
msgType
.
getData
(
tag
);
}
}
/**
* Returns the indicated value converted to the given type.
*
* @throws ArrayIndexOutOfBoundsException for invalid tags and indices
* @throws IllegalArgumentException if count is greater than one.
*/
private
Object
getObject
(
int
tag
,
int
desiredType
)
{
int
count
=
getCount
(
tag
);
if
(
count
==
0
){
return
getDefault
(
tag
);
}
if
(
count
>
1
){
throw
new
IllegalArgumentException
();
}
return
getObject
(
tag
,
0
,
desiredType
);
}
/**
* Returns the indicated value converted to the given type.
*
* @throws ArrayIndexOutOfBoundsException for invalid tags and indices
*/
private
Object
getObject
(
int
tag
,
int
index
,
int
desiredType
)
{
if
(
index
>=
getCount
(
tag
))
{
throw
new
ArrayIndexOutOfBoundsException
();
}
Object
o
=
values
.
elementAt
(
tag
);
Vector
v
=
null
;
if
(
o
instanceof
Vector
)
{
v
=
(
Vector
)
o
;
o
=
v
.
elementAt
(
index
);
}
Object
o2
=
convert
(
o
,
desiredType
);
if
(
o2
!=
o
&&
o
!=
null
)
{
if
(
v
==
null
){
setObject
(
tag
,
o2
);
}
else
{
v
.
setElementAt
(
o2
,
index
);
}
}
return
o2
;
}
/**
* Returns the wire type for the given tag. Calls getType() internally,
* so a wire type should be found for all non-empty tags, even if no
* message type is set and the tag was not previously read.
*/
private
final
int
getWireType
(
int
tag
)
{
int
tagType
=
getType
(
tag
);
switch
(
tagType
)
{
case
WIRETYPE_VARINT:
case
WIRETYPE_FIXED32:
case
WIRETYPE_FIXED64:
case
WIRETYPE_LENGTH_DELIMITED:
case
WIRETYPE_START_GROUP:
case
ProtoBufType
.
TYPE_UNDEFINED
:
return
tagType
;
case
ProtoBufType
.
TYPE_BOOL
:
case
ProtoBufType
.
TYPE_INT32
:
case
ProtoBufType
.
TYPE_INT64
:
case
ProtoBufType
.
TYPE_UINT32
:
case
ProtoBufType
.
TYPE_UINT64
:
case
ProtoBufType
.
TYPE_SINT32
:
case
ProtoBufType
.
TYPE_SINT64
:
case
ProtoBufType
.
TYPE_ENUM
:
return
WIRETYPE_VARINT
;
case
ProtoBufType
.
TYPE_DATA
:
case
ProtoBufType
.
TYPE_MESSAGE
:
case
ProtoBufType
.
TYPE_TEXT
:
case
ProtoBufType
.
TYPE_BYTES
:
case
ProtoBufType
.
TYPE_STRING
:
return
WIRETYPE_LENGTH_DELIMITED
;
case
ProtoBufType
.
TYPE_DOUBLE
:
case
ProtoBufType
.
TYPE_FIXED64
:
case
ProtoBufType
.
TYPE_SFIXED64
:
return
WIRETYPE_FIXED64
;
case
ProtoBufType
.
TYPE_FLOAT
:
case
ProtoBufType
.
TYPE_FIXED32
:
case
ProtoBufType
.
TYPE_SFIXED32
:
return
WIRETYPE_FIXED32
;
case
ProtoBufType
.
TYPE_GROUP
:
return
WIRETYPE_START_GROUP
;
default
:
throw
new
RuntimeException
(
MSG_UNSUPPORTED
+
':'
+
msgType
+
'/'
+
tag
+
'/'
+
tagType
);
}
}
/**
* Inserts a value.
*/
private
void
insertObject
(
int
tag
,
int
index
,
Object
o
)
{
assertTypeMatch
(
tag
,
o
);
int
count
=
getCount
(
tag
);
if
(
count
==
0
)
{
setObject
(
tag
,
o
);
}
else
{
Object
curr
=
values
.
elementAt
(
tag
);
Vector
v
;
if
(
curr
instanceof
Vector
)
{
v
=
(
Vector
)
curr
;
}
else
{
v
=
new
Vector
();
v
.
addElement
(
curr
);
values
.
setElementAt
(
v
,
tag
);
}
v
.
insertElementAt
(
o
,
index
);
}
}
/**
* Converts the object if a better suited class exists for the given .proto
* type. If the formats are not compatible, an exception is thrown.
*/
private
Object
convert
(
Object
obj
,
int
tagType
)
{
switch
(
tagType
)
{
case
ProtoBufType
.
TYPE_UNDEFINED
:
return
obj
;
case
ProtoBufType
.
TYPE_BOOL
:
if
(
obj
instanceof
Boolean
)
{
return
obj
;
}
switch
((
int
)
((
Long
)
obj
).
longValue
())
{
case
0
:
return
FALSE
;
case
1
:
return
TRUE
;
default
:
throw
new
IllegalArgumentException
(
MSG_MISMATCH
);
}
case
ProtoBufType
.
TYPE_FIXED32
:
case
ProtoBufType
.
TYPE_FIXED64
:
case
ProtoBufType
.
TYPE_INT32
:
case
ProtoBufType
.
TYPE_INT64
:
case
ProtoBufType
.
TYPE_SFIXED32
:
case
ProtoBufType
.
TYPE_SFIXED64
:
case
ProtoBufType
.
TYPE_SINT32
:
case
ProtoBufType
.
TYPE_SINT64
:
if
(
obj
instanceof
Boolean
)
{
return
SMALL_NUMBERS
[((
Boolean
)
obj
).
booleanValue
()
?
1
:
0
];
}
return
obj
;
case
ProtoBufType
.
TYPE_DATA
:
case
ProtoBufType
.
TYPE_BYTES
:
if
(
obj
instanceof
String
)
{
return
encodeUtf8
((
String
)
obj
);
}
else
if
(
obj
instanceof
ProtoBuf
)
{
ByteArrayOutputStream
buf
=
new
ByteArrayOutputStream
();
try
{
((
ProtoBuf
)
obj
).
outputTo
(
buf
);
return
buf
.
toByteArray
();
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
.
toString
());
}
}
return
obj
;
case
ProtoBufType
.
TYPE_TEXT
:
case
ProtoBufType
.
TYPE_STRING
:
if
(
obj
instanceof
byte
[])
{
byte
[]
data
=
(
byte
[])
obj
;
return
decodeUtf8
(
data
,
0
,
data
.
length
,
true
);
}
return
obj
;
case
ProtoBufType
.
TYPE_GROUP
:
case
ProtoBufType
.
TYPE_MESSAGE
:
if
(
obj
instanceof
byte
[])
{
try
{
return
new
ProtoBuf
(
null
).
parse
((
byte
[])
obj
);
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
.
toString
());
}
}
return
obj
;
default
:
// default includes FLOAT and DOUBLE
throw
new
RuntimeException
(
MSG_UNSUPPORTED
);
}
}
/**
* Reads a variable-size integer (up to 10 bytes for 64 bit) from the
* given input stream.
*
* @param is the stream to read from
* @param permitEOF if true, -1 is returned when EOF is reached instead of
* throwing an IOException
* @return the integer value read from the stream, or -1 if EOF is
* reached and permitEOF is true
* @throws IOException thrown for underlying IO issues and if EOF
* is reached and permitEOF is false
*/
static
long
readVarInt
(
InputStream
is
,
boolean
permitEOF
)
throws
IOException
{
long
result
=
0
;
int
shift
=
0
;
// max 10 byte wire format for 64 bit integer (7 bit data per byte)
for
(
int
i
=
0
;
i
<
VARINT_MAX_BYTES
;
i
++)
{
int
in
=
is
.
read
();
if
(
in
==
-
1
)
{
if
(
i
==
0
&&
permitEOF
)
{
return
-
1
;
}
else
{
throw
new
IOException
(
"EOF"
);
}
}
result
|=
((
long
)
(
in
&
0x07f
))
<<
shift
;
if
((
in
&
0x80
)
==
0
){
break
;
// get out early
}
shift
+=
7
;
}
return
result
;
}
/**
* Internal helper method to set a (single) value. Overwrites all existing
* values.
*/
private
void
setObject
(
int
tag
,
Object
o
)
{
if
(
values
.
size
()
<=
tag
)
{
values
.
setSize
(
tag
+
1
);
}
if
(
o
!=
null
)
{
assertTypeMatch
(
tag
,
o
);
}
values
.
setElementAt
(
o
,
tag
);
}
/**
* Write a variable-size integer to the given output stream.
*/
static
void
writeVarInt
(
OutputStream
os
,
long
value
)
throws
IOException
{
for
(
int
i
=
0
;
i
<
VARINT_MAX_BYTES
;
i
++)
{
int
toWrite
=
(
int
)
(
value
&
0x7f
);
value
>>>=
7
;
if
(
value
==
0
)
{
os
.
write
(
toWrite
);
break
;
}
else
{
os
.
write
(
toWrite
|
0x080
);
}
}
}
/**
* Returns a byte array containing the given string, encoded as UTF-8. The
* returned byte array contains at least s.length() bytes and at most
* 4 * s.length() bytes. UTF-16 surrogates are transcoded to UTF-8.
*
* @param s input string to be encoded
* @return UTF-8 encoded input string
*/
static
byte
[]
encodeUtf8
(
String
s
)
{
int
len
=
encodeUtf8
(
s
,
null
,
0
);
byte
[]
result
=
new
byte
[
len
];
encodeUtf8
(
s
,
result
,
0
);
return
result
;
}
/**
* 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
* 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)
if
(((
codeLo
&
0xfc00
)
^
(
code
&
0x0fc00
))
==
0x0400
){
i
+=
1
;
int
codeHi
;
if
((
codeLo
&
0xfc00
)
==
0x0d800
){
codeHi
=
codeLo
;
codeLo
=
code
;
}
else
{
codeHi
=
code
;
}
code
=
(((
codeHi
&
0x3ff
)
<<
10
)
|
(
codeLo
&
0x3ff
))
+
0x10000
;
}
}
if
(
code
<=
0x007f
)
{
if
(
buf
!=
null
){
buf
[
pos
]
=
(
byte
)
code
;
}
pos
+=
1
;
}
else
if
(
code
<=
0x07FF
)
{
// non-ASCII <= 0x7FF
if
(
buf
!=
null
){
buf
[
pos
]
=
(
byte
)
(
0xc0
|
(
code
>>
6
));
buf
[
pos
+
1
]
=
(
byte
)
(
0x80
|
(
code
&
0x3F
));
}
pos
+=
2
;
}
else
if
(
code
<=
0xFFFF
){
// 0x7FF < code <= 0xFFFF
if
(
buf
!=
null
){
buf
[
pos
]
=
(
byte
)
((
0xe0
|
(
code
>>
12
)));
buf
[
pos
+
1
]
=
(
byte
)
((
0x80
|
((
code
>>
6
)
&
0x3F
)));
buf
[
pos
+
2
]
=
(
byte
)
((
0x80
|
(
code
&
0x3F
)));
}
pos
+=
3
;
}
else
{
if
(
buf
!=
null
){
buf
[
pos
]
=
(
byte
)
((
0xf0
|
(
code
>>
18
)));
buf
[
pos
+
1
]
=
(
byte
)
((
0x80
|
((
code
>>
12
)
&
0x3F
)));
buf
[
pos
+
2
]
=
(
byte
)
((
0x80
|
((
code
>>
6
)
&
0x3F
)));
buf
[
pos
+
3
]
=
(
byte
)
((
0x80
|
(
code
&
0x3F
)));
}
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
* @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
* UTF-8 codes
* @return the string containing the UTF-8 decoding result
*/
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
if
(!
tolerant
){
throw
new
IllegalArgumentException
(
"Invalid UTF8"
);
}
sb
.
append
((
char
)
b
);
}
else
{
int
border
=
0xe0
;
int
count
=
1
;
int
minCode
=
128
;
int
mask
=
0x01f
;
while
(
b
>=
border
){
border
=
(
border
>>
1
)
|
0x80
;
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
){
if
(!
tolerant
){
throw
new
IllegalArgumentException
(
"Invalid UTF8"
);
}
// otherwise, assume zeroes
}
else
{
if
(!
tolerant
&&
(
data
[
pos
]
&
0xc0
)
!=
0x80
){
throw
new
IllegalArgumentException
(
"Invalid UTF8"
);
}
code
|=
(
data
[
pos
++]
&
0x3f
);
// six bit
}
}
// illegal code or surrogate code
if
(!
tolerant
&&
code
<
minCode
||
(
code
>=
0xd800
&&
code
<=
0xdfff
)){
throw
new
IllegalArgumentException
(
"Invalid UTF8"
);
}
if
(
code
<=
0x0ffff
){
sb
.
append
((
char
)
code
);
}
else
{
// surrogate UTF16
code
-=
0x10000
;
sb
.
append
((
char
)
(
0xd800
|
(
code
>>
10
)));
// high 10 bit
sb
.
append
((
char
)
(
0xdc00
|
(
code
&
0x3ff
)));
// low 10 bit
}
}
}
return
sb
.
toString
();
}
}
src/com/google/common/io/protocol/ProtoBufType.java
deleted
100644 → 0
View file @
a3cc5f17
// Copyright 2007 Google Inc.
// All Rights Reserved.
package
com
.
google
.
common
.
io
.
protocol
;
import
java.util.*
;
/**
* This class can be used to create a memory model of a .proto file. Currently,
* it is assumed that tags ids are not large. This could be improved by storing
* a start offset, relaxing the assumption to a dense number space.
*/
public
class
ProtoBufType
{
// Note: Values 0..15 are reserved for wire types!
public
static
final
int
TYPE_UNDEFINED
=
16
;
public
static
final
int
TYPE_DOUBLE
=
17
;
public
static
final
int
TYPE_FLOAT
=
18
;
public
static
final
int
TYPE_INT64
=
19
;
public
static
final
int
TYPE_UINT64
=
20
;
public
static
final
int
TYPE_INT32
=
21
;
public
static
final
int
TYPE_FIXED64
=
22
;
public
static
final
int
TYPE_FIXED32
=
23
;
public
static
final
int
TYPE_BOOL
=
24
;
public
static
final
int
TYPE_DATA
=
25
;
public
static
final
int
TYPE_GROUP
=
26
;
public
static
final
int
TYPE_MESSAGE
=
27
;
public
static
final
int
TYPE_TEXT
=
28
;
public
static
final
int
TYPE_UINT32
=
29
;
public
static
final
int
TYPE_ENUM
=
30
;
public
static
final
int
TYPE_SFIXED32
=
31
;
public
static
final
int
TYPE_SFIXED64
=
32
;
// new protobuf 2 types
public
static
final
int
TYPE_SINT32
=
33
;
public
static
final
int
TYPE_SINT64
=
34
;
public
static
final
int
TYPE_BYTES
=
35
;
public
static
final
int
TYPE_STRING
=
36
;
public
static
final
int
MASK_TYPE
=
0x0ff
;
public
static
final
int
MASK_MODIFIER
=
0x0ff00
;
public
static
final
int
REQUIRED
=
0x100
;
public
static
final
int
OPTIONAL
=
0x200
;
public
static
final
int
REPEATED
=
0x400
;
private
final
StringBuffer
types
=
new
StringBuffer
();
private
final
Vector
data
=
new
Vector
();
private
final
String
typeName
;
/**
* Empty constructor.
*/
public
ProtoBufType
()
{
typeName
=
null
;
}
/**
* Constructor including a type name for debugging purposes.
*/
public
ProtoBufType
(
String
typeName
)
{
this
.
typeName
=
typeName
;
}
/**
* Adds a tag description. The data parameter contains the group definition
* for group elements and the default value for regular elements.
*
* @param optionsAndType any legal combination (bitwise or) of REQUIRED
* or OPTIONAL and REPEATED and one of the TYPE_
* constants
* @param tag the tag id
* @param data the type for group elements (or the default value for
* regular elements in future versions)
* @return this is returned to permit cascading
*/
public
ProtoBufType
addElement
(
int
optionsAndType
,
int
tag
,
Object
data
)
{
while
(
types
.
length
()
<=
tag
)
{
types
.
append
((
char
)
TYPE_UNDEFINED
);
this
.
data
.
addElement
(
null
);
}
types
.
setCharAt
(
tag
,
(
char
)
optionsAndType
);
this
.
data
.
setElementAt
(
data
,
tag
);
return
this
;
}
/**
* Returns the type for the given tag id (without modifiers such as OPTIONAL,
* REPEATED). For undefined tags, TYPE_UNDEFINED is returned.
*/
public
int
getType
(
int
tag
)
{
return
(
tag
<
0
||
tag
>=
types
.
length
())
?
TYPE_UNDEFINED
:
(
types
.
charAt
(
tag
)
&
MASK_TYPE
);
}
/**
* Returns a bit combination of the modifiers for the given tag id
* (OPTIONAL, REPEATED, REQUIRED). For undefined tags, OPTIONAL|REPEATED
* is returned.
*/
public
int
getModifiers
(
int
tag
)
{
return
(
tag
<
0
||
tag
>=
types
.
length
())
?
(
OPTIONAL
|
REPEATED
)
:
(
types
.
charAt
(
tag
)
&
MASK_MODIFIER
);
}
/**
* Returns the data associated to a given tag (either the default value for
* regular elements or a ProtoBufType for groups and messages). For undefined
* tags, null is returned.
*/
public
Object
getData
(
int
tag
)
{
return
(
tag
<
0
||
tag
>=
data
.
size
())
?
null
:
data
.
elementAt
(
tag
);
}
/**
* Returns the type name set in the constructor for debugging purposes.
*/
public
String
toString
()
{
return
typeName
;
}
/**
* {@inheritDoc}
* <p>Two ProtoBufTypes are equals if the fields types are the same.
*/
public
boolean
equals
(
Object
object
)
{
if
(
null
==
object
)
{
// trivial check
return
false
;
}
else
if
(
this
==
object
)
{
// trivial check
return
true
;
}
else
if
(
this
.
getClass
()
!=
object
.
getClass
())
{
// different class
return
false
;
}
ProtoBufType
other
=
(
ProtoBufType
)
object
;
return
stringEquals
(
types
,
other
.
types
);
}
/**
* {@inheritDoc}
*/
public
int
hashCode
()
{
if
(
types
!=
null
)
{
return
types
.
hashCode
();
}
else
{
return
super
.
hashCode
();
}
}
public
static
boolean
stringEquals
(
CharSequence
a
,
CharSequence
b
)
{
if
(
a
==
b
)
return
true
;
int
length
;
if
(
a
!=
null
&&
b
!=
null
&&
(
length
=
a
.
length
())
==
b
.
length
())
{
if
(
a
instanceof
String
&&
b
instanceof
String
)
{
return
a
.
equals
(
b
);
}
else
{
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
if
(
a
.
charAt
(
i
)
!=
b
.
charAt
(
i
))
return
false
;
}
return
true
;
}
}
return
false
;
}
}
src/com/google/common/io/protocol/ProtoBufUtil.java
deleted
100644 → 0
View file @
a3cc5f17
// Copyright 2008 Google Inc. All Rights Reserved.
package
com
.
google
.
common
.
io
.
protocol
;
import
java.io.*
;
/**
* Utility functions for dealing with ProtoBuf objects consolidated from
* previous spot implementations across the codebase.
*
*/
public
final
class
ProtoBufUtil
{
private
ProtoBufUtil
()
{
}
/** Convenience method to return a string value from of a proto or "". */
public
static
String
getProtoValueOrEmpty
(
ProtoBuf
proto
,
int
tag
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
))
?
proto
.
getString
(
tag
)
:
""
;
}
catch
(
ClassCastException
e
)
{
return
""
;
}
}
/** Convenience method to return a string value from of a sub-proto or "". */
public
static
String
getSubProtoValueOrEmpty
(
ProtoBuf
proto
,
int
sub
,
int
tag
)
{
try
{
return
getProtoValueOrEmpty
(
getSubProtoOrNull
(
proto
,
sub
),
tag
);
}
catch
(
ClassCastException
e
)
{
return
""
;
}
}
/** Convenience method to get a subproto if the proto has it. */
public
static
ProtoBuf
getSubProtoOrNull
(
ProtoBuf
proto
,
int
sub
)
{
return
(
proto
!=
null
&&
proto
.
has
(
sub
))
?
proto
.
getProtoBuf
(
sub
)
:
null
;
}
/**
* Get an int with "tag" from the proto buffer. If the given field can't be
* retrieved, return the provided default value.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @param defaultValue The value to return if the field can't be retrieved.
* @return The result which should be an integer.
*/
public
static
int
getProtoValueOrDefault
(
ProtoBuf
proto
,
int
tag
,
int
defaultValue
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
))
?
proto
.
getInt
(
tag
)
:
defaultValue
;
}
catch
(
IllegalArgumentException
e
)
{
return
defaultValue
;
}
catch
(
ClassCastException
e
)
{
return
defaultValue
;
}
}
/**
* Get an Int with "tag" from the proto buffer.
* If the given field can't be retrieved, return 0.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @return The result which should be an integer.
*/
public
static
int
getProtoValueOrZero
(
ProtoBuf
proto
,
int
tag
)
{
return
getProtoValueOrDefault
(
proto
,
tag
,
0
);
}
/**
* Get an Long with "tag" from the proto buffer.
* If the given field can't be retrieved, return 0.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @return The result which should be an integer.
*/
public
static
long
getProtoLongValueOrZero
(
ProtoBuf
proto
,
int
tag
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
))
?
proto
.
getLong
(
tag
)
:
0L
;
}
catch
(
IllegalArgumentException
e
)
{
return
0L
;
}
catch
(
ClassCastException
e
)
{
return
0L
;
}
}
/**
* Get an Int with "tag" from the proto buffer.
* If the given field can't be retrieved, return -1.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @return The result which should be a long.
*/
public
static
long
getProtoValueOrNegativeOne
(
ProtoBuf
proto
,
int
tag
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
))
?
proto
.
getLong
(
tag
)
:
-
1
;
}
catch
(
IllegalArgumentException
e
)
{
return
-
1
;
}
catch
(
ClassCastException
e
)
{
return
-
1
;
}
}
/**
* Reads a single protocol buffer from the given input stream. This method is
* provided where the client needs incremental access to the contents of a
* protocol buffer which contains a sequence of protocol buffers.
* <p />
* Please use {@link #getInputStreamForProtoBufResponse} to obtain an input
* stream suitable for this method.
*
* @param umbrellaType the type of the "outer" protocol buffer containing
* the message to read
* @param is the stream to read the protocol buffer from
* @param result the result protocol buffer (must be empty, will be filled
* with the data read and the type will be set)
* @return the tag id of the message, -1 at the end of the stream
*/
public
static
int
readNextProtoBuf
(
ProtoBufType
umbrellaType
,
InputStream
is
,
ProtoBuf
result
)
throws
IOException
{
long
tagAndType
=
ProtoBuf
.
readVarInt
(
is
,
true
/* permits EOF */
);
if
(
tagAndType
==
-
1
)
{
return
-
1
;
}
if
((
tagAndType
&
7
)
!=
ProtoBuf
.
WIRETYPE_LENGTH_DELIMITED
)
{
throw
new
IOException
(
"Message expected"
);
}
int
tag
=
(
int
)
(
tagAndType
>>>
3
);
result
.
setType
((
ProtoBufType
)
umbrellaType
.
getData
(
tag
));
int
length
=
(
int
)
ProtoBuf
.
readVarInt
(
is
,
false
);
result
.
parse
(
is
,
length
);
return
tag
;
}
/**
* A wrapper for <code> getProtoValueOrNegativeOne </code> that drills into
* a sub message returning the long value if it exists, returning -1 if it
* does not.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @param sub The sub tag value that identifies which protocol buffer
* sub-field to retrieve.n
* @return The result which should be a long.
*/
public
static
long
getSubProtoValueOrNegativeOne
(
ProtoBuf
proto
,
int
sub
,
int
tag
)
{
try
{
return
getProtoValueOrNegativeOne
(
getSubProtoOrNull
(
proto
,
sub
),
tag
);
}
catch
(
IllegalArgumentException
e
)
{
return
-
1
;
}
catch
(
ClassCastException
e
)
{
return
-
1
;
}
}
/**
* A wrapper for {@link #getProtoValueOrDefault(ProtoBuf, int, int)} that
* drills into a sub message returning the int value if it exists, returning
* the given default if it does not.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* retrieve.
* @param sub The sub tag value that identifies which protocol buffer
* sub-field to retrieve.
* @param defaultValue The value to return if the field is not present.
* @return The result which should be a long.
*/
public
static
int
getSubProtoValueOrDefault
(
ProtoBuf
proto
,
int
sub
,
int
tag
,
int
defaultValue
)
{
try
{
return
getProtoValueOrDefault
(
getSubProtoOrNull
(
proto
,
sub
),
tag
,
defaultValue
);
}
catch
(
IllegalArgumentException
e
)
{
return
defaultValue
;
}
catch
(
ClassCastException
e
)
{
return
defaultValue
;
}
}
/**
* Creates a sub ProtoBuf of the given Protobuf and sets it.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* create.
* @return the sub ProtoBuf generated.
*/
public
static
ProtoBuf
createProtoBuf
(
ProtoBuf
proto
,
int
tag
)
{
ProtoBuf
child
=
proto
.
createGroup
(
tag
);
proto
.
setProtoBuf
(
tag
,
child
);
return
child
;
}
/**
* Creates a sub ProtoBuf of the given Protobuf and adds it.
*
* @param proto The proto buffer.
* @param tag The tag value that identifies which protocol buffer field to
* add.
* @return the sub ProtoBuf generated.
*/
public
static
ProtoBuf
addProtoBuf
(
ProtoBuf
proto
,
int
tag
)
{
ProtoBuf
child
=
proto
.
createGroup
(
tag
);
proto
.
addProtoBuf
(
tag
,
child
);
return
child
;
}
/**
* Writes the ProtoBuf to the given DataOutput. This is useful for unit
* tests.
*
* @param output The data output to write to.
* @param protoBuf The proto buffer.
*/
public
static
void
writeProtoBufToOutput
(
DataOutput
output
,
ProtoBuf
protoBuf
)
throws
IOException
{
ByteArrayOutputStream
baos
=
new
ByteArrayOutputStream
();
protoBuf
.
outputTo
(
baos
);
byte
[]
bytes
=
baos
.
toByteArray
();
output
.
writeInt
(
bytes
.
length
);
output
.
write
(
bytes
);
}
}
src/com/google/common/io/protocol/package.html
deleted
100644 → 0
View file @
a3cc5f17
<html>
<body>
{@hide}
</body>
</html>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment