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
7e013cac
Commit
7e013cac
authored
Jun 10, 2009
by
Mitsuru Oshima
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "ProtoBuf update"
This reverts commit 9aaf507646c866ab131bf2bcd973882ff9f553cf.
parent
babfb778
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
171 additions
and
653 deletions
+171
-653
IntMap.java
src/com/google/common/io/protocol/IntMap.java
+0
-383
ProtoBuf.java
src/com/google/common/io/protocol/ProtoBuf.java
+128
-188
ProtoBufType.java
src/com/google/common/io/protocol/ProtoBufType.java
+43
-63
ProtoBufUtil.java
src/com/google/common/io/protocol/ProtoBufUtil.java
+0
-19
No files found.
src/com/google/common/io/protocol/IntMap.java
deleted
100644 → 0
View file @
babfb778
// Copyright 2009 Google Inc. All Rights Reserved.
package
com
.
google
.
common
.
io
.
protocol
;
import
java.util.Enumeration
;
import
java.util.Hashtable
;
import
java.util.NoSuchElementException
;
/**
* A Map from primitive integers to Object values. This stores values
* for smaller keys in an Object array, and uses {@link Hashtable}
* only for larger keys. This is specifically designed to be used by
* J2me protocol buffer runtime ({@link ProtoBuf}, {@link ProtoBufType})
* to support large tags that are commonly used in Extensions/MessageSet.
*
* This class is not thread safe, so the client has to provide
* appropriate locking mechanism if the map is to be used from
* multiple threads.
*/
public
class
IntMap
{
private
static
final
int
MAX_LOWER_BUFFER_SIZE
=
64
;
private
static
final
int
INITIAL_LOWER_BUFFER_SIZE
=
8
;
/**
* An iterator that returns int keys of the IntMap. IntMap has its
* own Iterator instead of Enumeration to avoid autoboxing. This
* uses the same buffer of the IntMap, so you should not update the
* IntMap while the iterator is in use. Once the IntMap is changed,
* the behavior of preiously obtained iterator is undefined, and a new
* KeyIterator has to be used instead.
*/
public
class
KeyIterator
{
private
int
oneAheadIndex
=
0
;
private
int
currentKey
=
Integer
.
MIN_VALUE
;
private
Enumeration
higherKeyEnumerator
=
null
;
/**
* @returns true if there is more keys.
*/
public
boolean
hasNext
()
{
if
(
currentKey
!=
Integer
.
MIN_VALUE
)
{
return
true
;
}
if
(
oneAheadIndex
<=
maxLowerKey
)
{
for
(;
oneAheadIndex
<=
maxLowerKey
;
oneAheadIndex
++)
{
if
(
lower
[
oneAheadIndex
]
!=
null
)
{
// record the key, then increment the oneAheadIndex.
currentKey
=
oneAheadIndex
++;
return
true
;
}
}
}
if
(
higher
!=
null
)
{
if
(
higherKeyEnumerator
==
null
)
{
higherKeyEnumerator
=
higher
.
keys
();
}
if
(
higherKeyEnumerator
.
hasMoreElements
())
{
Integer
key
=
(
Integer
)
higherKeyEnumerator
.
nextElement
();
currentKey
=
key
.
intValue
();
return
true
;
}
}
return
false
;
}
/**
* @returns next key
* @throws NoSuchElementException if there is no more keys.
*/
public
int
next
()
{
if
(
currentKey
==
Integer
.
MIN_VALUE
&&
!
hasNext
())
{
throw
new
NoSuchElementException
();
}
int
key
=
currentKey
;
currentKey
=
Integer
.
MIN_VALUE
;
return
key
;
}
}
/** Stores values for lower keys */
private
Object
[]
lower
;
/** Hashtable for higher tags */
private
Hashtable
higher
;
/** A maximum key that has been ever added to the lower buffer.*/
private
int
maxLowerKey
;
/** A maximum key that has been ever added to the map.*/
private
int
maxKey
;
/** the number of elements in lower buffer */
private
int
lowerCount
;
/**
* Constructs an {@link IntMap} with default lower buffer size.
*/
public
IntMap
()
{
this
(
INITIAL_LOWER_BUFFER_SIZE
);
// can expand 3 times
}
/**
* Constructs an {@link IntMap} with the suggested initial lower buffer size.
* The argument is just a hint and may not be used. If its value is
* larger than {@link MAX_LOWER_BUFFER_SIZE} or negative, it will use the
* MAX_LOWER_BUFFER_SIZE instead.
*/
IntMap
(
int
initialLowerBufferSize
)
{
int
lowerBufferSize
=
INITIAL_LOWER_BUFFER_SIZE
;
if
(
initialLowerBufferSize
>
0
)
{
lowerBufferSize
=
Math
.
min
(
initialLowerBufferSize
,
MAX_LOWER_BUFFER_SIZE
);
}
lower
=
new
Object
[
lowerBufferSize
];
lowerCount
=
0
;
maxKey
=
Integer
.
MIN_VALUE
;
maxLowerKey
=
Integer
.
MIN_VALUE
;
}
/**
* A factory method to constructs an {@link IntMap} with the same
* lower buffer size.
*
* @return a new IntMap whose lower buffer size is same as
* this instance.
*/
public
IntMap
newIntMapWithSameBufferSize
()
{
return
new
IntMap
(
maxLowerKey
);
}
/**
* @return the {@link KeyIterator} of the map.
*/
public
KeyIterator
keys
()
{
return
new
KeyIterator
();
}
/**
* Returns max key that ever added to the map. Note that this is not
* max for current state. Removing the max key will not update the
* max key value. If nothing is added, it will return {@link
* Integer.MIN_VALUE}, which means you cannot tell if an value is
* added with MIN_VALUE key.
*/
public
int
maxKey
()
{
return
maxKey
;
}
/**
* Returns the number of key-value pairs in the map.
*/
public
int
size
()
{
return
higher
==
null
?
lowerCount
:
lowerCount
+
higher
.
size
();
}
/**
* @return true if the map is empty.
*/
public
boolean
isEmpty
()
{
return
size
()
==
0
;
}
/**
* Clears all key/value pairs. The map becomes empty after this
* operation, but does not release memory.
*/
public
void
clear
()
{
for
(
int
i
=
0
;
i
<
lower
.
length
;
i
++)
{
lower
[
i
]
=
null
;
}
if
(
higher
!=
null
)
higher
.
clear
();
maxKey
=
Integer
.
MIN_VALUE
;
maxLowerKey
=
Integer
.
MIN_VALUE
;
lowerCount
=
0
;
}
/**
* Returns the value associated with the given key.
*
* @param key a key
* @return the value associated with the given key. null if the map has
* no value for the key.
*/
public
Object
get
(
int
key
)
{
if
(
key
>
maxKey
)
{
return
null
;
}
else
if
(
0
<=
key
&&
key
<=
maxLowerKey
)
{
return
lower
[
key
];
}
else
if
(
higher
!=
null
)
{
return
higher
.
get
(
key
);
}
else
{
return
null
;
}
}
/**
* Maps the specified key to the given value in the {@link IntMap}.
* Caveat: Passing null value removes the value from the map. This is to
* keep the semantics used in {@link ProtoBuf}.
*
* @param key a key
* @param value the value to be added to the Map. If this is null,
* the key will be removed from the map. This method does nothing if
* the key does not exist and value is null.
*/
public
void
put
(
int
key
,
Object
value
)
{
if
(
value
==
null
)
{
remove
(
key
);
return
;
}
expandLowerIfNecessary
(
key
);
maxKey
=
Math
.
max
(
key
,
maxKey
);
if
(
0
<=
key
&&
key
<
lower
.
length
)
{
maxLowerKey
=
Math
.
max
(
key
,
maxLowerKey
);
if
(
lower
[
key
]
==
null
)
{
lowerCount
++;
}
lower
[
key
]
=
value
;
}
else
{
if
(
higher
==
null
)
{
higher
=
new
Hashtable
();
}
higher
.
put
(
key
,
value
);
}
}
/**
* Removes the key and corresponding value from the {@link IntMap}.
*
* @param key the key to remove. This method does nothing if the map does not
* have the value corresponding for the key.
* @return the removed value. null if the map does not have the value for
* the key.
*/
public
Object
remove
(
int
key
)
{
Object
deleted
=
null
;
if
(
0
<=
key
&&
key
<
lower
.
length
)
{
deleted
=
lower
[
key
];
if
(
deleted
!=
null
)
{
lowerCount
--;
}
lower
[
key
]
=
null
;
}
else
if
(
higher
!=
null
)
{
return
higher
.
remove
(
key
);
}
return
deleted
;
}
/**
* Tests if given key has a corresponding value in this {@link IntMap}.
*
* @param key possible key.
* @return <code>true</code> if the given key has the correspoding
* value. <code>false</code> otherwise.
*/
public
boolean
containsKey
(
int
key
)
{
if
(
0
<=
key
&&
key
<
lower
.
length
)
{
return
lower
[
key
]
!=
null
;
}
else
if
(
higher
!=
null
)
{
return
higher
.
containsKey
(
key
);
}
return
false
;
}
/**
* Returns hashcode for {@link IntMap}.
*/
public
int
hashCode
()
{
int
hashCode
=
1
;
for
(
int
i
=
0
;
i
<
lower
.
length
;
i
++)
{
Object
value
=
lower
[
i
];
if
(
value
!=
null
)
{
hashCode
=
31
*
hashCode
+
value
.
hashCode
()
+
i
;
}
}
// Hashtable in J2me does not implement hashCode(), so we simply
// use the size of hashtable.
return
higher
==
null
?
hashCode
:
hashCode
+
higher
.
size
();
}
/**
* Compares the equality. Two IntMaps are considered equals iff
* both map have the same key-value pairs.
* Caveat: This assumes that the Class of each value object implements
* equals correctly. This may not be the case in J2me.
*
* @param object an object to be compared with
* @return true if the specified Object is equal to this IntMap
*/
public
boolean
equals
(
Object
object
)
{
if
(
this
==
object
)
{
return
true
;
}
if
(
object
==
null
||
!(
object
instanceof
IntMap
))
{
return
false
;
}
IntMap
peer
=
(
IntMap
)
object
;
if
(
size
()
!=
peer
.
size
())
{
return
false
;
}
return
compareLowerBuffer
(
lower
,
peer
.
lower
)
&&
compareHashtable
(
higher
,
peer
.
higher
);
}
private
boolean
compareLowerBuffer
(
Object
[]
lower1
,
Object
[]
lower2
)
{
int
min
=
Math
.
min
(
lower1
.
length
,
lower2
.
length
);
for
(
int
i
=
0
;
i
<
min
;
i
++)
{
if
((
lower1
[
i
]
==
null
&&
lower2
[
i
]
!=
null
)
||
(
lower1
[
i
]
!=
null
&&
!
lower1
[
i
].
equals
(
lower2
[
i
])))
{
return
false
;
}
}
// make sure there are no values in remaining fields.
if
(
lower1
.
length
>
lower2
.
length
)
{
for
(
int
i
=
min
;
i
<
lower1
.
length
;
i
++)
{
if
(
lower1
[
i
]
!=
null
)
return
false
;
}
}
else
if
(
lower1
.
length
<
lower2
.
length
)
{
for
(
int
i
=
min
;
i
<
lower2
.
length
;
i
++)
{
if
(
lower2
[
i
]
!=
null
)
return
false
;
}
}
return
true
;
}
/**
* J2me's Hashtable does not implement equal, Bummer!
*/
private
static
boolean
compareHashtable
(
Hashtable
h1
,
Hashtable
h2
)
{
if
(
h1
==
h2
)
{
// null == null is caught here
return
true
;
}
if
(
h1
==
null
||
h2
==
null
)
{
return
false
;
}
if
(
h1
.
size
()
!=
h2
.
size
())
{
return
false
;
}
// Ensure the values are the same.
Enumeration
h1Keys
=
h1
.
keys
();
while
(
h1Keys
.
hasMoreElements
())
{
Object
key
=
h1Keys
.
nextElement
();
Object
h1Value
=
h1
.
get
(
key
);
Object
h2Value
=
h2
.
get
(
key
);
if
(!
h1Value
.
equals
(
h2Value
))
{
return
false
;
}
}
return
true
;
}
/**
* Expands lower buffer iff the key does not fit to current buffer size,
* but will fit in MAX buffer size.
*/
private
void
expandLowerIfNecessary
(
int
key
)
{
if
(
key
<=
MAX_LOWER_BUFFER_SIZE
&&
key
>=
lower
.
length
&&
key
>
0
)
{
int
size
=
lower
.
length
;
do
{
size
<<=
1
;
}
while
(
size
<=
key
);
size
=
Math
.
min
(
size
,
MAX_LOWER_BUFFER_SIZE
);
Object
[]
newLower
=
new
Object
[
size
];
System
.
arraycopy
(
lower
,
0
,
newLower
,
0
,
lower
.
length
);
lower
=
newLower
;
}
}
/* {@inheritDoc} */
public
String
toString
()
{
StringBuffer
buffer
=
new
StringBuffer
(
"IntMap{lower:"
);
for
(
int
i
=
0
;
i
<
lower
.
length
;
i
++)
{
if
(
lower
[
i
]
!=
null
)
{
buffer
.
append
(
i
);
buffer
.
append
(
"=>"
);
buffer
.
append
(
lower
[
i
]);
buffer
.
append
(
", "
);
}
}
buffer
.
append
(
", higher:"
+
higher
+
"}"
);
return
buffer
.
toString
();
}
}
src/com/google/common/io/protocol/ProtoBuf.java
View file @
7e013cac
...
...
@@ -7,7 +7,9 @@ import java.io.*;
import
java.util.*
;
/**
* Protocol buffer message object.
* 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
...
...
@@ -31,6 +33,7 @@ import java.util.*;
* 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
{
...
...
@@ -42,9 +45,7 @@ public class ProtoBuf {
private
static
final
String
MSG_MISMATCH
=
"Type mismatch"
;
private
static
final
String
MSG_UNSUPPORTED
=
"Unsupp.Type"
;
// see
// http://code.google.com/apis/protocolbuffers/docs/overview.html
// for more details about wire format.
// 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
;
...
...
@@ -55,19 +56,20 @@ public class ProtoBuf {
/** 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
IntMap
values
;
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
IntMap
wireTypes
;
/**
* Saved by a call to #getCachedDataSize(false) and returned in #getCachedSize()
*/
private
int
cachedSize
=
Integer
.
MIN_VALUE
;
private
final
StringBuffer
wireTypes
=
new
StringBuffer
();
/**
* Creates a protocol message according to the given description. The
...
...
@@ -76,22 +78,14 @@ public class ProtoBuf {
*/
public
ProtoBuf
(
ProtoBufType
type
)
{
this
.
msgType
=
type
;
if
(
type
!=
null
)
{
// if the type is known, use the type to create IntMaps.
values
=
type
.
newIntMapForProtoBuf
();
wireTypes
=
type
.
newIntMapForProtoBuf
();
}
else
{
values
=
new
IntMap
();
wireTypes
=
new
IntMap
();
}
}
/**
/**
* Clears all data stored in this ProtoBuf.
*/
public
void
clear
()
{
values
.
clear
(
);
wireTypes
.
clear
(
);
values
.
setSize
(
0
);
wireTypes
.
setLength
(
0
);
}
/**
...
...
@@ -216,7 +210,7 @@ public class ProtoBuf {
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
)
{
...
...
@@ -311,8 +305,7 @@ public class ProtoBuf {
* @param type the new type
*/
void
setType
(
ProtoBufType
type
)
{
// reject if the type is already set, or value is alreay set.
if
(!
values
.
isEmpty
()
||
if
(
values
.
size
()
!=
0
||
(
msgType
!=
null
&&
type
!=
null
&&
type
!=
msgType
))
{
throw
new
IllegalArgumentException
();
}
...
...
@@ -366,8 +359,7 @@ public class ProtoBuf {
* @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, or if we encounter bad data
* while reading.
* an unexpected position
*/
public
int
parse
(
InputStream
is
,
int
available
)
throws
IOException
{
...
...
@@ -384,7 +376,11 @@ public class ProtoBuf {
break
;
}
int
tag
=
(
int
)
(
tagAndType
>>>
3
);
wireTypes
.
put
(
tag
,
wireType
);
while
(
wireTypes
.
length
()
<=
tag
){
wireTypes
.
append
((
char
)
ProtoBufType
.
TYPE_UNDEFINED
);
}
wireTypes
.
setCharAt
(
tag
,
(
char
)
wireType
);
// first step: decode tag value
Object
value
;
switch
(
wireType
)
{
...
...
@@ -394,7 +390,8 @@ public class ProtoBuf {
if
(
isZigZagEncodedType
(
tag
))
{
v
=
zigZagDecode
(
v
);
}
value
=
v
;
value
=
(
v
>=
0
&&
v
<
SMALL_NUMBERS
.
length
)
?
SMALL_NUMBERS
[(
int
)
v
]
:
new
Long
(
v
);
break
;
// also used for fixed values
...
...
@@ -411,7 +408,9 @@ public class ProtoBuf {
shift
+=
8
;
}
value
=
v
;
value
=
(
v
>=
0
&&
v
<
SMALL_NUMBERS
.
length
)
?
SMALL_NUMBERS
[(
int
)
v
]
:
new
Long
(
v
);
break
;
case
WIRETYPE_LENGTH_DELIMITED:
...
...
@@ -446,8 +445,7 @@ public class ProtoBuf {
break
;
default
:
throw
new
IOException
(
"Unknown wire type "
+
wireType
+
", reading garbage data?"
);
throw
new
RuntimeException
(
MSG_UNSUPPORTED
+
wireType
);
}
insertObject
(
tag
,
getCount
(
tag
),
value
);
}
...
...
@@ -468,9 +466,9 @@ public class ProtoBuf {
throw
new
ArrayIndexOutOfBoundsException
();
}
if
(
count
==
1
){
values
.
remove
(
tag
);
values
.
setElementAt
(
null
,
tag
);
}
else
{
Vector
v
=
(
Vector
)
values
.
ge
t
(
tag
);
Vector
v
=
(
Vector
)
values
.
elementA
t
(
tag
);
v
.
removeElementAt
(
index
);
}
}
...
...
@@ -479,15 +477,12 @@ public class ProtoBuf {
* 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).
*
* @param tag the tag of the field
* @throws ArrayIndexOutOfBoundsException when tag is < 0
*/
public
int
getCount
(
int
tag
)
{
if
(
tag
<
0
)
{
throw
new
ArrayIndexOutOfBoundsException
(
tag
)
;
if
(
tag
>=
values
.
size
())
{
return
0
;
}
Object
o
=
values
.
ge
t
(
tag
);
Object
o
=
values
.
elementA
t
(
tag
);
if
(
o
==
null
){
return
0
;
}
...
...
@@ -507,69 +502,38 @@ public class ProtoBuf {
tagType
=
msgType
.
getType
(
tag
);
}
if
(
tagType
==
ProtoBufType
.
TYPE_UNDEFINED
)
{
Integer
tagTypeObj
=
(
Integer
)
wireTypes
.
get
(
tag
);
if
(
tagTypeObj
!=
null
)
{
tagType
=
tagTypeObj
.
intValue
();
}
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
)
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
()
{
return
getCachedDataSize
(
false
/* don't trust cache */
);
}
/**
* Each Protobuf keeps track of a <code> cachedSize </code> that is
* used to short circuit evaluation of its children's sizes. This value
* should only be trusted if you are reasonably certain it cannot be
* corrupt. (A corrupt cache can happen if any child ProtoBuf of this
* ProtoBuf has had a value set. In general, it is best to only trust
* the cache if you have just finished cleansing it.)
*
* <P/>The cache can be cleansed by calling this method with
* trustCache = false.
*
* @param trustCache if the cached size should be trusted. Set false to
* recompuate the size.
*/
private
int
getCachedDataSize
(
boolean
trustCache
)
{
if
(
cachedSize
!=
Integer
.
MIN_VALUE
&&
trustCache
)
{
return
cachedSize
;
}
int
size
=
0
;
IntMap
.
KeyIterator
itr
=
values
.
keys
();
while
(
itr
.
hasNext
())
{
int
tag
=
itr
.
next
();
for
(
int
tag
=
0
;
tag
<=
maxTag
();
tag
++)
{
for
(
int
i
=
0
;
i
<
getCount
(
tag
);
i
++)
{
size
+=
get
CachedDataSize
(
tag
,
i
,
trustCache
);
size
+=
get
DataSize
(
tag
,
i
);
}
}
cachedSize
=
size
;
return
cachedSize
;
}
return
size
;
}
/**
* Returns the size of the child.
*
* @param tag tag used to determine the type of this child
* @param i used to determine which count this child is
* @param trustSizeCache passed down to #getCachedDataSize()
/**
* Returns the size of the given value
*/
private
int
get
CachedDataSize
(
int
tag
,
int
i
,
boolean
trustSizeCache
)
{
private
int
get
DataSize
(
int
tag
,
int
i
)
{
int
tagSize
=
getVarIntSize
(
tag
<<
3
);
switch
(
getWireType
(
tag
)){
...
...
@@ -587,20 +551,20 @@ public class ProtoBuf {
// 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
[])
{
if
(
o
instanceof
byte
[]){
contentSize
=
((
byte
[])
o
).
length
;
}
else
if
(
o
instanceof
String
)
{
contentSize
=
encodeUtf8
((
String
)
o
,
null
,
0
);
}
else
{
contentSize
=
((
ProtoBuf
)
o
).
get
CachedDataSize
(
trustSizeCache
);
contentSize
=
((
ProtoBuf
)
o
).
get
DataSize
(
);
}
return
tagSize
+
getVarIntSize
(
contentSize
)
+
contentSize
;
}
...
...
@@ -620,93 +584,67 @@ public class ProtoBuf {
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
* @throws
IOException thrown if there is an IOException
*/
public
void
outputTo
(
OutputStream
os
)
throws
IOException
{
// We can't know what changed since we last output, so refresh the children.
getDataSize
();
outputToInternal
(
os
);
}
/**
* Recursive output method wrapped by #outputTo()
*
* @param os target output stream
* @throws IOException thrown if there is an IOException
*/
private
void
outputToInternal
(
OutputStream
os
)
throws
IOException
{
IntMap
.
KeyIterator
itr
=
values
.
keys
();
while
(
itr
.
hasNext
())
{
int
tag
=
itr
.
next
();
outputField
(
tag
,
os
);
}
}
/**
* Output a field indicated by the tag to given stream.
*
* @param tag the tag of the field to output.
* @param os target output stream
* @throws IOException thrown if there is an IOException
*/
private
void
outputField
(
int
tag
,
OutputStream
os
)
throws
IOException
{
int
size
=
getCount
(
tag
);
int
wireType
=
getWireType
(
tag
);
int
wireTypeTag
=
(
tag
<<
3
)
|
wireType
;
// ignore default values
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
writeVarInt
(
os
,
wireTypeTag
);
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
.
getCachedDataSize
(
true
));
msg
.
outputToInternal
(
os
);
}
break
;
case
WIRETYPE_START_GROUP:
((
ProtoBuf
)
getObject
(
tag
,
i
,
ProtoBufType
.
TYPE_GROUP
))
.
outputToInternal
(
os
);
writeVarInt
(
os
,
(
tag
<<
3
)
|
WIRETYPE_END_GROUP
);
break
;
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
;
default
:
throw
new
IllegalArgumentException
();
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
();
}
}
}
}
...
...
@@ -755,12 +693,12 @@ public class ProtoBuf {
outputTo
(
baos
);
return
baos
.
toByteArray
();
}
/**
* Returns the largest tag id used in this message (to simplify testing).
*/
public
int
maxTag
()
{
return
values
.
maxKey
()
;
return
values
.
size
()
-
1
;
}
/**
...
...
@@ -788,7 +726,8 @@ public class ProtoBuf {
* Sets the given tag to the given long value.
*/
public
void
setLong
(
int
tag
,
long
value
)
{
setObject
(
tag
,
value
);
setObject
(
tag
,
value
>=
0
&&
value
<
SMALL_NUMBERS
.
length
?
SMALL_NUMBERS
[(
int
)
value
]
:
new
Long
(
value
));
}
/**
...
...
@@ -856,7 +795,8 @@ public class ProtoBuf {
* 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
);
insertObject
(
tag
,
index
,
value
>=
0
&&
value
<
SMALL_NUMBERS
.
length
?
SMALL_NUMBERS
[(
int
)
value
]
:
new
Long
(
value
));
}
/**
...
...
@@ -939,8 +879,8 @@ public class ProtoBuf {
case
ProtoBufType
.
TYPE_GROUP
:
case
ProtoBufType
.
TYPE_MESSAGE
:
if
(
msgType
==
null
||
msgType
.
getData
(
tag
)
==
null
||
((
ProtoBuf
)
object
).
msgType
==
null
||
((
ProtoBuf
)
object
).
msgType
.
equals
(
msgType
.
getData
(
tag
)
))
{
((
ProtoBuf
)
object
).
msgType
==
null
||
((
ProtoBuf
)
object
).
msgType
==
msgType
.
getData
(
tag
))
{
return
;
}
}
...
...
@@ -1004,7 +944,7 @@ public class ProtoBuf {
throw
new
ArrayIndexOutOfBoundsException
();
}
Object
o
=
values
.
ge
t
(
tag
);
Object
o
=
values
.
elementA
t
(
tag
);
Vector
v
=
null
;
if
(
o
instanceof
Vector
)
{
...
...
@@ -1085,14 +1025,14 @@ public class ProtoBuf {
if
(
count
==
0
)
{
setObject
(
tag
,
o
);
}
else
{
Object
curr
=
values
.
ge
t
(
tag
);
Object
curr
=
values
.
elementA
t
(
tag
);
Vector
v
;
if
(
curr
instanceof
Vector
)
{
v
=
(
Vector
)
curr
;
}
else
{
v
=
new
Vector
();
v
.
addElement
(
curr
);
values
.
put
(
tag
,
v
);
values
.
setElementAt
(
v
,
tag
);
}
v
.
insertElementAt
(
o
,
index
);
}
...
...
@@ -1102,7 +1042,7 @@ public class ProtoBuf {
* 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
static
Object
convert
(
Object
obj
,
int
tagType
)
{
private
Object
convert
(
Object
obj
,
int
tagType
)
{
switch
(
tagType
)
{
case
ProtoBufType
.
TYPE_UNDEFINED
:
return
obj
;
...
...
@@ -1128,7 +1068,7 @@ public class ProtoBuf {
case
ProtoBufType
.
TYPE_SINT32
:
case
ProtoBufType
.
TYPE_SINT64
:
if
(
obj
instanceof
Boolean
)
{
return
((
Boolean
)
obj
).
booleanValue
()
?
1
:
0
;
return
SMALL_NUMBERS
[((
Boolean
)
obj
).
booleanValue
()
?
1
:
0
]
;
}
return
obj
;
case
ProtoBufType
.
TYPE_DATA
:
...
...
@@ -1213,13 +1153,13 @@ public class ProtoBuf {
* values.
*/
private
void
setObject
(
int
tag
,
Object
o
)
{
if
(
tag
<
0
)
{
throw
new
ArrayIndexOutOfBoundsException
(
);
if
(
values
.
size
()
<=
tag
)
{
values
.
setSize
(
tag
+
1
);
}
if
(
o
!=
null
)
{
assertTypeMatch
(
tag
,
o
);
}
values
.
put
(
tag
,
o
);
values
.
setElementAt
(
o
,
tag
);
}
/**
...
...
src/com/google/common/io/protocol/ProtoBufType.java
View file @
7e013cac
...
...
@@ -6,8 +6,9 @@ package com.google.common.io.protocol;
import
java.util.*
;
/**
* This class can be used to create a memory model of a .proto file.
*
* 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!
...
...
@@ -41,46 +42,11 @@ public class ProtoBufType {
public
static
final
int
REQUIRED
=
0x100
;
public
static
final
int
OPTIONAL
=
0x200
;
public
static
final
int
REPEATED
=
0x400
;
private
final
IntMap
types
=
new
IntMap
();
/*
* A struct to store field type and default object.
* Two TypeInfo objects are equal iff both have the
* euqal type and object.
*/
static
class
TypeInfo
{
private
int
type
;
private
Object
data
;
TypeInfo
(
int
t
,
Object
d
)
{
type
=
t
;
data
=
d
;
}
public
int
hashCode
()
{
return
type
;
}
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
!(
obj
instanceof
TypeInfo
))
{
return
false
;
}
TypeInfo
peerTypeInfo
=
(
TypeInfo
)
obj
;
return
type
==
peerTypeInfo
.
type
&&
(
data
==
peerTypeInfo
.
data
||
(
data
!=
null
&&
data
.
equals
(
peerTypeInfo
.
data
)));
}
public
String
toString
()
{
return
"TypeInfo{type="
+
type
+
", data="
+
data
+
"}"
;
}
};
private
final
StringBuffer
types
=
new
StringBuffer
();
private
final
Vector
data
=
new
Vector
();
private
final
String
typeName
;
/**
* Empty constructor.
*/
...
...
@@ -108,36 +74,35 @@ public class ProtoBufType {
* @return this is returned to permit cascading
*/
public
ProtoBufType
addElement
(
int
optionsAndType
,
int
tag
,
Object
data
)
{
types
.
put
(
tag
,
new
TypeInfo
(
optionsAndType
,
data
));
return
this
;
}
while
(
types
.
length
()
<=
tag
)
{
types
.
append
((
char
)
TYPE_UNDEFINED
);
this
.
data
.
addElement
(
null
);
}
types
.
setCharAt
(
tag
,
(
char
)
optionsAndType
);
this
.
data
.
setElementAt
(
data
,
tag
);
/**
* Returns a IntMap that has the same lower buffer size as types.
* This is for ProtoBuf to create IntMap with pre-allocated
* internal buffer.
*/
/* package protected */
IntMap
newIntMapForProtoBuf
()
{
return
types
.
newIntMapWithSameBufferSize
();
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
)
{
TypeInfo
typeInfo
=
(
TypeInfo
)
types
.
get
(
tag
);
return
typeInfo
==
null
?
TYPE_UNDEFINED
:
typeInfo
.
type
&
MASK_TYPE
;
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
)
{
TypeInfo
typeInfo
=
(
TypeInfo
)
types
.
get
(
tag
);
return
typeInfo
==
null
?
(
OPTIONAL
|
REPEATED
)
:
typeInfo
.
type
&
MASK_MODIFIER
;
return
(
tag
<
0
||
tag
>=
types
.
length
())
?
(
OPTIONAL
|
REPEATED
)
:
(
types
.
charAt
(
tag
)
&
MASK_MODIFIER
);
}
/**
...
...
@@ -146,15 +111,14 @@ public class ProtoBufType {
* tags, null is returned.
*/
public
Object
getData
(
int
tag
)
{
TypeInfo
typeInfo
=
(
TypeInfo
)
types
.
get
(
tag
);
return
typeInfo
==
null
?
typeInfo
:
typeInfo
.
data
;
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
"ProtoBufType Name: "
+
typeName
;
return
typeName
;
}
/**
...
...
@@ -174,9 +138,9 @@ public class ProtoBufType {
}
ProtoBufType
other
=
(
ProtoBufType
)
object
;
return
types
.
equals
(
other
.
types
);
return
stringEquals
(
types
,
other
.
types
);
}
/**
* {@inheritDoc}
*/
...
...
@@ -187,4 +151,20 @@ public class ProtoBufType {
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
View file @
7e013cac
...
...
@@ -22,25 +22,6 @@ public final class ProtoBufUtil {
}
}
/** Convenience method to return a string value from of a proto or null. */
public
static
String
getProtoValueOrNull
(
ProtoBuf
proto
,
int
tag
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
))
?
proto
.
getString
(
tag
)
:
null
;
}
catch
(
ClassCastException
e
)
{
return
null
;
}
}
/** Convenience method to return a string value from of a proto or null. */
public
static
String
getProtoValueOrNull
(
ProtoBuf
proto
,
int
tag
,
int
index
)
{
try
{
return
(
proto
!=
null
&&
proto
.
has
(
tag
)
&&
proto
.
getCount
(
tag
)
>
index
)
?
proto
.
getString
(
tag
,
index
)
:
null
;
}
catch
(
ClassCastException
e
)
{
return
null
;
}
}
/** Convenience method to return a string value from of a sub-proto or "". */
public
static
String
getSubProtoValueOrEmpty
(
ProtoBuf
proto
,
int
sub
,
int
tag
)
{
...
...
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