Add protobuf

- Copied from Chromium

Change-Id: I4b61e8282903feb2d64111934c9aa97955b06cf1
This commit is contained in:
Rintaro Kuroiwa 2013-10-17 14:37:33 -07:00
parent 1ada724850
commit 0972f4de20
377 changed files with 167292 additions and 0 deletions

528
third_party/protobuf/CHANGES.txt vendored Normal file
View File

@ -0,0 +1,528 @@
2012-09-19 version 2.5.0:
General
* New notion "import public" that allows a proto file to forward the content
it imports to its importers. For example,
// foo.proto
import public "bar.proto";
import "baz.proto";
// qux.proto
import "foo.proto";
// Stuff defined in bar.proto may be used in this file, but stuff from
// baz.proto may NOT be used without importing it explicitly.
This is useful for moving proto files. To move a proto file, just leave
a single "import public" in the old proto file.
* New enum option "allow_alias" that specifies whether different symbols can
be assigned the same numeric value. Default value is "true". Setting it to
false causes the compiler to reject enum definitions where multiple symbols
have the same numeric value.
C++
* New generated method set_allocated_foo(Type* foo) for message and string
fields. This method allows you to set the field to a pre-allocated object
and the containing message takes the ownership of that object.
* Added SetAllocatedExtension() and ReleaseExtension() to extensions API.
* Custom options are now formatted correctly when descriptors are printed in
text format.
* Various speed optimizations.
Java
* Comments in proto files are now collected and put into generated code as
comments for corresponding classes and data members.
* Added Parser to parse directly into messages without a Builder. For
example,
Foo foo = Foo.getParser().ParseFrom(input);
Using Parser is ~25% faster than using Builder to parse messages.
* Added getters/setters to access the underlying ByteString of a string field
directly.
* ByteString now supports more operations: substring(), prepend(), and
append(). The implementation of ByteString uses a binary tree structure
to support these operations efficiently.
* New method findInitializationErrors() that lists all missing required
fields.
* Various code size and speed optimizations.
Python
* Added support for dynamic message creation. DescriptorDatabase,
DescriptorPool, and MessageFactory work like their C++ couterparts to
simplify Descriptor construction from *DescriptorProtos, and MessageFactory
provides a message instance from a Descriptor.
* Added pickle support for protobuf messages.
* Unknown fields are now preserved after parsing.
* Fixed bug where custom options were not correctly populated. Custom
options can be accessed now.
* Added EnumTypeWrapper that provides better accessibility to enum types.
* Added ParseMessage(descriptor, bytes) to generate a new Message instance
from a descriptor and a byte string.
2011-05-01 version 2.4.1:
C++
* Fixed the frendship problem for old compilers to make the library now gcc 3
compatible again.
* Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h.
Java
* Removed usages of JDK 1.6 only features to make the library now JDK 1.5
compatible again.
* Fixed a bug about negative enum values.
* serialVersionUID is now defined in generated messages for java serializing.
* Fixed protoc to use java.lang.Object, which makes "Object" now a valid
message name again.
Python
* Experimental C++ implementation now requires C++ protobuf library installed.
See the README.txt in the python directory for details.
2011-02-02 version 2.4.0:
General
* The RPC (cc|java|py)_generic_services default value is now false instead of
true.
* Custom options can have aggregate types. For example,
message MyOption {
optional string comment = 1;
optional string author = 2;
}
extend google.protobuf.FieldOptions {
optional MyOption myoption = 12345;
}
This option can now be set as follows:
message SomeType {
optional int32 field = 1 [(myoption) = { comment:'x' author:'y' }];
}
C++
* Various speed and code size optimizations.
* Added a release_foo() method on string and message fields.
* Fixed gzip_output_stream sub-stream handling.
Java
* Builders now maintain sub-builders for sub-messages. Use getFooBuilder() to
get the builder for the sub-message "foo". This allows you to repeatedly
modify deeply-nested sub-messages without rebuilding them.
* Builder.build() no longer invalidates the Builder for generated messages
(You may continue to modify it and then build another message).
* Code generator will generate efficient equals() and hashCode()
implementations if new option java_generate_equals_and_hash is enabled.
(Otherwise, reflection-based implementations are used.)
* Generated messages now implement Serializable.
* Fields with [deprecated=true] will be marked with @Deprecated in Java.
* Added lazy conversion of UTF-8 encoded strings to String objects to improve
performance.
* Various optimizations.
* Enum value can be accessed directly, instead of calling getNumber() on the
enum member.
* For each enum value, an integer constant is also generated with the suffix
_VALUE.
Python
* Added an experimental C++ implementation for Python messages via a Python
extension. Implementation type is controlled by an environment variable
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION (valid values: "cpp" and "python")
The default value is currently "python" but will be changed to "cpp" in
future release.
* Improved performance on message instantiation significantly.
Most of the work on message instantiation is done just once per message
class, instead of once per message instance.
* Improved performance on text message parsing.
* Allow add() to forward keyword arguments to the concrete class.
E.g. instead of
item = repeated_field.add()
item.foo = bar
item.baz = quux
You can do:
repeated_field.add(foo=bar, baz=quux)
* Added a sort() interface to the BaseContainer.
* Added an extend() method to repeated composite fields.
* Added UTF8 debug string support.
2010-01-08 version 2.3.0:
General
* Parsers for repeated numeric fields now always accept both packed and
unpacked input. The [packed=true] option only affects serializers.
Therefore, it is possible to switch a field to packed format without
breaking backwards-compatibility -- as long as all parties are using
protobuf 2.3.0 or above, at least.
* The generic RPC service code generated by the C++, Java, and Python
generators can be disabled via file options:
option cc_generic_services = false;
option java_generic_services = false;
option py_generic_services = false;
This allows plugins to generate alternative code, possibly specific to some
particular RPC implementation.
protoc
* Now supports a plugin system for code generators. Plugins can generate
code for new languages or inject additional code into the output of other
code generators. Plugins are just binaries which accept a protocol buffer
on stdin and write a protocol buffer to stdout, so they may be written in
any language. See src/google/protobuf/compiler/plugin.proto.
**WARNING**: Plugins are experimental. The interface may change in a
future version.
* If the output location ends in .zip or .jar, protoc will write its output
to a zip/jar archive instead of a directory. For example:
protoc --java_out=myproto_srcs.jar --python_out=myproto.zip myproto.proto
Currently the archive contents are not compressed, though this could change
in the future.
* inf, -inf, and nan can now be used as default values for float and double
fields.
C++
* Various speed and code size optimizations.
* DynamicMessageFactory is now fully thread-safe.
* Message::Utf8DebugString() method is like DebugString() but avoids escaping
UTF-8 bytes.
* Compiled-in message types can now contain dynamic extensions, through use
of CodedInputStream::SetExtensionRegistry().
* Now compiles shared libraries (DLLs) by default on Cygwin and MinGW, to
match other platforms. Use --disable-shared to avoid this.
Java
* parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return
false/null instead of throwing an exception.
* Fixed some initialization ordering bugs.
* Fixes for OpenJDK 7.
Python
* 10-25 times faster than 2.2.0, still pure-Python.
* Calling a mutating method on a sub-message always instantiates the message
in its parent even if the mutating method doesn't actually mutate anything
(e.g. parsing from an empty string).
* Expanded descriptors a bit.
2009-08-11 version 2.2.0:
C++
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Fixed bug where Message.Swap(Message) was only implemented for
optimize_for_speed. Swap now properly implemented in both modes
(Issue 91).
* Added RemoveLast and SwapElements(index1, index2) to Reflection
interface for repeated elements.
* Added Swap(Message) to Reflection interface.
* Floating-point literals in generated code that are intended to be
single-precision now explicitly have 'f' suffix to avoid pedantic warnings
produced by some compilers.
* The [deprecated=true] option now causes the C++ code generator to generate
a GCC-style deprecation annotation (no-op on other compilers).
* google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the
EnumDescriptor for that type -- useful for templates which cannot call
SomeGeneratedEnumType_descriptor().
* Various optimizations and obscure bug fixes.
Java
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler
to generate code which only depends libprotobuf-lite, which is much smaller
than libprotobuf but lacks descriptors, reflection, and some other features.
* Lots of style cleanups.
Python
* Fixed endianness bug with floats and doubles.
* Text format parsing support.
* Fix bug with parsing packed repeated fields in embedded messages.
* Ability to initialize fields by passing keyword args to constructor.
* Support iterators in extend and __setslice__ for containers.
2009-05-13 version 2.1.0:
General
* Repeated fields of primitive types (types other that string, group, and
nested messages) may now use the option [packed = true] to get a more
efficient encoding. In the new encoding, the entire list is written
as a single byte blob using the "length-delimited" wire type. Within
this blob, the individual values are encoded the same way they would
be normally except without a tag before each value (thus, they are
tightly "packed").
* For each field, the generated code contains an integer constant assigned
to the field number. For example, the .proto file:
message Foo { optional int bar_baz = 123; }
would generate the following constants, all with the integer value 123:
C++: Foo::kBarBazFieldNumber
Java: Foo.BAR_BAZ_FIELD_NUMBER
Python: Foo.BAR_BAZ_FIELD_NUMBER
Constants are also generated for extensions, with the same naming scheme.
These constants may be used as switch cases.
* Updated bundled Google Test to version 1.3.0. Google Test is now bundled
in its verbatim form as a nested autoconf package, so you can drop in any
other version of Google Test if needed.
* optimize_for = SPEED is now the default, by popular demand. Use
optimize_for = CODE_SIZE if code size is more important in your app.
* It is now an error to define a default value for a repeated field.
Previously, this was silently ignored (it had no effect on the generated
code).
* Fields can now be marked deprecated like:
optional int32 foo = 1 [deprecated = true];
Currently this does not have any actual effect, but in the future the code
generators may generate deprecation annotations in each language.
* Cross-compiling should now be possible using the --with-protoc option to
configure. See README.txt for more info.
protoc
* --error_format=msvs option causes errors to be printed in Visual Studio
format, which should allow them to be clicked on in the build log to go
directly to the error location.
* The type name resolver will no longer resolve type names to fields. For
example, this now works:
message Foo {}
message Bar {
optional int32 Foo = 1;
optional Foo baz = 2;
}
Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get
an error because Bar.Foo is a field, not a type. Now the type of "baz"
resolves to the message type Foo. This change is unlikely to make a
difference to anyone who follows the Protocol Buffers style guide.
C++
* Several optimizations, including but not limited to:
- Serialization, especially to flat arrays, is 10%-50% faster, possibly
more for small objects.
- Several descriptor operations which previously required locking no longer
do.
- Descriptors are now constructed lazily on first use, rather than at
process startup time. This should save memory in programs which do not
use descriptors or reflection.
- UnknownFieldSet completely redesigned to be more efficient (especially in
terms of memory usage).
- Various optimizations to reduce code size (though the serialization speed
optimizations increased code size).
* Message interface has method ParseFromBoundedZeroCopyStream() which parses
a limited number of bytes from an input stream rather than parsing until
EOF.
* GzipInputStream and GzipOutputStream support reading/writing gzip- or
zlib-compressed streams if zlib is available.
(google/protobuf/io/gzip_stream.h)
* DescriptorPool::FindAllExtensions() and corresponding
DescriptorDatabase::FindAllExtensions() can be used to enumerate all
extensions of a given type.
* For each enum type Foo, protoc will generate functions:
const string& Foo_Name(Foo value);
bool Foo_Parse(const string& name, Foo* result);
The former returns the name of the enum constant corresponding to the given
value while the latter finds the value corresponding to a name.
* RepeatedField and RepeatedPtrField now have back-insertion iterators.
* String fields now have setters that take a char* and a size, in addition
to the existing ones that took char* or const string&.
* DescriptorPool::AllowUnknownDependencies() may be used to tell
DescriptorPool to create placeholder descriptors for unknown entities
referenced in a FileDescriptorProto. This can allow you to parse a .proto
file without having access to other .proto files that it imports, for
example.
* Updated gtest to latest version. The gtest package is now included as a
nested autoconf package, so it should be able to drop new versions into the
"gtest" subdirectory without modification.
Java
* Fixed bug where Message.mergeFrom(Message) failed to merge extensions.
* Message interface has new method toBuilder() which is equivalent to
newBuilderForType().mergeFrom(this).
* All enums now implement the ProtocolMessageEnum interface.
* Setting a field to null now throws NullPointerException.
* Fixed tendency for TextFormat's parsing to overflow the stack when
parsing large string values. The underlying problem is with Java's
regex implementation (which unfortunately uses recursive backtracking
rather than building an NFA). Worked around by making use of possesive
quantifiers.
* Generated service classes now also generate pure interfaces. For a service
Foo, Foo.Interface is a pure interface containing all of the service's
defined methods. Foo.newReflectiveService() can be called to wrap an
instance of this interface in a class that implements the generic
RpcService interface, which provides reflection support that is usually
needed by RPC server implementations.
* RPC interfaces now support blocking operation in addition to non-blocking.
The protocol compiler generates separate blocking and non-blocking stubs
which operate against separate blocking and non-blocking RPC interfaces.
RPC implementations will have to implement the new interfaces in order to
support blocking mode.
* New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and
writeDelimitedTo() read and write "delemited" messages from/to a stream,
meaning that the message size precedes the data. This way, you can write
multiple messages to a stream without having to worry about delimiting
them yourself.
* Throw a more descriptive exception when build() is double-called.
* Add a method to query whether CodedInputStream is at the end of the input
stream.
* Add a method to reset a CodedInputStream's size counter; useful when
reading many messages with the same stream.
* equals() and hashCode() now account for unknown fields.
Python
* Added slicing support for repeated scalar fields. Added slice retrieval and
removal of repeated composite fields.
* Updated RPC interfaces to allow for blocking operation. A client may
now pass None for a callback when making an RPC, in which case the
call will block until the response is received, and the response
object will be returned directly to the caller. This interface change
cannot be used in practice until RPC implementations are updated to
implement it.
* Changes to input_stream.py should make protobuf compatible with appengine.
2008-11-25 version 2.0.3:
protoc
* Enum values may now have custom options, using syntax similar to field
options.
* Fixed bug where .proto files which use custom options but don't actually
define them (i.e. they import another .proto file defining the options)
had to explicitly import descriptor.proto.
* Adjacent string literals in .proto files will now be concatenated, like in
C.
* If an input file is a Windows absolute path (e.g. "C:\foo\bar.proto") and
the import path only contains "." (or contains "." but does not contain
the file), protoc incorrectly thought that the file was under ".", because
it thought that the path was relative (since it didn't start with a slash).
This has been fixed.
C++
* Generated message classes now have a Swap() method which efficiently swaps
the contents of two objects.
* All message classes now have a SpaceUsed() method which returns an estimate
of the number of bytes of allocated memory currently owned by the object.
This is particularly useful when you are reusing a single message object
to improve performance but want to make sure it doesn't bloat up too large.
* New method Message::SerializeAsString() returns a string containing the
serialized data. May be more convenient than calling
SerializeToString(string*).
* In debug mode, log error messages when string-type fields are found to
contain bytes that are not valid UTF-8.
* Fixed bug where a message with multiple extension ranges couldn't parse
extensions.
* Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on
a message that contained no fields (but possibly contained extensions).
* Fixed ShortDebugString() to not be O(n^2). Durr.
* Fixed crash in TextFormat parsing if the first token in the input caused a
tokenization error.
* Fixed obscure bugs in zero_copy_stream_impl.cc.
* Added support for HP C++ on Tru64.
* Only build tests on "make check", not "make".
* Fixed alignment issue that caused crashes when using DynamicMessage on
64-bit Sparc machines.
* Simplify template usage to work with MSVC 2003.
* Work around GCC 4.3.x x86_64 compiler bug that caused crashes on startup.
(This affected Fedora 9 in particular.)
* Now works on "Solaris 10 using recent Sun Studio".
Java
* New overload of mergeFrom() which parses a slice of a byte array instead
of the whole thing.
* New method ByteString.asReadOnlyByteBuffer() does what it sounds like.
* Improved performance of isInitialized() when optimizing for code size.
Python
* Corrected ListFields() signature in Message base class to match what
subclasses actually implement.
* Some minor refactoring.
* Don't pass self as first argument to superclass constructor (no longer
allowed in Python 2.6).
2008-09-29 version 2.0.2:
General
* License changed from Apache 2.0 to New BSD.
* It is now possible to define custom "options", which are basically
annotations which may be placed on definitions in a .proto file.
For example, you might define a field option called "foo" like so:
import "google/protobuf/descriptor.proto"
extend google.protobuf.FieldOptions {
optional string foo = 12345;
}
Then you annotate a field using the "foo" option:
message MyMessage {
optional int32 some_field = 1 [(foo) = "bar"]
}
The value of this option is then visible via the message's
Descriptor:
const FieldDescriptor* field =
MyMessage::descriptor()->FindFieldByName("some_field");
assert(field->options().GetExtension(foo) == "bar");
This feature has been implemented and tested in C++ and Java.
Other languages may or may not need to do extra work to support
custom options, depending on how they construct descriptors.
C++
* Fixed some GCC warnings that only occur when using -pedantic.
* Improved static initialization code, making ordering more
predictable among other things.
* TextFormat will no longer accept messages which contain multiple
instances of a singular field. Previously, the latter instance
would overwrite the former.
* Now works on systems that don't have hash_map.
Java
* Print @Override annotation in generated code where appropriate.
Python
* Strings now use the "unicode" type rather than the "str" type.
String fields may still be assigned ASCII "str" values; they will
automatically be converted.
* Adding a property to an object representing a repeated field now
raises an exception. For example:
# No longer works (and never should have).
message.some_repeated_field.foo = 1
Windows
* We now build static libraries rather than DLLs by default on MSVC.
See vsprojects/readme.txt for more information.
2008-08-15 version 2.0.1:
protoc
* New flags --encode and --decode can be used to convert between protobuf text
format and binary format from the command-line.
* New flag --descriptor_set_out can be used to write FileDescriptorProtos for
all parsed files directly into a single output file. This is particularly
useful if you wish to parse .proto files from programs written in languages
other than C++: just run protoc as a background process and have it output
a FileDescriptorList, then parse that natively.
* Improved error message when an enum value's name conflicts with another
symbol defined in the enum type's scope, e.g. if two enum types declared
in the same scope have values with the same name. This is disallowed for
compatibility with C++, but this wasn't clear from the error.
* Fixed absolute output paths on Windows.
* Allow trailing slashes in --proto_path mappings.
C++
* Reflection objects are now per-class rather than per-instance. To make this
possible, the Reflection interface had to be changed such that all methods
take the Message instance as a parameter. This change improves performance
significantly in memory-bandwidth-limited use cases, since it makes the
message objects smaller. Note that source-incompatible interface changes
like this will not be made again after the library leaves beta.
* Heuristically detect sub-messages when printing unknown fields.
* Fix static initialization ordering bug that caused crashes at startup when
compiling on Mac with static linking.
* Fixed TokenizerTest when compiling with -DNDEBUG on Linux.
* Fixed incorrect definition of kint32min.
* Fix bytes type setter to work with byte sequences with embedded NULLs.
* Other irrelevant tweaks.
Java
* Fixed UnknownFieldSet's parsing of varints larger than 32 bits.
* Fixed TextFormat's parsing of "inf" and "nan".
* Fixed TextFormat's parsing of comments.
* Added info to Java POM that will be required when we upload the
package to a Maven repo.
Python
* MergeFrom(message) and CopyFrom(message) are now implemented.
* SerializeToString() raises an exception if the message is missing required
fields.
* Code organization improvements.
* Fixed doc comments for RpcController and RpcChannel, which had somehow been
swapped.
* Fixed text_format_test on Windows where floating-point exponents sometimes
contain extra zeros.
* Fix Python service CallMethod() implementation.
Other
* Improved readmes.
* VIM syntax highlighting improvements.
2008-07-07 version 2.0.0:
* First public release.

88
third_party/protobuf/CONTRIBUTORS.txt vendored Normal file
View File

@ -0,0 +1,88 @@
This file contains a list of people who have made large contributions
to the public version of Protocol Buffers.
Original Protocol Buffers design and implementation:
Sanjay Ghemawat <sanjay@google.com>
Jeff Dean <jeff@google.com>
Daniel Dulitz <daniel@google.com>
Craig Silverstein
Paul Haahr <haahr@google.com>
Corey Anderson <corin@google.com>
(and many others)
Proto2 C++ and Java primary author:
Kenton Varda <kenton@google.com>
Proto2 Python primary authors:
Will Robinson <robinson@google.com>
Petar Petrov <petar@google.com>
Large code contributions:
Jason Hsueh <jasonh@google.com>
Joseph Schorr <jschorr@google.com>
Wenbo Zhu <wenboz@google.com>
Large quantity of code reviews:
Scott Bruce <sbruce@google.com>
Frank Yellin
Neal Norwitz <nnorwitz@google.com>
Jeffrey Yasskin <jyasskin@google.com>
Ambrose Feinstein <ambrose@google.com>
Documentation:
Lisa Carey <lcarey@google.com>
Maven packaging:
Gregory Kick <gak@google.com>
Patch contributors:
Kevin Ko <kevin.s.ko@gmail.com>
* Small patch to handle trailing slashes in --proto_path flag.
Johan Euphrosine <proppy@aminche.com>
* Small patch to fix Python CallMethod().
Ulrich Kunitz <kune@deine-taler.de>
* Small optimizations to Python serialization.
Leandro Lucarella <llucax@gmail.com>
* VI syntax highlighting tweaks.
* Fix compiler to not make output executable.
Dilip Joseph <dilip.antony.joseph@gmail.com>
* Heuristic detection of sub-messages when printing unknown fields in
text format.
Brian Atkinson <nairb774@gmail.com>
* Added @Override annotation to generated Java code where appropriate.
Vincent Choinière <Choiniere.Vincent@hydro.qc.ca>
* Tru64 support.
Monty Taylor <monty.taylor@gmail.com>
* Solaris 10 + Sun Studio fixes.
Alek Storm <alek.storm@gmail.com>
* Slicing support for repeated scalar fields for the Python API.
Oleg Smolsky <oleg.smolsky@gmail.com>
* MS Visual Studio error format option.
* Detect unordered_map in stl_hash.m4.
Brian Olson <brianolson@google.com>
* gzip/zlib I/O support.
Michael Poole <mdpoole@troilus.org>
* Fixed warnings about generated constructors not explicitly initializing
all fields (only present with certain compiler settings).
* Added generation of field number constants.
Wink Saville <wink@google.com>
* Fixed initialization ordering problem in logging code.
Will Pierce <willp@nuclei.com>
* Small patch improving performance of in Python serialization.
Alexandre Vassalotti <alexandre@peadrop.com>
* Emacs mode for Protocol Buffers (editors/protobuf-mode.el).
Scott Stafford <scott.stafford@gmail.com>
* Added Swap(), SwapElements(), and RemoveLast() to Reflection interface.
Alexander Melnikov <alm@sibmail.ru>
* HPUX support.
Oliver Jowett <oliver.jowett@gmail.com>
* Detect whether zlib is new enough in configure script.
* Fixes for Solaris 10 32/64-bit confusion.
Evan Jones <evanj@mit.edu>
* Optimize Java serialization code when writing a small message to a stream.
* Optimize Java serialization of strings so that UTF-8 encoding happens only
once per string per serialization call.
* Clean up some Java warnings.
* Fix bug with permanent callbacks that delete themselves when run.
Michael Kucharski <m.kucharski@gmail.com>
* Added CodedInputStream.getTotalBytesRead().

33
third_party/protobuf/COPYING.txt vendored Normal file
View File

@ -0,0 +1,33 @@
Copyright 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This
support library is itself covered by the above license.

237
third_party/protobuf/INSTALL.txt vendored Normal file
View File

@ -0,0 +1,237 @@
This file contains detailed but generic information on building and
installing the C++ part of this project. For shorter instructions,
as well as instructions for compiling and installing the Java or
Python parts, see README.
======================================================================
Copyright 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software
Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
These are generic installation instructions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. (Caching is
disabled by default to prevent problems with accidental use of stale
cache files.)
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You only need
`configure.ac' if you want to change it or regenerate `configure' using
a newer version of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system. If you're
using `csh' on an old version of System V, you might need to type
`sh ./configure' instead to prevent `csh' from trying to execute
`configure' itself.
Running `configure' takes awhile. While running, it prints some
messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you must use a version of `make' that
supports the `VPATH' variable, such as GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
If you have to use a `make' that does not support the `VPATH'
variable, you have to compile the package for one architecture at a
time in the source code directory. After you have installed the
package for one architecture, use `make distclean' before reconfiguring
for another architecture.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin', `/usr/local/man', etc. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
give `configure' the option `--exec-prefix=PATH', the package will use
PATH as the prefix for installing programs and libraries.
Documentation and other data files will still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=PATH' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the `--target=TYPE' option to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
will cause the specified gcc to be used as the C compiler (unless it is
overridden in the site shell script).
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

39
third_party/protobuf/README.chromium vendored Normal file
View File

@ -0,0 +1,39 @@
Name: Protocol Buffers
Short Name: protobuf
URL: http://protobuf.googlecode.com/svn/trunk
License: BSD
License File: COPYING.txt
Version: unknown
Revision: r476
Security Critical: yes
Local files (not taken from upstream):
README.chromium
config.h
descriptor2_pb.py
protobuf_lite_java_descriptor_proto.py
protobuf_lite_java_parse_pom.py
A protobuf.gyp file has been added for building with Chromium.
This code has been patched to support unknown field retention in protobuf-lite.
See r62331 for the patch.
This code has been patched to ensure that files in the target protobuf_lite
do not include headers from protobuf_full. See r173228 for the patch.
This code has been patched to make the target protobuf_lite a component so that
targets that depend on it can be componentized. See http://crbug.com/172800 for
details, and r179806 for the patch.
Revision 504 was cherry-picked from upstream.
Revision 512 was cherry-picked from upstream.
Notes about Java:
We have not forked the Java version of protobuf-lite, so the Java version does
not support unknown field retention.
The list of Java files included in the lite profile for Java is parsed from the
maven java/pom.xml by the script protobuf_lite_java_parse_pom.py. See
'javac_includes' variable in protobuf_lite_javalib GYP target.

152
third_party/protobuf/README.txt vendored Normal file
View File

@ -0,0 +1,152 @@
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc.
http://code.google.com/apis/protocolbuffers/
C++ Installation - Unix
=======================
To build and install the C++ Protocol Buffer runtime and the Protocol
Buffer compiler (protoc) execute the following:
$ ./configure
$ make
$ make check
$ make install
If "make check" fails, you can still install, but it is likely that
some features of this library will not work correctly on your system.
Proceed at your own risk.
"make install" may require superuser privileges.
For advanced usage information on configure and make, see INSTALL.txt.
** Hint on install location **
By default, the package will be installed to /usr/local. However,
on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH.
You can add it, but it may be easier to just install to /usr
instead. To do this, invoke configure as follows:
./configure --prefix=/usr
If you already built the package with a different prefix, make sure
to run "make clean" before building again.
** Compiling dependent packages **
To compile a package that uses Protocol Buffers, you need to pass
various flags to your compiler and linker. As of version 2.2.0,
Protocol Buffers integrates with pkg-config to manage this. If you
have pkg-config installed, then you can invoke it to get a list of
flags like so:
pkg-config --cflags protobuf # print compiler flags
pkg-config --libs protobuf # print linker flags
pkg-config --cflags --libs protobuf # print both
For example:
c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf`
Note that packages written prior to the 2.2.0 release of Protocol
Buffers may not yet integrate with pkg-config to get flags, and may
not pass the correct set of flags to correctly link against
libprotobuf. If the package in question uses autoconf, you can
often fix the problem by invoking its configure script like:
configure CXXFLAGS="$(pkg-config --cflags protobuf)" \
LIBS="$(pkg-config --libs protobuf)"
This will force it to use the correct flags.
If you are writing an autoconf-based package that uses Protocol
Buffers, you should probably use the PKG_CHECK_MODULES macro in your
configure script like:
PKG_CHECK_MODULES([protobuf], [protobuf])
See the pkg-config man page for more info.
If you only want protobuf-lite, substitute "protobuf-lite" in place
of "protobuf" in these examples.
** Note for cross-compiling **
The makefiles normally invoke the protoc executable that they just
built in order to build tests. When cross-compiling, the protoc
executable may not be executable on the host machine. In this case,
you must build a copy of protoc for the host machine first, then use
the --with-protoc option to tell configure to use it instead. For
example:
./configure --with-protoc=protoc
This will use the installed protoc (found in your $PATH) instead of
trying to execute the one built during the build process. You can
also use an executable that hasn't been installed. For example, if
you built the protobuf package for your host machine in ../host,
you might do:
./configure --with-protoc=../host/src/protoc
Either way, you must make sure that the protoc executable you use
has the same version as the protobuf source code you are trying to
use it with.
** Note for Solaris users **
Solaris 10 x86 has a bug that will make linking fail, complaining
about libstdc++.la being invalid. We have included a work-around
in this package. To use the work-around, run configure as follows:
./configure LDFLAGS=-L$PWD/src/solaris
See src/solaris/libstdc++.la for more info on this bug.
** Note for HP C++ Tru64 users **
To compile invoke configure as follows:
./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM"
Also, you will need to use gmake instead of make.
C++ Installation - Windows
==========================
If you are using Microsoft Visual C++, see vsprojects/readme.txt.
If you are using Cygwin or MinGW, follow the Unix installation
instructions, above.
Binary Compatibility Warning
============================
Due to the nature of C++, it is unlikely that any two versions of the
Protocol Buffers C++ runtime libraries will have compatible ABIs.
That is, if you linked an executable against an older version of
libprotobuf, it is unlikely to work with a newer version without
re-compiling. This problem, when it occurs, will normally be detected
immediately on startup of your app. Still, you may want to consider
using static linkage. You can configure this package to install
static libraries only using:
./configure --disable-shared
Java and Python Installation
============================
The Java and Python runtime libraries for Protocol Buffers are located
in the java and python directories. See the README file in each
directory for more information on how to compile and install them.
Note that both of them require you to first install the Protocol
Buffer compiler (protoc), which is part of the C++ package.
Usage
=====
The complete documentation for Protocol Buffers is available via the
web at:
http://code.google.com/apis/protocolbuffers/

2
third_party/protobuf/__init__.py vendored Executable file
View File

@ -0,0 +1,2 @@

156
third_party/protobuf/config.h vendored Normal file
View File

@ -0,0 +1,156 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* the name of <hash_set> */
#define HASH_MAP_CLASS hash_map
/* the location of <hash_map> */
#if defined(USE_STLPORT)
#define HASH_MAP_H <hash_map>
#else
#define HASH_MAP_H <ext/hash_map>
#endif
/* the namespace of hash_map/hash_set */
#if defined(USE_STLPORT)
#define HASH_NAMESPACE std
#else
#define HASH_NAMESPACE __gnu_cxx
#endif
/* the name of <hash_set> */
#define HASH_SET_CLASS hash_set
/* the location of <hash_set> */
#if defined(USE_STLPORT)
#define HASH_SET_H <hash_set>
#else
#define HASH_SET_H <ext/hash_set>
#endif
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `ftruncate' function. */
#define HAVE_FTRUNCATE 1
/* define if the compiler has hash_map */
#define HAVE_HASH_MAP 1
/* define if the compiler has hash_set */
#define HAVE_HASH_SET 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the `mkdir' function. */
#define HAVE_MKDIR 1
/* Define if you have POSIX threads libraries and header files. */
#define HAVE_PTHREAD 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Enable classes using zlib compression. */
#define HAVE_ZLIB 1
/* Name of package */
#define PACKAGE "protobuf"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "protobuf@googlegroups.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "Protocol Buffers"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Protocol Buffers 2.3.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "protobuf"
/* Define to the version of this package. */
#define PACKAGE_VERSION "2.3.0"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
/* #undef PTHREAD_CREATE_JOINABLE */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "2.3.0"
/* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* # undef _ALL_SOURCE */
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for `stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Enable extensions on Solaris. */
#ifndef __EXTENSIONS__
# define __EXTENSIONS__ 1
#endif
#ifndef _POSIX_PTHREAD_SEMANTICS
# define _POSIX_PTHREAD_SEMANTICS 1
#endif
#ifndef _TANDEM_SOURCE
# define _TANDEM_SOURCE 1
#endif

1172
third_party/protobuf/descriptor_pb2.py vendored Executable file

File diff suppressed because one or more lines are too long

96
third_party/protobuf/java/README.txt vendored Normal file
View File

@ -0,0 +1,96 @@
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc.
This directory contains the Java Protocol Buffers runtime library.
Installation - With Maven
=========================
The Protocol Buffers build is managed using Maven. If you would
rather build without Maven, see below.
1) Install Apache Maven if you don't have it:
http://maven.apache.org/
2) Build the C++ code, or obtain a binary distribution of protoc. If
you install a binary distribution, make sure that it is the same
version as this package. If in doubt, run:
$ protoc --version
You will need to place the protoc executable in ../src. (If you
built it yourself, it should already be there.)
3) Run the tests:
$ mvn test
If some tests fail, this library may not work correctly on your
system. Continue at your own risk.
4) Install the library into your Maven repository:
$ mvn install
5) If you do not use Maven to manage your own build, you can build a
.jar file to use:
$ mvn package
The .jar will be placed in the "target" directory.
Installation - 'Lite' Version - With Maven
==========================================
Building the 'lite' version of the Java Protocol Buffers library is
the same as building the full version, except that all commands are
run using the 'lite' profile. (see
http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
E.g. to install the lite version of the jar, you would run:
$ mvn install -P lite
The resulting artifact has the 'lite' classifier. To reference it
for dependency resolution, you would specify it as:
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${version}</version>
<classifier>lite</classifier>
</dependency>
Installation - Without Maven
============================
If you would rather not install Maven to build the library, you may
follow these instructions instead. Note that these instructions skip
running unit tests.
1) Build the C++ code, or obtain a binary distribution of protoc. If
you install a binary distribution, make sure that it is the same
version as this package. If in doubt, run:
$ protoc --version
If you built the C++ code without installing, the compiler binary
should be located in ../src.
2) Invoke protoc to build DescriptorProtos.java:
$ protoc --java_out=src/main/java -I../src \
../src/google/protobuf/descriptor.proto
3) Compile the code in src/main/java using whatever means you prefer.
4) Install the classes wherever you prefer.
Usage
=====
The complete documentation for Protocol Buffers is available via the
web at:
http://code.google.com/apis/protocolbuffers/

205
third_party/protobuf/java/pom.xml vendored Normal file
View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.google</groupId>
<artifactId>google</artifactId>
<version>1</version>
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0-pre</version>
<packaging>bundle</packaging>
<name>Protocol Buffer Java API</name>
<description>
Protocol Buffers are a way of encoding structured data in an efficient yet
extensible format.
</description>
<inceptionYear>2008</inceptionYear>
<url>http://code.google.com/p/protobuf</url>
<licenses>
<license>
<name>New BSD license</name>
<url>http://www.opensource.org/licenses/bsd-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>http://code.google.com/p/protobuf/source/browse</url>
<connection>
scm:svn:http://protobuf.googlecode.com/svn/trunk/
</connection>
</scm>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymockclassextension</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<mkdir dir="target/generated-sources" />
<exec executable="../src/protoc">
<arg value="--java_out=target/generated-sources" />
<arg value="--proto_path=../src" />
<arg value="../src/google/protobuf/descriptor.proto" />
</exec>
</tasks>
<sourceRoot>target/generated-sources</sourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>generate-test-sources</id>
<phase>generate-test-sources</phase>
<configuration>
<tasks>
<mkdir dir="target/generated-test-sources" />
<exec executable="../src/protoc">
<arg value="--java_out=target/generated-test-sources" />
<arg value="--proto_path=../src" />
<arg value="--proto_path=src/test/java" />
<arg value="../src/google/protobuf/unittest.proto" />
<arg value="../src/google/protobuf/unittest_import.proto" />
<arg value="../src/google/protobuf/unittest_import_public.proto" />
<arg value="../src/google/protobuf/unittest_mset.proto" />
<arg
value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
<arg value="src/test/java/com/google/protobuf/nested_builders_test.proto" />
<arg value="src/test/java/com/google/protobuf/nested_extension.proto" />
<arg value="src/test/java/com/google/protobuf/nested_extension_lite.proto" />
<arg value="src/test/java/com/google/protobuf/non_nested_extension.proto" />
<arg value="src/test/java/com/google/protobuf/non_nested_extension_lite.proto" />
<arg value="src/test/java/com/google/protobuf/test_bad_identifiers.proto" />
<arg
value="../src/google/protobuf/unittest_optimize_for.proto" />
<arg
value="../src/google/protobuf/unittest_custom_options.proto" />
<arg value="../src/google/protobuf/unittest_lite.proto" />
<arg value="../src/google/protobuf/unittest_import_lite.proto" />
<arg value="../src/google/protobuf/unittest_import_public_lite.proto" />
<arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
<arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
<arg value="../src/google/protobuf/unittest_no_generic_services.proto" />
</exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>*</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>lite</id>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<includes>
<include>**/AbstractMessageLite.java</include>
<include>**/ByteString.java</include>
<include>**/CodedInputStream.java</include>
<include>**/CodedOutputStream.java</include>
<include>**/ExtensionRegistryLite.java</include>
<include>**/FieldSet.java</include>
<include>**/GeneratedMessageLite.java</include>
<include>**/Internal.java</include>
<include>**/InvalidProtocolBufferException.java</include>
<include>**/LazyStringArrayList.java</include>
<include>**/LazyStringList.java</include>
<include>**/MessageLite.java</include>
<include>**/MessageLiteOrBuilder.java</include>
<include>**/SmallSortedMap.java</include>
<include>**/UninitializedMessageException.java</include>
<include>**/UnmodifiableLazyStringList.java</include>
<include>**/WireFormat.java</include>
<include>**/Parser.java</include>
<include>**/AbstractParser.java</include>
<include>**/BoundedByteString.java</include>
<include>**/LiteralByteString.java</include>
<include>**/RopeByteString.java</include>
<include>**/Utf8.java</include>
<include>**/LazyField.java</include>
</includes>
<testIncludes>
<testInclude>**/LiteTest.java</testInclude>
<testInclude>**/*Lite.java</testInclude>
</testIncludes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/LiteTest.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<classifier>lite</classifier>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,930 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.GeneratedMessage.ExtendableBuilder;
import com.google.protobuf.Internal.EnumLite;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* A partial implementation of the {@link Message} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessage extends AbstractMessageLite
implements Message {
@SuppressWarnings("unchecked")
public boolean isInitialized() {
// Check that all required fields are present.
for (final FieldDescriptor field : getDescriptorForType().getFields()) {
if (field.isRequired()) {
if (!hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
for (final Message element : (List<Message>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
if (!((Message) entry.getValue()).isInitialized()) {
return false;
}
}
}
}
return true;
}
public List<String> findInitializationErrors() {
return Builder.findMissingFields(this);
}
public String getInitializationErrorString() {
return delimitWithCommas(findInitializationErrors());
}
private static String delimitWithCommas(List<String> parts) {
StringBuilder result = new StringBuilder();
for (String part : parts) {
if (result.length() > 0) {
result.append(", ");
}
result.append(part);
}
return result.toString();
}
@Override
public final String toString() {
return TextFormat.printToString(this);
}
public void writeTo(final CodedOutputStream output) throws IOException {
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
output.writeMessageSetExtension(field.getNumber(), (Message) value);
} else {
FieldSet.writeField(field, value, output);
}
}
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
unknownFields.writeAsMessageSetTo(output);
} else {
unknownFields.writeTo(output);
}
}
private int memoizedSize = -1;
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) {
return size;
}
size = 0;
final boolean isMessageSet =
getDescriptorForType().getOptions().getMessageSetWireFormat();
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (isMessageSet && field.isExtension() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
!field.isRepeated()) {
size += CodedOutputStream.computeMessageSetExtensionSize(
field.getNumber(), (Message) value);
} else {
size += FieldSet.computeFieldSize(field, value);
}
}
final UnknownFieldSet unknownFields = getUnknownFields();
if (isMessageSet) {
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size += unknownFields.getSerializedSize();
}
memoizedSize = size;
return size;
}
@Override
public boolean equals(final Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Message)) {
return false;
}
final Message otherMessage = (Message) other;
if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
return false;
}
return getAllFields().equals(otherMessage.getAllFields()) &&
getUnknownFields().equals(otherMessage.getUnknownFields());
}
@Override
public int hashCode() {
int hash = 41;
hash = (19 * hash) + getDescriptorForType().hashCode();
hash = hashFields(hash, getAllFields());
hash = (29 * hash) + getUnknownFields().hashCode();
return hash;
}
/** Get a hash code for given fields and values, using the given seed. */
@SuppressWarnings("unchecked")
protected int hashFields(int hash, Map<FieldDescriptor, Object> map) {
for (Map.Entry<FieldDescriptor, Object> entry : map.entrySet()) {
FieldDescriptor field = entry.getKey();
Object value = entry.getValue();
hash = (37 * hash) + field.getNumber();
if (field.getType() != FieldDescriptor.Type.ENUM){
hash = (53 * hash) + value.hashCode();
} else if (field.isRepeated()) {
List<? extends EnumLite> list = (List<? extends EnumLite>) value;
hash = (53 * hash) + hashEnumList(list);
} else {
hash = (53 * hash) + hashEnum((EnumLite) value);
}
}
return hash;
}
/**
* Helper method for implementing {@link Message#hashCode()}.
* @see Boolean#hashCode()
*/
protected static int hashLong(long n) {
return (int) (n ^ (n >>> 32));
}
/**
* Helper method for implementing {@link Message#hashCode()}.
* @see Boolean#hashCode()
*/
protected static int hashBoolean(boolean b) {
return b ? 1231 : 1237;
}
/**
* Package private helper method for AbstractParser to create
* UninitializedMessageException with missing field information.
*/
@Override
UninitializedMessageException newUninitializedMessageException() {
return Builder.newUninitializedMessageException(this);
}
/**
* Helper method for implementing {@link Message#hashCode()}.
* <p>
* This is needed because {@link java.lang.Enum#hashCode()} is final, but we
* need to use the field number as the hash code to ensure compatibility
* between statically and dynamically generated enum objects.
*/
protected static int hashEnum(EnumLite e) {
return e.getNumber();
}
/** Helper method for implementing {@link Message#hashCode()}. */
protected static int hashEnumList(List<? extends EnumLite> list) {
int hash = 1;
for (EnumLite e : list) {
hash = 31 * hash + hashEnum(e);
}
return hash;
}
// =================================================================
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType>
implements Message.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType clear() {
for (final Map.Entry<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
clearField(entry.getKey());
}
return (BuilderType) this;
}
public List<String> findInitializationErrors() {
return findMissingFields(this);
}
public String getInitializationErrorString() {
return delimitWithCommas(findInitializationErrors());
}
public BuilderType mergeFrom(final Message other) {
if (other.getDescriptorForType() != getDescriptorForType()) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
// Note: We don't attempt to verify that other's fields have valid
// types. Doing so would be a losing battle. We'd have to verify
// all sub-messages as well, and we'd have to make copies of all of
// them to insure that they don't change after verification (since
// the Message interface itself cannot enforce immutability of
// implementations).
// TODO(kenton): Provide a function somewhere called makeDeepCopy()
// which allows people to make secure deep copies of messages.
for (final Map.Entry<FieldDescriptor, Object> entry :
other.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
if (field.isRepeated()) {
for (final Object element : (List)entry.getValue()) {
addRepeatedField(field, element);
}
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
final Message existingValue = (Message)getField(field);
if (existingValue == existingValue.getDefaultInstanceForType()) {
setField(field, entry.getValue());
} else {
setField(field,
existingValue.newBuilderForType()
.mergeFrom(existingValue)
.mergeFrom((Message)entry.getValue())
.build());
}
} else {
setField(field, entry.getValue());
}
}
mergeUnknownFields(other.getUnknownFields());
return (BuilderType) this;
}
@Override
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
}
@Override
public BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final UnknownFieldSet.Builder unknownFields =
UnknownFieldSet.newBuilder(getUnknownFields());
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
getDescriptorForType(), this, null, tag)) {
// end group tag
break;
}
}
setUnknownFields(unknownFields.build());
return (BuilderType) this;
}
/** helper method to handle {@code builder} and {@code extensions}. */
private static void addRepeatedField(
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
FieldDescriptor field,
Object value) {
if (builder != null) {
builder.addRepeatedField(field, value);
} else {
extensions.addRepeatedField(field, value);
}
}
/** helper method to handle {@code builder} and {@code extensions}. */
private static void setField(
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
FieldDescriptor field,
Object value) {
if (builder != null) {
builder.setField(field, value);
} else {
extensions.setField(field, value);
}
}
/** helper method to handle {@code builder} and {@code extensions}. */
private static boolean hasOriginalMessage(
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
FieldDescriptor field) {
if (builder != null) {
return builder.hasField(field);
} else {
return extensions.hasField(field);
}
}
/** helper method to handle {@code builder} and {@code extensions}. */
private static Message getOriginalMessage(
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
FieldDescriptor field) {
if (builder != null) {
return (Message) builder.getField(field);
} else {
return (Message) extensions.getField(field);
}
}
/** helper method to handle {@code builder} and {@code extensions}. */
private static void mergeOriginalMessage(
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
FieldDescriptor field,
Message.Builder subBuilder) {
Message originalMessage = getOriginalMessage(builder, extensions, field);
if (originalMessage != null) {
subBuilder.mergeFrom(originalMessage);
}
}
/**
* Like {@link #mergeFrom(CodedInputStream, ExtensionRegistryLite)}, but
* parses a single field.
*
* When {@code builder} is not null, the method will parse and merge the
* field into {@code builder}. Otherwise, it will try to parse the field
* into {@code extensions}, when it's called by the parsing constructor in
* generated classes.
*
* Package-private because it is used by GeneratedMessage.ExtendableMessage.
* @param tag The tag, which should have already been read.
* @return {@code true} unless the tag is an end-group tag.
*/
static boolean mergeFieldFrom(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptor type,
Message.Builder builder,
FieldSet<FieldDescriptor> extensions,
int tag) throws IOException {
if (type.getOptions().getMessageSetWireFormat() &&
tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
mergeMessageSetExtensionFromCodedStream(
input, unknownFields, extensionRegistry, type, builder, extensions);
return true;
}
final int wireType = WireFormat.getTagWireType(tag);
final int fieldNumber = WireFormat.getTagFieldNumber(tag);
final FieldDescriptor field;
Message defaultInstance = null;
if (type.isExtensionNumber(fieldNumber)) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
final ExtensionRegistry.ExtensionInfo extension =
((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, fieldNumber);
if (extension == null) {
field = null;
} else {
field = extension.descriptor;
defaultInstance = extension.defaultInstance;
if (defaultInstance == null &&
field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalStateException(
"Message-typed extension lacked default instance: " +
field.getFullName());
}
}
} else {
field = null;
}
} else if (builder != null) {
field = type.findFieldByNumber(fieldNumber);
} else {
field = null;
}
boolean unknown = false;
boolean packed = false;
if (field == null) {
unknown = true; // Unknown field.
} else if (wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
false /* isPacked */)) {
packed = false;
} else if (field.isPackable() &&
wireType == FieldSet.getWireFormatForFieldType(
field.getLiteType(),
true /* isPacked */)) {
packed = true;
} else {
unknown = true; // Unknown wire type.
}
if (unknown) { // Unknown field or wrong wire type. Skip.
return unknownFields.mergeFieldFrom(tag, input);
}
if (packed) {
final int length = input.readRawVarint32();
final int limit = input.pushLimit(length);
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
final Object value = field.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
addRepeatedField(builder, extensions, field, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
final Object value =
FieldSet.readPrimitiveField(input, field.getLiteType());
addRepeatedField(builder, extensions, field, value);
}
}
input.popLimit(limit);
} else {
final Object value;
switch (field.getType()) {
case GROUP: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
mergeOriginalMessage(builder, extensions, field, subBuilder);
}
input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
value = subBuilder.buildPartial();
break;
}
case MESSAGE: {
final Message.Builder subBuilder;
if (defaultInstance != null) {
subBuilder = defaultInstance.newBuilderForType();
} else {
subBuilder = builder.newBuilderForField(field);
}
if (!field.isRepeated()) {
mergeOriginalMessage(builder, extensions, field, subBuilder);
}
input.readMessage(subBuilder, extensionRegistry);
value = subBuilder.buildPartial();
break;
}
case ENUM:
final int rawValue = input.readEnum();
value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
unknownFields.mergeVarintField(fieldNumber, rawValue);
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input, field.getLiteType());
break;
}
if (field.isRepeated()) {
addRepeatedField(builder, extensions, field, value);
} else {
setField(builder, extensions, field, value);
}
}
return true;
}
/**
* Called by {@code #mergeFieldFrom()} to parse a MessageSet extension.
* If {@code builder} is not null, this method will merge MessageSet into
* the builder. Otherwise, it will merge the MessageSet into {@code
* extensions}.
*/
private static void mergeMessageSetExtensionFromCodedStream(
CodedInputStream input,
UnknownFieldSet.Builder unknownFields,
ExtensionRegistryLite extensionRegistry,
Descriptor type,
Message.Builder builder,
FieldSet<FieldDescriptor> extensions) throws IOException {
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
int typeId = 0;
ByteString rawBytes = null; // If we encounter "message" before "typeId"
ExtensionRegistry.ExtensionInfo extension = null;
// Read bytes from input, if we get it's type first then parse it eagerly,
// otherwise we store the raw bytes in a local variable.
while (true) {
final int tag = input.readTag();
if (tag == 0) {
break;
}
if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
typeId = input.readUInt32();
if (typeId != 0) {
// extensionRegistry may be either ExtensionRegistry or
// ExtensionRegistryLite. Since the type we are parsing is a full
// message, only a full ExtensionRegistry could possibly contain
// extensions of it. Otherwise we will treat the registry as if it
// were empty.
if (extensionRegistry instanceof ExtensionRegistry) {
extension = ((ExtensionRegistry) extensionRegistry)
.findExtensionByNumber(type, typeId);
}
}
} else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
if (typeId != 0) {
if (extension != null && ExtensionRegistryLite.isEagerlyParseMessageSets()) {
// We already know the type, so we can parse directly from the
// input with no copying. Hooray!
eagerlyMergeMessageSetExtension(
input, extension, extensionRegistry, builder, extensions);
rawBytes = null;
continue;
}
}
// We haven't seen a type ID yet or we want parse message lazily.
rawBytes = input.readBytes();
} else { // Unknown tag. Skip it.
if (!input.skipField(tag)) {
break; // End of group
}
}
}
input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
// Process the raw bytes.
if (rawBytes != null && typeId != 0) { // Zero is not a valid type ID.
if (extension != null) { // We known the type
mergeMessageSetExtensionFromBytes(
rawBytes, extension, extensionRegistry, builder, extensions);
} else { // We don't know how to parse this. Ignore it.
if (rawBytes != null) {
unknownFields.mergeField(typeId, UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(rawBytes).build());
}
}
}
}
private static void eagerlyMergeMessageSetExtension(
CodedInputStream input,
ExtensionRegistry.ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
Message.Builder builder,
FieldSet<FieldDescriptor> extensions) throws IOException {
FieldDescriptor field = extension.descriptor;
Message value = null;
if (hasOriginalMessage(builder, extensions, field)) {
Message originalMessage =
getOriginalMessage(builder, extensions, field);
Message.Builder subBuilder = originalMessage.toBuilder();
input.readMessage(subBuilder, extensionRegistry);
value = subBuilder.buildPartial();
} else {
value = input.readMessage(extension.defaultInstance.getParserForType(),
extensionRegistry);
}
if (builder != null) {
builder.setField(field, value);
} else {
extensions.setField(field, value);
}
}
private static void mergeMessageSetExtensionFromBytes(
ByteString rawBytes,
ExtensionRegistry.ExtensionInfo extension,
ExtensionRegistryLite extensionRegistry,
Message.Builder builder,
FieldSet<FieldDescriptor> extensions) throws IOException {
FieldDescriptor field = extension.descriptor;
boolean hasOriginalValue = hasOriginalMessage(builder, extensions, field);
if (hasOriginalValue || ExtensionRegistryLite.isEagerlyParseMessageSets()) {
// If the field already exists, we just parse the field.
Message value = null;
if (hasOriginalValue) {
Message originalMessage =
getOriginalMessage(builder, extensions, field);
Message.Builder subBuilder= originalMessage.toBuilder();
subBuilder.mergeFrom(rawBytes, extensionRegistry);
value = subBuilder.buildPartial();
} else {
value = extension.defaultInstance.getParserForType()
.parsePartialFrom(rawBytes, extensionRegistry);
}
setField(builder, extensions, field, value);
} else {
// Use LazyField to load MessageSet lazily.
LazyField lazyField = new LazyField(
extension.defaultInstance, extensionRegistry, rawBytes);
if (builder != null) {
// TODO(xiangl): it looks like this method can only be invoked by
// ExtendableBuilder, but I'm not sure. So I double check the type of
// builder here. It may be useless and need more investigation.
if (builder instanceof ExtendableBuilder) {
builder.setField(field, lazyField);
} else {
builder.setField(field, lazyField.getValue());
}
} else {
extensions.setField(field, lazyField);
}
}
}
public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
setUnknownFields(
UnknownFieldSet.newBuilder(getUnknownFields())
.mergeFrom(unknownFields)
.build());
return (BuilderType) this;
}
public Message.Builder getFieldBuilder(final FieldDescriptor field) {
throw new UnsupportedOperationException(
"getFieldBuilder() called on an unsupported message type.");
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(Message message) {
return new UninitializedMessageException(findMissingFields(message));
}
/**
* Populates {@code this.missingFields} with the full "path" of each
* missing required field in the given message.
*/
private static List<String> findMissingFields(
final MessageOrBuilder message) {
final List<String> results = new ArrayList<String>();
findMissingFields(message, "", results);
return results;
}
/** Recursive helper implementing {@link #findMissingFields(Message)}. */
private static void findMissingFields(final MessageOrBuilder message,
final String prefix,
final List<String> results) {
for (final FieldDescriptor field :
message.getDescriptorForType().getFields()) {
if (field.isRequired() && !message.hasField(field)) {
results.add(prefix + field.getName());
}
}
for (final Map.Entry<FieldDescriptor, Object> entry :
message.getAllFields().entrySet()) {
final FieldDescriptor field = entry.getKey();
final Object value = entry.getValue();
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
if (field.isRepeated()) {
int i = 0;
for (final Object element : (List) value) {
findMissingFields((MessageOrBuilder) element,
subMessagePrefix(prefix, field, i++),
results);
}
} else {
if (message.hasField(field)) {
findMissingFields((MessageOrBuilder) value,
subMessagePrefix(prefix, field, -1),
results);
}
}
}
}
}
private static String subMessagePrefix(final String prefix,
final FieldDescriptor field,
final int index) {
final StringBuilder result = new StringBuilder(prefix);
if (field.isExtension()) {
result.append('(')
.append(field.getFullName())
.append(')');
} else {
result.append(field.getName());
}
if (index != -1) {
result.append('[')
.append(index)
.append(']');
}
result.append('.');
return result.toString();
}
// ===============================================================
// The following definitions seem to be required in order to make javac
// not produce weird errors like:
//
// java/com/google/protobuf/DynamicMessage.java:203: types
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> and
// com.google.protobuf.AbstractMessage.Builder<
// com.google.protobuf.DynamicMessage.Builder> are incompatible; both
// define mergeFrom(com.google.protobuf.ByteString), but with unrelated
// return types.
//
// Strangely, these lines are only needed if javac is invoked separately
// on AbstractMessage.java and AbstractMessageLite.java. If javac is
// invoked on both simultaneously, it works. (Or maybe the important
// point is whether or not DynamicMessage.java is compiled together with
// AbstractMessageLite.java -- not sure.) I suspect this is a compiler
// bug.
@Override
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return super.mergeFrom(data);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, off, len);
}
@Override
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, extensionRegistry);
}
@Override
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return super.mergeFrom(data, off, len, extensionRegistry);
}
@Override
public BuilderType mergeFrom(final InputStream input)
throws IOException {
return super.mergeFrom(input);
}
@Override
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeFrom(input, extensionRegistry);
}
@Override
public boolean mergeDelimitedFrom(final InputStream input)
throws IOException {
return super.mergeDelimitedFrom(input);
}
@Override
public boolean mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
return super.mergeDelimitedFrom(input, extensionRegistry);
}
}
}

View File

@ -0,0 +1,343 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
/**
* A partial implementation of the {@link MessageLite} interface which
* implements as many methods of that interface as possible in terms of other
* methods.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class AbstractMessageLite implements MessageLite {
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
public void writeTo(final OutputStream output) throws IOException {
final int bufferSize =
CodedOutputStream.computePreferredBufferSize(getSerializedSize());
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(final OutputStream output) throws IOException {
final int serialized = getSerializedSize();
final int bufferSize = CodedOutputStream.computePreferredBufferSize(
CodedOutputStream.computeRawVarint32Size(serialized) + serialized);
final CodedOutputStream codedOutput =
CodedOutputStream.newInstance(output, bufferSize);
codedOutput.writeRawVarint32(serialized);
writeTo(codedOutput);
codedOutput.flush();
}
/**
* Package private helper method for AbstractParser to create
* UninitializedMessageException.
*/
UninitializedMessageException newUninitializedMessageException() {
return new UninitializedMessageException(this);
}
/**
* A partial implementation of the {@link Message.Builder} interface which
* implements as many methods of that interface as possible in terms of
* other methods.
*/
@SuppressWarnings("unchecked")
public static abstract class Builder<BuilderType extends Builder>
implements MessageLite.Builder {
// The compiler produces an error if this is not declared explicitly.
@Override
public abstract BuilderType clone();
public BuilderType mergeFrom(final CodedInputStream input)
throws IOException {
return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry());
}
// Re-defined here for return type covariance.
public abstract BuilderType mergeFrom(
final CodedInputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException;
public BuilderType mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final ByteString data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length);
}
public BuilderType mergeFrom(final byte[] data, final int off,
final int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(
final byte[] data,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return mergeFrom(data, 0, data.length, extensionRegistry);
}
public BuilderType mergeFrom(
final byte[] data, final int off, final int len,
final ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input, extensionRegistry);
input.checkLastTagWas(0);
return (BuilderType) this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public BuilderType mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
public BuilderType mergeFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput, extensionRegistry);
codedInput.checkLastTagWas(0);
return (BuilderType) this;
}
/**
* An InputStream implementations which reads from some other InputStream
* but is limited to a particular number of bytes. Used by
* mergeDelimitedFrom(). This is intentionally package-private so that
* UnknownFieldSet can share it.
*/
static final class LimitedInputStream extends FilterInputStream {
private int limit;
LimitedInputStream(InputStream in, int limit) {
super(in);
this.limit = limit;
}
@Override
public int available() throws IOException {
return Math.min(super.available(), limit);
}
@Override
public int read() throws IOException {
if (limit <= 0) {
return -1;
}
final int result = super.read();
if (result >= 0) {
--limit;
}
return result;
}
@Override
public int read(final byte[] b, final int off, int len)
throws IOException {
if (limit <= 0) {
return -1;
}
len = Math.min(len, limit);
final int result = super.read(b, off, len);
if (result >= 0) {
limit -= result;
}
return result;
}
@Override
public long skip(final long n) throws IOException {
final long result = super.skip(Math.min(n, limit));
if (result >= 0) {
limit -= result;
}
return result;
}
}
public boolean mergeDelimitedFrom(
final InputStream input,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
}
final int size = CodedInputStream.readRawVarint32(firstByte, input);
final InputStream limitedInput = new LimitedInputStream(input, size);
mergeFrom(limitedInput, extensionRegistry);
return true;
}
public boolean mergeDelimitedFrom(final InputStream input)
throws IOException {
return mergeDelimitedFrom(input,
ExtensionRegistryLite.getEmptyRegistry());
}
/**
* Construct an UninitializedMessageException reporting missing fields in
* the given message.
*/
protected static UninitializedMessageException
newUninitializedMessageException(MessageLite message) {
return new UninitializedMessageException(message);
}
/**
* Adds the {@code values} to the {@code list}. This is a helper method
* used by generated code. Users should ignore it.
*
* @throws NullPointerException if any of the elements of {@code values} is
* null.
*/
protected static <T> void addAll(final Iterable<T> values,
final Collection<? super T> list) {
if (values instanceof LazyStringList) {
// For StringOrByteStringLists, check the underlying elements to avoid
// forcing conversions of ByteStrings to Strings.
checkForNullValues(((LazyStringList) values).getUnderlyingElements());
} else {
checkForNullValues(values);
}
if (values instanceof Collection) {
final Collection<T> collection = (Collection<T>) values;
list.addAll(collection);
} else {
for (final T value : values) {
list.add(value);
}
}
}
private static void checkForNullValues(final Iterable<?> values) {
for (final Object value : values) {
if (value == null) {
throw new NullPointerException();
}
}
}
}
}

View File

@ -0,0 +1,261 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A partial implementation of the {@link Parser} interface which implements
* as many methods of that interface as possible in terms of other methods.
*
* Note: This class implements all the convenience methods in the
* {@link Parser} interface. See {@link Parser} for related javadocs.
* Subclasses need to implement
* {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)}
*
* @author liujisi@google.com (Pherl Liu)
*/
public abstract class AbstractParser<MessageType extends MessageLite>
implements Parser<MessageType> {
/**
* Creates an UninitializedMessageException for MessageType.
*/
private UninitializedMessageException
newUninitializedMessageException(MessageType message) {
if (message instanceof AbstractMessageLite) {
return ((AbstractMessageLite) message).newUninitializedMessageException();
}
return new UninitializedMessageException(message);
}
/**
* Helper method to check if message is initialized.
*
* @throws InvalidProtocolBufferException if it is not initialized.
* @return The message to check.
*/
private MessageType checkMessageInitialized(MessageType message)
throws InvalidProtocolBufferException {
if (message != null && !message.isInitialized()) {
throw newUninitializedMessageException(message)
.asInvalidProtocolBufferException()
.setUnfinishedMessage(message);
}
return message;
}
private static final ExtensionRegistryLite EMPTY_REGISTRY
= ExtensionRegistryLite.getEmptyRegistry();
public MessageType parsePartialFrom(CodedInputStream input)
throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
public MessageType parseFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
public MessageType parseFrom(CodedInputStream input)
throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
public MessageType parsePartialFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
MessageType message;
try {
CodedInputStream input = data.newCodedInput();
message = parsePartialFrom(input, extensionRegistry);
try {
input.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
public MessageType parsePartialFrom(ByteString data)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, EMPTY_REGISTRY);
}
public MessageType parseFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(parsePartialFrom(data, extensionRegistry));
}
public MessageType parseFrom(ByteString data)
throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
public MessageType parsePartialFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
try {
CodedInputStream input = CodedInputStream.newInstance(data, off, len);
MessageType message = parsePartialFrom(input, extensionRegistry);
try {
input.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public MessageType parsePartialFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, off, len, EMPTY_REGISTRY);
}
public MessageType parsePartialFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, extensionRegistry);
}
public MessageType parsePartialFrom(byte[] data)
throws InvalidProtocolBufferException {
return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY);
}
public MessageType parseFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(data, off, len, extensionRegistry));
}
public MessageType parseFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
return parseFrom(data, off, len, EMPTY_REGISTRY);
}
public MessageType parseFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return parseFrom(data, 0, data.length, extensionRegistry);
}
public MessageType parseFrom(byte[] data)
throws InvalidProtocolBufferException {
return parseFrom(data, EMPTY_REGISTRY);
}
public MessageType parsePartialFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
CodedInputStream codedInput = CodedInputStream.newInstance(input);
MessageType message = parsePartialFrom(codedInput, extensionRegistry);
try {
codedInput.checkLastTagWas(0);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(message);
}
return message;
}
public MessageType parsePartialFrom(InputStream input)
throws InvalidProtocolBufferException {
return parsePartialFrom(input, EMPTY_REGISTRY);
}
public MessageType parseFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialFrom(input, extensionRegistry));
}
public MessageType parseFrom(InputStream input)
throws InvalidProtocolBufferException {
return parseFrom(input, EMPTY_REGISTRY);
}
public MessageType parsePartialDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
int size;
try {
int firstByte = input.read();
if (firstByte == -1) {
return null;
}
size = CodedInputStream.readRawVarint32(firstByte, input);
} catch (IOException e) {
throw new InvalidProtocolBufferException(e.getMessage());
}
InputStream limitedInput = new LimitedInputStream(input, size);
return parsePartialFrom(limitedInput, extensionRegistry);
}
public MessageType parsePartialDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException {
return parsePartialDelimitedFrom(input, EMPTY_REGISTRY);
}
public MessageType parseDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
return checkMessageInitialized(
parsePartialDelimitedFrom(input, extensionRegistry));
}
public MessageType parseDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException {
return parseDelimitedFrom(input, EMPTY_REGISTRY);
}
}

View File

@ -0,0 +1,51 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
* is the blocking equivalent to {@link RpcChannel}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingRpcChannel {
/**
* Call the given method of the remote service and blocks until it returns.
* {@code callBlockingMethod()} is the blocking equivalent to
* {@link RpcChannel#callMethod}.
*/
Message callBlockingMethod(
Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
Message responsePrototype) throws ServiceException;
}

View File

@ -0,0 +1,64 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Blocking equivalent to {@link Service}.
*
* @author kenton@google.com Kenton Varda
* @author cpovirk@google.com Chris Povirk
*/
public interface BlockingService {
/**
* Equivalent to {@link Service#getDescriptorForType}.
*/
Descriptors.ServiceDescriptor getDescriptorForType();
/**
* Equivalent to {@link Service#callMethod}, except that
* {@code callBlockingMethod()} returns the result of the RPC or throws a
* {@link ServiceException} if there is a failure, rather than passing the
* information to a callback.
*/
Message callBlockingMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request) throws ServiceException;
/**
* Equivalent to {@link Service#getRequestPrototype}.
*/
Message getRequestPrototype(Descriptors.MethodDescriptor method);
/**
* Equivalent to {@link Service#getResponsePrototype}.
*/
Message getResponsePrototype(Descriptors.MethodDescriptor method);
}

View File

@ -0,0 +1,163 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.NoSuchElementException;
/**
* This class is used to represent the substring of a {@link ByteString} over a
* single byte array. In terms of the public API of {@link ByteString}, you end
* up here by calling {@link ByteString#copyFrom(byte[])} followed by {@link
* ByteString#substring(int, int)}.
*
* <p>This class contains most of the overhead involved in creating a substring
* from a {@link LiteralByteString}. The overhead involves some range-checking
* and two extra fields.
*
* @author carlanton@google.com (Carl Haverl)
*/
class BoundedByteString extends LiteralByteString {
private final int bytesOffset;
private final int bytesLength;
/**
* Creates a {@code BoundedByteString} backed by the sub-range of given array,
* without copying.
*
* @param bytes array to wrap
* @param offset index to first byte to use in bytes
* @param length number of bytes to use from bytes
* @throws IllegalArgumentException if {@code offset < 0}, {@code length < 0},
* or if {@code offset + length >
* bytes.length}.
*/
BoundedByteString(byte[] bytes, int offset, int length) {
super(bytes);
if (offset < 0) {
throw new IllegalArgumentException("Offset too small: " + offset);
}
if (length < 0) {
throw new IllegalArgumentException("Length too small: " + offset);
}
if ((long) offset + length > bytes.length) {
throw new IllegalArgumentException(
"Offset+Length too large: " + offset + "+" + length);
}
this.bytesOffset = offset;
this.bytesLength = length;
}
/**
* Gets the byte at the given index.
* Throws {@link ArrayIndexOutOfBoundsException}
* for backwards-compatibility reasons although it would more properly be
* {@link IndexOutOfBoundsException}.
*
* @param index index of byte
* @return the value
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
@Override
public byte byteAt(int index) {
// We must check the index ourselves as we cannot rely on Java array index
// checking for substrings.
if (index < 0) {
throw new ArrayIndexOutOfBoundsException("Index too small: " + index);
}
if (index >= size()) {
throw new ArrayIndexOutOfBoundsException(
"Index too large: " + index + ", " + size());
}
return bytes[bytesOffset + index];
}
@Override
public int size() {
return bytesLength;
}
@Override
protected int getOffsetIntoBytes() {
return bytesOffset;
}
// =================================================================
// ByteString -> byte[]
@Override
protected void copyToInternal(byte[] target, int sourceOffset,
int targetOffset, int numberToCopy) {
System.arraycopy(bytes, getOffsetIntoBytes() + sourceOffset, target,
targetOffset, numberToCopy);
}
// =================================================================
// ByteIterator
@Override
public ByteIterator iterator() {
return new BoundedByteIterator();
}
private class BoundedByteIterator implements ByteIterator {
private int position;
private final int limit;
private BoundedByteIterator() {
position = getOffsetIntoBytes();
limit = position + size();
}
public boolean hasNext() {
return (position < limit);
}
public Byte next() {
// Boxing calls Byte.valueOf(byte), which does not instantiate.
return nextByte();
}
public byte nextByte() {
if (position >= limit) {
throw new NoSuchElementException();
}
return bytes[position++];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,970 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
* Immutable sequence of bytes. Substring is supported by sharing the reference
* to the immutable underlying bytes, as with {@link String}. Concatenation is
* likewise supported without copying (long strings) by building a tree of
* pieces in {@link RopeByteString}.
* <p>
* Like {@link String}, the contents of a {@link ByteString} can never be
* observed to change, not even in the presence of a data race or incorrect
* API usage in the client code.
*
* @author crazybob@google.com Bob Lee
* @author kenton@google.com Kenton Varda
* @author carlanton@google.com Carl Haverl
* @author martinrb@google.com Martin Buchholz
*/
public abstract class ByteString implements Iterable<Byte> {
/**
* When two strings to be concatenated have a combined length shorter than
* this, we just copy their bytes on {@link #concat(ByteString)}.
* The trade-off is copy size versus the overhead of creating tree nodes
* in {@link RopeByteString}.
*/
static final int CONCATENATE_BY_COPY_SIZE = 128;
/**
* When copying an InputStream into a ByteString with .readFrom(),
* the chunks in the underlying rope start at 256 bytes, but double
* each iteration up to 8192 bytes.
*/
static final int MIN_READ_FROM_CHUNK_SIZE = 0x100; // 256b
static final int MAX_READ_FROM_CHUNK_SIZE = 0x2000; // 8k
/**
* Empty {@code ByteString}.
*/
public static final ByteString EMPTY = new LiteralByteString(new byte[0]);
// This constructor is here to prevent subclassing outside of this package,
ByteString() {}
/**
* Gets the byte at the given index. This method should be used only for
* random access to individual bytes. To access bytes sequentially, use the
* {@link ByteIterator} returned by {@link #iterator()}, and call {@link
* #substring(int, int)} first if necessary.
*
* @param index index of byte
* @return the value
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
public abstract byte byteAt(int index);
/**
* Return a {@link ByteString.ByteIterator} over the bytes in the ByteString.
* To avoid auto-boxing, you may get the iterator manually and call
* {@link ByteIterator#nextByte()}.
*
* @return the iterator
*/
public abstract ByteIterator iterator();
/**
* This interface extends {@code Iterator<Byte>}, so that we can return an
* unboxed {@code byte}.
*/
public interface ByteIterator extends Iterator<Byte> {
/**
* An alternative to {@link Iterator#next()} that returns an
* unboxed primitive {@code byte}.
*
* @return the next {@code byte} in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
byte nextByte();
}
/**
* Gets the number of bytes.
*
* @return size in bytes
*/
public abstract int size();
/**
* Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
*
* @return true if this is zero bytes long
*/
public boolean isEmpty() {
return size() == 0;
}
// =================================================================
// ByteString -> substring
/**
* Return the substring from {@code beginIndex}, inclusive, to the end of the
* string.
*
* @param beginIndex start at this index
* @return substring sharing underlying data
* @throws IndexOutOfBoundsException if {@code beginIndex < 0} or
* {@code beginIndex > size()}.
*/
public ByteString substring(int beginIndex) {
return substring(beginIndex, size());
}
/**
* Return the substring from {@code beginIndex}, inclusive, to {@code
* endIndex}, exclusive.
*
* @param beginIndex start at this index
* @param endIndex the last character is the one before this index
* @return substring sharing underlying data
* @throws IndexOutOfBoundsException if {@code beginIndex < 0},
* {@code endIndex > size()}, or {@code beginIndex > endIndex}.
*/
public abstract ByteString substring(int beginIndex, int endIndex);
/**
* Tests if this bytestring starts with the specified prefix.
* Similar to {@link String#startsWith(String)}
*
* @param prefix the prefix.
* @return <code>true</code> if the byte sequence represented by the
* argument is a prefix of the byte sequence represented by
* this string; <code>false</code> otherwise.
*/
public boolean startsWith(ByteString prefix) {
return size() >= prefix.size() &&
substring(0, prefix.size()).equals(prefix);
}
// =================================================================
// byte[] -> ByteString
/**
* Copies the given bytes into a {@code ByteString}.
*
* @param bytes source array
* @param offset offset in source array
* @param size number of bytes to copy
* @return new {@code ByteString}
*/
public static ByteString copyFrom(byte[] bytes, int offset, int size) {
byte[] copy = new byte[size];
System.arraycopy(bytes, offset, copy, 0, size);
return new LiteralByteString(copy);
}
/**
* Copies the given bytes into a {@code ByteString}.
*
* @param bytes to copy
* @return new {@code ByteString}
*/
public static ByteString copyFrom(byte[] bytes) {
return copyFrom(bytes, 0, bytes.length);
}
/**
* Copies the next {@code size} bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
*
* @param bytes source buffer
* @param size number of bytes to copy
* @return new {@code ByteString}
*/
public static ByteString copyFrom(ByteBuffer bytes, int size) {
byte[] copy = new byte[size];
bytes.get(copy);
return new LiteralByteString(copy);
}
/**
* Copies the remaining bytes from a {@code java.nio.ByteBuffer} into
* a {@code ByteString}.
*
* @param bytes sourceBuffer
* @return new {@code ByteString}
*/
public static ByteString copyFrom(ByteBuffer bytes) {
return copyFrom(bytes, bytes.remaining());
}
/**
* Encodes {@code text} into a sequence of bytes using the named charset
* and returns the result as a {@code ByteString}.
*
* @param text source string
* @param charsetName encoding to use
* @return new {@code ByteString}
* @throws UnsupportedEncodingException if the encoding isn't found
*/
public static ByteString copyFrom(String text, String charsetName)
throws UnsupportedEncodingException {
return new LiteralByteString(text.getBytes(charsetName));
}
/**
* Encodes {@code text} into a sequence of UTF-8 bytes and returns the
* result as a {@code ByteString}.
*
* @param text source string
* @return new {@code ByteString}
*/
public static ByteString copyFromUtf8(String text) {
try {
return new LiteralByteString(text.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
// =================================================================
// InputStream -> ByteString
/**
* Completely reads the given stream's bytes into a
* {@code ByteString}, blocking if necessary until all bytes are
* read through to the end of the stream.
*
* <b>Performance notes:</b> The returned {@code ByteString} is an
* immutable tree of byte arrays ("chunks") of the stream data. The
* first chunk is small, with subsequent chunks each being double
* the size, up to 8K. If the caller knows the precise length of
* the stream and wishes to avoid all unnecessary copies and
* allocations, consider using the two-argument version of this
* method, below.
*
* @param streamToDrain The source stream, which is read completely
* but not closed.
* @return A new {@code ByteString} which is made up of chunks of
* various sizes, depending on the behavior of the underlying
* stream.
* @throws IOException IOException is thrown if there is a problem
* reading the underlying stream.
*/
public static ByteString readFrom(InputStream streamToDrain)
throws IOException {
return readFrom(
streamToDrain, MIN_READ_FROM_CHUNK_SIZE, MAX_READ_FROM_CHUNK_SIZE);
}
/**
* Completely reads the given stream's bytes into a
* {@code ByteString}, blocking if necessary until all bytes are
* read through to the end of the stream.
*
* <b>Performance notes:</b> The returned {@code ByteString} is an
* immutable tree of byte arrays ("chunks") of the stream data. The
* chunkSize parameter sets the size of these byte arrays. In
* particular, if the chunkSize is precisely the same as the length
* of the stream, unnecessary allocations and copies will be
* avoided. Otherwise, the chunks will be of the given size, except
* for the last chunk, which will be resized (via a reallocation and
* copy) to contain the remainder of the stream.
*
* @param streamToDrain The source stream, which is read completely
* but not closed.
* @param chunkSize The size of the chunks in which to read the
* stream.
* @return A new {@code ByteString} which is made up of chunks of
* the given size.
* @throws IOException IOException is thrown if there is a problem
* reading the underlying stream.
*/
public static ByteString readFrom(InputStream streamToDrain, int chunkSize)
throws IOException {
return readFrom(streamToDrain, chunkSize, chunkSize);
}
// Helper method that takes the chunk size range as a parameter.
public static ByteString readFrom(InputStream streamToDrain, int minChunkSize,
int maxChunkSize) throws IOException {
Collection<ByteString> results = new ArrayList<ByteString>();
// copy the inbound bytes into a list of chunks; the chunk size
// grows exponentially to support both short and long streams.
int chunkSize = minChunkSize;
while (true) {
ByteString chunk = readChunk(streamToDrain, chunkSize);
if (chunk == null) {
break;
}
results.add(chunk);
chunkSize = Math.min(chunkSize * 2, maxChunkSize);
}
return ByteString.copyFrom(results);
}
/**
* Blocks until a chunk of the given size can be made from the
* stream, or EOF is reached. Calls read() repeatedly in case the
* given stream implementation doesn't completely fill the given
* buffer in one read() call.
*
* @return A chunk of the desired size, or else a chunk as large as
* was available when end of stream was reached. Returns null if the
* given stream had no more data in it.
*/
private static ByteString readChunk(InputStream in, final int chunkSize)
throws IOException {
final byte[] buf = new byte[chunkSize];
int bytesRead = 0;
while (bytesRead < chunkSize) {
final int count = in.read(buf, bytesRead, chunkSize - bytesRead);
if (count == -1) {
break;
}
bytesRead += count;
}
if (bytesRead == 0) {
return null;
} else {
return ByteString.copyFrom(buf, 0, bytesRead);
}
}
// =================================================================
// Multiple ByteStrings -> One ByteString
/**
* Concatenate the given {@code ByteString} to this one. Short concatenations,
* of total size smaller than {@link ByteString#CONCATENATE_BY_COPY_SIZE}, are
* produced by copying the underlying bytes (as per Rope.java, <a
* href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
* BAP95 </a>. In general, the concatenate involves no copying.
*
* @param other string to concatenate
* @return a new {@code ByteString} instance
*/
public ByteString concat(ByteString other) {
int thisSize = size();
int otherSize = other.size();
if ((long) thisSize + otherSize >= Integer.MAX_VALUE) {
throw new IllegalArgumentException("ByteString would be too long: " +
thisSize + "+" + otherSize);
}
return RopeByteString.concatenate(this, other);
}
/**
* Concatenates all byte strings in the iterable and returns the result.
* This is designed to run in O(list size), not O(total bytes).
*
* <p>The returned {@code ByteString} is not necessarily a unique object.
* If the list is empty, the returned object is the singleton empty
* {@code ByteString}. If the list has only one element, that
* {@code ByteString} will be returned without copying.
*
* @param byteStrings strings to be concatenated
* @return new {@code ByteString}
*/
public static ByteString copyFrom(Iterable<ByteString> byteStrings) {
Collection<ByteString> collection;
if (!(byteStrings instanceof Collection)) {
collection = new ArrayList<ByteString>();
for (ByteString byteString : byteStrings) {
collection.add(byteString);
}
} else {
collection = (Collection<ByteString>) byteStrings;
}
ByteString result;
if (collection.isEmpty()) {
result = EMPTY;
} else {
result = balancedConcat(collection.iterator(), collection.size());
}
return result;
}
// Internal function used by copyFrom(Iterable<ByteString>).
// Create a balanced concatenation of the next "length" elements from the
// iterable.
private static ByteString balancedConcat(Iterator<ByteString> iterator,
int length) {
assert length >= 1;
ByteString result;
if (length == 1) {
result = iterator.next();
} else {
int halfLength = length >>> 1;
ByteString left = balancedConcat(iterator, halfLength);
ByteString right = balancedConcat(iterator, length - halfLength);
result = left.concat(right);
}
return result;
}
// =================================================================
// ByteString -> byte[]
/**
* Copies bytes into a buffer at the given offset.
*
* @param target buffer to copy into
* @param offset in the target buffer
* @throws IndexOutOfBoundsException if the offset is negative or too large
*/
public void copyTo(byte[] target, int offset) {
copyTo(target, 0, offset, size());
}
/**
* Copies bytes into a buffer.
*
* @param target buffer to copy into
* @param sourceOffset offset within these bytes
* @param targetOffset offset within the target buffer
* @param numberToCopy number of bytes to copy
* @throws IndexOutOfBoundsException if an offset or size is negative or too
* large
*/
public void copyTo(byte[] target, int sourceOffset, int targetOffset,
int numberToCopy) {
if (sourceOffset < 0) {
throw new IndexOutOfBoundsException("Source offset < 0: " + sourceOffset);
}
if (targetOffset < 0) {
throw new IndexOutOfBoundsException("Target offset < 0: " + targetOffset);
}
if (numberToCopy < 0) {
throw new IndexOutOfBoundsException("Length < 0: " + numberToCopy);
}
if (sourceOffset + numberToCopy > size()) {
throw new IndexOutOfBoundsException(
"Source end offset < 0: " + (sourceOffset + numberToCopy));
}
if (targetOffset + numberToCopy > target.length) {
throw new IndexOutOfBoundsException(
"Target end offset < 0: " + (targetOffset + numberToCopy));
}
if (numberToCopy > 0) {
copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
}
}
/**
* Internal (package private) implementation of
* @link{#copyTo(byte[],int,int,int}.
* It assumes that all error checking has already been performed and that
* @code{numberToCopy > 0}.
*/
protected abstract void copyToInternal(byte[] target, int sourceOffset,
int targetOffset, int numberToCopy);
/**
* Copies bytes into a ByteBuffer.
*
* @param target ByteBuffer to copy into.
* @throws java.nio.ReadOnlyBufferException if the {@code target} is read-only
* @throws java.nio.BufferOverflowException if the {@code target}'s
* remaining() space is not large enough to hold the data.
*/
public abstract void copyTo(ByteBuffer target);
/**
* Copies bytes to a {@code byte[]}.
*
* @return copied bytes
*/
public byte[] toByteArray() {
int size = size();
byte[] result = new byte[size];
copyToInternal(result, 0, 0, size);
return result;
}
/**
* Writes the complete contents of this byte string to
* the specified output stream argument.
*
* @param out the output stream to which to write the data.
* @throws IOException if an I/O error occurs.
*/
public abstract void writeTo(OutputStream out) throws IOException;
/**
* Constructs a read-only {@code java.nio.ByteBuffer} whose content
* is equal to the contents of this byte string.
* The result uses the same backing array as the byte string, if possible.
*
* @return wrapped bytes
*/
public abstract ByteBuffer asReadOnlyByteBuffer();
/**
* Constructs a list of read-only {@code java.nio.ByteBuffer} objects
* such that the concatenation of their contents is equal to the contents
* of this byte string. The result uses the same backing arrays as the
* byte string.
* <p>
* By returning a list, implementations of this method may be able to avoid
* copying even when there are multiple backing arrays.
*
* @return a list of wrapped bytes
*/
public abstract List<ByteBuffer> asReadOnlyByteBufferList();
/**
* Constructs a new {@code String} by decoding the bytes using the
* specified charset.
*
* @param charsetName encode using this charset
* @return new string
* @throws UnsupportedEncodingException if charset isn't recognized
*/
public abstract String toString(String charsetName)
throws UnsupportedEncodingException;
// =================================================================
// UTF-8 decoding
/**
* Constructs a new {@code String} by decoding the bytes as UTF-8.
*
* @return new string using UTF-8 encoding
*/
public String toStringUtf8() {
try {
return toString("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF-8 not supported?", e);
}
}
/**
* Tells whether this {@code ByteString} represents a well-formed UTF-8
* byte sequence, such that the original bytes can be converted to a
* String object and then round tripped back to bytes without loss.
*
* <p>More precisely, returns {@code true} whenever: <pre> {@code
* Arrays.equals(byteString.toByteArray(),
* new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
* }</pre>
*
* <p>This method returns {@code false} for "overlong" byte sequences,
* as well as for 3-byte sequences that would map to a surrogate
* character, in accordance with the restricted definition of UTF-8
* introduced in Unicode 3.1. Note that the UTF-8 decoder included in
* Oracle's JDK has been modified to also reject "overlong" byte
* sequences, but (as of 2011) still accepts 3-byte surrogate
* character byte sequences.
*
* <p>See the Unicode Standard,</br>
* Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
*
* @return whether the bytes in this {@code ByteString} are a
* well-formed UTF-8 byte sequence
*/
public abstract boolean isValidUtf8();
/**
* Tells whether the given byte sequence is a well-formed, malformed, or
* incomplete UTF-8 byte sequence. This method accepts and returns a partial
* state result, allowing the bytes for a complete UTF-8 byte sequence to be
* composed from multiple {@code ByteString} segments.
*
* @param state either {@code 0} (if this is the initial decoding operation)
* or the value returned from a call to a partial decoding method for the
* previous bytes
* @param offset offset of the first byte to check
* @param length number of bytes to check
*
* @return {@code -1} if the partial byte sequence is definitely malformed,
* {@code 0} if it is well-formed (no additional input needed), or, if the
* byte sequence is "incomplete", i.e. apparently terminated in the middle of
* a character, an opaque integer "state" value containing enough information
* to decode the character when passed to a subsequent invocation of a
* partial decoding method.
*/
protected abstract int partialIsValidUtf8(int state, int offset, int length);
// =================================================================
// equals() and hashCode()
@Override
public abstract boolean equals(Object o);
/**
* Return a non-zero hashCode depending only on the sequence of bytes
* in this ByteString.
*
* @return hashCode value for this object
*/
@Override
public abstract int hashCode();
// =================================================================
// Input stream
/**
* Creates an {@code InputStream} which can be used to read the bytes.
* <p>
* The {@link InputStream} returned by this method is guaranteed to be
* completely non-blocking. The method {@link InputStream#available()}
* returns the number of bytes remaining in the stream. The methods
* {@link InputStream#read(byte[]), {@link InputStream#read(byte[],int,int)}
* and {@link InputStream#skip(long)} will read/skip as many bytes as are
* available.
* <p>
* The methods in the returned {@link InputStream} might <b>not</b> be
* thread safe.
*
* @return an input stream that returns the bytes of this byte string.
*/
public abstract InputStream newInput();
/**
* Creates a {@link CodedInputStream} which can be used to read the bytes.
* Using this is often more efficient than creating a {@link CodedInputStream}
* that wraps the result of {@link #newInput()}.
*
* @return stream based on wrapped data
*/
public abstract CodedInputStream newCodedInput();
// =================================================================
// Output stream
/**
* Creates a new {@link Output} with the given initial capacity. Call {@link
* Output#toByteString()} to create the {@code ByteString} instance.
* <p>
* A {@link ByteString.Output} offers the same functionality as a
* {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
* rather than a {@code byte} array.
*
* @param initialCapacity estimate of number of bytes to be written
* @return {@code OutputStream} for building a {@code ByteString}
*/
public static Output newOutput(int initialCapacity) {
return new Output(initialCapacity);
}
/**
* Creates a new {@link Output}. Call {@link Output#toByteString()} to create
* the {@code ByteString} instance.
* <p>
* A {@link ByteString.Output} offers the same functionality as a
* {@link ByteArrayOutputStream}, except that it returns a {@link ByteString}
* rather than a {@code byte array}.
*
* @return {@code OutputStream} for building a {@code ByteString}
*/
public static Output newOutput() {
return new Output(CONCATENATE_BY_COPY_SIZE);
}
/**
* Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
* create the {@code ByteString} instance.
*/
public static final class Output extends OutputStream {
// Implementation note.
// The public methods of this class must be synchronized. ByteStrings
// are guaranteed to be immutable. Without some sort of locking, it could
// be possible for one thread to call toByteSring(), while another thread
// is still modifying the underlying byte array.
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
// argument passed by user, indicating initial capacity.
private final int initialCapacity;
// ByteStrings to be concatenated to create the result
private final ArrayList<ByteString> flushedBuffers;
// Total number of bytes in the ByteStrings of flushedBuffers
private int flushedBuffersTotalBytes;
// Current buffer to which we are writing
private byte[] buffer;
// Location in buffer[] to which we write the next byte.
private int bufferPos;
/**
* Creates a new ByteString output stream with the specified
* initial capacity.
*
* @param initialCapacity the initial capacity of the output stream.
*/
Output(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("Buffer size < 0");
}
this.initialCapacity = initialCapacity;
this.flushedBuffers = new ArrayList<ByteString>();
this.buffer = new byte[initialCapacity];
}
@Override
public synchronized void write(int b) {
if (bufferPos == buffer.length) {
flushFullBuffer(1);
}
buffer[bufferPos++] = (byte)b;
}
@Override
public synchronized void write(byte[] b, int offset, int length) {
if (length <= buffer.length - bufferPos) {
// The bytes can fit into the current buffer.
System.arraycopy(b, offset, buffer, bufferPos, length);
bufferPos += length;
} else {
// Use up the current buffer
int copySize = buffer.length - bufferPos;
System.arraycopy(b, offset, buffer, bufferPos, copySize);
offset += copySize;
length -= copySize;
// Flush the buffer, and get a new buffer at least big enough to cover
// what we still need to output
flushFullBuffer(length);
System.arraycopy(b, offset, buffer, 0 /* count */, length);
bufferPos = length;
}
}
/**
* Creates a byte string. Its size is the current size of this output
* stream and its output has been copied to it.
*
* @return the current contents of this output stream, as a byte string.
*/
public synchronized ByteString toByteString() {
flushLastBuffer();
return ByteString.copyFrom(flushedBuffers);
}
/**
* Implement java.util.Arrays.copyOf() for jdk 1.5.
*/
private byte[] copyArray(byte[] buffer, int length) {
byte[] result = new byte[length];
System.arraycopy(buffer, 0, result, 0, Math.min(buffer.length, length));
return result;
}
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument.
*
* @param out the output stream to which to write the data.
* @throws IOException if an I/O error occurs.
*/
public void writeTo(OutputStream out) throws IOException {
ByteString[] cachedFlushBuffers;
byte[] cachedBuffer;
int cachedBufferPos;
synchronized (this) {
// Copy the information we need into local variables so as to hold
// the lock for as short a time as possible.
cachedFlushBuffers =
flushedBuffers.toArray(new ByteString[flushedBuffers.size()]);
cachedBuffer = buffer;
cachedBufferPos = bufferPos;
}
for (ByteString byteString : cachedFlushBuffers) {
byteString.writeTo(out);
}
out.write(copyArray(cachedBuffer, cachedBufferPos));
}
/**
* Returns the current size of the output stream.
*
* @return the current size of the output stream
*/
public synchronized int size() {
return flushedBuffersTotalBytes + bufferPos;
}
/**
* Resets this stream, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*/
public synchronized void reset() {
flushedBuffers.clear();
flushedBuffersTotalBytes = 0;
bufferPos = 0;
}
@Override
public String toString() {
return String.format("<ByteString.Output@%s size=%d>",
Integer.toHexString(System.identityHashCode(this)), size());
}
/**
* Internal function used by writers. The current buffer is full, and the
* writer needs a new buffer whose size is at least the specified minimum
* size.
*/
private void flushFullBuffer(int minSize) {
flushedBuffers.add(new LiteralByteString(buffer));
flushedBuffersTotalBytes += buffer.length;
// We want to increase our total capacity by 50%, but as a minimum,
// the new buffer should also at least be >= minSize and
// >= initial Capacity.
int newSize = Math.max(initialCapacity,
Math.max(minSize, flushedBuffersTotalBytes >>> 1));
buffer = new byte[newSize];
bufferPos = 0;
}
/**
* Internal function used by {@link #toByteString()}. The current buffer may
* or may not be full, but it needs to be flushed.
*/
private void flushLastBuffer() {
if (bufferPos < buffer.length) {
if (bufferPos > 0) {
byte[] bufferCopy = copyArray(buffer, bufferPos);
flushedBuffers.add(new LiteralByteString(bufferCopy));
}
// We reuse this buffer for further writes.
} else {
// Buffer is completely full. Huzzah.
flushedBuffers.add(new LiteralByteString(buffer));
// 99% of the time, we're not going to use this OutputStream again.
// We set buffer to an empty byte stream so that we're handling this
// case without wasting space. In the rare case that more writes
// *do* occur, this empty buffer will be flushed and an appropriately
// sized new buffer will be created.
buffer = EMPTY_BYTE_ARRAY;
}
flushedBuffersTotalBytes += bufferPos;
bufferPos = 0;
}
}
/**
* Constructs a new {@code ByteString} builder, which allows you to
* efficiently construct a {@code ByteString} by writing to a {@link
* CodedOutputStream}. Using this is much more efficient than calling {@code
* newOutput()} and wrapping that in a {@code CodedOutputStream}.
*
* <p>This is package-private because it's a somewhat confusing interface.
* Users can call {@link Message#toByteString()} instead of calling this
* directly.
*
* @param size The target byte size of the {@code ByteString}. You must write
* exactly this many bytes before building the result.
* @return the builder
*/
static CodedBuilder newCodedBuilder(int size) {
return new CodedBuilder(size);
}
/** See {@link ByteString#newCodedBuilder(int)}. */
static final class CodedBuilder {
private final CodedOutputStream output;
private final byte[] buffer;
private CodedBuilder(int size) {
buffer = new byte[size];
output = CodedOutputStream.newInstance(buffer);
}
public ByteString build() {
output.checkNoSpaceLeft();
// We can be confident that the CodedOutputStream will not modify the
// underlying bytes anymore because it already wrote all of them. So,
// no need to make a copy.
return new LiteralByteString(buffer);
}
public CodedOutputStream getCodedOutput() {
return output;
}
}
// =================================================================
// Methods {@link RopeByteString} needs on instances, which aren't part of the
// public API.
/**
* Return the depth of the tree representing this {@code ByteString}, if any,
* whose root is this node. If this is a leaf node, return 0.
*
* @return tree depth or zero
*/
protected abstract int getTreeDepth();
/**
* Return {@code true} if this ByteString is literal (a leaf node) or a
* flat-enough tree in the sense of {@link RopeByteString}.
*
* @return true if the tree is flat enough
*/
protected abstract boolean isBalanced();
/**
* Return the cached hash code if available.
*
* @return value of cached hash code or 0 if not computed yet
*/
protected abstract int peekCachedHashCode();
/**
* Compute the hash across the value bytes starting with the given hash, and
* return the result. This is used to compute the hash across strings
* represented as a set of pieces by allowing the hash computation to be
* continued from piece to piece.
*
* @param h starting hash value
* @param offset offset into this value to start looking at data values
* @param length number of data values to include in the hash computation
* @return ending hash value
*/
protected abstract int partialHash(int h, int offset, int length);
@Override
public String toString() {
return String.format("<ByteString@%s size=%d>",
Integer.toHexString(System.identityHashCode(this)), size());
}
}

View File

@ -0,0 +1,920 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Reads and decodes protocol message fields.
*
* This class contains two kinds of methods: methods that read specific
* protocol message constructs and field types (e.g. {@link #readTag()} and
* {@link #readInt32()}) and methods that read low-level values (e.g.
* {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading
* encoded protocol messages, you should use the former methods, but if you are
* reading some other format of your own design, use the latter.
*
* @author kenton@google.com Kenton Varda
*/
public final class CodedInputStream {
/**
* Create a new CodedInputStream wrapping the given InputStream.
*/
public static CodedInputStream newInstance(final InputStream input) {
return new CodedInputStream(input);
}
/**
* Create a new CodedInputStream wrapping the given byte array.
*/
public static CodedInputStream newInstance(final byte[] buf) {
return newInstance(buf, 0, buf.length);
}
/**
* Create a new CodedInputStream wrapping the given byte array slice.
*/
public static CodedInputStream newInstance(final byte[] buf, final int off,
final int len) {
CodedInputStream result = new CodedInputStream(buf, off, len);
try {
// Some uses of CodedInputStream can be more efficient if they know
// exactly how many bytes are available. By pushing the end point of the
// buffer as a limit, we allow them to get this information via
// getBytesUntilLimit(). Pushing a limit that we know is at the end of
// the stream can never hurt, since we can never past that point anyway.
result.pushLimit(len);
} catch (InvalidProtocolBufferException ex) {
// The only reason pushLimit() might throw an exception here is if len
// is negative. Normally pushLimit()'s parameter comes directly off the
// wire, so it's important to catch exceptions in case of corrupt or
// malicious data. However, in this case, we expect that len is not a
// user-supplied value, so we can assume that it being negative indicates
// a programming error. Therefore, throwing an unchecked exception is
// appropriate.
throw new IllegalArgumentException(ex);
}
return result;
}
// -----------------------------------------------------------------
/**
* Attempt to read a field tag, returning zero if we have reached EOF.
* Protocol message parsers use this to read tags, since a protocol message
* may legally end wherever a tag occurs, and zero is not a valid tag number.
*/
public int readTag() throws IOException {
if (isAtEnd()) {
lastTag = 0;
return 0;
}
lastTag = readRawVarint32();
if (WireFormat.getTagFieldNumber(lastTag) == 0) {
// If we actually read zero (or any tag number corresponding to field
// number zero), that's not a valid tag.
throw InvalidProtocolBufferException.invalidTag();
}
return lastTag;
}
/**
* Verifies that the last call to readTag() returned the given tag value.
* This is used to verify that a nested group ended with the correct
* end tag.
*
* @throws InvalidProtocolBufferException {@code value} does not match the
* last tag.
*/
public void checkLastTagWas(final int value)
throws InvalidProtocolBufferException {
if (lastTag != value) {
throw InvalidProtocolBufferException.invalidEndTag();
}
}
/**
* Reads and discards a single field, given its tag value.
*
* @return {@code false} if the tag is an endgroup tag, in which case
* nothing is skipped. Otherwise, returns {@code true}.
*/
public boolean skipField(final int tag) throws IOException {
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
readInt32();
return true;
case WireFormat.WIRETYPE_FIXED64:
readRawLittleEndian64();
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
skipRawBytes(readRawVarint32());
return true;
case WireFormat.WIRETYPE_START_GROUP:
skipMessage();
checkLastTagWas(
WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
WireFormat.WIRETYPE_END_GROUP));
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
readRawLittleEndian32();
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Reads and discards an entire message. This will read either until EOF
* or until an endgroup tag, whichever comes first.
*/
public void skipMessage() throws IOException {
while (true) {
final int tag = readTag();
if (tag == 0 || !skipField(tag)) {
return;
}
}
}
// -----------------------------------------------------------------
/** Read a {@code double} field value from the stream. */
public double readDouble() throws IOException {
return Double.longBitsToDouble(readRawLittleEndian64());
}
/** Read a {@code float} field value from the stream. */
public float readFloat() throws IOException {
return Float.intBitsToFloat(readRawLittleEndian32());
}
/** Read a {@code uint64} field value from the stream. */
public long readUInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int64} field value from the stream. */
public long readInt64() throws IOException {
return readRawVarint64();
}
/** Read an {@code int32} field value from the stream. */
public int readInt32() throws IOException {
return readRawVarint32();
}
/** Read a {@code fixed64} field value from the stream. */
public long readFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read a {@code fixed32} field value from the stream. */
public int readFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read a {@code bool} field value from the stream. */
public boolean readBool() throws IOException {
return readRawVarint32() != 0;
}
/** Read a {@code string} field value from the stream. */
public String readString() throws IOException {
final int size = readRawVarint32();
if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final String result = new String(buffer, bufferPos, size, "UTF-8");
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return new String(readRawBytes(size), "UTF-8");
}
}
/** Read a {@code group} field value from the stream. */
public void readGroup(final int fieldNumber,
final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
++recursionDepth;
builder.mergeFrom(this, extensionRegistry);
checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
--recursionDepth;
}
/** Read a {@code group} field value from the stream. */
public <T extends MessageLite> T readGroup(
final int fieldNumber,
final Parser<T> parser,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
++recursionDepth;
T result = parser.parsePartialFrom(this, extensionRegistry);
checkLastTagWas(
WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
--recursionDepth;
return result;
}
/**
* Reads a {@code group} field value from the stream and merges it into the
* given {@link UnknownFieldSet}.
*
* @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
* you can just call {@link #readGroup}.
*/
@Deprecated
public void readUnknownGroup(final int fieldNumber,
final MessageLite.Builder builder)
throws IOException {
// We know that UnknownFieldSet will ignore any ExtensionRegistry so it
// is safe to pass null here. (We can't call
// ExtensionRegistry.getEmptyRegistry() because that would make this
// class depend on ExtensionRegistry, which is not part of the lite
// library.)
readGroup(fieldNumber, builder, null);
}
/** Read an embedded message field value from the stream. */
public void readMessage(final MessageLite.Builder builder,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
final int length = readRawVarint32();
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
final int oldLimit = pushLimit(length);
++recursionDepth;
builder.mergeFrom(this, extensionRegistry);
checkLastTagWas(0);
--recursionDepth;
popLimit(oldLimit);
}
/** Read an embedded message field value from the stream. */
public <T extends MessageLite> T readMessage(
final Parser<T> parser,
final ExtensionRegistryLite extensionRegistry)
throws IOException {
int length = readRawVarint32();
if (recursionDepth >= recursionLimit) {
throw InvalidProtocolBufferException.recursionLimitExceeded();
}
final int oldLimit = pushLimit(length);
++recursionDepth;
T result = parser.parsePartialFrom(this, extensionRegistry);
checkLastTagWas(0);
--recursionDepth;
popLimit(oldLimit);
return result;
}
/** Read a {@code bytes} field value from the stream. */
public ByteString readBytes() throws IOException {
final int size = readRawVarint32();
if (size == 0) {
return ByteString.EMPTY;
} else if (size <= (bufferSize - bufferPos) && size > 0) {
// Fast path: We already have the bytes in a contiguous buffer, so
// just copy directly from it.
final ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
bufferPos += size;
return result;
} else {
// Slow path: Build a byte array first then copy it.
return ByteString.copyFrom(readRawBytes(size));
}
}
/** Read a {@code uint32} field value from the stream. */
public int readUInt32() throws IOException {
return readRawVarint32();
}
/**
* Read an enum field value from the stream. Caller is responsible
* for converting the numeric value to an actual enum.
*/
public int readEnum() throws IOException {
return readRawVarint32();
}
/** Read an {@code sfixed32} field value from the stream. */
public int readSFixed32() throws IOException {
return readRawLittleEndian32();
}
/** Read an {@code sfixed64} field value from the stream. */
public long readSFixed64() throws IOException {
return readRawLittleEndian64();
}
/** Read an {@code sint32} field value from the stream. */
public int readSInt32() throws IOException {
return decodeZigZag32(readRawVarint32());
}
/** Read an {@code sint64} field value from the stream. */
public long readSInt64() throws IOException {
return decodeZigZag64(readRawVarint64());
}
// =================================================================
/**
* Read a raw Varint from the stream. If larger than 32 bits, discard the
* upper bits.
*/
public int readRawVarint32() throws IOException {
byte tmp = readRawByte();
if (tmp >= 0) {
return tmp;
}
int result = tmp & 0x7f;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if ((tmp = readRawByte()) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
result |= (tmp = readRawByte()) << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
if (readRawByte() >= 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
}
}
}
return result;
}
/**
* Reads a varint from the input one byte at a time, so that it does not
* read any bytes after the end of the varint. If you simply wrapped the
* stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
* then you would probably end up reading past the end of the varint since
* CodedInputStream buffers its input.
*/
static int readRawVarint32(final InputStream input) throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
return readRawVarint32(firstByte, input);
}
/**
* Like {@link #readRawVarint32(InputStream)}, but expects that the caller
* has already read one byte. This allows the caller to determine if EOF
* has been reached before attempting to read.
*/
public static int readRawVarint32(
final int firstByte, final InputStream input) throws IOException {
if ((firstByte & 0x80) == 0) {
return firstByte;
}
int result = firstByte & 0x7f;
int offset = 7;
for (; offset < 32; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
result |= (b & 0x7f) << offset;
if ((b & 0x80) == 0) {
return result;
}
}
// Keep reading up to 64 bits.
for (; offset < 64; offset += 7) {
final int b = input.read();
if (b == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
if ((b & 0x80) == 0) {
return result;
}
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a raw Varint from the stream. */
public long readRawVarint64() throws IOException {
int shift = 0;
long result = 0;
while (shift < 64) {
final byte b = readRawByte();
result |= (long)(b & 0x7F) << shift;
if ((b & 0x80) == 0) {
return result;
}
shift += 7;
}
throw InvalidProtocolBufferException.malformedVarint();
}
/** Read a 32-bit little-endian integer from the stream. */
public int readRawLittleEndian32() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
return (((int)b1 & 0xff) ) |
(((int)b2 & 0xff) << 8) |
(((int)b3 & 0xff) << 16) |
(((int)b4 & 0xff) << 24);
}
/** Read a 64-bit little-endian integer from the stream. */
public long readRawLittleEndian64() throws IOException {
final byte b1 = readRawByte();
final byte b2 = readRawByte();
final byte b3 = readRawByte();
final byte b4 = readRawByte();
final byte b5 = readRawByte();
final byte b6 = readRawByte();
final byte b7 = readRawByte();
final byte b8 = readRawByte();
return (((long)b1 & 0xff) ) |
(((long)b2 & 0xff) << 8) |
(((long)b3 & 0xff) << 16) |
(((long)b4 & 0xff) << 24) |
(((long)b5 & 0xff) << 32) |
(((long)b6 & 0xff) << 40) |
(((long)b7 & 0xff) << 48) |
(((long)b8 & 0xff) << 56);
}
/**
* Decode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 32-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 32-bit integer.
*/
public static int decodeZigZag32(final int n) {
return (n >>> 1) ^ -(n & 1);
}
/**
* Decode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
* into values that can be efficiently encoded with varint. (Otherwise,
* negative values must be sign-extended to 64 bits to be varint encoded,
* thus always taking 10 bytes on the wire.)
*
* @param n An unsigned 64-bit integer, stored in a signed int because
* Java has no explicit unsigned support.
* @return A signed 64-bit integer.
*/
public static long decodeZigZag64(final long n) {
return (n >>> 1) ^ -(n & 1);
}
// -----------------------------------------------------------------
private final byte[] buffer;
private int bufferSize;
private int bufferSizeAfterLimit;
private int bufferPos;
private final InputStream input;
private int lastTag;
/**
* The total number of bytes read before the current buffer. The total
* bytes read up to the current position can be computed as
* {@code totalBytesRetired + bufferPos}. This value may be negative if
* reading started in the middle of the current buffer (e.g. if the
* constructor that takes a byte array and an offset was used).
*/
private int totalBytesRetired;
/** The absolute position of the end of the current message. */
private int currentLimit = Integer.MAX_VALUE;
/** See setRecursionLimit() */
private int recursionDepth;
private int recursionLimit = DEFAULT_RECURSION_LIMIT;
/** See setSizeLimit() */
private int sizeLimit = DEFAULT_SIZE_LIMIT;
private static final int DEFAULT_RECURSION_LIMIT = 64;
private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
private static final int BUFFER_SIZE = 4096;
private CodedInputStream(final byte[] buffer, final int off, final int len) {
this.buffer = buffer;
bufferSize = off + len;
bufferPos = off;
totalBytesRetired = -off;
input = null;
}
private CodedInputStream(final InputStream input) {
buffer = new byte[BUFFER_SIZE];
bufferSize = 0;
bufferPos = 0;
totalBytesRetired = 0;
this.input = input;
}
/**
* Set the maximum message recursion depth. In order to prevent malicious
* messages from causing stack overflows, {@code CodedInputStream} limits
* how deeply messages may be nested. The default limit is 64.
*
* @return the old limit.
*/
public int setRecursionLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Recursion limit cannot be negative: " + limit);
}
final int oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}
/**
* Set the maximum message size. In order to prevent malicious
* messages from exhausting memory or causing integer overflows,
* {@code CodedInputStream} limits how large a message may be.
* The default limit is 64MB. You should set this limit as small
* as you can without harming your app's functionality. Note that
* size limits only apply when reading from an {@code InputStream}, not
* when constructed around a raw byte array (nor with
* {@link ByteString#newCodedInput}).
* <p>
* If you want to read several messages from a single CodedInputStream, you
* could call {@link #resetSizeCounter()} after each one to avoid hitting the
* size limit.
*
* @return the old limit.
*/
public int setSizeLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException(
"Size limit cannot be negative: " + limit);
}
final int oldLimit = sizeLimit;
sizeLimit = limit;
return oldLimit;
}
/**
* Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
*/
public void resetSizeCounter() {
totalBytesRetired = -bufferPos;
}
/**
* Sets {@code currentLimit} to (current position) + {@code byteLimit}. This
* is called when descending into a length-delimited embedded message.
*
* <p>Note that {@code pushLimit()} does NOT affect how many bytes the
* {@code CodedInputStream} reads from an underlying {@code InputStream} when
* refreshing its buffer. If you need to prevent reading past a certain
* point in the underlying {@code InputStream} (e.g. because you expect it to
* contain more data after the end of the message which you need to handle
* differently) then you must place a wrapper around your {@code InputStream}
* which limits the amount of data that can be read from it.
*
* @return the old limit.
*/
public int pushLimit(int byteLimit) throws InvalidProtocolBufferException {
if (byteLimit < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
byteLimit += totalBytesRetired + bufferPos;
final int oldLimit = currentLimit;
if (byteLimit > oldLimit) {
throw InvalidProtocolBufferException.truncatedMessage();
}
currentLimit = byteLimit;
recomputeBufferSizeAfterLimit();
return oldLimit;
}
private void recomputeBufferSizeAfterLimit() {
bufferSize += bufferSizeAfterLimit;
final int bufferEnd = totalBytesRetired + bufferSize;
if (bufferEnd > currentLimit) {
// Limit is in current buffer.
bufferSizeAfterLimit = bufferEnd - currentLimit;
bufferSize -= bufferSizeAfterLimit;
} else {
bufferSizeAfterLimit = 0;
}
}
/**
* Discards the current limit, returning to the previous limit.
*
* @param oldLimit The old limit, as returned by {@code pushLimit}.
*/
public void popLimit(final int oldLimit) {
currentLimit = oldLimit;
recomputeBufferSizeAfterLimit();
}
/**
* Returns the number of bytes to be read before the current limit.
* If no limit is set, returns -1.
*/
public int getBytesUntilLimit() {
if (currentLimit == Integer.MAX_VALUE) {
return -1;
}
final int currentAbsolutePosition = totalBytesRetired + bufferPos;
return currentLimit - currentAbsolutePosition;
}
/**
* Returns true if the stream has reached the end of the input. This is the
* case if either the end of the underlying input source has been reached or
* if the stream has reached a limit created using {@link #pushLimit(int)}.
*/
public boolean isAtEnd() throws IOException {
return bufferPos == bufferSize && !refillBuffer(false);
}
/**
* The total bytes read up to the current position. Calling
* {@link #resetSizeCounter()} resets this value to zero.
*/
public int getTotalBytesRead() {
return totalBytesRetired + bufferPos;
}
/**
* Called with {@code this.buffer} is empty to read more bytes from the
* input. If {@code mustSucceed} is true, refillBuffer() guarantees that
* either there will be at least one byte in the buffer when it returns
* or it will throw an exception. If {@code mustSucceed} is false,
* refillBuffer() returns false if no more bytes were available.
*/
private boolean refillBuffer(final boolean mustSucceed) throws IOException {
if (bufferPos < bufferSize) {
throw new IllegalStateException(
"refillBuffer() called when buffer wasn't empty.");
}
if (totalBytesRetired + bufferSize == currentLimit) {
// Oops, we hit a limit.
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
}
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = (input == null) ? -1 : input.read(buffer);
if (bufferSize == 0 || bufferSize < -1) {
throw new IllegalStateException(
"InputStream#read(byte[]) returned invalid result: " + bufferSize +
"\nThe InputStream implementation is buggy.");
}
if (bufferSize == -1) {
bufferSize = 0;
if (mustSucceed) {
throw InvalidProtocolBufferException.truncatedMessage();
} else {
return false;
}
} else {
recomputeBufferSizeAfterLimit();
final int totalBytesRead =
totalBytesRetired + bufferSize + bufferSizeAfterLimit;
if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
}
return true;
}
}
/**
* Read one byte from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte readRawByte() throws IOException {
if (bufferPos == bufferSize) {
refillBuffer(true);
}
return buffer[bufferPos++];
}
/**
* Read a fixed size of bytes from the input.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public byte[] readRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
final byte[] bytes = new byte[size];
System.arraycopy(buffer, bufferPos, bytes, 0, size);
bufferPos += size;
return bytes;
} else if (size < BUFFER_SIZE) {
// Reading more bytes than are in the buffer, but not an excessive number
// of bytes. We can safely allocate the resulting array ahead of time.
// First copy what we have.
final byte[] bytes = new byte[size];
int pos = bufferSize - bufferPos;
System.arraycopy(buffer, bufferPos, bytes, 0, pos);
bufferPos = bufferSize;
// We want to use refillBuffer() and then copy from the buffer into our
// byte array rather than reading directly into our byte array because
// the input may be unbuffered.
refillBuffer(true);
while (size - pos > bufferSize) {
System.arraycopy(buffer, 0, bytes, pos, bufferSize);
pos += bufferSize;
bufferPos = bufferSize;
refillBuffer(true);
}
System.arraycopy(buffer, 0, bytes, pos, size - pos);
bufferPos = size - pos;
return bytes;
} else {
// The size is very large. For security reasons, we can't allocate the
// entire byte array yet. The size comes directly from the input, so a
// maliciously-crafted message could provide a bogus very large size in
// order to trick the app into allocating a lot of memory. We avoid this
// by allocating and reading only a small chunk at a time, so that the
// malicious message must actually *be* extremely large to cause
// problems. Meanwhile, we limit the allowed size of a message elsewhere.
// Remember the buffer markers since we'll have to copy the bytes out of
// it later.
final int originalBufferPos = bufferPos;
final int originalBufferSize = bufferSize;
// Mark the current buffer consumed.
totalBytesRetired += bufferSize;
bufferPos = 0;
bufferSize = 0;
// Read all the rest of the bytes we need.
int sizeLeft = size - (originalBufferSize - originalBufferPos);
final List<byte[]> chunks = new ArrayList<byte[]>();
while (sizeLeft > 0) {
final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
int pos = 0;
while (pos < chunk.length) {
final int n = (input == null) ? -1 :
input.read(chunk, pos, chunk.length - pos);
if (n == -1) {
throw InvalidProtocolBufferException.truncatedMessage();
}
totalBytesRetired += n;
pos += n;
}
sizeLeft -= chunk.length;
chunks.add(chunk);
}
// OK, got everything. Now concatenate it all into one buffer.
final byte[] bytes = new byte[size];
// Start by copying the leftover bytes from this.buffer.
int pos = originalBufferSize - originalBufferPos;
System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
// And now all the chunks.
for (final byte[] chunk : chunks) {
System.arraycopy(chunk, 0, bytes, pos, chunk.length);
pos += chunk.length;
}
// Done.
return bytes;
}
}
/**
* Reads and discards {@code size} bytes.
*
* @throws InvalidProtocolBufferException The end of the stream or the current
* limit was reached.
*/
public void skipRawBytes(final int size) throws IOException {
if (size < 0) {
throw InvalidProtocolBufferException.negativeSize();
}
if (totalBytesRetired + bufferPos + size > currentLimit) {
// Read to the end of the stream anyway.
skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
// Then fail.
throw InvalidProtocolBufferException.truncatedMessage();
}
if (size <= bufferSize - bufferPos) {
// We have all the bytes we need already.
bufferPos += size;
} else {
// Skipping more bytes than are in the buffer. First skip what we have.
int pos = bufferSize - bufferPos;
bufferPos = bufferSize;
// Keep refilling the buffer until we get to the point we wanted to skip
// to. This has the side effect of ensuring the limits are updated
// correctly.
refillBuffer(true);
while (size - pos > bufferSize) {
pos += bufferSize;
bufferPos = bufferSize;
refillBuffer(true);
}
bufferPos = size - pos;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,482 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.io.InputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/**
* An implementation of {@link Message} that can represent arbitrary types,
* given a {@link Descriptors.Descriptor}.
*
* @author kenton@google.com Kenton Varda
*/
public final class DynamicMessage extends AbstractMessage {
private final Descriptor type;
private final FieldSet<FieldDescriptor> fields;
private final UnknownFieldSet unknownFields;
private int memoizedSize = -1;
/**
* Construct a {@code DynamicMessage} using the given {@code FieldSet}.
*/
private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
UnknownFieldSet unknownFields) {
this.type = type;
this.fields = fields;
this.unknownFields = unknownFields;
}
/**
* Get a {@code DynamicMessage} representing the default instance of the
* given type.
*/
public static DynamicMessage getDefaultInstance(Descriptor type) {
return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
UnknownFieldSet.getDefaultInstance());
}
/** Parse a message of the given type from the given input stream. */
public static DynamicMessage parseFrom(Descriptor type,
CodedInputStream input)
throws IOException {
return newBuilder(type).mergeFrom(input).buildParsed();
}
/** Parse a message of the given type from the given input stream. */
public static DynamicMessage parseFrom(
Descriptor type,
CodedInputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, ByteString data)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, ByteString data,
ExtensionRegistry extensionRegistry)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, byte[] data)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data).buildParsed();
}
/** Parse {@code data} as a message of the given type and return it. */
public static DynamicMessage parseFrom(Descriptor type, byte[] data,
ExtensionRegistry extensionRegistry)
throws InvalidProtocolBufferException {
return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
}
/** Parse a message of the given type from {@code input} and return it. */
public static DynamicMessage parseFrom(Descriptor type, InputStream input)
throws IOException {
return newBuilder(type).mergeFrom(input).buildParsed();
}
/** Parse a message of the given type from {@code input} and return it. */
public static DynamicMessage parseFrom(Descriptor type, InputStream input,
ExtensionRegistry extensionRegistry)
throws IOException {
return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
}
/** Construct a {@link Message.Builder} for the given type. */
public static Builder newBuilder(Descriptor type) {
return new Builder(type);
}
/**
* Construct a {@link Message.Builder} for a message of the same type as
* {@code prototype}, and initialize it with {@code prototype}'s contents.
*/
public static Builder newBuilder(Message prototype) {
return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
}
// -----------------------------------------------------------------
// Implementation of Message interface.
public Descriptor getDescriptorForType() {
return type;
}
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
if (field.isRepeated()) {
result = Collections.emptyList();
} else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
private static boolean isInitialized(Descriptor type,
FieldSet<FieldDescriptor> fields) {
// Check that all required fields are present.
for (final FieldDescriptor field : type.getFields()) {
if (field.isRequired()) {
if (!fields.hasField(field)) {
return false;
}
}
}
// Check that embedded messages are initialized.
return fields.isInitialized();
}
@Override
public boolean isInitialized() {
return isInitialized(type, fields);
}
@Override
public void writeTo(CodedOutputStream output) throws IOException {
if (type.getOptions().getMessageSetWireFormat()) {
fields.writeMessageSetTo(output);
unknownFields.writeAsMessageSetTo(output);
} else {
fields.writeTo(output);
unknownFields.writeTo(output);
}
}
@Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
if (type.getOptions().getMessageSetWireFormat()) {
size = fields.getMessageSetSerializedSize();
size += unknownFields.getSerializedSizeAsMessageSet();
} else {
size = fields.getSerializedSize();
size += unknownFields.getSerializedSize();
}
memoizedSize = size;
return size;
}
public Builder newBuilderForType() {
return new Builder(type);
}
public Builder toBuilder() {
return newBuilderForType().mergeFrom(this);
}
public Parser<DynamicMessage> getParserForType() {
return new AbstractParser<DynamicMessage>() {
public DynamicMessage parsePartialFrom(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
Builder builder = newBuilder(type);
try {
builder.mergeFrom(input, extensionRegistry);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(builder.buildPartial());
} catch (IOException e) {
throw new InvalidProtocolBufferException(e.getMessage())
.setUnfinishedMessage(builder.buildPartial());
}
return builder.buildPartial();
}
};
}
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
throw new IllegalArgumentException(
"FieldDescriptor does not match message type.");
}
}
// =================================================================
/**
* Builder for {@link DynamicMessage}s.
*/
public static final class Builder extends AbstractMessage.Builder<Builder> {
private final Descriptor type;
private FieldSet<FieldDescriptor> fields;
private UnknownFieldSet unknownFields;
/** Construct a {@code Builder} for the given type. */
private Builder(Descriptor type) {
this.type = type;
this.fields = FieldSet.newFieldSet();
this.unknownFields = UnknownFieldSet.getDefaultInstance();
}
// ---------------------------------------------------------------
// Implementation of Message.Builder interface.
@Override
public Builder clear() {
if (fields.isImmutable()) {
fields = FieldSet.newFieldSet();
} else {
fields.clear();
}
unknownFields = UnknownFieldSet.getDefaultInstance();
return this;
}
@Override
public Builder mergeFrom(Message other) {
if (other instanceof DynamicMessage) {
// This should be somewhat faster than calling super.mergeFrom().
DynamicMessage otherDynamicMessage = (DynamicMessage) other;
if (otherDynamicMessage.type != type) {
throw new IllegalArgumentException(
"mergeFrom(Message) can only merge messages of the same type.");
}
ensureIsMutable();
fields.mergeFrom(otherDynamicMessage.fields);
mergeUnknownFields(otherDynamicMessage.unknownFields);
return this;
} else {
return super.mergeFrom(other);
}
}
public DynamicMessage build() {
if (!isInitialized()) {
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields));
}
return buildPartial();
}
/**
* Helper for DynamicMessage.parseFrom() methods to call. Throws
* {@link InvalidProtocolBufferException} instead of
* {@link UninitializedMessageException}.
*/
private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
if (!isInitialized()) {
throw newUninitializedMessageException(
new DynamicMessage(type, fields, unknownFields))
.asInvalidProtocolBufferException();
}
return buildPartial();
}
public DynamicMessage buildPartial() {
fields.makeImmutable();
DynamicMessage result =
new DynamicMessage(type, fields, unknownFields);
return result;
}
@Override
public Builder clone() {
Builder result = new Builder(type);
result.fields.mergeFrom(fields);
result.mergeUnknownFields(unknownFields);
return result;
}
public boolean isInitialized() {
return DynamicMessage.isInitialized(type, fields);
}
public Descriptor getDescriptorForType() {
return type;
}
public DynamicMessage getDefaultInstanceForType() {
return getDefaultInstance(type);
}
public Map<FieldDescriptor, Object> getAllFields() {
return fields.getAllFields();
}
public Builder newBuilderForField(FieldDescriptor field) {
verifyContainingType(field);
if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"newBuilderForField is only valid for fields with message type.");
}
return new Builder(field.getMessageType());
}
public boolean hasField(FieldDescriptor field) {
verifyContainingType(field);
return fields.hasField(field);
}
public Object getField(FieldDescriptor field) {
verifyContainingType(field);
Object result = fields.getField(field);
if (result == null) {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
result = getDefaultInstance(field.getMessageType());
} else {
result = field.getDefaultValue();
}
}
return result;
}
public Builder setField(FieldDescriptor field, Object value) {
verifyContainingType(field);
ensureIsMutable();
fields.setField(field, value);
return this;
}
public Builder clearField(FieldDescriptor field) {
verifyContainingType(field);
ensureIsMutable();
fields.clearField(field);
return this;
}
public int getRepeatedFieldCount(FieldDescriptor field) {
verifyContainingType(field);
return fields.getRepeatedFieldCount(field);
}
public Object getRepeatedField(FieldDescriptor field, int index) {
verifyContainingType(field);
return fields.getRepeatedField(field, index);
}
public Builder setRepeatedField(FieldDescriptor field,
int index, Object value) {
verifyContainingType(field);
ensureIsMutable();
fields.setRepeatedField(field, index, value);
return this;
}
public Builder addRepeatedField(FieldDescriptor field, Object value) {
verifyContainingType(field);
ensureIsMutable();
fields.addRepeatedField(field, value);
return this;
}
public UnknownFieldSet getUnknownFields() {
return unknownFields;
}
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
this.unknownFields = unknownFields;
return this;
}
@Override
public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
this.unknownFields =
UnknownFieldSet.newBuilder(this.unknownFields)
.mergeFrom(unknownFields)
.build();
return this;
}
/** Verifies that the field is a field of this message. */
private void verifyContainingType(FieldDescriptor field) {
if (field.getContainingType() != type) {
throw new IllegalArgumentException(
"FieldDescriptor does not match message type.");
}
}
private void ensureIsMutable() {
if (fields.isImmutable()) {
fields = fields.clone();
}
}
@Override
public com.google.protobuf.Message.Builder getFieldBuilder(FieldDescriptor field) {
// TODO(xiangl): need implementation for dynamic message
throw new UnsupportedOperationException(
"getFieldBuilder() called on a dynamic message type.");
}
}
}

View File

@ -0,0 +1,266 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* A table of known extensions, searchable by name or field number. When
* parsing a protocol message that might have extensions, you must provide
* an {@code ExtensionRegistry} in which you have registered any extensions
* that you want to be able to parse. Otherwise, those extensions will just
* be treated like unknown fields.
*
* <p>For example, if you had the {@code .proto} file:
*
* <pre>
* option java_class = "MyProto";
*
* message Foo {
* extensions 1000 to max;
* }
*
* extend Foo {
* optional int32 bar;
* }
* </pre>
*
* Then you might write code like:
*
* <pre>
* ExtensionRegistry registry = ExtensionRegistry.newInstance();
* registry.add(MyProto.bar);
* MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
* </pre>
*
* <p>Background:
*
* <p>You might wonder why this is necessary. Two alternatives might come to
* mind. First, you might imagine a system where generated extensions are
* automatically registered when their containing classes are loaded. This
* is a popular technique, but is bad design; among other things, it creates a
* situation where behavior can change depending on what classes happen to be
* loaded. It also introduces a security vulnerability, because an
* unprivileged class could cause its code to be called unexpectedly from a
* privileged class by registering itself as an extension of the right type.
*
* <p>Another option you might consider is lazy parsing: do not parse an
* extension until it is first requested, at which point the caller must
* provide a type to use. This introduces a different set of problems. First,
* it would require a mutex lock any time an extension was accessed, which
* would be slow. Second, corrupt data would not be detected until first
* access, at which point it would be much harder to deal with it. Third, it
* could violate the expectation that message objects are immutable, since the
* type provided could be any arbitrary message class. An unprivileged user
* could take advantage of this to inject a mutable object into a message
* belonging to privileged code and create mischief.
*
* @author kenton@google.com Kenton Varda
*/
public final class ExtensionRegistry extends ExtensionRegistryLite {
/** Construct a new, empty instance. */
public static ExtensionRegistry newInstance() {
return new ExtensionRegistry();
}
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistry getEmptyRegistry() {
return EMPTY;
}
/** Returns an unmodifiable view of the registry. */
@Override
public ExtensionRegistry getUnmodifiable() {
return new ExtensionRegistry(this);
}
/** A (Descriptor, Message) pair, returned by lookup methods. */
public static final class ExtensionInfo {
/** The extension's descriptor. */
public final FieldDescriptor descriptor;
/**
* A default instance of the extension's type, if it has a message type.
* Otherwise, {@code null}.
*/
public final Message defaultInstance;
private ExtensionInfo(final FieldDescriptor descriptor) {
this.descriptor = descriptor;
defaultInstance = null;
}
private ExtensionInfo(final FieldDescriptor descriptor,
final Message defaultInstance) {
this.descriptor = descriptor;
this.defaultInstance = defaultInstance;
}
}
/**
* Find an extension by fully-qualified field name, in the proto namespace.
* I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
* a match is found.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByName(final String fullName) {
return extensionsByName.get(fullName);
}
/**
* Find an extension by containing type and field number.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
final int fieldNumber) {
return extensionsByNumber.get(
new DescriptorIntPair(containingType, fieldNumber));
}
/** Add an extension from a generated file to the registry. */
public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
if (extension.getDescriptor().getJavaType() ==
FieldDescriptor.JavaType.MESSAGE) {
if (extension.getMessageDefaultInstance() == null) {
throw new IllegalStateException(
"Registered message-type extension had null default instance: " +
extension.getDescriptor().getFullName());
}
add(new ExtensionInfo(extension.getDescriptor(),
extension.getMessageDefaultInstance()));
} else {
add(new ExtensionInfo(extension.getDescriptor(), null));
}
}
/** Add a non-message-type extension to the registry by descriptor. */
public void add(final FieldDescriptor type) {
if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() must be provided a default instance when " +
"adding an embedded message extension.");
}
add(new ExtensionInfo(type, null));
}
/** Add a message-type extension to the registry by descriptor. */
public void add(final FieldDescriptor type, final Message defaultInstance) {
if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() provided a default instance for a " +
"non-message extension.");
}
add(new ExtensionInfo(type, defaultInstance));
}
// =================================================================
// Private stuff.
private ExtensionRegistry() {
this.extensionsByName = new HashMap<String, ExtensionInfo>();
this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
}
private ExtensionRegistry(ExtensionRegistry other) {
super(other);
this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
private final Map<String, ExtensionInfo> extensionsByName;
private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
private ExtensionRegistry(boolean empty) {
super(ExtensionRegistryLite.getEmptyRegistry());
this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
this.extensionsByNumber =
Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
}
private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
private void add(final ExtensionInfo extension) {
if (!extension.descriptor.isExtension()) {
throw new IllegalArgumentException(
"ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
"(non-extension) field.");
}
extensionsByName.put(extension.descriptor.getFullName(), extension);
extensionsByNumber.put(
new DescriptorIntPair(extension.descriptor.getContainingType(),
extension.descriptor.getNumber()),
extension);
final FieldDescriptor field = extension.descriptor;
if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
field.getType() == FieldDescriptor.Type.MESSAGE &&
field.isOptional() &&
field.getExtensionScope() == field.getMessageType()) {
// This is an extension of a MessageSet type defined within the extension
// type's own scope. For backwards-compatibility, allow it to be looked
// up by type name.
extensionsByName.put(field.getMessageType().getFullName(), extension);
}
}
/** A (GenericDescriptor, int) pair, used as a map key. */
private static final class DescriptorIntPair {
private final Descriptor descriptor;
private final int number;
DescriptorIntPair(final Descriptor descriptor, final int number) {
this.descriptor = descriptor;
this.number = number;
}
@Override
public int hashCode() {
return descriptor.hashCode() * ((1 << 16) - 1) + number;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof DescriptorIntPair)) {
return false;
}
final DescriptorIntPair other = (DescriptorIntPair)obj;
return descriptor == other.descriptor && number == other.number;
}
}
}

View File

@ -0,0 +1,185 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
* <p>
* If all of your types are lite types, then you only need to use
* {@code ExtensionRegistryLite}. Similarly, if all your types are regular
* types, then you only need {@link ExtensionRegistry}. Typically it does not
* make sense to mix the two, since if you have any regular types in your
* program, you then require the full runtime and lose all the benefits of
* the lite runtime, so you might as well make all your types be regular types.
* However, in some cases (e.g. when depending on multiple third-party libraries
* where one uses lite types and one uses regular), you may find yourself
* wanting to mix the two. In this case things get more complicated.
* <p>
* There are three factors to consider: Whether the type being extended is
* lite, whether the embedded type (in the case of a message-typed extension)
* is lite, and whether the extension itself is lite. Since all three are
* declared in different files, they could all be different. Here are all
* the combinations and which type of registry to use:
* <pre>
* Extended type Inner type Extension Use registry
* =======================================================================
* lite lite lite ExtensionRegistryLite
* lite regular lite ExtensionRegistry
* regular regular regular ExtensionRegistry
* all other combinations not supported
* </pre>
* <p>
* Note that just as regular types are not allowed to contain lite-type fields,
* they are also not allowed to contain lite-type extensions. This is because
* regular types must be fully accessible via reflection, which in turn means
* that all the inner messages must also support reflection. On the other hand,
* since regular types implement the entire lite interface, there is no problem
* with embedding regular types inside lite types.
*
* @author kenton@google.com Kenton Varda
*/
public class ExtensionRegistryLite {
// Set true to enable lazy parsing feature for MessageSet.
//
// TODO(xiangl): Now we use a global flag to control whether enable lazy
// parsing feature for MessageSet, which may be too crude for some
// applications. Need to support this feature on smaller granularity.
private static volatile boolean eagerlyParseMessageSets = false;
public static boolean isEagerlyParseMessageSets() {
return eagerlyParseMessageSets;
}
public static void setEagerlyParseMessageSets(boolean isEagerlyParse) {
eagerlyParseMessageSets = isEagerlyParse;
}
/** Construct a new, empty instance. */
public static ExtensionRegistryLite newInstance() {
return new ExtensionRegistryLite();
}
/** Get the unmodifiable singleton empty instance. */
public static ExtensionRegistryLite getEmptyRegistry() {
return EMPTY;
}
/** Returns an unmodifiable view of the registry. */
public ExtensionRegistryLite getUnmodifiable() {
return new ExtensionRegistryLite(this);
}
/**
* Find an extension by containing type and field number.
*
* @return Information about the extension if found, or {@code null}
* otherwise.
*/
@SuppressWarnings("unchecked")
public <ContainingType extends MessageLite>
GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
findLiteExtensionByNumber(
final ContainingType containingTypeDefaultInstance,
final int fieldNumber) {
return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
extensionsByNumber.get(
new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
}
/** Add an extension from a lite generated file to the registry. */
public final void add(
final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
extensionsByNumber.put(
new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
extension.getNumber()),
extension);
}
// =================================================================
// Private stuff.
// Constructors are package-private so that ExtensionRegistry can subclass
// this.
ExtensionRegistryLite() {
this.extensionsByNumber =
new HashMap<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>();
}
ExtensionRegistryLite(ExtensionRegistryLite other) {
if (other == EMPTY) {
this.extensionsByNumber = Collections.emptyMap();
} else {
this.extensionsByNumber =
Collections.unmodifiableMap(other.extensionsByNumber);
}
}
private final Map<ObjectIntPair,
GeneratedMessageLite.GeneratedExtension<?, ?>>
extensionsByNumber;
private ExtensionRegistryLite(boolean empty) {
this.extensionsByNumber = Collections.emptyMap();
}
private static final ExtensionRegistryLite EMPTY =
new ExtensionRegistryLite(true);
/** A (Object, int) pair, used as a map key. */
private static final class ObjectIntPair {
private final Object object;
private final int number;
ObjectIntPair(final Object object, final int number) {
this.object = object;
this.number = number;
}
@Override
public int hashCode() {
return System.identityHashCode(object) * ((1 << 16) - 1) + number;
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof ObjectIntPair)) {
return false;
}
final ObjectIntPair other = (ObjectIntPair)obj;
return object == other.object && number == other.number;
}
}
}

View File

@ -0,0 +1,861 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.LazyField.LazyIterator;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* A class which represents an arbitrary set of fields of some message type.
* This is used to implement {@link DynamicMessage}, and also to represent
* extensions in {@link GeneratedMessage}. This class is package-private,
* since outside users should probably be using {@link DynamicMessage}.
*
* @author kenton@google.com Kenton Varda
*/
final class FieldSet<FieldDescriptorType extends
FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
/**
* Interface for a FieldDescriptor or lite extension descriptor. This
* prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
*/
public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
extends Comparable<T> {
int getNumber();
WireFormat.FieldType getLiteType();
WireFormat.JavaType getLiteJavaType();
boolean isRepeated();
boolean isPacked();
Internal.EnumLiteMap<?> getEnumType();
// If getLiteJavaType() == MESSAGE, this merges a message object of the
// type into a builder of the type. Returns {@code to}.
MessageLite.Builder internalMergeFrom(
MessageLite.Builder to, MessageLite from);
}
private final SmallSortedMap<FieldDescriptorType, Object> fields;
private boolean isImmutable;
private boolean hasLazyField = false;
/** Construct a new FieldSet. */
private FieldSet() {
this.fields = SmallSortedMap.newFieldMap(16);
}
/**
* Construct an empty FieldSet. This is only used to initialize
* DEFAULT_INSTANCE.
*/
private FieldSet(final boolean dummy) {
this.fields = SmallSortedMap.newFieldMap(0);
makeImmutable();
}
/** Construct a new FieldSet. */
public static <T extends FieldSet.FieldDescriptorLite<T>>
FieldSet<T> newFieldSet() {
return new FieldSet<T>();
}
/** Get an immutable empty FieldSet. */
@SuppressWarnings("unchecked")
public static <T extends FieldSet.FieldDescriptorLite<T>>
FieldSet<T> emptySet() {
return DEFAULT_INSTANCE;
}
@SuppressWarnings("rawtypes")
private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
/** Make this FieldSet immutable from this point forward. */
@SuppressWarnings("unchecked")
public void makeImmutable() {
if (isImmutable) {
return;
}
fields.makeImmutable();
isImmutable = true;
}
/**
* Returns whether the FieldSet is immutable. This is true if it is the
* {@link #emptySet} or if {@link #makeImmutable} were called.
*
* @return whether the FieldSet is immutable.
*/
public boolean isImmutable() {
return isImmutable;
}
/**
* Clones the FieldSet. The returned FieldSet will be mutable even if the
* original FieldSet was immutable.
*
* @return the newly cloned FieldSet
*/
@Override
public FieldSet<FieldDescriptorType> clone() {
// We can't just call fields.clone because List objects in the map
// should not be shared.
FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
FieldDescriptorType descriptor = entry.getKey();
clone.setField(descriptor, entry.getValue());
}
for (Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
FieldDescriptorType descriptor = entry.getKey();
clone.setField(descriptor, entry.getValue());
}
clone.hasLazyField = hasLazyField;
return clone;
}
// =================================================================
/** See {@link Message.Builder#clear()}. */
public void clear() {
fields.clear();
hasLazyField = false;
}
/**
* Get a simple map containing all the fields.
*/
public Map<FieldDescriptorType, Object> getAllFields() {
if (hasLazyField) {
SmallSortedMap<FieldDescriptorType, Object> result =
SmallSortedMap.newFieldMap(16);
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
cloneFieldEntry(result, fields.getArrayEntryAt(i));
}
for (Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
cloneFieldEntry(result, entry);
}
if (fields.isImmutable()) {
result.makeImmutable();
}
return result;
}
return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
}
private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
Map.Entry<FieldDescriptorType, Object> entry) {
FieldDescriptorType key = entry.getKey();
Object value = entry.getValue();
if (value instanceof LazyField) {
map.put(key, ((LazyField) value).getValue());
} else {
map.put(key, value);
}
}
/**
* Get an iterator to the field map. This iterator should not be leaked out
* of the protobuf library as it is not protected from mutation when fields
* is not immutable.
*/
public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
if (hasLazyField) {
return new LazyIterator<FieldDescriptorType>(
fields.entrySet().iterator());
}
return fields.entrySet().iterator();
}
/**
* Useful for implementing
* {@link Message#hasField(Descriptors.FieldDescriptor)}.
*/
public boolean hasField(final FieldDescriptorType descriptor) {
if (descriptor.isRepeated()) {
throw new IllegalArgumentException(
"hasField() can only be called on non-repeated fields.");
}
return fields.get(descriptor) != null;
}
/**
* Useful for implementing
* {@link Message#getField(Descriptors.FieldDescriptor)}. This method
* returns {@code null} if the field is not set; in this case it is up
* to the caller to fetch the field's default value.
*/
public Object getField(final FieldDescriptorType descriptor) {
Object o = fields.get(descriptor);
if (o instanceof LazyField) {
return ((LazyField) o).getValue();
}
return o;
}
/**
* Useful for implementing
* {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public void setField(final FieldDescriptorType descriptor,
Object value) {
if (descriptor.isRepeated()) {
if (!(value instanceof List)) {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
// Wrap the contents in a new list so that the caller cannot change
// the list's contents after setting it.
final List newList = new ArrayList();
newList.addAll((List) value);
for (final Object element : newList) {
verifyType(descriptor.getLiteType(), element);
}
value = newList;
} else {
verifyType(descriptor.getLiteType(), value);
}
if (value instanceof LazyField) {
hasLazyField = true;
}
fields.put(descriptor, value);
}
/**
* Useful for implementing
* {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
*/
public void clearField(final FieldDescriptorType descriptor) {
fields.remove(descriptor);
if (fields.isEmpty()) {
hasLazyField = false;
}
}
/**
* Useful for implementing
* {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
*/
public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getField(descriptor);
if (value == null) {
return 0;
} else {
return ((List<?>) value).size();
}
}
/**
* Useful for implementing
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
*/
public Object getRepeatedField(final FieldDescriptorType descriptor,
final int index) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object value = getField(descriptor);
if (value == null) {
throw new IndexOutOfBoundsException();
} else {
return ((List<?>) value).get(index);
}
}
/**
* Useful for implementing
* {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
*/
@SuppressWarnings("unchecked")
public void setRepeatedField(final FieldDescriptorType descriptor,
final int index,
final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"getRepeatedField() can only be called on repeated fields.");
}
final Object list = getField(descriptor);
if (list == null) {
throw new IndexOutOfBoundsException();
}
verifyType(descriptor.getLiteType(), value);
((List<Object>) list).set(index, value);
}
/**
* Useful for implementing
* {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
*/
@SuppressWarnings("unchecked")
public void addRepeatedField(final FieldDescriptorType descriptor,
final Object value) {
if (!descriptor.isRepeated()) {
throw new IllegalArgumentException(
"addRepeatedField() can only be called on repeated fields.");
}
verifyType(descriptor.getLiteType(), value);
final Object existingValue = getField(descriptor);
List<Object> list;
if (existingValue == null) {
list = new ArrayList<Object>();
fields.put(descriptor, list);
} else {
list = (List<Object>) existingValue;
}
list.add(value);
}
/**
* Verifies that the given object is of the correct type to be a valid
* value for the given field. (For repeated fields, this checks if the
* object is the right type to be one element of the field.)
*
* @throws IllegalArgumentException The value is not of the right type.
*/
private static void verifyType(final WireFormat.FieldType type,
final Object value) {
if (value == null) {
throw new NullPointerException();
}
boolean isValid = false;
switch (type.getJavaType()) {
case INT: isValid = value instanceof Integer ; break;
case LONG: isValid = value instanceof Long ; break;
case FLOAT: isValid = value instanceof Float ; break;
case DOUBLE: isValid = value instanceof Double ; break;
case BOOLEAN: isValid = value instanceof Boolean ; break;
case STRING: isValid = value instanceof String ; break;
case BYTE_STRING: isValid = value instanceof ByteString; break;
case ENUM:
// TODO(kenton): Caller must do type checking here, I guess.
isValid = value instanceof Internal.EnumLite;
break;
case MESSAGE:
// TODO(kenton): Caller must do type checking here, I guess.
isValid =
(value instanceof MessageLite) || (value instanceof LazyField);
break;
}
if (!isValid) {
// TODO(kenton): When chaining calls to setField(), it can be hard to
// tell from the stack trace which exact call failed, since the whole
// chain is considered one line of code. It would be nice to print
// more information here, e.g. naming the field. We used to do that.
// But we can't now that FieldSet doesn't use descriptors. Maybe this
// isn't a big deal, though, since it would only really apply when using
// reflection and generally people don't chain reflection setters.
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
// =================================================================
// Parsing and serialization
/**
* See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
* itself does not have any way of knowing about required fields that
* aren't actually present in the set, it is up to the caller to check
* that all required fields are present.
*/
public boolean isInitialized() {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
if (!isInitialized(fields.getArrayEntryAt(i))) {
return false;
}
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
if (!isInitialized(entry)) {
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
private boolean isInitialized(
final Map.Entry<FieldDescriptorType, Object> entry) {
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
if (descriptor.isRepeated()) {
for (final MessageLite element:
(List<MessageLite>) entry.getValue()) {
if (!element.isInitialized()) {
return false;
}
}
} else {
Object value = entry.getValue();
if (value instanceof MessageLite) {
if (!((MessageLite) value).isInitialized()) {
return false;
}
} else if (value instanceof LazyField) {
return true;
} else {
throw new IllegalArgumentException(
"Wrong object type used with protocol message reflection.");
}
}
}
return true;
}
/**
* Given a field type, return the wire type.
*
* @returns One of the {@code WIRETYPE_} constants defined in
* {@link WireFormat}.
*/
static int getWireFormatForFieldType(final WireFormat.FieldType type,
boolean isPacked) {
if (isPacked) {
return WireFormat.WIRETYPE_LENGTH_DELIMITED;
} else {
return type.getWireType();
}
}
/**
* Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
* {@link FieldSet}.
*/
public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
mergeFromField(other.fields.getArrayEntryAt(i));
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
other.fields.getOverflowEntries()) {
mergeFromField(entry);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void mergeFromField(
final Map.Entry<FieldDescriptorType, Object> entry) {
final FieldDescriptorType descriptor = entry.getKey();
Object otherValue = entry.getValue();
if (otherValue instanceof LazyField) {
otherValue = ((LazyField) otherValue).getValue();
}
if (descriptor.isRepeated()) {
Object value = getField(descriptor);
if (value == null) {
// Our list is empty, but we still need to make a defensive copy of
// the other list since we don't know if the other FieldSet is still
// mutable.
fields.put(descriptor, new ArrayList((List) otherValue));
} else {
// Concatenate the lists.
((List) value).addAll((List) otherValue);
}
} else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
Object value = getField(descriptor);
if (value == null) {
fields.put(descriptor, otherValue);
} else {
// Merge the messages.
fields.put(
descriptor,
descriptor.internalMergeFrom(
((MessageLite) value).toBuilder(), (MessageLite) otherValue)
.build());
}
} else {
fields.put(descriptor, otherValue);
}
}
// TODO(kenton): Move static parsing and serialization methods into some
// other class. Probably WireFormat.
/**
* Read a field of any primitive type from a CodedInputStream. Enums,
* groups, and embedded messages are not handled by this method.
*
* @param input The stream from which to read.
* @param type Declared type of the field.
* @return An object representing the field's value, of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
public static Object readPrimitiveField(
CodedInputStream input,
final WireFormat.FieldType type) throws IOException {
switch (type) {
case DOUBLE : return input.readDouble ();
case FLOAT : return input.readFloat ();
case INT64 : return input.readInt64 ();
case UINT64 : return input.readUInt64 ();
case INT32 : return input.readInt32 ();
case FIXED64 : return input.readFixed64 ();
case FIXED32 : return input.readFixed32 ();
case BOOL : return input.readBool ();
case STRING : return input.readString ();
case BYTES : return input.readBytes ();
case UINT32 : return input.readUInt32 ();
case SFIXED32: return input.readSFixed32();
case SFIXED64: return input.readSFixed64();
case SINT32 : return input.readSInt32 ();
case SINT64 : return input.readSInt64 ();
case GROUP:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle nested groups.");
case MESSAGE:
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle embedded messages.");
case ENUM:
// We don't handle enums because we don't know what to do if the
// value is not recognized.
throw new IllegalArgumentException(
"readPrimitiveField() cannot handle enums.");
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
/** See {@link Message#writeTo(CodedOutputStream)}. */
public void writeTo(final CodedOutputStream output)
throws IOException {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
final Map.Entry<FieldDescriptorType, Object> entry =
fields.getArrayEntryAt(i);
writeField(entry.getKey(), entry.getValue(), output);
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
writeField(entry.getKey(), entry.getValue(), output);
}
}
/**
* Like {@link #writeTo} but uses MessageSet wire format.
*/
public void writeMessageSetTo(final CodedOutputStream output)
throws IOException {
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
writeMessageSetTo(fields.getArrayEntryAt(i), output);
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
writeMessageSetTo(entry, output);
}
}
private void writeMessageSetTo(
final Map.Entry<FieldDescriptorType, Object> entry,
final CodedOutputStream output) throws IOException {
final FieldDescriptorType descriptor = entry.getKey();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
!descriptor.isRepeated() && !descriptor.isPacked()) {
output.writeMessageSetExtension(entry.getKey().getNumber(),
(MessageLite) entry.getValue());
} else {
writeField(descriptor, entry.getValue(), output);
}
}
/**
* Write a single tag-value pair to the stream.
*
* @param output The output stream.
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static void writeElement(final CodedOutputStream output,
final WireFormat.FieldType type,
final int number,
final Object value) throws IOException {
// Special case for groups, which need a start and end tag; other fields
// can just use writeTag() and writeFieldNoTag().
if (type == WireFormat.FieldType.GROUP) {
output.writeGroup(number, (MessageLite) value);
} else {
output.writeTag(number, getWireFormatForFieldType(type, false));
writeElementNoTag(output, type, value);
}
}
/**
* Write a field of arbitrary type, without its tag, to the stream.
*
* @param output The output stream.
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static void writeElementNoTag(
final CodedOutputStream output,
final WireFormat.FieldType type,
final Object value) throws IOException {
switch (type) {
case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
case FLOAT : output.writeFloatNoTag ((Float ) value); break;
case INT64 : output.writeInt64NoTag ((Long ) value); break;
case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
case INT32 : output.writeInt32NoTag ((Integer ) value); break;
case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
case STRING : output.writeStringNoTag ((String ) value); break;
case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
case ENUM:
output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
break;
}
}
/** Write a single field. */
public static void writeField(final FieldDescriptorLite<?> descriptor,
final Object value,
final CodedOutputStream output)
throws IOException {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
final List<?> valueList = (List<?>)value;
if (descriptor.isPacked()) {
output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
// Compute the total data size so the length can be written.
int dataSize = 0;
for (final Object element : valueList) {
dataSize += computeElementSizeNoTag(type, element);
}
output.writeRawVarint32(dataSize);
// Write the data itself, without any tags.
for (final Object element : valueList) {
writeElementNoTag(output, type, element);
}
} else {
for (final Object element : valueList) {
writeElement(output, type, number, element);
}
}
} else {
if (value instanceof LazyField) {
writeElement(output, type, number, ((LazyField) value).getValue());
} else {
writeElement(output, type, number, value);
}
}
}
/**
* See {@link Message#getSerializedSize()}. It's up to the caller to cache
* the resulting size if desired.
*/
public int getSerializedSize() {
int size = 0;
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
final Map.Entry<FieldDescriptorType, Object> entry =
fields.getArrayEntryAt(i);
size += computeFieldSize(entry.getKey(), entry.getValue());
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
size += computeFieldSize(entry.getKey(), entry.getValue());
}
return size;
}
/**
* Like {@link #getSerializedSize} but uses MessageSet wire format.
*/
public int getMessageSetSerializedSize() {
int size = 0;
for (int i = 0; i < fields.getNumArrayEntries(); i++) {
size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
}
for (final Map.Entry<FieldDescriptorType, Object> entry :
fields.getOverflowEntries()) {
size += getMessageSetSerializedSize(entry);
}
return size;
}
private int getMessageSetSerializedSize(
final Map.Entry<FieldDescriptorType, Object> entry) {
final FieldDescriptorType descriptor = entry.getKey();
Object value = entry.getValue();
if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
&& !descriptor.isRepeated() && !descriptor.isPacked()) {
if (value instanceof LazyField) {
return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
entry.getKey().getNumber(), (LazyField) value);
} else {
return CodedOutputStream.computeMessageSetExtensionSize(
entry.getKey().getNumber(), (MessageLite) value);
}
} else {
return computeFieldSize(descriptor, value);
}
}
/**
* Compute the number of bytes that would be needed to encode a
* single tag/value pair of arbitrary type.
*
* @param type The field's type.
* @param number The field's number.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static int computeElementSize(
final WireFormat.FieldType type,
final int number, final Object value) {
int tagSize = CodedOutputStream.computeTagSize(number);
if (type == WireFormat.FieldType.GROUP) {
tagSize *= 2;
}
return tagSize + computeElementSizeNoTag(type, value);
}
/**
* Compute the number of bytes that would be needed to encode a
* particular value of arbitrary type, excluding tag.
*
* @param type The field's type.
* @param value Object representing the field's value. Must be of the exact
* type which would be returned by
* {@link Message#getField(Descriptors.FieldDescriptor)} for
* this field.
*/
private static int computeElementSizeNoTag(
final WireFormat.FieldType type, final Object value) {
switch (type) {
// Note: Minor violation of 80-char limit rule here because this would
// actually be harder to read if we wrapped the lines.
case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
case MESSAGE:
if (value instanceof LazyField) {
return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
} else {
return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
}
case ENUM:
return CodedOutputStream.computeEnumSizeNoTag(
((Internal.EnumLite) value).getNumber());
}
throw new RuntimeException(
"There is no way to get here, but the compiler thinks otherwise.");
}
/**
* Compute the number of bytes needed to encode a particular field.
*/
public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
final Object value) {
WireFormat.FieldType type = descriptor.getLiteType();
int number = descriptor.getNumber();
if (descriptor.isRepeated()) {
if (descriptor.isPacked()) {
int dataSize = 0;
for (final Object element : (List<?>)value) {
dataSize += computeElementSizeNoTag(type, element);
}
return dataSize +
CodedOutputStream.computeTagSize(number) +
CodedOutputStream.computeRawVarint32Size(dataSize);
} else {
int size = 0;
for (final Object element : (List<?>)value) {
size += computeElementSize(type, number, element);
}
return size;
}
} else {
return computeElementSize(type, number, value);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,797 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Lite version of {@link GeneratedMessage}.
*
* @author kenton@google.com Kenton Varda
*/
public abstract class GeneratedMessageLite extends AbstractMessageLite
implements Serializable {
private static final long serialVersionUID = 1L;
protected GeneratedMessageLite() {
}
protected GeneratedMessageLite(Builder builder) {
}
public Parser<? extends MessageLite> getParserForType() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return input.skipField(tag);
}
/**
* Used by parsing constructors in generated classes.
*/
protected void makeExtensionsImmutable() {
// Noop for messages without extensions.
}
@SuppressWarnings("unchecked")
public abstract static class Builder<MessageType extends GeneratedMessageLite,
BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType> {
protected Builder() {}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public BuilderType clear() {
return (BuilderType) this;
}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
/** All subclasses implement this. */
public abstract BuilderType mergeFrom(MessageType message);
// Defined here for return type covariance.
public abstract MessageType getDefaultInstanceForType();
/**
* Called by subclasses to parse an unknown field.
* @return {@code true} unless the tag is an end-group tag.
*/
protected boolean parseUnknownField(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return input.skipField(tag);
}
}
// =================================================================
// Extensions-related stuff
/**
* Lite equivalent of {@link com.google.protobuf.GeneratedMessage.ExtendableMessageOrBuilder}.
*/
public interface ExtendableMessageOrBuilder<
MessageType extends ExtendableMessage> extends MessageLiteOrBuilder {
/** Check if a singular extension is present. */
<Type> boolean hasExtension(
GeneratedExtension<MessageType, Type> extension);
/** Get the number of elements in a repeated extension. */
<Type> int getExtensionCount(
GeneratedExtension<MessageType, List<Type>> extension);
/** Get the value of an extension. */
<Type> Type getExtension(GeneratedExtension<MessageType, Type> extension);
/** Get one element of a repeated extension. */
<Type> Type getExtension(
GeneratedExtension<MessageType, List<Type>> extension,
int index);
}
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
*/
public abstract static class ExtendableMessage<
MessageType extends ExtendableMessage<MessageType>>
extends GeneratedMessageLite
implements ExtendableMessageOrBuilder<MessageType> {
private final FieldSet<ExtensionDescriptor> extensions;
protected ExtendableMessage() {
this.extensions = FieldSet.newFieldSet();
}
protected ExtendableMessage(ExtendableBuilder<MessageType, ?> builder) {
this.extensions = builder.buildExtensions();
}
private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
getDefaultInstanceForType()) {
// This can only happen if someone uses unchecked operations.
throw new IllegalArgumentException(
"This extension is for a different message type. Please make " +
"sure that you are not suppressing any generics type warnings.");
}
}
/** Check if a singular extension is present. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> boolean hasExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
return extensions.hasField(extension.descriptor);
}
/** Get the number of elements in a repeated extension. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
verifyExtensionContainingType(extension);
return extensions.getRepeatedFieldCount(extension.descriptor);
}
/** Get the value of an extension. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
final Object value = extensions.getField(extension.descriptor);
if (value == null) {
return extension.defaultValue;
} else {
return (Type) value;
}
}
/** Get one element of a repeated extension. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
verifyExtensionContainingType(extension);
return (Type) extensions.getRepeatedField(extension.descriptor, index);
}
/** Called by subclasses to check if all extensions are initialized. */
protected boolean extensionsAreInitialized() {
return extensions.isInitialized();
}
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
@Override
protected boolean parseUnknownField(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
return GeneratedMessageLite.parseUnknownField(
extensions,
getDefaultInstanceForType(),
input,
extensionRegistry,
tag);
}
/**
* Used by parsing constructors in generated classes.
*/
@Override
protected void makeExtensionsImmutable() {
extensions.makeImmutable();
}
/**
* Used by subclasses to serialize extensions. Extension ranges may be
* interleaved with field numbers, but we must write them in canonical
* (sorted by field number) order. ExtensionWriter helps us write
* individual ranges of extensions at once.
*/
protected class ExtensionWriter {
// Imagine how much simpler this code would be if Java iterators had
// a way to get the next element without advancing the iterator.
private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
extensions.iterator();
private Map.Entry<ExtensionDescriptor, Object> next;
private final boolean messageSetWireFormat;
private ExtensionWriter(boolean messageSetWireFormat) {
if (iter.hasNext()) {
next = iter.next();
}
this.messageSetWireFormat = messageSetWireFormat;
}
public void writeUntil(final int end, final CodedOutputStream output)
throws IOException {
while (next != null && next.getKey().getNumber() < end) {
ExtensionDescriptor extension = next.getKey();
if (messageSetWireFormat && extension.getLiteJavaType() ==
WireFormat.JavaType.MESSAGE &&
!extension.isRepeated()) {
output.writeMessageSetExtension(extension.getNumber(),
(MessageLite) next.getValue());
} else {
FieldSet.writeField(extension, next.getValue(), output);
}
if (iter.hasNext()) {
next = iter.next();
} else {
next = null;
}
}
}
}
protected ExtensionWriter newExtensionWriter() {
return new ExtensionWriter(false);
}
protected ExtensionWriter newMessageSetExtensionWriter() {
return new ExtensionWriter(true);
}
/** Called by subclasses to compute the size of extensions. */
protected int extensionsSerializedSize() {
return extensions.getSerializedSize();
}
protected int extensionsSerializedSizeAsMessageSet() {
return extensions.getMessageSetSerializedSize();
}
}
/**
* Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
*/
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
MessageType extends ExtendableMessage<MessageType>,
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<MessageType, BuilderType>
implements ExtendableMessageOrBuilder<MessageType> {
protected ExtendableBuilder() {}
private FieldSet<ExtensionDescriptor> extensions = FieldSet.emptySet();
private boolean extensionsIsMutable;
@Override
public BuilderType clear() {
extensions.clear();
extensionsIsMutable = false;
return super.clear();
}
private void ensureExtensionsIsMutable() {
if (!extensionsIsMutable) {
extensions = extensions.clone();
extensionsIsMutable = true;
}
}
/**
* Called by the build code path to create a copy of the extensions for
* building the message.
*/
private FieldSet<ExtensionDescriptor> buildExtensions() {
extensions.makeImmutable();
extensionsIsMutable = false;
return extensions;
}
private void verifyExtensionContainingType(
final GeneratedExtension<MessageType, ?> extension) {
if (extension.getContainingTypeDefaultInstance() !=
getDefaultInstanceForType()) {
// This can only happen if someone uses unchecked operations.
throw new IllegalArgumentException(
"This extension is for a different message type. Please make " +
"sure that you are not suppressing any generics type warnings.");
}
}
/** Check if a singular extension is present. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> boolean hasExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
return extensions.hasField(extension.descriptor);
}
/** Get the number of elements in a repeated extension. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> int getExtensionCount(
final GeneratedExtension<MessageType, List<Type>> extension) {
verifyExtensionContainingType(extension);
return extensions.getRepeatedFieldCount(extension.descriptor);
}
/** Get the value of an extension. */
//@Override (Java 1.6 override semantics, but we must support 1.5)
@SuppressWarnings("unchecked")
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, Type> extension) {
verifyExtensionContainingType(extension);
final Object value = extensions.getField(extension.descriptor);
if (value == null) {
return extension.defaultValue;
} else {
return (Type) value;
}
}
/** Get one element of a repeated extension. */
@SuppressWarnings("unchecked")
//@Override (Java 1.6 override semantics, but we must support 1.5)
public final <Type> Type getExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index) {
verifyExtensionContainingType(extension);
return (Type) extensions.getRepeatedField(extension.descriptor, index);
}
// This is implemented here only to work around an apparent bug in the
// Java compiler and/or build system. See bug #1898463. The mere presence
// of this dummy clone() implementation makes it go away.
@Override
public BuilderType clone() {
throw new UnsupportedOperationException(
"This is supposed to be overridden by subclasses.");
}
/** Set the value of an extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, Type> extension,
final Type value) {
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
extensions.setField(extension.descriptor, value);
return (BuilderType) this;
}
/** Set the value of one element of a repeated extension. */
public final <Type> BuilderType setExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final int index, final Type value) {
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
extensions.setRepeatedField(extension.descriptor, index, value);
return (BuilderType) this;
}
/** Append a value to a repeated extension. */
public final <Type> BuilderType addExtension(
final GeneratedExtension<MessageType, List<Type>> extension,
final Type value) {
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
extensions.addRepeatedField(extension.descriptor, value);
return (BuilderType) this;
}
/** Clear an extension. */
public final <Type> BuilderType clearExtension(
final GeneratedExtension<MessageType, ?> extension) {
verifyExtensionContainingType(extension);
ensureExtensionsIsMutable();
extensions.clearField(extension.descriptor);
return (BuilderType) this;
}
/** Called by subclasses to check if all extensions are initialized. */
protected boolean extensionsAreInitialized() {
return extensions.isInitialized();
}
/**
* Called by subclasses to parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
@Override
protected boolean parseUnknownField(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
ensureExtensionsIsMutable();
return GeneratedMessageLite.parseUnknownField(
extensions,
getDefaultInstanceForType(),
input,
extensionRegistry,
tag);
}
protected final void mergeExtensionFields(final MessageType other) {
ensureExtensionsIsMutable();
extensions.mergeFrom(((ExtendableMessage) other).extensions);
}
}
// -----------------------------------------------------------------
/**
* Parse an unknown field or an extension.
* @return {@code true} unless the tag is an end-group tag.
*/
private static <MessageType extends MessageLite>
boolean parseUnknownField(
FieldSet<ExtensionDescriptor> extensions,
MessageType defaultInstance,
CodedInputStream input,
ExtensionRegistryLite extensionRegistry,
int tag) throws IOException {
int wireType = WireFormat.getTagWireType(tag);
int fieldNumber = WireFormat.getTagFieldNumber(tag);
GeneratedExtension<MessageType, ?> extension =
extensionRegistry.findLiteExtensionByNumber(
defaultInstance, fieldNumber);
boolean unknown = false;
boolean packed = false;
if (extension == null) {
unknown = true; // Unknown field.
} else if (wireType == FieldSet.getWireFormatForFieldType(
extension.descriptor.getLiteType(),
false /* isPacked */)) {
packed = false; // Normal, unpacked value.
} else if (extension.descriptor.isRepeated &&
extension.descriptor.type.isPackable() &&
wireType == FieldSet.getWireFormatForFieldType(
extension.descriptor.getLiteType(),
true /* isPacked */)) {
packed = true; // Packed value.
} else {
unknown = true; // Wrong wire type.
}
if (unknown) { // Unknown field or wrong wire type. Skip.
return input.skipField(tag);
}
if (packed) {
int length = input.readRawVarint32();
int limit = input.pushLimit(length);
if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
int rawValue = input.readEnum();
Object value =
extension.descriptor.getEnumType().findValueByNumber(rawValue);
if (value == null) {
// If the number isn't recognized as a valid value for this
// enum, drop it (don't even add it to unknownFields).
return true;
}
extensions.addRepeatedField(extension.descriptor, value);
}
} else {
while (input.getBytesUntilLimit() > 0) {
Object value =
FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
extensions.addRepeatedField(extension.descriptor, value);
}
}
input.popLimit(limit);
} else {
Object value;
switch (extension.descriptor.getLiteJavaType()) {
case MESSAGE: {
MessageLite.Builder subBuilder = null;
if (!extension.descriptor.isRepeated()) {
MessageLite existingValue =
(MessageLite) extensions.getField(extension.descriptor);
if (existingValue != null) {
subBuilder = existingValue.toBuilder();
}
}
if (subBuilder == null) {
subBuilder = extension.messageDefaultInstance.newBuilderForType();
}
if (extension.descriptor.getLiteType() ==
WireFormat.FieldType.GROUP) {
input.readGroup(extension.getNumber(),
subBuilder, extensionRegistry);
} else {
input.readMessage(subBuilder, extensionRegistry);
}
value = subBuilder.build();
break;
}
case ENUM:
int rawValue = input.readEnum();
value = extension.descriptor.getEnumType()
.findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// drop it.
if (value == null) {
return true;
}
break;
default:
value = FieldSet.readPrimitiveField(input,
extension.descriptor.getLiteType());
break;
}
if (extension.descriptor.isRepeated()) {
extensions.addRepeatedField(extension.descriptor, value);
} else {
extensions.setField(extension.descriptor, value);
}
}
return true;
}
// -----------------------------------------------------------------
/** For use by generated code only. */
public static <ContainingType extends MessageLite, Type>
GeneratedExtension<ContainingType, Type>
newSingularGeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type) {
return new GeneratedExtension<ContainingType, Type>(
containingTypeDefaultInstance,
defaultValue,
messageDefaultInstance,
new ExtensionDescriptor(enumTypeMap, number, type,
false /* isRepeated */,
false /* isPacked */));
}
/** For use by generated code only. */
public static <ContainingType extends MessageLite, Type>
GeneratedExtension<ContainingType, Type>
newRepeatedGeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final MessageLite messageDefaultInstance,
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isPacked) {
@SuppressWarnings("unchecked") // Subclasses ensure Type is a List
Type emptyList = (Type) Collections.emptyList();
return new GeneratedExtension<ContainingType, Type>(
containingTypeDefaultInstance,
emptyList,
messageDefaultInstance,
new ExtensionDescriptor(
enumTypeMap, number, type, true /* isRepeated */, isPacked));
}
private static final class ExtensionDescriptor
implements FieldSet.FieldDescriptorLite<
ExtensionDescriptor> {
private ExtensionDescriptor(
final Internal.EnumLiteMap<?> enumTypeMap,
final int number,
final WireFormat.FieldType type,
final boolean isRepeated,
final boolean isPacked) {
this.enumTypeMap = enumTypeMap;
this.number = number;
this.type = type;
this.isRepeated = isRepeated;
this.isPacked = isPacked;
}
private final Internal.EnumLiteMap<?> enumTypeMap;
private final int number;
private final WireFormat.FieldType type;
private final boolean isRepeated;
private final boolean isPacked;
public int getNumber() {
return number;
}
public WireFormat.FieldType getLiteType() {
return type;
}
public WireFormat.JavaType getLiteJavaType() {
return type.getJavaType();
}
public boolean isRepeated() {
return isRepeated;
}
public boolean isPacked() {
return isPacked;
}
public Internal.EnumLiteMap<?> getEnumType() {
return enumTypeMap;
}
@SuppressWarnings("unchecked")
public MessageLite.Builder internalMergeFrom(
MessageLite.Builder to, MessageLite from) {
return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
}
public int compareTo(ExtensionDescriptor other) {
return number - other.number;
}
}
/**
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
*
* Users should ignore the contents of this class and only use objects of
* this type as parameters to extension accessors and ExtensionRegistry.add().
*/
public static final class GeneratedExtension<
ContainingType extends MessageLite, Type> {
private GeneratedExtension(
final ContainingType containingTypeDefaultInstance,
final Type defaultValue,
final MessageLite messageDefaultInstance,
final ExtensionDescriptor descriptor) {
// Defensive checks to verify the correct initialization order of
// GeneratedExtensions and their related GeneratedMessages.
if (containingTypeDefaultInstance == null) {
throw new IllegalArgumentException(
"Null containingTypeDefaultInstance");
}
if (descriptor.getLiteType() == WireFormat.FieldType.MESSAGE &&
messageDefaultInstance == null) {
throw new IllegalArgumentException(
"Null messageDefaultInstance");
}
this.containingTypeDefaultInstance = containingTypeDefaultInstance;
this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor;
}
private final ContainingType containingTypeDefaultInstance;
private final Type defaultValue;
private final MessageLite messageDefaultInstance;
private final ExtensionDescriptor descriptor;
/**
* Default instance of the type being extended, used to identify that type.
*/
public ContainingType getContainingTypeDefaultInstance() {
return containingTypeDefaultInstance;
}
/** Get the field number. */
public int getNumber() {
return descriptor.getNumber();
}
/**
* If the extension is an embedded message, this is the default instance of
* that type.
*/
public MessageLite getMessageDefaultInstance() {
return messageDefaultInstance;
}
}
/**
* A serialized (serializable) form of the generated message. Stores the
* message as a class name and a byte array.
*/
static final class SerializedForm implements Serializable {
private static final long serialVersionUID = 0L;
private String messageClassName;
private byte[] asBytes;
/**
* Creates the serialized form by calling {@link com.google.protobuf.MessageLite#toByteArray}.
* @param regularForm the message to serialize
*/
SerializedForm(MessageLite regularForm) {
messageClassName = regularForm.getClass().getName();
asBytes = regularForm.toByteArray();
}
/**
* When read from an ObjectInputStream, this method converts this object
* back to the regular form. Part of Java's serialization magic.
* @return a GeneratedMessage of the type that was serialized
*/
@SuppressWarnings("unchecked")
protected Object readResolve() throws ObjectStreamException {
try {
Class messageClass = Class.forName(messageClassName);
Method newBuilder = messageClass.getMethod("newBuilder");
MessageLite.Builder builder =
(MessageLite.Builder) newBuilder.invoke(null);
builder.mergeFrom(asBytes);
return builder.buildPartial();
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find proto buffer class", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Unable to find newBuilder method", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unable to call newBuilder method", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Error calling newBuilder", e.getCause());
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException("Unable to understand proto buffer", e);
}
}
}
/**
* Replaces this object in the output stream with a serialized form.
* Part of Java's serialization magic. Generated sub-classes must override
* this method by calling {@code return super.writeReplace();}
* @return a SerializedForm of this message
*/
protected Object writeReplace() throws ObjectStreamException {
return new SerializedForm(this);
}
}

View File

@ -0,0 +1,153 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
/**
* The classes contained within are used internally by the Protocol Buffer
* library and generated message implementations. They are public only because
* those generated messages do not reside in the {@code protobuf} package.
* Others should not use this class directly.
*
* @author kenton@google.com (Kenton Varda)
*/
public class Internal {
/**
* Helper called by generated code to construct default values for string
* fields.
* <p>
* The protocol compiler does not actually contain a UTF-8 decoder -- it
* just pushes UTF-8-encoded text around without touching it. The one place
* where this presents a problem is when generating Java string literals.
* Unicode characters in the string literal would normally need to be encoded
* using a Unicode escape sequence, which would require decoding them.
* To get around this, protoc instead embeds the UTF-8 bytes into the
* generated code and leaves it to the runtime library to decode them.
* <p>
* It gets worse, though. If protoc just generated a byte array, like:
* new byte[] {0x12, 0x34, 0x56, 0x78}
* Java actually generates *code* which allocates an array and then fills
* in each value. This is much less efficient than just embedding the bytes
* directly into the bytecode. To get around this, we need another
* work-around. String literals are embedded directly, so protoc actually
* generates a string literal corresponding to the bytes. The easiest way
* to do this is to use the ISO-8859-1 character set, which corresponds to
* the first 256 characters of the Unicode range. Protoc can then use
* good old CEscape to generate the string.
* <p>
* So we have a string literal which represents a set of bytes which
* represents another string. This function -- stringDefaultValue --
* converts from the generated string to the string we actually want. The
* generated code calls this automatically.
*/
public static String stringDefaultValue(String bytes) {
try {
return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// both of the above character sets.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Helper called by generated code to construct default values for bytes
* fields.
* <p>
* This is a lot like {@link #stringDefaultValue}, but for bytes fields.
* In this case we only need the second of the two hacks -- allowing us to
* embed raw bytes as a string literal with ISO-8859-1 encoding.
*/
public static ByteString bytesDefaultValue(String bytes) {
try {
return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
} catch (UnsupportedEncodingException e) {
// This should never happen since all JVMs are required to implement
// ISO-8859-1.
throw new IllegalStateException(
"Java VM does not support a standard character set.", e);
}
}
/**
* Helper called by generated code to determine if a byte array is a valid
* UTF-8 encoded string such that the original bytes can be converted to
* a String object and then back to a byte array round tripping the bytes
* without loss. More precisely, returns {@code true} whenever:
* <pre> {@code
* Arrays.equals(byteString.toByteArray(),
* new String(byteString.toByteArray(), "UTF-8").getBytes("UTF-8"))
* }</pre>
*
* <p>This method rejects "overlong" byte sequences, as well as
* 3-byte sequences that would map to a surrogate character, in
* accordance with the restricted definition of UTF-8 introduced in
* Unicode 3.1. Note that the UTF-8 decoder included in Oracle's
* JDK has been modified to also reject "overlong" byte sequences,
* but currently (2011) still accepts 3-byte surrogate character
* byte sequences.
*
* <p>See the Unicode Standard,</br>
* Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
*
* <p>As of 2011-02, this method simply returns the result of {@link
* ByteString#isValidUtf8()}. Calling that method directly is preferred.
*
* @param byteString the string to check
* @return whether the byte array is round trippable
*/
public static boolean isValidUtf8(ByteString byteString) {
return byteString.isValidUtf8();
}
/**
* Interface for an enum value or value descriptor, to be used in FieldSet.
* The lite library stores enum values directly in FieldSets but the full
* library stores EnumValueDescriptors in order to better support reflection.
*/
public interface EnumLite {
int getNumber();
}
/**
* Interface for an object which maps integers to {@link EnumLite}s.
* {@link Descriptors.EnumDescriptor} implements this interface by mapping
* numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
* every generated enum type has a static method internalGetValueMap() which
* returns an implementation of this type that maps numbers to enum values.
*/
public interface EnumLiteMap<T extends EnumLite> {
T findValueByNumber(int number);
}
}

View File

@ -0,0 +1,114 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
/**
* Thrown when a protocol message being parsed is invalid in some way,
* e.g. it contains a malformed varint or a negative byte length.
*
* @author kenton@google.com Kenton Varda
*/
public class InvalidProtocolBufferException extends IOException {
private static final long serialVersionUID = -1616151763072450476L;
private MessageLite unfinishedMessage = null;
public InvalidProtocolBufferException(final String description) {
super(description);
}
/**
* Attaches an unfinished message to the exception to support best-effort
* parsing in {@code Parser} interface.
*
* @return this
*/
public InvalidProtocolBufferException setUnfinishedMessage(
MessageLite unfinishedMessage) {
this.unfinishedMessage = unfinishedMessage;
return this;
}
/**
* Returns the unfinished message attached to the exception, or null if
* no message is attached.
*/
public MessageLite getUnfinishedMessage() {
return unfinishedMessage;
}
static InvalidProtocolBufferException truncatedMessage() {
return new InvalidProtocolBufferException(
"While parsing a protocol message, the input ended unexpectedly " +
"in the middle of a field. This could mean either than the " +
"input has been truncated or that an embedded message " +
"misreported its own length.");
}
static InvalidProtocolBufferException negativeSize() {
return new InvalidProtocolBufferException(
"CodedInputStream encountered an embedded string or message " +
"which claimed to have negative size.");
}
static InvalidProtocolBufferException malformedVarint() {
return new InvalidProtocolBufferException(
"CodedInputStream encountered a malformed varint.");
}
static InvalidProtocolBufferException invalidTag() {
return new InvalidProtocolBufferException(
"Protocol message contained an invalid tag (zero).");
}
static InvalidProtocolBufferException invalidEndTag() {
return new InvalidProtocolBufferException(
"Protocol message end-group tag did not match expected tag.");
}
static InvalidProtocolBufferException invalidWireType() {
return new InvalidProtocolBufferException(
"Protocol message tag had invalid wire type.");
}
static InvalidProtocolBufferException recursionLimitExceeded() {
return new InvalidProtocolBufferException(
"Protocol message had too many levels of nesting. May be malicious. " +
"Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
}
static InvalidProtocolBufferException sizeLimitExceeded() {
return new InvalidProtocolBufferException(
"Protocol message was too large. May be malicious. " +
"Use CodedInputStream.setSizeLimit() to increase the size limit.");
}
}

View File

@ -0,0 +1,210 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
/**
* LazyField encapsulates the logic of lazily parsing message fields. It stores
* the message in a ByteString initially and then parse it on-demand.
*
* LazyField is thread-compatible e.g. concurrent read are safe, however,
* synchronizations are needed under read/write situations.
*
* Now LazyField is only used to lazily load MessageSet.
* TODO(xiangl): Use LazyField to lazily load all messages.
*
* @author xiangl@google.com (Xiang Li)
*/
class LazyField {
final private MessageLite defaultInstance;
final private ExtensionRegistryLite extensionRegistry;
// Mutable because it is initialized lazily.
private ByteString bytes;
private volatile MessageLite value;
private volatile boolean isDirty = false;
public LazyField(MessageLite defaultInstance,
ExtensionRegistryLite extensionRegistry, ByteString bytes) {
this.defaultInstance = defaultInstance;
this.extensionRegistry = extensionRegistry;
this.bytes = bytes;
}
public MessageLite getValue() {
ensureInitialized();
return value;
}
/**
* LazyField is not thread-safe for write access. Synchronizations are needed
* under read/write situations.
*/
public MessageLite setValue(MessageLite value) {
MessageLite originalValue = this.value;
this.value = value;
bytes = null;
isDirty = true;
return originalValue;
}
/**
* Due to the optional field can be duplicated at the end of serialized
* bytes, which will make the serialized size changed after LazyField
* parsed. Be careful when using this method.
*/
public int getSerializedSize() {
if (isDirty) {
return value.getSerializedSize();
}
return bytes.size();
}
public ByteString toByteString() {
if (!isDirty) {
return bytes;
}
synchronized (this) {
if (!isDirty) {
return bytes;
}
bytes = value.toByteString();
isDirty = false;
return bytes;
}
}
@Override
public int hashCode() {
ensureInitialized();
return value.hashCode();
}
@Override
public boolean equals(Object obj) {
ensureInitialized();
return value.equals(obj);
}
@Override
public String toString() {
ensureInitialized();
return value.toString();
}
private void ensureInitialized() {
if (value != null) {
return;
}
synchronized (this) {
if (value != null) {
return;
}
try {
if (bytes != null) {
value = defaultInstance.getParserForType()
.parseFrom(bytes, extensionRegistry);
}
} catch (IOException e) {
// TODO(xiangl): Refactory the API to support the exception thrown from
// lazily load messages.
}
}
}
// ====================================================
/**
* LazyEntry and LazyIterator are used to encapsulate the LazyField, when
* users iterate all fields from FieldSet.
*/
static class LazyEntry<K> implements Entry<K, Object> {
private Entry<K, LazyField> entry;
private LazyEntry(Entry<K, LazyField> entry) {
this.entry = entry;
}
public K getKey() {
return entry.getKey();
}
public Object getValue() {
LazyField field = entry.getValue();
if (field == null) {
return null;
}
return field.getValue();
}
public LazyField getField() {
return entry.getValue();
}
public Object setValue(Object value) {
if (!(value instanceof MessageLite)) {
throw new IllegalArgumentException(
"LazyField now only used for MessageSet, "
+ "and the value of MessageSet must be an instance of MessageLite");
}
return entry.getValue().setValue((MessageLite) value);
}
}
static class LazyIterator<K> implements Iterator<Entry<K, Object>> {
private Iterator<Entry<K, Object>> iterator;
public LazyIterator(Iterator<Entry<K, Object>> iterator) {
this.iterator = iterator;
}
public boolean hasNext() {
return iterator.hasNext();
}
@SuppressWarnings("unchecked")
public Entry<K, Object> next() {
Entry<K, ?> entry = iterator.next();
if (entry.getValue() instanceof LazyField) {
return new LazyEntry<K>((Entry<K, LazyField>) entry);
}
return (Entry<K, Object>) entry;
}
public void remove() {
iterator.remove();
}
}
}

View File

@ -0,0 +1,178 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.List;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.RandomAccess;
/**
* An implementation of {@link LazyStringList} that wraps an ArrayList. Each
* element is either a ByteString or a String. It caches the last one requested
* which is most likely the one needed next. This minimizes memory usage while
* satisfying the most common use cases.
* <p>
* <strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access an <tt>ArrayList</tt> instance concurrently,
* and at least one of the threads modifies the list structurally, it
* <i>must</i> be synchronized externally. (A structural modification is
* any operation that adds or deletes one or more elements, or explicitly
* resizes the backing array; merely setting the value of an element is not
* a structural modification.) This is typically accomplished by
* synchronizing on some object that naturally encapsulates the list.
* <p>
* If the implementation is accessed via concurrent reads, this is thread safe.
* Conversions are done in a thread safe manner. It's possible that the
* conversion may happen more than once if two threads attempt to access the
* same element and the modifications were not visible to each other, but this
* will not result in any corruption of the list or change in behavior other
* than performance.
*
* @author jonp@google.com (Jon Perlow)
*/
public class LazyStringArrayList extends AbstractList<String>
implements LazyStringList, RandomAccess {
public final static LazyStringList EMPTY = new UnmodifiableLazyStringList(
new LazyStringArrayList());
private final List<Object> list;
public LazyStringArrayList() {
list = new ArrayList<Object>();
}
public LazyStringArrayList(LazyStringList from) {
list = new ArrayList<Object>(from.size());
addAll(from);
}
public LazyStringArrayList(List<String> from) {
list = new ArrayList<Object>(from);
}
@Override
public String get(int index) {
Object o = list.get(index);
if (o instanceof String) {
return (String) o;
} else {
ByteString bs = (ByteString) o;
String s = bs.toStringUtf8();
if (bs.isValidUtf8()) {
list.set(index, s);
}
return s;
}
}
@Override
public int size() {
return list.size();
}
@Override
public String set(int index, String s) {
Object o = list.set(index, s);
return asString(o);
}
@Override
public void add(int index, String element) {
list.add(index, element);
modCount++;
}
@Override
public boolean addAll(Collection<? extends String> c) {
// The default implementation of AbstractCollection.addAll(Collection)
// delegates to add(Object). This implementation instead delegates to
// addAll(int, Collection), which makes a special case for Collections
// which are instances of LazyStringList.
return addAll(size(), c);
}
@Override
public boolean addAll(int index, Collection<? extends String> c) {
// When copying from another LazyStringList, directly copy the underlying
// elements rather than forcing each element to be decoded to a String.
Collection<?> collection = c instanceof LazyStringList
? ((LazyStringList) c).getUnderlyingElements() : c;
boolean ret = list.addAll(index, collection);
modCount++;
return ret;
}
@Override
public String remove(int index) {
Object o = list.remove(index);
modCount++;
return asString(o);
}
public void clear() {
list.clear();
modCount++;
}
// @Override
public void add(ByteString element) {
list.add(element);
modCount++;
}
// @Override
public ByteString getByteString(int index) {
Object o = list.get(index);
if (o instanceof String) {
ByteString b = ByteString.copyFromUtf8((String) o);
list.set(index, b);
return b;
} else {
return (ByteString) o;
}
}
private String asString(Object o) {
if (o instanceof String) {
return (String) o;
} else {
return ((ByteString) o).toStringUtf8();
}
}
public List<?> getUnderlyingElements() {
return Collections.unmodifiableList(list);
}
}

View File

@ -0,0 +1,81 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.List;
/**
* An interface extending {@code List<String>} that also provides access to the
* items of the list as UTF8-encoded ByteString objects. This is used by the
* protocol buffer implementation to support lazily converting bytes parsed
* over the wire to String objects until needed and also increases the
* efficiency of serialization if the String was never requested as the
* ByteString is already cached.
* <p>
* This only adds additional methods that are required for the use in the
* protocol buffer code in order to be able successfully round trip byte arrays
* through parsing and serialization without conversion to strings. It's not
* attempting to support the functionality of say {@code List<ByteString>}, hence
* why only these two very specific methods are added.
*
* @author jonp@google.com (Jon Perlow)
*/
public interface LazyStringList extends List<String> {
/**
* Returns the element at the specified position in this list as a ByteString.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()})
*/
ByteString getByteString(int index);
/**
* Appends the specified element to the end of this list (optional
* operation).
*
* @param element element to be appended to this list
* @throws UnsupportedOperationException if the <tt>add</tt> operation
* is not supported by this list
*/
void add(ByteString element);
/**
* Returns an unmodifiable List of the underlying elements, each of
* which is either a {@code String} or its equivalent UTF-8 encoded
* {@code ByteString}. It is an error for the caller to modify the returned
* List, and attempting to do so will result in an
* {@link UnsupportedOperationException}.
*/
List<?> getUnderlyingElements();
}

View File

@ -0,0 +1,349 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
/**
* This class implements a {@link com.google.protobuf.ByteString} backed by a
* single array of bytes, contiguous in memory. It supports substring by
* pointing to only a sub-range of the underlying byte array, meaning that a
* substring will reference the full byte-array of the string it's made from,
* exactly as with {@link String}.
*
* @author carlanton@google.com (Carl Haverl)
*/
class LiteralByteString extends ByteString {
protected final byte[] bytes;
/**
* Creates a {@code LiteralByteString} backed by the given array, without
* copying.
*
* @param bytes array to wrap
*/
LiteralByteString(byte[] bytes) {
this.bytes = bytes;
}
@Override
public byte byteAt(int index) {
// Unlike most methods in this class, this one is a direct implementation
// ignoring the potential offset because we need to do range-checking in the
// substring case anyway.
return bytes[index];
}
@Override
public int size() {
return bytes.length;
}
// =================================================================
// ByteString -> substring
@Override
public ByteString substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException(
"Beginning index: " + beginIndex + " < 0");
}
if (endIndex > size()) {
throw new IndexOutOfBoundsException("End index: " + endIndex + " > " +
size());
}
int substringLength = endIndex - beginIndex;
if (substringLength < 0) {
throw new IndexOutOfBoundsException(
"Beginning index larger than ending index: " + beginIndex + ", "
+ endIndex);
}
ByteString result;
if (substringLength == 0) {
result = ByteString.EMPTY;
} else {
result = new BoundedByteString(bytes, getOffsetIntoBytes() + beginIndex,
substringLength);
}
return result;
}
// =================================================================
// ByteString -> byte[]
@Override
protected void copyToInternal(byte[] target, int sourceOffset,
int targetOffset, int numberToCopy) {
// Optimized form, not for subclasses, since we don't call
// getOffsetIntoBytes() or check the 'numberToCopy' parameter.
System.arraycopy(bytes, sourceOffset, target, targetOffset, numberToCopy);
}
@Override
public void copyTo(ByteBuffer target) {
target.put(bytes, getOffsetIntoBytes(), size()); // Copies bytes
}
@Override
public ByteBuffer asReadOnlyByteBuffer() {
ByteBuffer byteBuffer =
ByteBuffer.wrap(bytes, getOffsetIntoBytes(), size());
return byteBuffer.asReadOnlyBuffer();
}
@Override
public List<ByteBuffer> asReadOnlyByteBufferList() {
// Return the ByteBuffer generated by asReadOnlyByteBuffer() as a singleton
List<ByteBuffer> result = new ArrayList<ByteBuffer>(1);
result.add(asReadOnlyByteBuffer());
return result;
}
@Override
public void writeTo(OutputStream outputStream) throws IOException {
outputStream.write(toByteArray());
}
@Override
public String toString(String charsetName)
throws UnsupportedEncodingException {
return new String(bytes, getOffsetIntoBytes(), size(), charsetName);
}
// =================================================================
// UTF-8 decoding
@Override
public boolean isValidUtf8() {
int offset = getOffsetIntoBytes();
return Utf8.isValidUtf8(bytes, offset, offset + size());
}
@Override
protected int partialIsValidUtf8(int state, int offset, int length) {
int index = getOffsetIntoBytes() + offset;
return Utf8.partialIsValidUtf8(state, bytes, index, index + length);
}
// =================================================================
// equals() and hashCode()
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof ByteString)) {
return false;
}
if (size() != ((ByteString) other).size()) {
return false;
}
if (size() == 0) {
return true;
}
if (other instanceof LiteralByteString) {
return equalsRange((LiteralByteString) other, 0, size());
} else if (other instanceof RopeByteString) {
return other.equals(this);
} else {
throw new IllegalArgumentException(
"Has a new type of ByteString been created? Found "
+ other.getClass());
}
}
/**
* Check equality of the substring of given length of this object starting at
* zero with another {@code LiteralByteString} substring starting at offset.
*
* @param other what to compare a substring in
* @param offset offset into other
* @param length number of bytes to compare
* @return true for equality of substrings, else false.
*/
boolean equalsRange(LiteralByteString other, int offset, int length) {
if (length > other.size()) {
throw new IllegalArgumentException(
"Length too large: " + length + size());
}
if (offset + length > other.size()) {
throw new IllegalArgumentException(
"Ran off end of other: " + offset + ", " + length + ", " +
other.size());
}
byte[] thisBytes = bytes;
byte[] otherBytes = other.bytes;
int thisLimit = getOffsetIntoBytes() + length;
for (int thisIndex = getOffsetIntoBytes(), otherIndex =
other.getOffsetIntoBytes() + offset;
(thisIndex < thisLimit); ++thisIndex, ++otherIndex) {
if (thisBytes[thisIndex] != otherBytes[otherIndex]) {
return false;
}
}
return true;
}
/**
* Cached hash value. Intentionally accessed via a data race, which
* is safe because of the Java Memory Model's "no out-of-thin-air values"
* guarantees for ints.
*/
private int hash = 0;
/**
* Compute the hashCode using the traditional algorithm from {@link
* ByteString}.
*
* @return hashCode value
*/
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
int size = size();
h = partialHash(size, 0, size);
if (h == 0) {
h = 1;
}
hash = h;
}
return h;
}
@Override
protected int peekCachedHashCode() {
return hash;
}
@Override
protected int partialHash(int h, int offset, int length) {
byte[] thisBytes = bytes;
for (int i = getOffsetIntoBytes() + offset, limit = i + length; i < limit;
i++) {
h = h * 31 + thisBytes[i];
}
return h;
}
// =================================================================
// Input stream
@Override
public InputStream newInput() {
return new ByteArrayInputStream(bytes, getOffsetIntoBytes(),
size()); // No copy
}
@Override
public CodedInputStream newCodedInput() {
// We trust CodedInputStream not to modify the bytes, or to give anyone
// else access to them.
return CodedInputStream
.newInstance(bytes, getOffsetIntoBytes(), size()); // No copy
}
// =================================================================
// ByteIterator
@Override
public ByteIterator iterator() {
return new LiteralByteIterator();
}
private class LiteralByteIterator implements ByteIterator {
private int position;
private final int limit;
private LiteralByteIterator() {
position = 0;
limit = size();
}
public boolean hasNext() {
return (position < limit);
}
public Byte next() {
// Boxing calls Byte.valueOf(byte), which does not instantiate.
return nextByte();
}
public byte nextByte() {
try {
return bytes[position++];
} catch (ArrayIndexOutOfBoundsException e) {
throw new NoSuchElementException(e.getMessage());
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// =================================================================
// Internal methods
@Override
protected int getTreeDepth() {
return 0;
}
@Override
protected boolean isBalanced() {
return true;
}
/**
* Offset into {@code bytes[]} to use, non-zero for substrings.
*
* @return always 0 for this class
*/
protected int getOffsetIntoBytes() {
return 0;
}
}

View File

@ -0,0 +1,237 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
// mergeFrom*() could return BuilderType for better type-safety.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* Abstract interface implemented by Protocol Message objects.
* <p>
* See also {@link MessageLite}, which defines most of the methods that typical
* users care about. {@link Message} adds to it methods that are not available
* in the "lite" runtime. The biggest added features are introspection and
* reflection -- i.e., getting descriptors for the message type and accessing
* the field values dynamically.
*
* @author kenton@google.com Kenton Varda
*/
public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)
Parser<? extends Message> getParserForType();
// -----------------------------------------------------------------
// Comparison and hashing
/**
* Compares the specified object with this message for equality. Returns
* {@code true} if the given object is a message of the same type (as
* defined by {@code getDescriptorForType()}) and has identical values for
* all of its fields. Subclasses must implement this; inheriting
* {@code Object.equals()} is incorrect.
*
* @param other object to be compared for equality with this message
* @return {@code true} if the specified object is equal to this message
*/
@Override
boolean equals(Object other);
/**
* Returns the hash code value for this message. The hash code of a message
* should mix the message's type (object identity of the descriptor) with its
* contents (known and unknown field values). Subclasses must implement this;
* inheriting {@code Object.hashCode()} is incorrect.
*
* @return the hash code value for this message
* @see Map#hashCode()
*/
@Override
int hashCode();
// -----------------------------------------------------------------
// Convenience methods.
/**
* Converts the message to a string in protocol buffer text format. This is
* just a trivial wrapper around {@link
* TextFormat#printToString(MessageOrBuilder)}.
*/
@Override
String toString();
// =================================================================
// Builders
// (From MessageLite, re-declared here only for return type covariance.)
Builder newBuilderForType();
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
interface Builder extends MessageLite.Builder, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder clear();
/**
* Merge {@code other} into the message being built. {@code other} must
* have the exact same type as {@code this} (i.e.
* {@code getDescriptorForType() == other.getDescriptorForType()}).
*
* Merging occurs as follows. For each field:<br>
* * For singular primitive fields, if the field is set in {@code other},
* then {@code other}'s value overwrites the value in this message.<br>
* * For singular message fields, if the field is set in {@code other},
* it is merged into the corresponding sub-message of this message
* using the same merging rules.<br>
* * For repeated fields, the elements in {@code other} are concatenated
* with the elements in this message.
*
* This is equivalent to the {@code Message::MergeFrom} method in C++.
*/
Builder mergeFrom(Message other);
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Message build();
Message buildPartial();
Builder clone();
Builder mergeFrom(CodedInputStream input) throws IOException;
Builder mergeFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Get the message's type's descriptor.
* See {@link Message#getDescriptorForType()}.
*/
Descriptors.Descriptor getDescriptorForType();
/**
* Create a Builder for messages of the appropriate type for the given
* field. Messages built with this can then be passed to setField(),
* setRepeatedField(), or addRepeatedField().
*/
Builder newBuilderForField(Descriptors.FieldDescriptor field);
/**
* Get a nested builder instance for the given field.
* <p>
* Normally, we hold a reference to the immutable message object for the
* message type field. Some implementations(the generated message builders),
* however, can also hold a reference to the builder object (a nested
* builder) for the field.
* <p>
* If the field is already backed up by a nested builder, the nested builder
* will be returned. Otherwise, a new field builder will be created and
* returned. The original message field (if exist) will be merged into the
* field builder, which will then be nested into its parent builder.
* <p>
* NOTE: implementations that do not support nested builders will throw
* <code>UnsupportedException</code>.
*/
Builder getFieldBuilder(Descriptors.FieldDescriptor field);
/**
* Sets a field to the given value. The value must be of the correct type
* for this field, i.e. the same type that
* {@link Message#getField(Descriptors.FieldDescriptor)} would return.
*/
Builder setField(Descriptors.FieldDescriptor field, Object value);
/**
* Clears the field. This is exactly equivalent to calling the generated
* "clear" accessor method corresponding to the field.
*/
Builder clearField(Descriptors.FieldDescriptor field);
/**
* Sets an element of a repeated field to the given value. The value must
* be of the correct type for this field, i.e. the same type that
* {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
* return.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Builder setRepeatedField(Descriptors.FieldDescriptor field,
int index, Object value);
/**
* Like {@code setRepeatedField}, but appends the value as a new element.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
/** Set the {@link UnknownFieldSet} for this message. */
Builder setUnknownFields(UnknownFieldSet unknownFields);
/**
* Merge some unknown fields into the {@link UnknownFieldSet} for this
* message.
*/
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
// ---------------------------------------------------------------
// Convenience methods.
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
Builder mergeFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
Builder mergeFrom(InputStream input) throws IOException;
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
boolean mergeDelimitedFrom(InputStream input)
throws IOException;
boolean mergeDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View File

@ -0,0 +1,319 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
// mergeFrom*() could return BuilderType for better type-safety.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Abstract interface implemented by Protocol Message objects.
*
* <p>This interface is implemented by all protocol message objects. Non-lite
* messages additionally implement the Message interface, which is a subclass
* of MessageLite. Use MessageLite instead when you only need the subset of
* features which it supports -- namely, nothing that uses descriptors or
* reflection. You can instruct the protocol compiler to generate classes
* which implement only MessageLite, not the full Message interface, by adding
* the follow line to the .proto file:
* <pre>
* option optimize_for = LITE_RUNTIME;
* </pre>
*
* <p>This is particularly useful on resource-constrained systems where the
* full protocol buffers runtime library is too big.
*
* <p>Note that on non-constrained systems (e.g. servers) when you need to link
* in lots of protocol definitions, a better way to reduce total code footprint
* is to use {@code optimize_for = CODE_SIZE}. This will make the generated
* code smaller while still supporting all the same features (at the expense of
* speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
* small number of message types linked into your binary, in which case the
* size of the protocol buffers runtime itself is the biggest problem.
*
* @author kenton@google.com Kenton Varda
*/
public interface MessageLite extends MessageLiteOrBuilder {
/**
* Serializes the message and writes it to {@code output}. This does not
* flush or close the stream.
*/
void writeTo(CodedOutputStream output) throws IOException;
/**
* Get the number of bytes required to encode this message. The result
* is only computed on the first call and memoized after that.
*/
int getSerializedSize();
/**
* Gets the parser for a message of the same type as this message.
*/
Parser<? extends MessageLite> getParserForType();
// -----------------------------------------------------------------
// Convenience methods.
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
ByteString toByteString();
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around
* {@link #writeTo(CodedOutputStream)}.
*/
byte[] toByteArray();
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
* not flush or close the stream.
* <p>
* NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
* any more data to the stream after the message, you must somehow ensure
* that the parser on the receiving end does not interpret this as being
* part of the protocol message. This can be done e.g. by writing the size
* of the message before the data, then making sure to limit the input to
* that size on the receiving end (e.g. by wrapping the InputStream in one
* which limits the input). Alternatively, just use
* {@link #writeDelimitedTo(OutputStream)}.
*/
void writeTo(OutputStream output) throws IOException;
/**
* Like {@link #writeTo(OutputStream)}, but writes the size of the message
* as a varint before writing the data. This allows more data to be written
* to the stream after the message without the need to delimit the message
* data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
* the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
* to parse messages written by this method.
*/
void writeDelimitedTo(OutputStream output) throws IOException;
// =================================================================
// Builders
/**
* Constructs a new builder for a message of the same type as this message.
*/
Builder newBuilderForType();
/**
* Constructs a builder initialized with the current message. Use this to
* derive a new message from the current one.
*/
Builder toBuilder();
/**
* Abstract interface implemented by Protocol Message builders.
*/
interface Builder extends MessageLiteOrBuilder, Cloneable {
/** Resets all fields to their default values. */
Builder clear();
/**
* Constructs the message based on the state of the Builder. Subsequent
* changes to the Builder will not affect the returned message.
* @throws UninitializedMessageException The message is missing one or more
* required fields (i.e. {@link #isInitialized()} returns false).
* Use {@link #buildPartial()} to bypass this check.
*/
MessageLite build();
/**
* Like {@link #build()}, but does not throw an exception if the message
* is missing required fields. Instead, a partial message is returned.
* Subsequent changes to the Builder will not affect the returned message.
*/
MessageLite buildPartial();
/**
* Clones the Builder.
* @see Object#clone()
*/
Builder clone();
/**
* Parses a message of this type from the input and merges it with this
* message.
*
* <p>Warning: This does not verify that all required fields are present in
* the input message. If you call {@link #build()} without setting all
* required fields, it will throw an {@link UninitializedMessageException},
* which is a {@code RuntimeException} and thus might not be caught. There
* are a few good ways to deal with this:
* <ul>
* <li>Call {@link #isInitialized()} to verify that all required fields
* are set before building.
* <li>Use {@code buildPartial()} to build, which ignores missing
* required fields.
* </ul>
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
Builder mergeFrom(CodedInputStream input) throws IOException;
/**
* Like {@link Builder#mergeFrom(CodedInputStream)}, but also
* parses extensions. The extensions that you want to be able to parse
* must be registered in {@code extensionRegistry}. Extensions not in
* the registry will be treated as unknown fields.
*/
Builder mergeFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
// ---------------------------------------------------------------
// Convenience methods.
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*
* @return this
*/
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
Builder mergeFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*
* @return this
*/
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*
* @return this
*/
Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
Builder mergeFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse {@code data} as a message of this type and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
Builder mergeFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}. Note that this method always
* reads the <i>entire</i> input (unless it throws an exception). If you
* want it to stop earlier, you will need to wrap your input in some
* wrapper stream that limits reading. Or, use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
* and {@link #mergeDelimitedFrom(InputStream)} to read it.
* <p>
* Despite usually reading the entire input, this does not close the stream.
*
* @return this
*/
Builder mergeFrom(InputStream input) throws IOException;
/**
* Parse a message of this type from {@code input} and merge it with the
* message being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream,ExtensionRegistryLite)}.
*
* @return this
*/
Builder mergeFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
/**
* Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
* Instead, the size of the message (encoded as a varint) is read first,
* then the message data. Use
* {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
* this format.
*
* @return True if successful, or false if the stream is at EOF when the
* method starts. Any other error (including reaching EOF during
* parsing) will cause an exception to be thrown.
*/
boolean mergeDelimitedFrom(InputStream input)
throws IOException;
/**
* Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
*/
boolean mergeDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws IOException;
}
}

View File

@ -0,0 +1,60 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Base interface for methods common to {@link MessageLite}
* and {@link MessageLite.Builder} to provide type equivalency.
*
* @author jonp@google.com (Jon Perlow)
*/
public interface MessageLiteOrBuilder {
/**
* Get an instance of the type with no fields set. Because no fields are set,
* all getters for singular fields will return default values and repeated
* fields will appear empty.
* This may or may not be a singleton. This differs from the
* {@code getDefaultInstance()} method of generated message classes in that
* this method is an abstract method of the {@code MessageLite} interface
* whereas {@code getDefaultInstance()} is a static method of a specific
* class. They return the same thing.
*/
MessageLite getDefaultInstanceForType();
/**
* Returns true if all required fields in the message and all embedded
* messages are set, false otherwise.
*
* <p>See also: {@link MessageOrBuilder#getInitializationErrorString()}
*/
boolean isInitialized();
}

View File

@ -0,0 +1,129 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.List;
import java.util.Map;
/**
* Base interface for methods common to {@link Message} and
* {@link Message.Builder} to provide type equivalency.
*
* @author jonp@google.com (Jon Perlow)
*/
public interface MessageOrBuilder extends MessageLiteOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)
//@Override (Java 1.6 override semantics, but we must support 1.5)
Message getDefaultInstanceForType();
/**
* Returns a list of field paths (e.g. "foo.bar.baz") of required fields
* which are not set in this message. You should call
* {@link MessageLiteOrBuilder#isInitialized()} first to check if there
* are any missing fields, as that method is likely to be much faster
* than this one even when the message is fully-initialized.
*/
List<String> findInitializationErrors();
/**
* Returns a comma-delimited list of required fields which are not set
* in this message object. You should call
* {@link MessageLiteOrBuilder#isInitialized()} first to check if there
* are any missing fields, as that method is likely to be much faster
* than this one even when the message is fully-initialized.
*/
String getInitializationErrorString();
/**
* Get the message's type's descriptor. This differs from the
* {@code getDescriptor()} method of generated message classes in that
* this method is an abstract method of the {@code Message} interface
* whereas {@code getDescriptor()} is a static method of a specific class.
* They return the same thing.
*/
Descriptors.Descriptor getDescriptorForType();
/**
* Returns a collection of all the fields in this message which are set
* and their corresponding values. A singular ("required" or "optional")
* field is set iff hasField() returns true for that field. A "repeated"
* field is set iff getRepeatedFieldSize() is greater than zero. The
* values are exactly what would be returned by calling
* {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
* is guaranteed to be a sorted map, so iterating over it will return fields
* in order by field number.
* <br>
* If this is for a builder, the returned map may or may not reflect future
* changes to the builder. Either way, the returned map is itself
* unmodifiable.
*/
Map<Descriptors.FieldDescriptor, Object> getAllFields();
/**
* Returns true if the given field is set. This is exactly equivalent to
* calling the generated "has" accessor method corresponding to the field.
* @throws IllegalArgumentException The field is a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
boolean hasField(Descriptors.FieldDescriptor field);
/**
* Obtains the value of the given field, or the default value if it is
* not set. For primitive fields, the boxed primitive value is returned.
* For enum fields, the EnumValueDescriptor for the value is returned. For
* embedded message fields, the sub-message is returned. For repeated
* fields, a java.util.List is returned.
*/
Object getField(Descriptors.FieldDescriptor field);
/**
* Gets the number of elements of a repeated field. This is exactly
* equivalent to calling the generated "Count" accessor method corresponding
* to the field.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
/**
* Gets an element of a repeated field. For primitive fields, the boxed
* primitive value is returned. For enum fields, the EnumValueDescriptor
* for the value is returned. For embedded message fields, the sub-message
* is returned.
* @throws IllegalArgumentException The field is not a repeated field, or
* {@code field.getContainingType() != getDescriptorForType()}.
*/
Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
/** Get the {@link UnknownFieldSet} for this message. */
UnknownFieldSet getUnknownFields();
}

View File

@ -0,0 +1,259 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.InputStream;
/**
* Abstract interface for parsing Protocol Messages.
*
* @author liujisi@google.com (Pherl Liu)
*/
public interface Parser<MessageType> {
/**
* Parses a message of {@code MessageType} from the input.
*
* <p>Note: The caller should call
* {@link CodedInputStream#checkLastTagWas(int)} after calling this to
* verify that the last tag seen was the appropriate end-group tag,
* or zero for EOF.
*/
public MessageType parseFrom(CodedInputStream input)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(CodedInputStream)}, but also parses extensions.
* The extensions that you want to be able to parse must be registered in
* {@code extensionRegistry}. Extensions not in the registry will be treated
* as unknown fields.
*/
public MessageType parseFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(CodedInputStream)}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialFrom(CodedInputStream input)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(CodedInputStream input, ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialFrom(CodedInputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
// ---------------------------------------------------------------
// Convenience methods.
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
*/
public MessageType parseFrom(ByteString data)
throws InvalidProtocolBufferException;
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
*/
public MessageType parseFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(ByteString)}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialFrom(ByteString data)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialFrom(ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
*/
public MessageType parseFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
*/
public MessageType parseFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
*/
public MessageType parseFrom(byte[] data)
throws InvalidProtocolBufferException;
/**
* Parses {@code data} as a message of {@code MessageType}.
* This is just a small wrapper around
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
*/
public MessageType parseFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(byte[], int, int)}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(ByteString, ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialFrom(byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(byte[])}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialFrom(byte[] data)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(byte[], ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialFrom(byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Parse a message of {@code MessageType} from {@code input}.
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
* Note that this method always reads the <i>entire</i> input (unless it
* throws an exception). If you want it to stop earlier, you will need to
* wrap your input in some wrapper stream that limits reading. Or, use
* {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write your
* message and {@link #parseDelimitedFrom(InputStream)} to read it.
* <p>
* Despite usually reading the entire input, this does not close the stream.
*/
public MessageType parseFrom(InputStream input)
throws InvalidProtocolBufferException;
/**
* Parses a message of {@code MessageType} from {@code input}.
* This is just a small wrapper around
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
*/
public MessageType parseFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(InputStream)}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialFrom(InputStream input)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(InputStream, ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseFrom(InputStream)}, but does not read util EOF.
* Instead, the size of message (encoded as a varint) is read first,
* then the message data. Use
* {@link MessageLite#writeDelimitedTo(java.io.OutputStream)} to write
* messages in this format.
*
* @return True if successful, or false if the stream is at EOF when the
* method starts. Any other error (including reaching EOF during
* parsing) will cause an exception to be thrown.
*/
public MessageType parseDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseDelimitedFrom(InputStream)} but supporting extensions.
*/
public MessageType parseDelimitedFrom(InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseDelimitedFrom(InputStream)}, but does not throw an
* exception if the message is missing required fields. Instead, a partial
* message is returned.
*/
public MessageType parsePartialDelimitedFrom(InputStream input)
throws InvalidProtocolBufferException;
/**
* Like {@link #parseDelimitedFrom(InputStream, ExtensionRegistryLite)},
* but does not throw an exception if the message is missing required fields.
* Instead, a partial message is returned.
*/
public MessageType parsePartialDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
}

View File

@ -0,0 +1,58 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
/**
* Interface of useful methods added to all enums generated by the protocol
* compiler.
*/
public interface ProtocolMessageEnum extends Internal.EnumLite {
/**
* Return the value's numeric value as defined in the .proto file.
*/
int getNumber();
/**
* Return the value's descriptor, which contains information such as
* value name, number, and type.
*/
EnumValueDescriptor getValueDescriptor();
/**
* Return the enum type's descriptor, which contains information
* about each defined value, etc.
*/
EnumDescriptor getDescriptorForType();
}

View File

@ -0,0 +1,696 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* {@code RepeatedFieldBuilder} implements a structure that a protocol
* message uses to hold a repeated field of other protocol messages. It supports
* the classical use case of adding immutable {@link Message}'s to the
* repeated field and is highly optimized around this (no extra memory
* allocations and sharing of immutable arrays).
* <br>
* It also supports the additional use case of adding a {@link Message.Builder}
* to the repeated field and deferring conversion of that {@code Builder}
* to an immutable {@code Message}. In this way, it's possible to maintain
* a tree of {@code Builder}'s that acts as a fully read/write data
* structure.
* <br>
* Logically, one can think of a tree of builders as converting the entire tree
* to messages when build is called on the root or when any method is called
* that desires a Message instead of a Builder. In terms of the implementation,
* the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
* classes cache messages that were created so that messages only need to be
* created when some change occured in its builder or a builder for one of its
* descendants.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*
* @author jonp@google.com (Jon Perlow)
*/
public class RepeatedFieldBuilder
<MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
implements GeneratedMessage.BuilderParent {
// Parent to send changes to.
private GeneratedMessage.BuilderParent parent;
// List of messages. Never null. It may be immutable, in which case
// isMessagesListImmutable will be true. See note below.
private List<MType> messages;
// Whether messages is an mutable array that can be modified.
private boolean isMessagesListMutable;
// List of builders. May be null, in which case, no nested builders were
// created. If not null, entries represent the builder for that index.
private List<SingleFieldBuilder<MType, BType, IType>> builders;
// Here are the invariants for messages and builders:
// 1. messages is never null and its count corresponds to the number of items
// in the repeated field.
// 2. If builders is non-null, messages and builders MUST always
// contain the same number of items.
// 3. Entries in either array can be null, but for any index, there MUST be
// either a Message in messages or a builder in builders.
// 4. If the builder at an index is non-null, the builder is
// authoritative. This is the case where a Builder was set on the index.
// Any message in the messages array MUST be ignored.
// t. If the builder at an index is null, the message in the messages
// list is authoritative. This is the case where a Message (not a Builder)
// was set directly for an index.
// Indicates that we've built a message and so we are now obligated
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
private boolean isClean;
// A view of this builder that exposes a List interface of messages. This is
// initialized on demand. This is fully backed by this object and all changes
// are reflected in it. Access to any item converts it to a message if it
// was a builder.
private MessageExternalList<MType, BType, IType> externalMessageList;
// A view of this builder that exposes a List interface of builders. This is
// initialized on demand. This is fully backed by this object and all changes
// are reflected in it. Access to any item converts it to a builder if it
// was a message.
private BuilderExternalList<MType, BType, IType> externalBuilderList;
// A view of this builder that exposes a List interface of the interface
// implemented by messages and builders. This is initialized on demand. This
// is fully backed by this object and all changes are reflected in it.
// Access to any item returns either a builder or message depending on
// what is most efficient.
private MessageOrBuilderExternalList<MType, BType, IType>
externalMessageOrBuilderList;
/**
* Constructs a new builder with an empty list of messages.
*
* @param messages the current list of messages
* @param isMessagesListMutable Whether the messages list is mutable
* @param parent a listener to notify of changes
* @param isClean whether the builder is initially marked clean
*/
public RepeatedFieldBuilder(
List<MType> messages,
boolean isMessagesListMutable,
GeneratedMessage.BuilderParent parent,
boolean isClean) {
this.messages = messages;
this.isMessagesListMutable = isMessagesListMutable;
this.parent = parent;
this.isClean = isClean;
}
public void dispose() {
// Null out parent so we stop sending it invalidations.
parent = null;
}
/**
* Ensures that the list of messages is mutable so it can be updated. If it's
* immutable, a copy is made.
*/
private void ensureMutableMessageList() {
if (!isMessagesListMutable) {
messages = new ArrayList<MType>(messages);
isMessagesListMutable = true;
}
}
/**
* Ensures that the list of builders is not null. If it's null, the list is
* created and initialized to be the same size as the messages list with
* null entries.
*/
private void ensureBuilders() {
if (this.builders == null) {
this.builders =
new ArrayList<SingleFieldBuilder<MType, BType, IType>>(
messages.size());
for (int i = 0; i < messages.size(); i++) {
builders.add(null);
}
}
}
/**
* Gets the count of items in the list.
*
* @return the count of items in the list.
*/
public int getCount() {
return messages.size();
}
/**
* Gets whether the list is empty.
*
* @return whether the list is empty
*/
public boolean isEmpty() {
return messages.isEmpty();
}
/**
* Get the message at the specified index. If the message is currently stored
* as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it.
*
* @param index the index of the message to get
* @return the message for the specified index
*/
public MType getMessage(int index) {
return getMessage(index, false);
}
/**
* Get the message at the specified index. If the message is currently stored
* as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it.
*
* @param index the index of the message to get
* @param forBuild this is being called for build so we want to make sure
* we SingleFieldBuilder.build to send dirty invalidations
* @return the message for the specified index
*/
private MType getMessage(int index, boolean forBuild) {
if (this.builders == null) {
// We don't have any builders -- return the current Message.
// This is the case where no builder was created, so we MUST have a
// Message.
return messages.get(index);
}
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
// We don't have a builder -- return the current message.
// This is the case where no builder was created for the entry at index,
// so we MUST have a message.
return messages.get(index);
} else {
return forBuild ? builder.build() : builder.getMessage();
}
}
/**
* Gets a builder for the specified index. If no builder has been created for
* that index, a builder is created on demand by calling
* {@link Message#toBuilder}.
*
* @param index the index of the message to get
* @return The builder for that index
*/
public BType getBuilder(int index) {
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
MType message = messages.get(index);
builder = new SingleFieldBuilder<MType, BType, IType>(
message, this, isClean);
builders.set(index, builder);
}
return builder.getBuilder();
}
/**
* Gets the base class interface for the specified index. This may either be
* a builder or a message. It will return whatever is more efficient.
*
* @param index the index of the message to get
* @return the message or builder for the index as the base class interface
*/
@SuppressWarnings("unchecked")
public IType getMessageOrBuilder(int index) {
if (this.builders == null) {
// We don't have any builders -- return the current Message.
// This is the case where no builder was created, so we MUST have a
// Message.
return (IType) messages.get(index);
}
SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
if (builder == null) {
// We don't have a builder -- return the current message.
// This is the case where no builder was created for the entry at index,
// so we MUST have a message.
return (IType) messages.get(index);
} else {
return builder.getMessageOrBuilder();
}
}
/**
* Sets a message at the specified index replacing the existing item at
* that index.
*
* @param index the index to set.
* @param message the message to set
* @return the builder
*/
public RepeatedFieldBuilder<MType, BType, IType> setMessage(
int index, MType message) {
if (message == null) {
throw new NullPointerException();
}
ensureMutableMessageList();
messages.set(index, message);
if (builders != null) {
SingleFieldBuilder<MType, BType, IType> entry =
builders.set(index, null);
if (entry != null) {
entry.dispose();
}
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends the specified element to the end of this list.
*
* @param message the message to add
* @return the builder
*/
public RepeatedFieldBuilder<MType, BType, IType> addMessage(
MType message) {
if (message == null) {
throw new NullPointerException();
}
ensureMutableMessageList();
messages.add(message);
if (builders != null) {
builders.add(null);
}
onChanged();
incrementModCounts();
return this;
}
/**
* Inserts the specified message at the specified position in this list.
* Shifts the element currently at that position (if any) and any subsequent
* elements to the right (adds one to their indices).
*
* @param index the index at which to insert the message
* @param message the message to add
* @return the builder
*/
public RepeatedFieldBuilder<MType, BType, IType> addMessage(
int index, MType message) {
if (message == null) {
throw new NullPointerException();
}
ensureMutableMessageList();
messages.add(index, message);
if (builders != null) {
builders.add(index, null);
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends all of the messages in the specified collection to the end of
* this list, in the order that they are returned by the specified
* collection's iterator.
*
* @param values the messages to add
* @return the builder
*/
public RepeatedFieldBuilder<MType, BType, IType> addAllMessages(
Iterable<? extends MType> values) {
for (final MType value : values) {
if (value == null) {
throw new NullPointerException();
}
}
if (values instanceof Collection) {
@SuppressWarnings("unchecked") final
Collection<MType> collection = (Collection<MType>) values;
if (collection.size() == 0) {
return this;
}
ensureMutableMessageList();
for (MType value : values) {
addMessage(value);
}
} else {
ensureMutableMessageList();
for (MType value : values) {
addMessage(value);
}
}
onChanged();
incrementModCounts();
return this;
}
/**
* Appends a new builder to the end of this list and returns the builder.
*
* @param message the message to add which is the basis of the builder
* @return the new builder
*/
public BType addBuilder(MType message) {
ensureMutableMessageList();
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder =
new SingleFieldBuilder<MType, BType, IType>(
message, this, isClean);
messages.add(null);
builders.add(builder);
onChanged();
incrementModCounts();
return builder.getBuilder();
}
/**
* Inserts a new builder at the specified position in this list.
* Shifts the element currently at that position (if any) and any subsequent
* elements to the right (adds one to their indices).
*
* @param index the index at which to insert the builder
* @param message the message to add which is the basis of the builder
* @return the builder
*/
public BType addBuilder(int index, MType message) {
ensureMutableMessageList();
ensureBuilders();
SingleFieldBuilder<MType, BType, IType> builder =
new SingleFieldBuilder<MType, BType, IType>(
message, this, isClean);
messages.add(index, null);
builders.add(index, builder);
onChanged();
incrementModCounts();
return builder.getBuilder();
}
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index at which to remove the message
*/
public void remove(int index) {
ensureMutableMessageList();
messages.remove(index);
if (builders != null) {
SingleFieldBuilder<MType, BType, IType> entry =
builders.remove(index);
if (entry != null) {
entry.dispose();
}
}
onChanged();
incrementModCounts();
}
/**
* Removes all of the elements from this list.
* The list will be empty after this call returns.
*/
public void clear() {
messages = Collections.emptyList();
isMessagesListMutable = false;
if (builders != null) {
for (SingleFieldBuilder<MType, BType, IType> entry :
builders) {
if (entry != null) {
entry.dispose();
}
}
builders = null;
}
onChanged();
incrementModCounts();
}
/**
* Builds the list of messages from the builder and returns them.
*
* @return an immutable list of messages
*/
public List<MType> build() {
// Now that build has been called, we are required to dispatch
// invalidations.
isClean = true;
if (!isMessagesListMutable && builders == null) {
// We still have an immutable list and we never created a builder.
return messages;
}
boolean allMessagesInSync = true;
if (!isMessagesListMutable) {
// We still have an immutable list. Let's see if any of them are out
// of sync with their builders.
for (int i = 0; i < messages.size(); i++) {
Message message = messages.get(i);
SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
if (builder != null) {
if (builder.build() != message) {
allMessagesInSync = false;
break;
}
}
}
if (allMessagesInSync) {
// Immutable list is still in sync.
return messages;
}
}
// Need to make sure messages is up to date
ensureMutableMessageList();
for (int i = 0; i < messages.size(); i++) {
messages.set(i, getMessage(i, true));
}
// We're going to return our list as immutable so we mark that we can
// no longer update it.
messages = Collections.unmodifiableList(messages);
isMessagesListMutable = false;
return messages;
}
/**
* Gets a view of the builder as a list of messages. The returned list is live
* and will reflect any changes to the underlying builder.
*
* @return the messages in the list
*/
public List<MType> getMessageList() {
if (externalMessageList == null) {
externalMessageList =
new MessageExternalList<MType, BType, IType>(this);
}
return externalMessageList;
}
/**
* Gets a view of the builder as a list of builders. This returned list is
* live and will reflect any changes to the underlying builder.
*
* @return the builders in the list
*/
public List<BType> getBuilderList() {
if (externalBuilderList == null) {
externalBuilderList =
new BuilderExternalList<MType, BType, IType>(this);
}
return externalBuilderList;
}
/**
* Gets a view of the builder as a list of MessageOrBuilders. This returned
* list is live and will reflect any changes to the underlying builder.
*
* @return the builders in the list
*/
public List<IType> getMessageOrBuilderList() {
if (externalMessageOrBuilderList == null) {
externalMessageOrBuilderList =
new MessageOrBuilderExternalList<MType, BType, IType>(this);
}
return externalMessageOrBuilderList;
}
/**
* Called when a the builder or one of its nested children has changed
* and any parent should be notified of its invalidation.
*/
private void onChanged() {
if (isClean && parent != null) {
parent.markDirty();
// Don't keep dispatching invalidations until build is called again.
isClean = false;
}
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void markDirty() {
onChanged();
}
/**
* Increments the mod counts so that an ConcurrentModificationException can
* be thrown if calling code tries to modify the builder while its iterating
* the list.
*/
private void incrementModCounts() {
if (externalMessageList != null) {
externalMessageList.incrementModCount();
}
if (externalBuilderList != null) {
externalBuilderList.incrementModCount();
}
if (externalMessageOrBuilderList != null) {
externalMessageOrBuilderList.incrementModCount();
}
}
/**
* Provides a live view of the builder as a list of messages.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class MessageExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<MType> implements List<MType> {
RepeatedFieldBuilder<MType, BType, IType> builder;
MessageExternalList(
RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
public int size() {
return this.builder.getCount();
}
public MType get(int index) {
return builder.getMessage(index);
}
void incrementModCount() {
modCount++;
}
}
/**
* Provides a live view of the builder as a list of builders.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class BuilderExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<BType> implements List<BType> {
RepeatedFieldBuilder<MType, BType, IType> builder;
BuilderExternalList(
RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
public int size() {
return this.builder.getCount();
}
public BType get(int index) {
return builder.getBuilder(index);
}
void incrementModCount() {
modCount++;
}
}
/**
* Provides a live view of the builder as a list of builders.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*/
private static class MessageOrBuilderExternalList<
MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
extends AbstractList<IType> implements List<IType> {
RepeatedFieldBuilder<MType, BType, IType> builder;
MessageOrBuilderExternalList(
RepeatedFieldBuilder<MType, BType, IType> builder) {
this.builder = builder;
}
public int size() {
return this.builder.getCount();
}
public IType get(int index) {
return builder.getMessageOrBuilder(index);
}
void incrementModCount() {
modCount++;
}
}
}

View File

@ -0,0 +1,943 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Stack;
/**
* Class to represent {@code ByteStrings} formed by concatenation of other
* ByteStrings, without copying the data in the pieces. The concatenation is
* represented as a tree whose leaf nodes are each a {@link LiteralByteString}.
*
* <p>Most of the operation here is inspired by the now-famous paper <a
* href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
* BAP95 </a> Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and
* michael plass
*
* <p>The algorithms described in the paper have been implemented for character
* strings in {@link com.google.common.string.Rope} and in the c++ class {@code
* cord.cc}.
*
* <p>Fundamentally the Rope algorithm represents the collection of pieces as a
* binary tree. BAP95 uses a Fibonacci bound relating depth to a minimum
* sequence length, sequences that are too short relative to their depth cause a
* tree rebalance. More precisely, a tree of depth d is "balanced" in the
* terminology of BAP95 if its length is at least F(d+2), where F(n) is the
* n-the Fibonacci number. Thus for depths 0, 1, 2, 3, 4, 5,... we have minimum
* lengths 1, 2, 3, 5, 8, 13,...
*
* @author carlanton@google.com (Carl Haverl)
*/
class RopeByteString extends ByteString {
/**
* BAP95. Let Fn be the nth Fibonacci number. A {@link RopeByteString} of
* depth n is "balanced", i.e flat enough, if its length is at least Fn+2,
* e.g. a "balanced" {@link RopeByteString} of depth 1 must have length at
* least 2, of depth 4 must have length >= 8, etc.
*
* <p>There's nothing special about using the Fibonacci numbers for this, but
* they are a reasonable sequence for encapsulating the idea that we are OK
* with longer strings being encoded in deeper binary trees.
*
* <p>For 32-bit integers, this array has length 46.
*/
private static final int[] minLengthByDepth;
static {
// Dynamically generate the list of Fibonacci numbers the first time this
// class is accessed.
List<Integer> numbers = new ArrayList<Integer>();
// we skip the first Fibonacci number (1). So instead of: 1 1 2 3 5 8 ...
// we have: 1 2 3 5 8 ...
int f1 = 1;
int f2 = 1;
// get all the values until we roll over.
while (f2 > 0) {
numbers.add(f2);
int temp = f1 + f2;
f1 = f2;
f2 = temp;
}
// we include this here so that we can index this array to [x + 1] in the
// loops below.
numbers.add(Integer.MAX_VALUE);
minLengthByDepth = new int[numbers.size()];
for (int i = 0; i < minLengthByDepth.length; i++) {
// unbox all the values
minLengthByDepth[i] = numbers.get(i);
}
}
private final int totalLength;
private final ByteString left;
private final ByteString right;
private final int leftLength;
private final int treeDepth;
/**
* Create a new RopeByteString, which can be thought of as a new tree node, by
* recording references to the two given strings.
*
* @param left string on the left of this node, should have {@code size() >
* 0}
* @param right string on the right of this node, should have {@code size() >
* 0}
*/
private RopeByteString(ByteString left, ByteString right) {
this.left = left;
this.right = right;
leftLength = left.size();
totalLength = leftLength + right.size();
treeDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
}
/**
* Concatenate the given strings while performing various optimizations to
* slow the growth rate of tree depth and tree node count. The result is
* either a {@link LiteralByteString} or a {@link RopeByteString}
* depending on which optimizations, if any, were applied.
*
* <p>Small pieces of length less than {@link
* ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
* BAP95. Large pieces are referenced without copy.
*
* @param left string on the left
* @param right string on the right
* @return concatenation representing the same sequence as the given strings
*/
static ByteString concatenate(ByteString left, ByteString right) {
ByteString result;
RopeByteString leftRope =
(left instanceof RopeByteString) ? (RopeByteString) left : null;
if (right.size() == 0) {
result = left;
} else if (left.size() == 0) {
result = right;
} else {
int newLength = left.size() + right.size();
if (newLength < ByteString.CONCATENATE_BY_COPY_SIZE) {
// Optimization from BAP95: For short (leaves in paper, but just short
// here) total length, do a copy of data to a new leaf.
result = concatenateBytes(left, right);
} else if (leftRope != null
&& leftRope.right.size() + right.size() < CONCATENATE_BY_COPY_SIZE) {
// Optimization from BAP95: As an optimization of the case where the
// ByteString is constructed by repeated concatenate, recognize the case
// where a short string is concatenated to a left-hand node whose
// right-hand branch is short. In the paper this applies to leaves, but
// we just look at the length here. This has the advantage of shedding
// references to unneeded data when substrings have been taken.
//
// When we recognize this case, we do a copy of the data and create a
// new parent node so that the depth of the result is the same as the
// given left tree.
ByteString newRight = concatenateBytes(leftRope.right, right);
result = new RopeByteString(leftRope.left, newRight);
} else if (leftRope != null
&& leftRope.left.getTreeDepth() > leftRope.right.getTreeDepth()
&& leftRope.getTreeDepth() > right.getTreeDepth()) {
// Typically for concatenate-built strings the left-side is deeper than
// the right. This is our final attempt to concatenate without
// increasing the tree depth. We'll redo the the node on the RHS. This
// is yet another optimization for building the string by repeatedly
// concatenating on the right.
ByteString newRight = new RopeByteString(leftRope.right, right);
result = new RopeByteString(leftRope.left, newRight);
} else {
// Fine, we'll add a node and increase the tree depth--unless we
// rebalance ;^)
int newDepth = Math.max(left.getTreeDepth(), right.getTreeDepth()) + 1;
if (newLength >= minLengthByDepth[newDepth]) {
// The tree is shallow enough, so don't rebalance
result = new RopeByteString(left, right);
} else {
result = new Balancer().balance(left, right);
}
}
}
return result;
}
/**
* Concatenates two strings by copying data values. This is called in a few
* cases in order to reduce the growth of the number of tree nodes.
*
* @param left string on the left
* @param right string on the right
* @return string formed by copying data bytes
*/
private static LiteralByteString concatenateBytes(ByteString left,
ByteString right) {
int leftSize = left.size();
int rightSize = right.size();
byte[] bytes = new byte[leftSize + rightSize];
left.copyTo(bytes, 0, 0, leftSize);
right.copyTo(bytes, 0, leftSize, rightSize);
return new LiteralByteString(bytes); // Constructor wraps bytes
}
/**
* Create a new RopeByteString for testing only while bypassing all the
* defenses of {@link #concatenate(ByteString, ByteString)}. This allows
* testing trees of specific structure. We are also able to insert empty
* leaves, though these are dis-allowed, so that we can make sure the
* implementation can withstand their presence.
*
* @param left string on the left of this node
* @param right string on the right of this node
* @return an unsafe instance for testing only
*/
static RopeByteString newInstanceForTest(ByteString left, ByteString right) {
return new RopeByteString(left, right);
}
/**
* Gets the byte at the given index.
* Throws {@link ArrayIndexOutOfBoundsException} for backwards-compatibility
* reasons although it would more properly be {@link
* IndexOutOfBoundsException}.
*
* @param index index of byte
* @return the value
* @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
*/
@Override
public byte byteAt(int index) {
if (index < 0) {
throw new ArrayIndexOutOfBoundsException("Index < 0: " + index);
}
if (index > totalLength) {
throw new ArrayIndexOutOfBoundsException(
"Index > length: " + index + ", " + totalLength);
}
byte result;
// Find the relevant piece by recursive descent
if (index < leftLength) {
result = left.byteAt(index);
} else {
result = right.byteAt(index - leftLength);
}
return result;
}
@Override
public int size() {
return totalLength;
}
// =================================================================
// Pieces
@Override
protected int getTreeDepth() {
return treeDepth;
}
/**
* Determines if the tree is balanced according to BAP95, which means the tree
* is flat-enough with respect to the bounds. Note that this definition of
* balanced is one where sub-trees of balanced trees are not necessarily
* balanced.
*
* @return true if the tree is balanced
*/
@Override
protected boolean isBalanced() {
return totalLength >= minLengthByDepth[treeDepth];
}
/**
* Takes a substring of this one. This involves recursive descent along the
* left and right edges of the substring, and referencing any wholly contained
* segments in between. Any leaf nodes entirely uninvolved in the substring
* will not be referenced by the substring.
*
* <p>Substrings of {@code length < 2} should result in at most a single
* recursive call chain, terminating at a leaf node. Thus the result will be a
* {@link LiteralByteString}. {@link #RopeByteString(ByteString,
* ByteString)}.
*
* @param beginIndex start at this index
* @param endIndex the last character is the one before this index
* @return substring leaf node or tree
*/
@Override
public ByteString substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException(
"Beginning index: " + beginIndex + " < 0");
}
if (endIndex > totalLength) {
throw new IndexOutOfBoundsException(
"End index: " + endIndex + " > " + totalLength);
}
int substringLength = endIndex - beginIndex;
if (substringLength < 0) {
throw new IndexOutOfBoundsException(
"Beginning index larger than ending index: " + beginIndex + ", "
+ endIndex);
}
ByteString result;
if (substringLength == 0) {
// Empty substring
result = ByteString.EMPTY;
} else if (substringLength == totalLength) {
// The whole string
result = this;
} else {
// Proper substring
if (endIndex <= leftLength) {
// Substring on the left
result = left.substring(beginIndex, endIndex);
} else if (beginIndex >= leftLength) {
// Substring on the right
result = right
.substring(beginIndex - leftLength, endIndex - leftLength);
} else {
// Split substring
ByteString leftSub = left.substring(beginIndex);
ByteString rightSub = right.substring(0, endIndex - leftLength);
// Intentionally not rebalancing, since in many cases these two
// substrings will already be less deep than the top-level
// RopeByteString we're taking a substring of.
result = new RopeByteString(leftSub, rightSub);
}
}
return result;
}
// =================================================================
// ByteString -> byte[]
@Override
protected void copyToInternal(byte[] target, int sourceOffset,
int targetOffset, int numberToCopy) {
if (sourceOffset + numberToCopy <= leftLength) {
left.copyToInternal(target, sourceOffset, targetOffset, numberToCopy);
} else if (sourceOffset >= leftLength) {
right.copyToInternal(target, sourceOffset - leftLength, targetOffset,
numberToCopy);
} else {
int leftLength = this.leftLength - sourceOffset;
left.copyToInternal(target, sourceOffset, targetOffset, leftLength);
right.copyToInternal(target, 0, targetOffset + leftLength,
numberToCopy - leftLength);
}
}
@Override
public void copyTo(ByteBuffer target) {
left.copyTo(target);
right.copyTo(target);
}
@Override
public ByteBuffer asReadOnlyByteBuffer() {
ByteBuffer byteBuffer = ByteBuffer.wrap(toByteArray());
return byteBuffer.asReadOnlyBuffer();
}
@Override
public List<ByteBuffer> asReadOnlyByteBufferList() {
// Walk through the list of LiteralByteString's that make up this
// rope, and add each one as a read-only ByteBuffer.
List<ByteBuffer> result = new ArrayList<ByteBuffer>();
PieceIterator pieces = new PieceIterator(this);
while (pieces.hasNext()) {
LiteralByteString byteString = pieces.next();
result.add(byteString.asReadOnlyByteBuffer());
}
return result;
}
@Override
public void writeTo(OutputStream outputStream) throws IOException {
left.writeTo(outputStream);
right.writeTo(outputStream);
}
@Override
public String toString(String charsetName)
throws UnsupportedEncodingException {
return new String(toByteArray(), charsetName);
}
// =================================================================
// UTF-8 decoding
@Override
public boolean isValidUtf8() {
int leftPartial = left.partialIsValidUtf8(Utf8.COMPLETE, 0, leftLength);
int state = right.partialIsValidUtf8(leftPartial, 0, right.size());
return state == Utf8.COMPLETE;
}
@Override
protected int partialIsValidUtf8(int state, int offset, int length) {
int toIndex = offset + length;
if (toIndex <= leftLength) {
return left.partialIsValidUtf8(state, offset, length);
} else if (offset >= leftLength) {
return right.partialIsValidUtf8(state, offset - leftLength, length);
} else {
int leftLength = this.leftLength - offset;
int leftPartial = left.partialIsValidUtf8(state, offset, leftLength);
return right.partialIsValidUtf8(leftPartial, 0, length - leftLength);
}
}
// =================================================================
// equals() and hashCode()
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof ByteString)) {
return false;
}
ByteString otherByteString = (ByteString) other;
if (totalLength != otherByteString.size()) {
return false;
}
if (totalLength == 0) {
return true;
}
// You don't really want to be calling equals on long strings, but since
// we cache the hashCode, we effectively cache inequality. We use the cached
// hashCode if it's already computed. It's arguable we should compute the
// hashCode here, and if we're going to be testing a bunch of byteStrings,
// it might even make sense.
if (hash != 0) {
int cachedOtherHash = otherByteString.peekCachedHashCode();
if (cachedOtherHash != 0 && hash != cachedOtherHash) {
return false;
}
}
return equalsFragments(otherByteString);
}
/**
* Determines if this string is equal to another of the same length by
* iterating over the leaf nodes. On each step of the iteration, the
* overlapping segments of the leaves are compared.
*
* @param other string of the same length as this one
* @return true if the values of this string equals the value of the given
* one
*/
private boolean equalsFragments(ByteString other) {
int thisOffset = 0;
Iterator<LiteralByteString> thisIter = new PieceIterator(this);
LiteralByteString thisString = thisIter.next();
int thatOffset = 0;
Iterator<LiteralByteString> thatIter = new PieceIterator(other);
LiteralByteString thatString = thatIter.next();
int pos = 0;
while (true) {
int thisRemaining = thisString.size() - thisOffset;
int thatRemaining = thatString.size() - thatOffset;
int bytesToCompare = Math.min(thisRemaining, thatRemaining);
// At least one of the offsets will be zero
boolean stillEqual = (thisOffset == 0)
? thisString.equalsRange(thatString, thatOffset, bytesToCompare)
: thatString.equalsRange(thisString, thisOffset, bytesToCompare);
if (!stillEqual) {
return false;
}
pos += bytesToCompare;
if (pos >= totalLength) {
if (pos == totalLength) {
return true;
}
throw new IllegalStateException();
}
// We always get to the end of at least one of the pieces
if (bytesToCompare == thisRemaining) { // If reached end of this
thisOffset = 0;
thisString = thisIter.next();
} else {
thisOffset += bytesToCompare;
}
if (bytesToCompare == thatRemaining) { // If reached end of that
thatOffset = 0;
thatString = thatIter.next();
} else {
thatOffset += bytesToCompare;
}
}
}
/**
* Cached hash value. Intentionally accessed via a data race, which is safe
* because of the Java Memory Model's "no out-of-thin-air values" guarantees
* for ints.
*/
private int hash = 0;
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
h = totalLength;
h = partialHash(h, 0, totalLength);
if (h == 0) {
h = 1;
}
hash = h;
}
return h;
}
@Override
protected int peekCachedHashCode() {
return hash;
}
@Override
protected int partialHash(int h, int offset, int length) {
int toIndex = offset + length;
if (toIndex <= leftLength) {
return left.partialHash(h, offset, length);
} else if (offset >= leftLength) {
return right.partialHash(h, offset - leftLength, length);
} else {
int leftLength = this.leftLength - offset;
int leftPartial = left.partialHash(h, offset, leftLength);
return right.partialHash(leftPartial, 0, length - leftLength);
}
}
// =================================================================
// Input stream
@Override
public CodedInputStream newCodedInput() {
return CodedInputStream.newInstance(new RopeInputStream());
}
@Override
public InputStream newInput() {
return new RopeInputStream();
}
/**
* This class implements the balancing algorithm of BAP95. In the paper the
* authors use an array to keep track of pieces, while here we use a stack.
* The tree is balanced by traversing subtrees in left to right order, and the
* stack always contains the part of the string we've traversed so far.
*
* <p>One surprising aspect of the algorithm is the result of balancing is not
* necessarily balanced, though it is nearly balanced. For details, see
* BAP95.
*/
private static class Balancer {
// Stack containing the part of the string, starting from the left, that
// we've already traversed. The final string should be the equivalent of
// concatenating the strings on the stack from bottom to top.
private final Stack<ByteString> prefixesStack = new Stack<ByteString>();
private ByteString balance(ByteString left, ByteString right) {
doBalance(left);
doBalance(right);
// Sweep stack to gather the result
ByteString partialString = prefixesStack.pop();
while (!prefixesStack.isEmpty()) {
ByteString newLeft = prefixesStack.pop();
partialString = new RopeByteString(newLeft, partialString);
}
// We should end up with a RopeByteString since at a minimum we will
// create one from concatenating left and right
return partialString;
}
private void doBalance(ByteString root) {
// BAP95: Insert balanced subtrees whole. This means the result might not
// be balanced, leading to repeated rebalancings on concatenate. However,
// these rebalancings are shallow due to ignoring balanced subtrees, and
// relatively few calls to insert() result.
if (root.isBalanced()) {
insert(root);
} else if (root instanceof RopeByteString) {
RopeByteString rbs = (RopeByteString) root;
doBalance(rbs.left);
doBalance(rbs.right);
} else {
throw new IllegalArgumentException(
"Has a new type of ByteString been created? Found " +
root.getClass());
}
}
/**
* Push a string on the balance stack (BAP95). BAP95 uses an array and
* calls the elements in the array 'bins'. We instead use a stack, so the
* 'bins' of lengths are represented by differences between the elements of
* minLengthByDepth.
*
* <p>If the length bin for our string, and all shorter length bins, are
* empty, we just push it on the stack. Otherwise, we need to start
* concatenating, putting the given string in the "middle" and continuing
* until we land in an empty length bin that matches the length of our
* concatenation.
*
* @param byteString string to place on the balance stack
*/
private void insert(ByteString byteString) {
int depthBin = getDepthBinForLength(byteString.size());
int binEnd = minLengthByDepth[depthBin + 1];
// BAP95: Concatenate all trees occupying bins representing the length of
// our new piece or of shorter pieces, to the extent that is possible.
// The goal is to clear the bin which our piece belongs in, but that may
// not be entirely possible if there aren't enough longer bins occupied.
if (prefixesStack.isEmpty() || prefixesStack.peek().size() >= binEnd) {
prefixesStack.push(byteString);
} else {
int binStart = minLengthByDepth[depthBin];
// Concatenate the subtrees of shorter length
ByteString newTree = prefixesStack.pop();
while (!prefixesStack.isEmpty()
&& prefixesStack.peek().size() < binStart) {
ByteString left = prefixesStack.pop();
newTree = new RopeByteString(left, newTree);
}
// Concatenate the given string
newTree = new RopeByteString(newTree, byteString);
// Continue concatenating until we land in an empty bin
while (!prefixesStack.isEmpty()) {
depthBin = getDepthBinForLength(newTree.size());
binEnd = minLengthByDepth[depthBin + 1];
if (prefixesStack.peek().size() < binEnd) {
ByteString left = prefixesStack.pop();
newTree = new RopeByteString(left, newTree);
} else {
break;
}
}
prefixesStack.push(newTree);
}
}
private int getDepthBinForLength(int length) {
int depth = Arrays.binarySearch(minLengthByDepth, length);
if (depth < 0) {
// It wasn't an exact match, so convert to the index of the containing
// fragment, which is one less even than the insertion point.
int insertionPoint = -(depth + 1);
depth = insertionPoint - 1;
}
return depth;
}
}
/**
* This class is a continuable tree traversal, which keeps the state
* information which would exist on the stack in a recursive traversal instead
* on a stack of "Bread Crumbs". The maximum depth of the stack in this
* iterator is the same as the depth of the tree being traversed.
*
* <p>This iterator is used to implement
* {@link RopeByteString#equalsFragments(ByteString)}.
*/
private static class PieceIterator implements Iterator<LiteralByteString> {
private final Stack<RopeByteString> breadCrumbs =
new Stack<RopeByteString>();
private LiteralByteString next;
private PieceIterator(ByteString root) {
next = getLeafByLeft(root);
}
private LiteralByteString getLeafByLeft(ByteString root) {
ByteString pos = root;
while (pos instanceof RopeByteString) {
RopeByteString rbs = (RopeByteString) pos;
breadCrumbs.push(rbs);
pos = rbs.left;
}
return (LiteralByteString) pos;
}
private LiteralByteString getNextNonEmptyLeaf() {
while (true) {
// Almost always, we go through this loop exactly once. However, if
// we discover an empty string in the rope, we toss it and try again.
if (breadCrumbs.isEmpty()) {
return null;
} else {
LiteralByteString result = getLeafByLeft(breadCrumbs.pop().right);
if (!result.isEmpty()) {
return result;
}
}
}
}
public boolean hasNext() {
return next != null;
}
/**
* Returns the next item and advances one {@code LiteralByteString}.
*
* @return next non-empty LiteralByteString or {@code null}
*/
public LiteralByteString next() {
if (next == null) {
throw new NoSuchElementException();
}
LiteralByteString result = next;
next = getNextNonEmptyLeaf();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// =================================================================
// ByteIterator
@Override
public ByteIterator iterator() {
return new RopeByteIterator();
}
private class RopeByteIterator implements ByteString.ByteIterator {
private final PieceIterator pieces;
private ByteIterator bytes;
int bytesRemaining;
private RopeByteIterator() {
pieces = new PieceIterator(RopeByteString.this);
bytes = pieces.next().iterator();
bytesRemaining = size();
}
public boolean hasNext() {
return (bytesRemaining > 0);
}
public Byte next() {
return nextByte(); // Does not instantiate a Byte
}
public byte nextByte() {
if (!bytes.hasNext()) {
bytes = pieces.next().iterator();
}
--bytesRemaining;
return bytes.nextByte();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* This class is the {@link RopeByteString} equivalent for
* {@link ByteArrayInputStream}.
*/
private class RopeInputStream extends InputStream {
// Iterates through the pieces of the rope
private PieceIterator pieceIterator;
// The current piece
private LiteralByteString currentPiece;
// The size of the current piece
private int currentPieceSize;
// The index of the next byte to read in the current piece
private int currentPieceIndex;
// The offset of the start of the current piece in the rope byte string
private int currentPieceOffsetInRope;
// Offset in the buffer at which user called mark();
private int mark;
public RopeInputStream() {
initialize();
}
@Override
public int read(byte b[], int offset, int length) {
if (b == null) {
throw new NullPointerException();
} else if (offset < 0 || length < 0 || length > b.length - offset) {
throw new IndexOutOfBoundsException();
}
return readSkipInternal(b, offset, length);
}
@Override
public long skip(long length) {
if (length < 0) {
throw new IndexOutOfBoundsException();
} else if (length > Integer.MAX_VALUE) {
length = Integer.MAX_VALUE;
}
return readSkipInternal(null, 0, (int) length);
}
/**
* Internal implementation of read and skip. If b != null, then read the
* next {@code length} bytes into the buffer {@code b} at
* offset {@code offset}. If b == null, then skip the next {@code length)
* bytes.
* <p>
* This method assumes that all error checking has already happened.
* <p>
* Returns the actual number of bytes read or skipped.
*/
private int readSkipInternal(byte b[], int offset, int length) {
int bytesRemaining = length;
while (bytesRemaining > 0) {
advanceIfCurrentPieceFullyRead();
if (currentPiece == null) {
if (bytesRemaining == length) {
// We didn't manage to read anything
return -1;
}
break;
} else {
// Copy the bytes from this piece.
int currentPieceRemaining = currentPieceSize - currentPieceIndex;
int count = Math.min(currentPieceRemaining, bytesRemaining);
if (b != null) {
currentPiece.copyTo(b, currentPieceIndex, offset, count);
offset += count;
}
currentPieceIndex += count;
bytesRemaining -= count;
}
}
// Return the number of bytes read.
return length - bytesRemaining;
}
@Override
public int read() throws IOException {
advanceIfCurrentPieceFullyRead();
if (currentPiece == null) {
return -1;
} else {
return currentPiece.byteAt(currentPieceIndex++) & 0xFF;
}
}
@Override
public int available() throws IOException {
int bytesRead = currentPieceOffsetInRope + currentPieceIndex;
return RopeByteString.this.size() - bytesRead;
}
@Override
public boolean markSupported() {
return true;
}
@Override
public void mark(int readAheadLimit) {
// Set the mark to our position in the byte string
mark = currentPieceOffsetInRope + currentPieceIndex;
}
@Override
public synchronized void reset() {
// Just reinitialize and skip the specified number of bytes.
initialize();
readSkipInternal(null, 0, mark);
}
/** Common initialization code used by both the constructor and reset() */
private void initialize() {
pieceIterator = new PieceIterator(RopeByteString.this);
currentPiece = pieceIterator.next();
currentPieceSize = currentPiece.size();
currentPieceIndex = 0;
currentPieceOffsetInRope = 0;
}
/**
* Skips to the next piece if we have read all the data in the current
* piece. Sets currentPiece to null if we have reached the end of the
* input.
*/
private void advanceIfCurrentPieceFullyRead() {
if (currentPiece != null && currentPieceIndex == currentPieceSize) {
// Generally, we can only go through this loop at most once, since
// empty strings can't end up in a rope. But better to test.
currentPieceOffsetInRope += currentPieceSize;
currentPieceIndex = 0;
if (pieceIterator.hasNext()) {
currentPiece = pieceIterator.next();
currentPieceSize = currentPiece.size();
} else {
currentPiece = null;
currentPieceSize = 0;
}
}
}
}
}

View File

@ -0,0 +1,47 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Interface for an RPC callback, normally called when an RPC completes.
* {@code ParameterType} is normally the method's response message type.
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcCallback<ParameterType> {
void run(ParameterType parameter);
}

View File

@ -0,0 +1,71 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
* communication line to a {@link Service} which can be used to call that
* {@link Service}'s methods. The {@link Service} may be running on another
* machine. Normally, you should not call an {@code RpcChannel} directly, but
* instead construct a stub {@link Service} wrapping it. Example:
*
* <pre>
* RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
* RpcController controller = rpcImpl.newController();
* MyService service = MyService.newStub(channel);
* service.myMethod(controller, request, callback);
* </pre>
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcChannel {
/**
* Call the given method of the remote service. This method is similar to
* {@code Service.callMethod()} with one important difference: the caller
* decides the types of the {@code Message} objects, not the callee. The
* request may be of any type as long as
* {@code request.getDescriptor() == method.getInputType()}.
* The response passed to the callback will be of the same type as
* {@code responsePrototype} (which must have
* {@code getDescriptor() == method.getOutputType()}).
*/
void callMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
Message responsePrototype,
RpcCallback<Message> done);
}

View File

@ -0,0 +1,118 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* <p>An {@code RpcController} mediates a single method call. The primary
* purpose of the controller is to provide a way to manipulate settings
* specific to the RPC implementation and to find out about RPC-level errors.
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* <p>The methods provided by the {@code RpcController} interface are intended
* to be a "least common denominator" set of features which we expect all
* implementations to support. Specific implementations may provide more
* advanced features (e.g. deadline propagation).
*
* @author kenton@google.com Kenton Varda
*/
public interface RpcController {
// -----------------------------------------------------------------
// These calls may be made from the client side only. Their results
// are undefined on the server side (may throw RuntimeExceptions).
/**
* Resets the RpcController to its initial state so that it may be reused in
* a new call. This can be called from the client side only. It must not
* be called while an RPC is in progress.
*/
void reset();
/**
* After a call has finished, returns true if the call failed. The possible
* reasons for failure depend on the RPC implementation. {@code failed()}
* most only be called on the client side, and must not be called before a
* call has finished.
*/
boolean failed();
/**
* If {@code failed()} is {@code true}, returns a human-readable description
* of the error.
*/
String errorText();
/**
* Advises the RPC system that the caller desires that the RPC call be
* canceled. The RPC system may cancel it immediately, may wait awhile and
* then cancel it, or may not even cancel the call at all. If the call is
* canceled, the "done" callback will still be called and the RpcController
* will indicate that the call failed at that time.
*/
void startCancel();
// -----------------------------------------------------------------
// These calls may be made from the server side only. Their results
// are undefined on the client side (may throw RuntimeExceptions).
/**
* Causes {@code failed()} to return true on the client side. {@code reason}
* will be incorporated into the message returned by {@code errorText()}.
* If you find you need to return machine-readable information about
* failures, you should incorporate it into your response protocol buffer
* and should NOT call {@code setFailed()}.
*/
void setFailed(String reason);
/**
* If {@code true}, indicates that the client canceled the RPC, so the server
* may as well give up on replying to it. This method must be called on the
* server side only. The server should still call the final "done" callback.
*/
boolean isCanceled();
/**
* Asks that the given callback be called when the RPC is canceled. The
* parameter passed to the callback will always be {@code null}. The
* callback will always be called exactly once. If the RPC completes without
* being canceled, the callback will be called after completion. If the RPC
* has already been canceled when NotifyOnCancel() is called, the callback
* will be called immediately.
*
* <p>{@code notifyOnCancel()} must be called no more than once per request.
* It must be called on the server side only.
*/
void notifyOnCancel(RpcCallback<Object> callback);
}

View File

@ -0,0 +1,135 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Grab-bag of utility functions useful when dealing with RPCs.
*
* @author kenton@google.com Kenton Varda
*/
public final class RpcUtil {
private RpcUtil() {}
/**
* Take an {@code RpcCallback<Message>} and convert it to an
* {@code RpcCallback} accepting a specific message type. This is always
* type-safe (parameter type contravariance).
*/
@SuppressWarnings("unchecked")
public static <Type extends Message> RpcCallback<Type>
specializeCallback(final RpcCallback<Message> originalCallback) {
return (RpcCallback<Type>)originalCallback;
// The above cast works, but only due to technical details of the Java
// implementation. A more theoretically correct -- but less efficient --
// implementation would be as follows:
// return new RpcCallback<Type>() {
// public void run(Type parameter) {
// originalCallback.run(parameter);
// }
// };
}
/**
* Take an {@code RpcCallback} accepting a specific message type and convert
* it to an {@code RpcCallback<Message>}. The generalized callback will
* accept any message object which has the same descriptor, and will convert
* it to the correct class before calling the original callback. However,
* if the generalized callback is given a message with a different descriptor,
* an exception will be thrown.
*/
public static <Type extends Message>
RpcCallback<Message> generalizeCallback(
final RpcCallback<Type> originalCallback,
final Class<Type> originalClass,
final Type defaultInstance) {
return new RpcCallback<Message>() {
public void run(final Message parameter) {
Type typedParameter;
try {
typedParameter = originalClass.cast(parameter);
} catch (ClassCastException ignored) {
typedParameter = copyAsType(defaultInstance, parameter);
}
originalCallback.run(typedParameter);
}
};
}
/**
* Creates a new message of type "Type" which is a copy of "source". "source"
* must have the same descriptor but may be a different class (e.g.
* DynamicMessage).
*/
@SuppressWarnings("unchecked")
private static <Type extends Message> Type copyAsType(
final Type typeDefaultInstance, final Message source) {
return (Type)typeDefaultInstance.newBuilderForType()
.mergeFrom(source)
.build();
}
/**
* Creates a callback which can only be called once. This may be useful for
* security, when passing a callback to untrusted code: most callbacks do
* not expect to be called more than once, so doing so may expose bugs if it
* is not prevented.
*/
public static <ParameterType>
RpcCallback<ParameterType> newOneTimeCallback(
final RpcCallback<ParameterType> originalCallback) {
return new RpcCallback<ParameterType>() {
private boolean alreadyCalled = false;
public void run(final ParameterType parameter) {
synchronized(this) {
if (alreadyCalled) {
throw new AlreadyCalledException();
}
alreadyCalled = true;
}
originalCallback.run(parameter);
}
};
}
/**
* Exception thrown when a one-time callback is called more than once.
*/
public static final class AlreadyCalledException extends RuntimeException {
private static final long serialVersionUID = 5469741279507848266L;
public AlreadyCalledException() {
super("This RpcCallback was already called and cannot be called " +
"multiple times.");
}
}
}

View File

@ -0,0 +1,117 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Abstract base interface for protocol-buffer-based RPC services. Services
* themselves are abstract classes (implemented either by servers or as
* stubs), but they subclass this base interface. The methods of this
* interface can be used to call the methods of the service without knowing
* its exact type at compile time (analogous to the Message interface).
*
* <p>Starting with version 2.3.0, RPC implementations should not try to build
* on this, but should instead provide code generator plugins which generate
* code specific to the particular RPC implementation. This way the generated
* code can be more appropriate for the implementation in use and can avoid
* unnecessary layers of indirection.
*
* @author kenton@google.com Kenton Varda
*/
public interface Service {
/**
* Get the {@code ServiceDescriptor} describing this service and its methods.
*/
Descriptors.ServiceDescriptor getDescriptorForType();
/**
* <p>Call a method of the service specified by MethodDescriptor. This is
* normally implemented as a simple {@code switch()} that calls the standard
* definitions of the service's methods.
*
* <p>Preconditions:
* <ul>
* <li>{@code method.getService() == getDescriptorForType()}
* <li>{@code request} is of the exact same class as the object returned by
* {@code getRequestPrototype(method)}.
* <li>{@code controller} is of the correct type for the RPC implementation
* being used by this Service. For stubs, the "correct type" depends
* on the RpcChannel which the stub is using. Server-side Service
* implementations are expected to accept whatever type of
* {@code RpcController} the server-side RPC implementation uses.
* </ul>
*
* <p>Postconditions:
* <ul>
* <li>{@code done} will be called when the method is complete. This may be
* before {@code callMethod()} returns or it may be at some point in
* the future.
* <li>The parameter to {@code done} is the response. It must be of the
* exact same type as would be returned by
* {@code getResponsePrototype(method)}.
* <li>If the RPC failed, the parameter to {@code done} will be
* {@code null}. Further details about the failure can be found by
* querying {@code controller}.
* </ul>
*/
void callMethod(Descriptors.MethodDescriptor method,
RpcController controller,
Message request,
RpcCallback<Message> done);
/**
* <p>{@code callMethod()} requires that the request passed in is of a
* particular subclass of {@code Message}. {@code getRequestPrototype()}
* gets the default instances of this type for a given method. You can then
* call {@code Message.newBuilderForType()} on this instance to
* construct a builder to build an object which you can then pass to
* {@code callMethod()}.
*
* <p>Example:
* <pre>
* MethodDescriptor method =
* service.getDescriptorForType().findMethodByName("Foo");
* Message request =
* stub.getRequestPrototype(method).newBuilderForType()
* .mergeFrom(input).build();
* service.callMethod(method, request, callback);
* </pre>
*/
Message getRequestPrototype(Descriptors.MethodDescriptor method);
/**
* Like {@code getRequestPrototype()}, but gets a prototype of the response
* message. {@code getResponsePrototype()} is generally not needed because
* the {@code Service} implementation constructs the response message itself,
* but it may be useful in some cases to know ahead of time what type of
* object will be returned.
*/
Message getResponsePrototype(Descriptors.MethodDescriptor method);
}

View File

@ -0,0 +1,52 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* Thrown by blocking RPC methods when a failure occurs.
*
* @author cpovirk@google.com (Chris Povirk)
*/
public class ServiceException extends Exception {
private static final long serialVersionUID = -1219262335729891920L;
public ServiceException(final String message) {
super(message);
}
public ServiceException(final Throwable cause) {
super(cause);
}
public ServiceException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,241 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* {@code SingleFieldBuilder} implements a structure that a protocol
* message uses to hold a single field of another protocol message. It supports
* the classical use case of setting an immutable {@link Message} as the value
* of the field and is highly optimized around this.
* <br>
* It also supports the additional use case of setting a {@link Message.Builder}
* as the field and deferring conversion of that {@code Builder}
* to an immutable {@code Message}. In this way, it's possible to maintain
* a tree of {@code Builder}'s that acts as a fully read/write data
* structure.
* <br>
* Logically, one can think of a tree of builders as converting the entire tree
* to messages when build is called on the root or when any method is called
* that desires a Message instead of a Builder. In terms of the implementation,
* the {@code SingleFieldBuilder} and {@code RepeatedFieldBuilder}
* classes cache messages that were created so that messages only need to be
* created when some change occured in its builder or a builder for one of its
* descendants.
*
* @param <MType> the type of message for the field
* @param <BType> the type of builder for the field
* @param <IType> the common interface for the message and the builder
*
* @author jonp@google.com (Jon Perlow)
*/
public class SingleFieldBuilder
<MType extends GeneratedMessage,
BType extends GeneratedMessage.Builder,
IType extends MessageOrBuilder>
implements GeneratedMessage.BuilderParent {
// Parent to send changes to.
private GeneratedMessage.BuilderParent parent;
// Invariant: one of builder or message fields must be non-null.
// If set, this is the case where we are backed by a builder. In this case,
// message field represents a cached message for the builder (or null if
// there is no cached message).
private BType builder;
// If builder is non-null, this represents a cached message from the builder.
// If builder is null, this is the authoritative message for the field.
private MType message;
// Indicates that we've built a message and so we are now obligated
// to dispatch dirty invalidations. See GeneratedMessage.BuilderListener.
private boolean isClean;
public SingleFieldBuilder(
MType message,
GeneratedMessage.BuilderParent parent,
boolean isClean) {
if (message == null) {
throw new NullPointerException();
}
this.message = message;
this.parent = parent;
this.isClean = isClean;
}
public void dispose() {
// Null out parent so we stop sending it invalidations.
parent = null;
}
/**
* Get the message for the field. If the message is currently stored
* as a {@code Builder}, it is converted to a {@code Message} by
* calling {@link Message.Builder#buildPartial} on it. If no message has
* been set, returns the default instance of the message.
*
* @return the message for the field
*/
@SuppressWarnings("unchecked")
public MType getMessage() {
if (message == null) {
// If message is null, the invariant is that we must be have a builder.
message = (MType) builder.buildPartial();
}
return message;
}
/**
* Builds the message and returns it.
*
* @return the message
*/
public MType build() {
// Now that build has been called, we are required to dispatch
// invalidations.
isClean = true;
return getMessage();
}
/**
* Gets a builder for the field. If no builder has been created yet, a
* builder is created on demand by calling {@link Message#toBuilder}.
*
* @return The builder for the field
*/
@SuppressWarnings("unchecked")
public BType getBuilder() {
if (builder == null) {
// builder.mergeFrom() on a fresh builder
// does not create any sub-objects with independent clean/dirty states,
// therefore setting the builder itself to clean without actually calling
// build() cannot break any invariants.
builder = (BType) message.newBuilderForType(this);
builder.mergeFrom(message); // no-op if message is the default message
builder.markClean();
}
return builder;
}
/**
* Gets the base class interface for the field. This may either be a builder
* or a message. It will return whatever is more efficient.
*
* @return the message or builder for the field as the base class interface
*/
@SuppressWarnings("unchecked")
public IType getMessageOrBuilder() {
if (builder != null) {
return (IType) builder;
} else {
return (IType) message;
}
}
/**
* Sets a message for the field replacing any existing value.
*
* @param message the message to set
* @return the builder
*/
public SingleFieldBuilder<MType, BType, IType> setMessage(
MType message) {
if (message == null) {
throw new NullPointerException();
}
this.message = message;
if (builder != null) {
builder.dispose();
builder = null;
}
onChanged();
return this;
}
/**
* Merges the field from another field.
*
* @param value the value to merge from
* @return the builder
*/
public SingleFieldBuilder<MType, BType, IType> mergeFrom(
MType value) {
if (builder == null && message == message.getDefaultInstanceForType()) {
message = value;
} else {
getBuilder().mergeFrom(value);
}
onChanged();
return this;
}
/**
* Clears the value of the field.
*
* @return the builder
*/
@SuppressWarnings("unchecked")
public SingleFieldBuilder<MType, BType, IType> clear() {
message = (MType) (message != null ?
message.getDefaultInstanceForType() :
builder.getDefaultInstanceForType());
if (builder != null) {
builder.dispose();
builder = null;
}
onChanged();
return this;
}
/**
* Called when a the builder or one of its nested children has changed
* and any parent should be notified of its invalidation.
*/
private void onChanged() {
// If builder is null, this is the case where onChanged is being called
// from setMessage or clear.
if (builder != null) {
message = null;
}
if (isClean && parent != null) {
parent.markDirty();
// Don't keep dispatching invalidations until build is called again.
isClean = false;
}
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void markDirty() {
onChanged();
}
}

View File

@ -0,0 +1,618 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
/**
* A custom map implementation from FieldDescriptor to Object optimized to
* minimize the number of memory allocations for instances with a small number
* of mappings. The implementation stores the first {@code k} mappings in an
* array for a configurable value of {@code k}, allowing direct access to the
* corresponding {@code Entry}s without the need to create an Iterator. The
* remaining entries are stored in an overflow map. Iteration over the entries
* in the map should be done as follows:
*
* <pre> {@code
* for (int i = 0; i < fieldMap.getNumArrayEntries(); i++) {
* process(fieldMap.getArrayEntryAt(i));
* }
* for (Map.Entry<K, V> entry : fieldMap.getOverflowEntries()) {
* process(entry);
* }
* }</pre>
*
* The resulting iteration is in order of ascending field tag number. The
* object returned by {@link #entrySet()} adheres to the same contract but is
* less efficient as it necessarily involves creating an object for iteration.
* <p>
* The tradeoff for this memory efficiency is that the worst case running time
* of the {@code put()} operation is {@code O(k + lg n)}, which happens when
* entries are added in descending order. {@code k} should be chosen such that
* it covers enough common cases without adversely affecting larger maps. In
* practice, the worst case scenario does not happen for extensions because
* extension fields are serialized and deserialized in order of ascending tag
* number, but the worst case scenario can happen for DynamicMessages.
* <p>
* The running time for all other operations is similar to that of
* {@code TreeMap}.
* <p>
* Instances are not thread-safe until {@link #makeImmutable()} is called,
* after which any modifying operation will result in an
* {@link UnsupportedOperationException}.
*
* @author darick@google.com Darick Tong
*/
// This class is final for all intents and purposes because the constructor is
// private. However, the FieldDescriptor-specific logic is encapsulated in
// a subclass to aid testability of the core logic.
class SmallSortedMap<K extends Comparable<K>, V> extends AbstractMap<K, V> {
/**
* Creates a new instance for mapping FieldDescriptors to their values.
* The {@link #makeImmutable()} implementation will convert the List values
* of any repeated fields to unmodifiable lists.
*
* @param arraySize The size of the entry array containing the
* lexicographically smallest mappings.
*/
static <FieldDescriptorType extends
FieldSet.FieldDescriptorLite<FieldDescriptorType>>
SmallSortedMap<FieldDescriptorType, Object> newFieldMap(int arraySize) {
return new SmallSortedMap<FieldDescriptorType, Object>(arraySize) {
@Override
@SuppressWarnings("unchecked")
public void makeImmutable() {
if (!isImmutable()) {
for (int i = 0; i < getNumArrayEntries(); i++) {
final Map.Entry<FieldDescriptorType, Object> entry =
getArrayEntryAt(i);
if (entry.getKey().isRepeated()) {
final List value = (List) entry.getValue();
entry.setValue(Collections.unmodifiableList(value));
}
}
for (Map.Entry<FieldDescriptorType, Object> entry :
getOverflowEntries()) {
if (entry.getKey().isRepeated()) {
final List value = (List) entry.getValue();
entry.setValue(Collections.unmodifiableList(value));
}
}
}
super.makeImmutable();
}
};
}
/**
* Creates a new instance for testing.
*
* @param arraySize The size of the entry array containing the
* lexicographically smallest mappings.
*/
static <K extends Comparable<K>, V> SmallSortedMap<K, V> newInstanceForTest(
int arraySize) {
return new SmallSortedMap<K, V>(arraySize);
}
private final int maxArraySize;
// The "entry array" is actually a List because generic arrays are not
// allowed. ArrayList also nicely handles the entry shifting on inserts and
// removes.
private List<Entry> entryList;
private Map<K, V> overflowEntries;
private boolean isImmutable;
// The EntrySet is a stateless view of the Map. It's initialized the first
// time it is requested and reused henceforth.
private volatile EntrySet lazyEntrySet;
/**
* @code arraySize Size of the array in which the lexicographically smallest
* mappings are stored. (i.e. the {@code k} referred to in the class
* documentation).
*/
private SmallSortedMap(int arraySize) {
this.maxArraySize = arraySize;
this.entryList = Collections.emptyList();
this.overflowEntries = Collections.emptyMap();
}
/** Make this map immutable from this point forward. */
public void makeImmutable() {
if (!isImmutable) {
// Note: There's no need to wrap the entryList in an unmodifiableList
// because none of the list's accessors are exposed. The iterator() of
// overflowEntries, on the other hand, is exposed so it must be made
// unmodifiable.
overflowEntries = overflowEntries.isEmpty() ?
Collections.<K, V>emptyMap() :
Collections.unmodifiableMap(overflowEntries);
isImmutable = true;
}
}
/** @return Whether {@link #makeImmutable()} has been called. */
public boolean isImmutable() {
return isImmutable;
}
/** @return The number of entries in the entry array. */
public int getNumArrayEntries() {
return entryList.size();
}
/** @return The array entry at the given {@code index}. */
public Map.Entry<K, V> getArrayEntryAt(int index) {
return entryList.get(index);
}
/** @return There number of overflow entries. */
public int getNumOverflowEntries() {
return overflowEntries.size();
}
/** @return An iterable over the overflow entries. */
public Iterable<Map.Entry<K, V>> getOverflowEntries() {
return overflowEntries.isEmpty() ?
EmptySet.<Map.Entry<K, V>>iterable() :
overflowEntries.entrySet();
}
@Override
public int size() {
return entryList.size() + overflowEntries.size();
}
/**
* The implementation throws a {@code ClassCastException} if o is not an
* object of type {@code K}.
*
* {@inheritDoc}
*/
@Override
public boolean containsKey(Object o) {
@SuppressWarnings("unchecked")
final K key = (K) o;
return binarySearchInArray(key) >= 0 || overflowEntries.containsKey(key);
}
/**
* The implementation throws a {@code ClassCastException} if o is not an
* object of type {@code K}.
*
* {@inheritDoc}
*/
@Override
public V get(Object o) {
@SuppressWarnings("unchecked")
final K key = (K) o;
final int index = binarySearchInArray(key);
if (index >= 0) {
return entryList.get(index).getValue();
}
return overflowEntries.get(key);
}
@Override
public V put(K key, V value) {
checkMutable();
final int index = binarySearchInArray(key);
if (index >= 0) {
// Replace existing array entry.
return entryList.get(index).setValue(value);
}
ensureEntryArrayMutable();
final int insertionPoint = -(index + 1);
if (insertionPoint >= maxArraySize) {
// Put directly in overflow.
return getOverflowEntriesMutable().put(key, value);
}
// Insert new Entry in array.
if (entryList.size() == maxArraySize) {
// Shift the last array entry into overflow.
final Entry lastEntryInArray = entryList.remove(maxArraySize - 1);
getOverflowEntriesMutable().put(lastEntryInArray.getKey(),
lastEntryInArray.getValue());
}
entryList.add(insertionPoint, new Entry(key, value));
return null;
}
@Override
public void clear() {
checkMutable();
if (!entryList.isEmpty()) {
entryList.clear();
}
if (!overflowEntries.isEmpty()) {
overflowEntries.clear();
}
}
/**
* The implementation throws a {@code ClassCastException} if o is not an
* object of type {@code K}.
*
* {@inheritDoc}
*/
@Override
public V remove(Object o) {
checkMutable();
@SuppressWarnings("unchecked")
final K key = (K) o;
final int index = binarySearchInArray(key);
if (index >= 0) {
return removeArrayEntryAt(index);
}
// overflowEntries might be Collections.unmodifiableMap(), so only
// call remove() if it is non-empty.
if (overflowEntries.isEmpty()) {
return null;
} else {
return overflowEntries.remove(key);
}
}
private V removeArrayEntryAt(int index) {
checkMutable();
final V removed = entryList.remove(index).getValue();
if (!overflowEntries.isEmpty()) {
// Shift the first entry in the overflow to be the last entry in the
// array.
final Iterator<Map.Entry<K, V>> iterator =
getOverflowEntriesMutable().entrySet().iterator();
entryList.add(new Entry(iterator.next()));
iterator.remove();
}
return removed;
}
/**
* @param key The key to find in the entry array.
* @return The returned integer position follows the same semantics as the
* value returned by {@link java.util.Arrays#binarySearch()}.
*/
private int binarySearchInArray(K key) {
int left = 0;
int right = entryList.size() - 1;
// Optimization: For the common case in which entries are added in
// ascending tag order, check the largest element in the array before
// doing a full binary search.
if (right >= 0) {
int cmp = key.compareTo(entryList.get(right).getKey());
if (cmp > 0) {
return -(right + 2); // Insert point is after "right".
} else if (cmp == 0) {
return right;
}
}
while (left <= right) {
int mid = (left + right) / 2;
int cmp = key.compareTo(entryList.get(mid).getKey());
if (cmp < 0) {
right = mid - 1;
} else if (cmp > 0) {
left = mid + 1;
} else {
return mid;
}
}
return -(left + 1);
}
/**
* Similar to the AbstractMap implementation of {@code keySet()} and
* {@code values()}, the entry set is created the first time this method is
* called, and returned in response to all subsequent calls.
*
* {@inheritDoc}
*/
@Override
public Set<Map.Entry<K, V>> entrySet() {
if (lazyEntrySet == null) {
lazyEntrySet = new EntrySet();
}
return lazyEntrySet;
}
/**
* @throws UnsupportedOperationException if {@link #makeImmutable()} has
* has been called.
*/
private void checkMutable() {
if (isImmutable) {
throw new UnsupportedOperationException();
}
}
/**
* @return a {@link SortedMap} to which overflow entries mappings can be
* added or removed.
* @throws UnsupportedOperationException if {@link #makeImmutable()} has been
* called.
*/
@SuppressWarnings("unchecked")
private SortedMap<K, V> getOverflowEntriesMutable() {
checkMutable();
if (overflowEntries.isEmpty() && !(overflowEntries instanceof TreeMap)) {
overflowEntries = new TreeMap<K, V>();
}
return (SortedMap<K, V>) overflowEntries;
}
/**
* Lazily creates the entry list. Any code that adds to the list must first
* call this method.
*/
private void ensureEntryArrayMutable() {
checkMutable();
if (entryList.isEmpty() && !(entryList instanceof ArrayList)) {
entryList = new ArrayList<Entry>(maxArraySize);
}
}
/**
* Entry implementation that implements Comparable in order to support
* binary search within the entry array. Also checks mutability in
* {@link #setValue()}.
*/
private class Entry implements Map.Entry<K, V>, Comparable<Entry> {
private final K key;
private V value;
Entry(Map.Entry<K, V> copy) {
this(copy.getKey(), copy.getValue());
}
Entry(K key, V value) {
this.key = key;
this.value = value;
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public K getKey() {
return key;
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public V getValue() {
return value;
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public int compareTo(Entry other) {
return getKey().compareTo(other.getKey());
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public V setValue(V newValue) {
checkMutable();
final V oldValue = this.value;
this.value = newValue;
return oldValue;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Map.Entry)) {
return false;
}
@SuppressWarnings("unchecked")
Map.Entry<?, ?> other = (Map.Entry<?, ?>) o;
return equals(key, other.getKey()) && equals(value, other.getValue());
}
@Override
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
@Override
public String toString() {
return key + "=" + value;
}
/** equals() that handles null values. */
private boolean equals(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
}
/**
* Stateless view of the entries in the field map.
*/
private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new EntryIterator();
}
@Override
public int size() {
return SmallSortedMap.this.size();
}
/**
* Throws a {@link ClassCastException} if o is not of the expected type.
*
* {@inheritDoc}
*/
@Override
public boolean contains(Object o) {
@SuppressWarnings("unchecked")
final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
final V existing = get(entry.getKey());
final V value = entry.getValue();
return existing == value ||
(existing != null && existing.equals(value));
}
@Override
public boolean add(Map.Entry<K, V> entry) {
if (!contains(entry)) {
put(entry.getKey(), entry.getValue());
return true;
}
return false;
}
/**
* Throws a {@link ClassCastException} if o is not of the expected type.
*
* {@inheritDoc}
*/
@Override
public boolean remove(Object o) {
@SuppressWarnings("unchecked")
final Map.Entry<K, V> entry = (Map.Entry<K, V>) o;
if (contains(entry)) {
SmallSortedMap.this.remove(entry.getKey());
return true;
}
return false;
}
@Override
public void clear() {
SmallSortedMap.this.clear();
}
}
/**
* Iterator implementation that switches from the entry array to the overflow
* entries appropriately.
*/
private class EntryIterator implements Iterator<Map.Entry<K, V>> {
private int pos = -1;
private boolean nextCalledBeforeRemove;
private Iterator<Map.Entry<K, V>> lazyOverflowIterator;
//@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasNext() {
return (pos + 1) < entryList.size() ||
getOverflowIterator().hasNext();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public Map.Entry<K, V> next() {
nextCalledBeforeRemove = true;
// Always increment pos so that we know whether the last returned value
// was from the array or from overflow.
if (++pos < entryList.size()) {
return entryList.get(pos);
}
return getOverflowIterator().next();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void remove() {
if (!nextCalledBeforeRemove) {
throw new IllegalStateException("remove() was called before next()");
}
nextCalledBeforeRemove = false;
checkMutable();
if (pos < entryList.size()) {
removeArrayEntryAt(pos--);
} else {
getOverflowIterator().remove();
}
}
/**
* It is important to create the overflow iterator only after the array
* entries have been iterated over because the overflow entry set changes
* when the client calls remove() on the array entries, which invalidates
* any existing iterators.
*/
private Iterator<Map.Entry<K, V>> getOverflowIterator() {
if (lazyOverflowIterator == null) {
lazyOverflowIterator = overflowEntries.entrySet().iterator();
}
return lazyOverflowIterator;
}
}
/**
* Helper class that holds immutable instances of an Iterable/Iterator that
* we return when the overflow entries is empty. This eliminates the creation
* of an Iterator object when there is nothing to iterate over.
*/
private static class EmptySet {
private static final Iterator<Object> ITERATOR = new Iterator<Object>() {
//@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasNext() {
return false;
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public Object next() {
throw new NoSuchElementException();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void remove() {
throw new UnsupportedOperationException();
}
};
private static final Iterable<Object> ITERABLE = new Iterable<Object>() {
//@Override (Java 1.6 override semantics, but we must support 1.5)
public Iterator<Object> iterator() {
return ITERATOR;
}
};
@SuppressWarnings("unchecked")
static <T> Iterable<T> iterable() {
return (Iterable<T>) ITERABLE;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.Collections;
import java.util.List;
/**
* Thrown when attempting to build a protocol message that is missing required
* fields. This is a {@code RuntimeException} because it normally represents
* a programming error: it happens when some code which constructs a message
* fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
* throw this; they throw an {@link InvalidProtocolBufferException} if
* required fields are missing, because it is not a programming error to
* receive an incomplete message. In other words,
* {@code UninitializedMessageException} should never be thrown by correct
* code, but {@code InvalidProtocolBufferException} might be.
*
* @author kenton@google.com Kenton Varda
*/
public class UninitializedMessageException extends RuntimeException {
private static final long serialVersionUID = -7466929953374883507L;
public UninitializedMessageException(final MessageLite message) {
super("Message was missing required fields. (Lite runtime could not " +
"determine which fields were missing).");
missingFields = null;
}
public UninitializedMessageException(final List<String> missingFields) {
super(buildDescription(missingFields));
this.missingFields = missingFields;
}
private final List<String> missingFields;
/**
* Get a list of human-readable names of required fields missing from this
* message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
* Returns null if the lite runtime was used, since it lacks the ability to
* find missing fields.
*/
public List<String> getMissingFields() {
return Collections.unmodifiableList(missingFields);
}
/**
* Converts this exception to an {@link InvalidProtocolBufferException}.
* When a parsed message is missing required fields, this should be thrown
* instead of {@code UninitializedMessageException}.
*/
public InvalidProtocolBufferException asInvalidProtocolBufferException() {
return new InvalidProtocolBufferException(getMessage());
}
/** Construct the description string for this exception. */
private static String buildDescription(final List<String> missingFields) {
final StringBuilder description =
new StringBuilder("Message missing required fields: ");
boolean first = true;
for (final String field : missingFields) {
if (first) {
first = false;
} else {
description.append(", ");
}
description.append(field);
}
return description.toString();
}
}

View File

@ -0,0 +1,978 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* {@code UnknownFieldSet} is used to keep track of fields which were seen when
* parsing a protocol message but whose field numbers or types are unrecognized.
* This most frequently occurs when new fields are added to a message type
* and then messages containing those fields are read by old software that was
* compiled before the new types were added.
*
* <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
* {@link Message.Builder} contains an {@link Builder}).
*
* <p>Most users will never need to use this class.
*
* @author kenton@google.com Kenton Varda
*/
public final class UnknownFieldSet implements MessageLite {
private UnknownFieldSet() {}
/** Create a new {@link Builder}. */
public static Builder newBuilder() {
return Builder.create();
}
/**
* Create a new {@link Builder} and initialize it to be a copy
* of {@code copyFrom}.
*/
public static Builder newBuilder(final UnknownFieldSet copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code UnknownFieldSet}. */
public static UnknownFieldSet getDefaultInstance() {
return defaultInstance;
}
public UnknownFieldSet getDefaultInstanceForType() {
return defaultInstance;
}
private static final UnknownFieldSet defaultInstance =
new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
/**
* Construct an {@code UnknownFieldSet} around the given map. The map is
* expected to be immutable.
*/
private UnknownFieldSet(final Map<Integer, Field> fields) {
this.fields = fields;
}
private Map<Integer, Field> fields;
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
return (other instanceof UnknownFieldSet) &&
fields.equals(((UnknownFieldSet) other).fields);
}
@Override
public int hashCode() {
return fields.hashCode();
}
/** Get a map of fields in the set by number. */
public Map<Integer, Field> asMap() {
return fields;
}
/** Check if the given field number is present in the set. */
public boolean hasField(final int number) {
return fields.containsKey(number);
}
/**
* Get a field by number. Returns an empty field if not present. Never
* returns {@code null}.
*/
public Field getField(final int number) {
final Field result = fields.get(number);
return (result == null) ? Field.getDefaultInstance() : result;
}
/** Serializes the set and writes it to {@code output}. */
public void writeTo(final CodedOutputStream output) throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeTo(entry.getKey(), output);
}
}
/**
* Converts the set to a string in protocol buffer text format. This is
* just a trivial wrapper around
* {@link TextFormat#printToString(UnknownFieldSet)}.
*/
@Override
public String toString() {
return TextFormat.printToString(this);
}
/**
* Serializes the message to a {@code ByteString} and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public ByteString toByteString() {
try {
final ByteString.CodedBuilder out =
ByteString.newCodedBuilder(getSerializedSize());
writeTo(out.getCodedOutput());
return out.build();
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a ByteString threw an IOException (should " +
"never happen).", e);
}
}
/**
* Serializes the message to a {@code byte} array and returns it. This is
* just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public byte[] toByteArray() {
try {
final byte[] result = new byte[getSerializedSize()];
final CodedOutputStream output = CodedOutputStream.newInstance(result);
writeTo(output);
output.checkNoSpaceLeft();
return result;
} catch (final IOException e) {
throw new RuntimeException(
"Serializing to a byte array threw an IOException " +
"(should never happen).", e);
}
}
/**
* Serializes the message and writes it to {@code output}. This is just a
* trivial wrapper around {@link #writeTo(CodedOutputStream)}.
*/
public void writeTo(final OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
writeTo(codedOutput);
codedOutput.flush();
}
public void writeDelimitedTo(OutputStream output) throws IOException {
final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
codedOutput.writeRawVarint32(getSerializedSize());
writeTo(codedOutput);
codedOutput.flush();
}
/** Get the number of bytes required to encode this set. */
public int getSerializedSize() {
int result = 0;
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSize(entry.getKey());
}
return result;
}
/**
* Serializes the set and writes it to {@code output} using
* {@code MessageSet} wire format.
*/
public void writeAsMessageSetTo(final CodedOutputStream output)
throws IOException {
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
entry.getValue().writeAsMessageSetExtensionTo(
entry.getKey(), output);
}
}
/**
* Get the number of bytes required to encode this set using
* {@code MessageSet} wire format.
*/
public int getSerializedSizeAsMessageSet() {
int result = 0;
for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
result += entry.getValue().getSerializedSizeAsMessageSetExtension(
entry.getKey());
}
return result;
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
/** Parse an {@code UnknownFieldSet} from the given input stream. */
public static UnknownFieldSet parseFrom(final CodedInputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(final ByteString data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
public static UnknownFieldSet parseFrom(final byte[] data)
throws InvalidProtocolBufferException {
return newBuilder().mergeFrom(data).build();
}
/** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
public static UnknownFieldSet parseFrom(final InputStream input)
throws IOException {
return newBuilder().mergeFrom(input).build();
}
public Builder newBuilderForType() {
return newBuilder();
}
public Builder toBuilder() {
return newBuilder().mergeFrom(this);
}
/**
* Builder for {@link UnknownFieldSet}s.
*
* <p>Note that this class maintains {@link Field.Builder}s for all fields
* in the set. Thus, adding one element to an existing {@link Field} does not
* require making a copy. This is important for efficient parsing of
* unknown repeated fields. However, it implies that {@link Field}s cannot
* be constructed independently, nor can two {@link UnknownFieldSet}s share
* the same {@code Field} object.
*
* <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder implements MessageLite.Builder {
// This constructor should never be called directly (except from 'create').
private Builder() {}
private Map<Integer, Field> fields;
// Optimization: We keep around a builder for the last field that was
// modified so that we can efficiently add to it multiple times in a
// row (important when parsing an unknown repeated field).
private int lastFieldNumber;
private Field.Builder lastField;
private static Builder create() {
Builder builder = new Builder();
builder.reinitialize();
return builder;
}
/**
* Get a field builder for the given field number which includes any
* values that already exist.
*/
private Field.Builder getFieldBuilder(final int number) {
if (lastField != null) {
if (number == lastFieldNumber) {
return lastField;
}
// Note: addField() will reset lastField and lastFieldNumber.
addField(lastFieldNumber, lastField.build());
}
if (number == 0) {
return null;
} else {
final Field existing = fields.get(number);
lastFieldNumber = number;
lastField = Field.newBuilder();
if (existing != null) {
lastField.mergeFrom(existing);
}
return lastField;
}
}
/**
* Build the {@link UnknownFieldSet} and return it.
*
* <p>Once {@code build()} has been called, the {@code Builder} will no
* longer be usable. Calling any method after {@code build()} will result
* in undefined behavior and can cause a {@code NullPointerException} to be
* thrown.
*/
public UnknownFieldSet build() {
getFieldBuilder(0); // Force lastField to be built.
final UnknownFieldSet result;
if (fields.isEmpty()) {
result = getDefaultInstance();
} else {
result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
}
fields = null;
return result;
}
public UnknownFieldSet buildPartial() {
// No required fields, so this is the same as build().
return build();
}
@Override
public Builder clone() {
getFieldBuilder(0); // Force lastField to be built.
return UnknownFieldSet.newBuilder().mergeFrom(
new UnknownFieldSet(fields));
}
public UnknownFieldSet getDefaultInstanceForType() {
return UnknownFieldSet.getDefaultInstance();
}
private void reinitialize() {
fields = Collections.emptyMap();
lastFieldNumber = 0;
lastField = null;
}
/** Reset the builder to an empty set. */
public Builder clear() {
reinitialize();
return this;
}
/**
* Merge the fields from {@code other} into this set. If a field number
* exists in both sets, {@code other}'s values for that field will be
* appended to the values in this set.
*/
public Builder mergeFrom(final UnknownFieldSet other) {
if (other != getDefaultInstance()) {
for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
mergeField(entry.getKey(), entry.getValue());
}
}
return this;
}
/**
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, the two are merged.
*/
public Builder mergeField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
if (hasField(number)) {
getFieldBuilder(number).mergeFrom(field);
} else {
// Optimization: We could call getFieldBuilder(number).mergeFrom(field)
// in this case, but that would create a copy of the Field object.
// We'd rather reuse the one passed to us, so call addField() instead.
addField(number, field);
}
return this;
}
/**
* Convenience method for merging a new field containing a single varint
* value. This is used in particular when an unknown enum value is
* encountered.
*/
public Builder mergeVarintField(final int number, final int value) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
getFieldBuilder(number).addVarint(value);
return this;
}
/** Check if the given field number is present in the set. */
public boolean hasField(final int number) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
return number == lastFieldNumber || fields.containsKey(number);
}
/**
* Add a field to the {@code UnknownFieldSet}. If a field with the same
* number already exists, it is removed.
*/
public Builder addField(final int number, final Field field) {
if (number == 0) {
throw new IllegalArgumentException("Zero is not a valid field number.");
}
if (lastField != null && lastFieldNumber == number) {
// Discard this.
lastField = null;
lastFieldNumber = 0;
}
if (fields.isEmpty()) {
fields = new TreeMap<Integer,Field>();
}
fields.put(number, field);
return this;
}
/**
* Get all present {@code Field}s as an immutable {@code Map}. If more
* fields are added, the changes may or may not be reflected in this map.
*/
public Map<Integer, Field> asMap() {
getFieldBuilder(0); // Force lastField to be built.
return Collections.unmodifiableMap(fields);
}
/**
* Parse an entire message from {@code input} and merge its fields into
* this set.
*/
public Builder mergeFrom(final CodedInputStream input) throws IOException {
while (true) {
final int tag = input.readTag();
if (tag == 0 || !mergeFieldFrom(tag, input)) {
break;
}
}
return this;
}
/**
* Parse a single field from {@code input} and merge it into this set.
* @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an end group tag.
*/
public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
throws IOException {
final int number = WireFormat.getTagFieldNumber(tag);
switch (WireFormat.getTagWireType(tag)) {
case WireFormat.WIRETYPE_VARINT:
getFieldBuilder(number).addVarint(input.readInt64());
return true;
case WireFormat.WIRETYPE_FIXED64:
getFieldBuilder(number).addFixed64(input.readFixed64());
return true;
case WireFormat.WIRETYPE_LENGTH_DELIMITED:
getFieldBuilder(number).addLengthDelimited(input.readBytes());
return true;
case WireFormat.WIRETYPE_START_GROUP:
final Builder subBuilder = newBuilder();
input.readGroup(number, subBuilder,
ExtensionRegistry.getEmptyRegistry());
getFieldBuilder(number).addGroup(subBuilder.build());
return true;
case WireFormat.WIRETYPE_END_GROUP:
return false;
case WireFormat.WIRETYPE_FIXED32:
getFieldBuilder(number).addFixed32(input.readFixed32());
return true;
default:
throw InvalidProtocolBufferException.invalidWireType();
}
}
/**
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final ByteString data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = data.newCodedInput();
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a ByteString threw an IOException (should " +
"never happen).", e);
}
}
/**
* Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final byte[] data)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input = CodedInputStream.newInstance(data);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (final InvalidProtocolBufferException e) {
throw e;
} catch (final IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
/**
* Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
* set being built. This is just a small wrapper around
* {@link #mergeFrom(CodedInputStream)}.
*/
public Builder mergeFrom(final InputStream input) throws IOException {
final CodedInputStream codedInput = CodedInputStream.newInstance(input);
mergeFrom(codedInput);
codedInput.checkLastTagWas(0);
return this;
}
public boolean mergeDelimitedFrom(InputStream input)
throws IOException {
final int firstByte = input.read();
if (firstByte == -1) {
return false;
}
final int size = CodedInputStream.readRawVarint32(firstByte, input);
final InputStream limitedInput = new LimitedInputStream(input, size);
mergeFrom(limitedInput);
return true;
}
public boolean mergeDelimitedFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeDelimitedFrom(input);
}
public Builder mergeFrom(
CodedInputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public Builder mergeFrom(
ByteString data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(byte[] data, int off, int len)
throws InvalidProtocolBufferException {
try {
final CodedInputStream input =
CodedInputStream.newInstance(data, off, len);
mergeFrom(input);
input.checkLastTagWas(0);
return this;
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (IOException e) {
throw new RuntimeException(
"Reading from a byte array threw an IOException (should " +
"never happen).", e);
}
}
public Builder mergeFrom(
byte[] data,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data);
}
public Builder mergeFrom(
byte[] data, int off, int len,
ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
// UnknownFieldSet has no extensions.
return mergeFrom(data, off, len);
}
public Builder mergeFrom(
InputStream input,
ExtensionRegistryLite extensionRegistry) throws IOException {
// UnknownFieldSet has no extensions.
return mergeFrom(input);
}
public boolean isInitialized() {
// UnknownFieldSets do not have required fields, so they are always
// initialized.
return true;
}
}
/**
* Represents a single field in an {@code UnknownFieldSet}.
*
* <p>A {@code Field} consists of five lists of values. The lists correspond
* to the five "wire types" used in the protocol buffer binary format.
* The wire type of each field can be determined from the encoded form alone,
* without knowing the field's declared type. So, we are able to parse
* unknown values at least this far and separate them. Normally, only one
* of the five lists will contain any values, since it is impossible to
* define a valid message type that declares two different types for the
* same field number. However, the code is designed to allow for the case
* where the same unknown field number is encountered using multiple different
* wire types.
*
* <p>{@code Field} is an immutable class. To construct one, you must use a
* {@link Builder}.
*
* @see UnknownFieldSet
*/
public static final class Field {
private Field() {}
/** Construct a new {@link Builder}. */
public static Builder newBuilder() {
return Builder.create();
}
/**
* Construct a new {@link Builder} and initialize it to a copy of
* {@code copyFrom}.
*/
public static Builder newBuilder(final Field copyFrom) {
return newBuilder().mergeFrom(copyFrom);
}
/** Get an empty {@code Field}. */
public static Field getDefaultInstance() {
return fieldDefaultInstance;
}
private static final Field fieldDefaultInstance = newBuilder().build();
/** Get the list of varint values for this field. */
public List<Long> getVarintList() { return varint; }
/** Get the list of fixed32 values for this field. */
public List<Integer> getFixed32List() { return fixed32; }
/** Get the list of fixed64 values for this field. */
public List<Long> getFixed64List() { return fixed64; }
/** Get the list of length-delimited values for this field. */
public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
/**
* Get the list of embedded group values for this field. These are
* represented using {@link UnknownFieldSet}s rather than {@link Message}s
* since the group's type is presumably unknown.
*/
public List<UnknownFieldSet> getGroupList() { return group; }
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (!(other instanceof Field)) {
return false;
}
return Arrays.equals(getIdentityArray(),
((Field) other).getIdentityArray());
}
@Override
public int hashCode() {
return Arrays.hashCode(getIdentityArray());
}
/**
* Returns the array of objects to be used to uniquely identify this
* {@link Field} instance.
*/
private Object[] getIdentityArray() {
return new Object[] {
varint,
fixed32,
fixed64,
lengthDelimited,
group};
}
/**
* Serializes the field, including field number, and writes it to
* {@code output}.
*/
public void writeTo(final int fieldNumber, final CodedOutputStream output)
throws IOException {
for (final long value : varint) {
output.writeUInt64(fieldNumber, value);
}
for (final int value : fixed32) {
output.writeFixed32(fieldNumber, value);
}
for (final long value : fixed64) {
output.writeFixed64(fieldNumber, value);
}
for (final ByteString value : lengthDelimited) {
output.writeBytes(fieldNumber, value);
}
for (final UnknownFieldSet value : group) {
output.writeGroup(fieldNumber, value);
}
}
/**
* Get the number of bytes required to encode this field, including field
* number.
*/
public int getSerializedSize(final int fieldNumber) {
int result = 0;
for (final long value : varint) {
result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
}
for (final int value : fixed32) {
result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
}
for (final long value : fixed64) {
result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
}
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeBytesSize(fieldNumber, value);
}
for (final UnknownFieldSet value : group) {
result += CodedOutputStream.computeGroupSize(fieldNumber, value);
}
return result;
}
/**
* Serializes the field, including field number, and writes it to
* {@code output}, using {@code MessageSet} wire format.
*/
public void writeAsMessageSetExtensionTo(
final int fieldNumber,
final CodedOutputStream output)
throws IOException {
for (final ByteString value : lengthDelimited) {
output.writeRawMessageSetExtension(fieldNumber, value);
}
}
/**
* Get the number of bytes required to encode this field, including field
* number, using {@code MessageSet} wire format.
*/
public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
int result = 0;
for (final ByteString value : lengthDelimited) {
result += CodedOutputStream.computeRawMessageSetExtensionSize(
fieldNumber, value);
}
return result;
}
private List<Long> varint;
private List<Integer> fixed32;
private List<Long> fixed64;
private List<ByteString> lengthDelimited;
private List<UnknownFieldSet> group;
/**
* Used to build a {@link Field} within an {@link UnknownFieldSet}.
*
* <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
*/
public static final class Builder {
// This constructor should never be called directly (except from 'create').
private Builder() {}
private static Builder create() {
Builder builder = new Builder();
builder.result = new Field();
return builder;
}
private Field result;
/**
* Build the field. After {@code build()} has been called, the
* {@code Builder} is no longer usable. Calling any other method will
* result in undefined behavior and can cause a
* {@code NullPointerException} to be thrown.
*/
public Field build() {
if (result.varint == null) {
result.varint = Collections.emptyList();
} else {
result.varint = Collections.unmodifiableList(result.varint);
}
if (result.fixed32 == null) {
result.fixed32 = Collections.emptyList();
} else {
result.fixed32 = Collections.unmodifiableList(result.fixed32);
}
if (result.fixed64 == null) {
result.fixed64 = Collections.emptyList();
} else {
result.fixed64 = Collections.unmodifiableList(result.fixed64);
}
if (result.lengthDelimited == null) {
result.lengthDelimited = Collections.emptyList();
} else {
result.lengthDelimited =
Collections.unmodifiableList(result.lengthDelimited);
}
if (result.group == null) {
result.group = Collections.emptyList();
} else {
result.group = Collections.unmodifiableList(result.group);
}
final Field returnMe = result;
result = null;
return returnMe;
}
/** Discard the field's contents. */
public Builder clear() {
result = new Field();
return this;
}
/**
* Merge the values in {@code other} into this field. For each list
* of values, {@code other}'s values are append to the ones in this
* field.
*/
public Builder mergeFrom(final Field other) {
if (!other.varint.isEmpty()) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
}
result.varint.addAll(other.varint);
}
if (!other.fixed32.isEmpty()) {
if (result.fixed32 == null) {
result.fixed32 = new ArrayList<Integer>();
}
result.fixed32.addAll(other.fixed32);
}
if (!other.fixed64.isEmpty()) {
if (result.fixed64 == null) {
result.fixed64 = new ArrayList<Long>();
}
result.fixed64.addAll(other.fixed64);
}
if (!other.lengthDelimited.isEmpty()) {
if (result.lengthDelimited == null) {
result.lengthDelimited = new ArrayList<ByteString>();
}
result.lengthDelimited.addAll(other.lengthDelimited);
}
if (!other.group.isEmpty()) {
if (result.group == null) {
result.group = new ArrayList<UnknownFieldSet>();
}
result.group.addAll(other.group);
}
return this;
}
/** Add a varint value. */
public Builder addVarint(final long value) {
if (result.varint == null) {
result.varint = new ArrayList<Long>();
}
result.varint.add(value);
return this;
}
/** Add a fixed32 value. */
public Builder addFixed32(final int value) {
if (result.fixed32 == null) {
result.fixed32 = new ArrayList<Integer>();
}
result.fixed32.add(value);
return this;
}
/** Add a fixed64 value. */
public Builder addFixed64(final long value) {
if (result.fixed64 == null) {
result.fixed64 = new ArrayList<Long>();
}
result.fixed64.add(value);
return this;
}
/** Add a length-delimited value. */
public Builder addLengthDelimited(final ByteString value) {
if (result.lengthDelimited == null) {
result.lengthDelimited = new ArrayList<ByteString>();
}
result.lengthDelimited.add(value);
return this;
}
/** Add an embedded group. */
public Builder addGroup(final UnknownFieldSet value) {
if (result.group == null) {
result.group = new ArrayList<UnknownFieldSet>();
}
result.group.add(value);
return this;
}
}
}
/**
* Parser to implement MessageLite interface.
*/
public static final class Parser extends AbstractParser<UnknownFieldSet> {
public UnknownFieldSet parsePartialFrom(
CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException {
Builder builder = newBuilder();
try {
builder.mergeFrom(input);
} catch (InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(builder.buildPartial());
} catch (IOException e) {
throw new InvalidProtocolBufferException(e.getMessage())
.setUnfinishedMessage(builder.buildPartial());
}
return builder.buildPartial();
}
}
private static final Parser PARSER = new Parser();
public final Parser getParserForType() {
return PARSER;
}
}

View File

@ -0,0 +1,152 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.util.AbstractList;
import java.util.RandomAccess;
import java.util.List;
import java.util.ListIterator;
import java.util.Iterator;
/**
* An implementation of {@link LazyStringList} that wraps another
* {@link LazyStringList} such that it cannot be modified via the wrapper.
*
* @author jonp@google.com (Jon Perlow)
*/
public class UnmodifiableLazyStringList extends AbstractList<String>
implements LazyStringList, RandomAccess {
private final LazyStringList list;
public UnmodifiableLazyStringList(LazyStringList list) {
this.list = list;
}
@Override
public String get(int index) {
return list.get(index);
}
@Override
public int size() {
return list.size();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public ByteString getByteString(int index) {
return list.getByteString(index);
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void add(ByteString element) {
throw new UnsupportedOperationException();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public ListIterator<String> listIterator(final int index) {
return new ListIterator<String>() {
ListIterator<String> iter = list.listIterator(index);
//@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasNext() {
return iter.hasNext();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public String next() {
return iter.next();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasPrevious() {
return iter.hasPrevious();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public String previous() {
return iter.previous();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public int nextIndex() {
return iter.nextIndex();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public int previousIndex() {
return iter.previousIndex();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void remove() {
throw new UnsupportedOperationException();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void set(String o) {
throw new UnsupportedOperationException();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void add(String o) {
throw new UnsupportedOperationException();
}
};
}
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
Iterator<String> iter = list.iterator();
//@Override (Java 1.6 override semantics, but we must support 1.5)
public boolean hasNext() {
return iter.hasNext();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public String next() {
return iter.next();
}
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public List<?> getUnderlyingElements() {
// The returned value is already unmodifiable.
return list.getUnderlyingElements();
}
}

View File

@ -0,0 +1,349 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* A set of low-level, high-performance static utility methods related
* to the UTF-8 character encoding. This class has no dependencies
* outside of the core JDK libraries.
*
* <p>There are several variants of UTF-8. The one implemented by
* this class is the restricted definition of UTF-8 introduced in
* Unicode 3.1, which mandates the rejection of "overlong" byte
* sequences as well as rejection of 3-byte surrogate codepoint byte
* sequences. Note that the UTF-8 decoder included in Oracle's JDK
* has been modified to also reject "overlong" byte sequences, but (as
* of 2011) still accepts 3-byte surrogate codepoint byte sequences.
*
* <p>The byte sequences considered valid by this class are exactly
* those that can be roundtrip converted to Strings and back to bytes
* using the UTF-8 charset, without loss: <pre> {@code
* Arrays.equals(bytes, new String(bytes, "UTF-8").getBytes("UTF-8"))
* }</pre>
*
* <p>See the Unicode Standard,</br>
* Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
* Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
*
* <p>This class supports decoding of partial byte sequences, so that the
* bytes in a complete UTF-8 byte sequences can be stored in multiple
* segments. Methods typically return {@link #MALFORMED} if the partial
* byte sequence is definitely not well-formed, {@link #COMPLETE} if it is
* well-formed in the absence of additional input, or if the byte sequence
* apparently terminated in the middle of a character, an opaque integer
* "state" value containing enough information to decode the character when
* passed to a subsequent invocation of a partial decoding method.
*
* @author martinrb@google.com (Martin Buchholz)
*/
final class Utf8 {
private Utf8() {}
/**
* State value indicating that the byte sequence is well-formed and
* complete (no further bytes are needed to complete a character).
*/
public static final int COMPLETE = 0;
/**
* State value indicating that the byte sequence is definitely not
* well-formed.
*/
public static final int MALFORMED = -1;
// Other state values include the partial bytes of the incomplete
// character to be decoded in the simplest way: we pack the bytes
// into the state int in little-endian order. For example:
//
// int state = byte1 ^ (byte2 << 8) ^ (byte3 << 16);
//
// Such a state is unpacked thus (note the ~ operation for byte2 to
// undo byte1's sign-extension bits):
//
// int byte1 = (byte) state;
// int byte2 = (byte) ~(state >> 8);
// int byte3 = (byte) (state >> 16);
//
// We cannot store a zero byte in the state because it would be
// indistinguishable from the absence of a byte. But we don't need
// to, because partial bytes must always be negative. When building
// a state, we ensure that byte1 is negative and subsequent bytes
// are valid trailing bytes.
/**
* Returns {@code true} if the given byte array is a well-formed
* UTF-8 byte sequence.
*
* <p>This is a convenience method, equivalent to a call to {@code
* isValidUtf8(bytes, 0, bytes.length)}.
*/
public static boolean isValidUtf8(byte[] bytes) {
return isValidUtf8(bytes, 0, bytes.length);
}
/**
* Returns {@code true} if the given byte array slice is a
* well-formed UTF-8 byte sequence. The range of bytes to be
* checked extends from index {@code index}, inclusive, to {@code
* limit}, exclusive.
*
* <p>This is a convenience method, equivalent to {@code
* partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}.
*/
public static boolean isValidUtf8(byte[] bytes, int index, int limit) {
return partialIsValidUtf8(bytes, index, limit) == COMPLETE;
}
/**
* Tells whether the given byte array slice is a well-formed,
* malformed, or incomplete UTF-8 byte sequence. The range of bytes
* to be checked extends from index {@code index}, inclusive, to
* {@code limit}, exclusive.
*
* @param state either {@link Utf8#COMPLETE} (if this is the initial decoding
* operation) or the value returned from a call to a partial decoding method
* for the previous bytes
*
* @return {@link #MALFORMED} if the partial byte sequence is
* definitely not well-formed, {@link #COMPLETE} if it is well-formed
* (no additional input needed), or if the byte sequence is
* "incomplete", i.e. apparently terminated in the middle of a character,
* an opaque integer "state" value containing enough information to
* decode the character when passed to a subsequent invocation of a
* partial decoding method.
*/
public static int partialIsValidUtf8(
int state, byte[] bytes, int index, int limit) {
if (state != COMPLETE) {
// The previous decoding operation was incomplete (or malformed).
// We look for a well-formed sequence consisting of bytes from
// the previous decoding operation (stored in state) together
// with bytes from the array slice.
//
// We expect such "straddler characters" to be rare.
if (index >= limit) { // No bytes? No progress.
return state;
}
int byte1 = (byte) state;
// byte1 is never ASCII.
if (byte1 < (byte) 0xE0) {
// two-byte form
// Simultaneously checks for illegal trailing-byte in
// leading position and overlong 2-byte form.
if (byte1 < (byte) 0xC2 ||
// byte2 trailing-byte test
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
// three-byte form
// Get byte2 from saved state or array
int byte2 = (byte) ~(state >> 8);
if (byte2 == 0) {
byte2 = bytes[index++];
if (index >= limit) {
return incompleteStateFor(byte1, byte2);
}
}
if (byte2 > (byte) 0xBF ||
// overlong? 5 most significant bits must not all be zero
(byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
// illegal surrogate codepoint?
(byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
// byte3 trailing-byte test
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
} else {
// four-byte form
// Get byte2 and byte3 from saved state or array
int byte2 = (byte) ~(state >> 8);
int byte3 = 0;
if (byte2 == 0) {
byte2 = bytes[index++];
if (index >= limit) {
return incompleteStateFor(byte1, byte2);
}
} else {
byte3 = (byte) (state >> 16);
}
if (byte3 == 0) {
byte3 = bytes[index++];
if (index >= limit) {
return incompleteStateFor(byte1, byte2, byte3);
}
}
// If we were called with state == MALFORMED, then byte1 is 0xFF,
// which never occurs in well-formed UTF-8, and so we will return
// MALFORMED again below.
if (byte2 > (byte) 0xBF ||
// Check that 1 <= plane <= 16. Tricky optimized form of:
// if (byte1 > (byte) 0xF4 ||
// byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
(((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
// byte3 trailing-byte test
byte3 > (byte) 0xBF ||
// byte4 trailing-byte test
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
}
}
return partialIsValidUtf8(bytes, index, limit);
}
/**
* Tells whether the given byte array slice is a well-formed,
* malformed, or incomplete UTF-8 byte sequence. The range of bytes
* to be checked extends from index {@code index}, inclusive, to
* {@code limit}, exclusive.
*
* <p>This is a convenience method, equivalent to a call to {@code
* partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}.
*
* @return {@link #MALFORMED} if the partial byte sequence is
* definitely not well-formed, {@link #COMPLETE} if it is well-formed
* (no additional input needed), or if the byte sequence is
* "incomplete", i.e. apparently terminated in the middle of a character,
* an opaque integer "state" value containing enough information to
* decode the character when passed to a subsequent invocation of a
* partial decoding method.
*/
public static int partialIsValidUtf8(
byte[] bytes, int index, int limit) {
// Optimize for 100% ASCII.
// Hotspot loves small simple top-level loops like this.
while (index < limit && bytes[index] >= 0) {
index++;
}
return (index >= limit) ? COMPLETE :
partialIsValidUtf8NonAscii(bytes, index, limit);
}
private static int partialIsValidUtf8NonAscii(
byte[] bytes, int index, int limit) {
for (;;) {
int byte1, byte2;
// Optimize for interior runs of ASCII bytes.
do {
if (index >= limit) {
return COMPLETE;
}
} while ((byte1 = bytes[index++]) >= 0);
if (byte1 < (byte) 0xE0) {
// two-byte form
if (index >= limit) {
return byte1;
}
// Simultaneously checks for illegal trailing-byte in
// leading position and overlong 2-byte form.
if (byte1 < (byte) 0xC2 ||
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
} else if (byte1 < (byte) 0xF0) {
// three-byte form
if (index >= limit - 1) { // incomplete sequence
return incompleteStateFor(bytes, index, limit);
}
if ((byte2 = bytes[index++]) > (byte) 0xBF ||
// overlong? 5 most significant bits must not all be zero
(byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) ||
// check for illegal surrogate codepoints
(byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) ||
// byte3 trailing-byte test
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
} else {
// four-byte form
if (index >= limit - 2) { // incomplete sequence
return incompleteStateFor(bytes, index, limit);
}
if ((byte2 = bytes[index++]) > (byte) 0xBF ||
// Check that 1 <= plane <= 16. Tricky optimized form of:
// if (byte1 > (byte) 0xF4 ||
// byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
// byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
(((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 ||
// byte3 trailing-byte test
bytes[index++] > (byte) 0xBF ||
// byte4 trailing-byte test
bytes[index++] > (byte) 0xBF) {
return MALFORMED;
}
}
}
}
private static int incompleteStateFor(int byte1) {
return (byte1 > (byte) 0xF4) ?
MALFORMED : byte1;
}
private static int incompleteStateFor(int byte1, int byte2) {
return (byte1 > (byte) 0xF4 ||
byte2 > (byte) 0xBF) ?
MALFORMED : byte1 ^ (byte2 << 8);
}
private static int incompleteStateFor(int byte1, int byte2, int byte3) {
return (byte1 > (byte) 0xF4 ||
byte2 > (byte) 0xBF ||
byte3 > (byte) 0xBF) ?
MALFORMED : byte1 ^ (byte2 << 8) ^ (byte3 << 16);
}
private static int incompleteStateFor(byte[] bytes, int index, int limit) {
int byte1 = bytes[index - 1];
switch (limit - index) {
case 0: return incompleteStateFor(byte1);
case 1: return incompleteStateFor(byte1, bytes[index]);
case 2: return incompleteStateFor(byte1, bytes[index], bytes[index + 1]);
default: throw new AssertionError();
}
}
}

View File

@ -0,0 +1,163 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* This class is used internally by the Protocol Buffer library and generated
* message implementations. It is public only because those generated messages
* do not reside in the {@code protobuf} package. Others should not use this
* class directly.
*
* This class contains constants and helper functions useful for dealing with
* the Protocol Buffer wire format.
*
* @author kenton@google.com Kenton Varda
*/
public final class WireFormat {
// Do not allow instantiation.
private WireFormat() {}
public static final int WIRETYPE_VARINT = 0;
public static final int WIRETYPE_FIXED64 = 1;
public static final int WIRETYPE_LENGTH_DELIMITED = 2;
public static final int WIRETYPE_START_GROUP = 3;
public static final int WIRETYPE_END_GROUP = 4;
public static final int WIRETYPE_FIXED32 = 5;
static final int TAG_TYPE_BITS = 3;
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
/** Given a tag value, determines the wire type (the lower 3 bits). */
static int getTagWireType(final int tag) {
return tag & TAG_TYPE_MASK;
}
/** Given a tag value, determines the field number (the upper 29 bits). */
public static int getTagFieldNumber(final int tag) {
return tag >>> TAG_TYPE_BITS;
}
/** Makes a tag value given a field number and wire type. */
static int makeTag(final int fieldNumber, final int wireType) {
return (fieldNumber << TAG_TYPE_BITS) | wireType;
}
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum JavaType {
INT(0),
LONG(0L),
FLOAT(0F),
DOUBLE(0D),
BOOLEAN(false),
STRING(""),
BYTE_STRING(ByteString.EMPTY),
ENUM(null),
MESSAGE(null);
JavaType(final Object defaultDefault) {
this.defaultDefault = defaultDefault;
}
/**
* The default default value for fields of this type, if it's a primitive
* type.
*/
Object getDefaultDefault() {
return defaultDefault;
}
private final Object defaultDefault;
}
/**
* Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
* only here to support the lite runtime and should not be used by users.
*/
public enum FieldType {
DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
INT64 (JavaType.LONG , WIRETYPE_VARINT ),
UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
INT32 (JavaType.INT , WIRETYPE_VARINT ),
FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) {
public boolean isPackable() { return false; }
},
MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) {
public boolean isPackable() { return false; }
},
UINT32 (JavaType.INT , WIRETYPE_VARINT ),
ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
SINT32 (JavaType.INT , WIRETYPE_VARINT ),
SINT64 (JavaType.LONG , WIRETYPE_VARINT );
FieldType(final JavaType javaType, final int wireType) {
this.javaType = javaType;
this.wireType = wireType;
}
private final JavaType javaType;
private final int wireType;
public JavaType getJavaType() { return javaType; }
public int getWireType() { return wireType; }
public boolean isPackable() { return true; }
}
// Field numbers for fields in MessageSet wire format.
static final int MESSAGE_SET_ITEM = 1;
static final int MESSAGE_SET_TYPE_ID = 2;
static final int MESSAGE_SET_MESSAGE = 3;
// Tag numbers.
static final int MESSAGE_SET_ITEM_TAG =
makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
static final int MESSAGE_SET_ITEM_END_TAG =
makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
static final int MESSAGE_SET_TYPE_ID_TAG =
makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
static final int MESSAGE_SET_MESSAGE_TAG =
makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
}

View File

@ -0,0 +1,509 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import junit.framework.TestCase;
import java.util.Map;
/**
* Unit test for {@link AbstractMessage}.
*
* @author kenton@google.com Kenton Varda
*/
public class AbstractMessageTest extends TestCase {
/**
* Extends AbstractMessage and wraps some other message object. The methods
* of the Message interface which aren't explicitly implemented by
* AbstractMessage are forwarded to the wrapped object. This allows us to
* test that AbstractMessage's implementations work even if the wrapped
* object does not use them.
*/
private static class AbstractMessageWrapper extends AbstractMessage {
private final Message wrappedMessage;
public AbstractMessageWrapper(Message wrappedMessage) {
this.wrappedMessage = wrappedMessage;
}
public Descriptors.Descriptor getDescriptorForType() {
return wrappedMessage.getDescriptorForType();
}
public AbstractMessageWrapper getDefaultInstanceForType() {
return new AbstractMessageWrapper(
wrappedMessage.getDefaultInstanceForType());
}
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
return wrappedMessage.getAllFields();
}
public boolean hasField(Descriptors.FieldDescriptor field) {
return wrappedMessage.hasField(field);
}
public Object getField(Descriptors.FieldDescriptor field) {
return wrappedMessage.getField(field);
}
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
return wrappedMessage.getRepeatedFieldCount(field);
}
public Object getRepeatedField(
Descriptors.FieldDescriptor field, int index) {
return wrappedMessage.getRepeatedField(field, index);
}
public UnknownFieldSet getUnknownFields() {
return wrappedMessage.getUnknownFields();
}
public Builder newBuilderForType() {
return new Builder(wrappedMessage.newBuilderForType());
}
public Builder toBuilder() {
return new Builder(wrappedMessage.toBuilder());
}
static class Builder extends AbstractMessage.Builder<Builder> {
private final Message.Builder wrappedBuilder;
public Builder(Message.Builder wrappedBuilder) {
this.wrappedBuilder = wrappedBuilder;
}
public AbstractMessageWrapper build() {
return new AbstractMessageWrapper(wrappedBuilder.build());
}
public AbstractMessageWrapper buildPartial() {
return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
}
public Builder clone() {
return new Builder(wrappedBuilder.clone());
}
public boolean isInitialized() {
return clone().buildPartial().isInitialized();
}
public Descriptors.Descriptor getDescriptorForType() {
return wrappedBuilder.getDescriptorForType();
}
public AbstractMessageWrapper getDefaultInstanceForType() {
return new AbstractMessageWrapper(
wrappedBuilder.getDefaultInstanceForType());
}
public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
return wrappedBuilder.getAllFields();
}
public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
return new Builder(wrappedBuilder.newBuilderForField(field));
}
public boolean hasField(Descriptors.FieldDescriptor field) {
return wrappedBuilder.hasField(field);
}
public Object getField(Descriptors.FieldDescriptor field) {
return wrappedBuilder.getField(field);
}
public Builder setField(Descriptors.FieldDescriptor field, Object value) {
wrappedBuilder.setField(field, value);
return this;
}
public Builder clearField(Descriptors.FieldDescriptor field) {
wrappedBuilder.clearField(field);
return this;
}
public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
return wrappedBuilder.getRepeatedFieldCount(field);
}
public Object getRepeatedField(
Descriptors.FieldDescriptor field, int index) {
return wrappedBuilder.getRepeatedField(field, index);
}
public Builder setRepeatedField(Descriptors.FieldDescriptor field,
int index, Object value) {
wrappedBuilder.setRepeatedField(field, index, value);
return this;
}
public Builder addRepeatedField(
Descriptors.FieldDescriptor field, Object value) {
wrappedBuilder.addRepeatedField(field, value);
return this;
}
public UnknownFieldSet getUnknownFields() {
return wrappedBuilder.getUnknownFields();
}
public Builder setUnknownFields(UnknownFieldSet unknownFields) {
wrappedBuilder.setUnknownFields(unknownFields);
return this;
}
@Override
public Message.Builder getFieldBuilder(FieldDescriptor field) {
return wrappedBuilder.getFieldBuilder(field);
}
}
public Parser<? extends Message> getParserForType() {
return wrappedMessage.getParserForType();
}
}
// =================================================================
TestUtil.ReflectionTester reflectionTester =
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
TestUtil.ReflectionTester extensionsReflectionTester =
new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
TestUtil.getExtensionRegistry());
public void testClear() throws Exception {
AbstractMessageWrapper message =
new AbstractMessageWrapper.Builder(
TestAllTypes.newBuilder(TestUtil.getAllSet()))
.clear().build();
TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
}
public void testCopy() throws Exception {
AbstractMessageWrapper message =
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
.mergeFrom(TestUtil.getAllSet()).build();
TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
}
public void testSerializedSize() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
assertEquals(message.getSerializedSize(),
abstractMessage.getSerializedSize());
}
public void testSerialization() throws Exception {
Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
TestUtil.assertAllFieldsSet(
TestAllTypes.parseFrom(abstractMessage.toByteString()));
assertEquals(TestUtil.getAllSet().toByteString(),
abstractMessage.toByteString());
}
public void testParsing() throws Exception {
AbstractMessageWrapper.Builder builder =
new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
AbstractMessageWrapper message =
builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
}
public void testParsingUninitialized() throws Exception {
TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
builder.getOptionalMessageBuilder().setDummy2(10);
ByteString bytes = builder.buildPartial().toByteString();
Message.Builder abstractMessageBuilder =
new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder());
// mergeFrom() should not throw initialization error.
abstractMessageBuilder.mergeFrom(bytes).buildPartial();
try {
abstractMessageBuilder.mergeFrom(bytes).build();
fail();
} catch (UninitializedMessageException ex) {
// pass
}
// test DynamicMessage directly.
Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder(
TestRequiredForeign.getDescriptor());
// mergeFrom() should not throw initialization error.
dynamicMessageBuilder.mergeFrom(bytes).buildPartial();
try {
dynamicMessageBuilder.mergeFrom(bytes).build();
fail();
} catch (UninitializedMessageException ex) {
// pass
}
}
public void testPackedSerialization() throws Exception {
Message abstractMessage =
new AbstractMessageWrapper(TestUtil.getPackedSet());
TestUtil.assertPackedFieldsSet(
TestPackedTypes.parseFrom(abstractMessage.toByteString()));
assertEquals(TestUtil.getPackedSet().toByteString(),
abstractMessage.toByteString());
}
public void testPackedParsing() throws Exception {
AbstractMessageWrapper.Builder builder =
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
AbstractMessageWrapper message =
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
}
public void testUnpackedSerialization() throws Exception {
Message abstractMessage =
new AbstractMessageWrapper(TestUtil.getUnpackedSet());
TestUtil.assertUnpackedFieldsSet(
TestUnpackedTypes.parseFrom(abstractMessage.toByteString()));
assertEquals(TestUtil.getUnpackedSet().toByteString(),
abstractMessage.toByteString());
}
public void testParsePackedToUnpacked() throws Exception {
AbstractMessageWrapper.Builder builder =
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
AbstractMessageWrapper message =
builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
TestUtil.assertUnpackedFieldsSet(
(TestUnpackedTypes) message.wrappedMessage);
}
public void testParseUnpackedToPacked() throws Exception {
AbstractMessageWrapper.Builder builder =
new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
AbstractMessageWrapper message =
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
}
public void testUnpackedParsing() throws Exception {
AbstractMessageWrapper.Builder builder =
new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder());
AbstractMessageWrapper message =
builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build();
TestUtil.assertUnpackedFieldsSet(
(TestUnpackedTypes) message.wrappedMessage);
}
public void testOptimizedForSize() throws Exception {
// We're mostly only checking that this class was compiled successfully.
TestOptimizedForSize message =
TestOptimizedForSize.newBuilder().setI(1).build();
message = TestOptimizedForSize.parseFrom(message.toByteString());
assertEquals(2, message.getSerializedSize());
}
// -----------------------------------------------------------------
// Tests for isInitialized().
private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
TestRequired.getDefaultInstance();
private static final TestRequired TEST_REQUIRED_INITIALIZED =
TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
public void testIsInitialized() throws Exception {
TestRequired.Builder builder = TestRequired.newBuilder();
AbstractMessageWrapper.Builder abstractBuilder =
new AbstractMessageWrapper.Builder(builder);
assertFalse(abstractBuilder.isInitialized());
assertEquals("a, b, c", abstractBuilder.getInitializationErrorString());
builder.setA(1);
assertFalse(abstractBuilder.isInitialized());
assertEquals("b, c", abstractBuilder.getInitializationErrorString());
builder.setB(1);
assertFalse(abstractBuilder.isInitialized());
assertEquals("c", abstractBuilder.getInitializationErrorString());
builder.setC(1);
assertTrue(abstractBuilder.isInitialized());
assertEquals("", abstractBuilder.getInitializationErrorString());
}
public void testForeignIsInitialized() throws Exception {
TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
AbstractMessageWrapper.Builder abstractBuilder =
new AbstractMessageWrapper.Builder(builder);
assertTrue(abstractBuilder.isInitialized());
assertEquals("", abstractBuilder.getInitializationErrorString());
builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
assertEquals(
"optional_message.a, optional_message.b, optional_message.c",
abstractBuilder.getInitializationErrorString());
builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
assertTrue(abstractBuilder.isInitialized());
assertEquals("", abstractBuilder.getInitializationErrorString());
builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(abstractBuilder.isInitialized());
assertEquals(
"repeated_message[0].a, repeated_message[0].b, repeated_message[0].c",
abstractBuilder.getInitializationErrorString());
builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
assertTrue(abstractBuilder.isInitialized());
assertEquals("", abstractBuilder.getInitializationErrorString());
}
// -----------------------------------------------------------------
// Tests for mergeFrom
static final TestAllTypes MERGE_SOURCE =
TestAllTypes.newBuilder()
.setOptionalInt32(1)
.setOptionalString("foo")
.setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
.addRepeatedString("bar")
.build();
static final TestAllTypes MERGE_DEST =
TestAllTypes.newBuilder()
.setOptionalInt64(2)
.setOptionalString("baz")
.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
.addRepeatedString("qux")
.build();
static final String MERGE_RESULT_TEXT =
"optional_int32: 1\n" +
"optional_int64: 2\n" +
"optional_string: \"foo\"\n" +
"optional_foreign_message {\n" +
" c: 3\n" +
"}\n" +
"repeated_string: \"qux\"\n" +
"repeated_string: \"bar\"\n";
public void testMergeFrom() throws Exception {
AbstractMessageWrapper result =
new AbstractMessageWrapper.Builder(
TestAllTypes.newBuilder(MERGE_DEST))
.mergeFrom(MERGE_SOURCE).build();
assertEquals(MERGE_RESULT_TEXT, result.toString());
}
// -----------------------------------------------------------------
// Tests for equals and hashCode
public void testEqualsAndHashCode() throws Exception {
TestAllTypes a = TestUtil.getAllSet();
TestAllTypes b = TestAllTypes.newBuilder().build();
TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
TestAllExtensions e = TestUtil.getAllExtensionsSet();
TestAllExtensions f = TestAllExtensions.newBuilder(e)
.addExtension(UnittestProto.repeatedInt32Extension, 999).build();
checkEqualsIsConsistent(a);
checkEqualsIsConsistent(b);
checkEqualsIsConsistent(c);
checkEqualsIsConsistent(d);
checkEqualsIsConsistent(e);
checkEqualsIsConsistent(f);
checkNotEqual(a, b);
checkNotEqual(a, c);
checkNotEqual(a, d);
checkNotEqual(a, e);
checkNotEqual(a, f);
checkNotEqual(b, c);
checkNotEqual(b, d);
checkNotEqual(b, e);
checkNotEqual(b, f);
checkNotEqual(c, d);
checkNotEqual(c, e);
checkNotEqual(c, f);
checkNotEqual(d, e);
checkNotEqual(d, f);
checkNotEqual(e, f);
// Deserializing into the TestEmptyMessage such that every field
// is an {@link UnknownFieldSet.Field}.
UnittestProto.TestEmptyMessage eUnknownFields =
UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
UnittestProto.TestEmptyMessage fUnknownFields =
UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
checkNotEqual(eUnknownFields, fUnknownFields);
checkEqualsIsConsistent(eUnknownFields);
checkEqualsIsConsistent(fUnknownFields);
// Subsequent reconstitutions should be identical
UnittestProto.TestEmptyMessage eUnknownFields2 =
UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
}
/**
* Asserts that the given proto has symmetric equals and hashCode methods.
*/
private void checkEqualsIsConsistent(Message message) {
// Object should be equal to itself.
assertEquals(message, message);
// Object should be equal to a dynamic copy of itself.
DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
checkEqualsIsConsistent(message, dynamic);
}
/**
* Asserts that the given protos are equal and have the same hash code.
*/
private void checkEqualsIsConsistent(Message message1, Message message2) {
assertEquals(message1, message2);
assertEquals(message2, message1);
assertEquals(message2.hashCode(), message1.hashCode());
}
/**
* Asserts that the given protos are not equal and have different hash codes.
*
* @warning It's valid for non-equal objects to have the same hash code, so
* this test is stricter than it needs to be. However, this should happen
* relatively rarely.
*/
private void checkNotEqual(Message m1, Message m2) {
String equalsError = String.format("%s should not be equal to %s", m1, m2);
assertFalse(equalsError, m1.equals(m2));
assertFalse(equalsError, m2.equals(m1));
assertFalse(
String.format("%s should have a different hash code from %s", m1, m2),
m1.hashCode() == m2.hashCode());
}
}

View File

@ -0,0 +1,68 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
/**
* This class tests {@link BoundedByteString}, which extends {@link LiteralByteString},
* by inheriting the tests from {@link LiteralByteStringTest}. The only method which
* is strange enough that it needs to be overridden here is {@link #testToString()}.
*
* @author carlanton@google.com (Carl Haverl)
*/
public class BoundedByteStringTest extends LiteralByteStringTest {
@Override
protected void setUp() throws Exception {
classUnderTest = "BoundedByteString";
byte[] sourceBytes = ByteStringTest.getTestBytes(2341, 11337766L);
int from = 100;
int to = sourceBytes.length - 100;
stringUnderTest = ByteString.copyFrom(sourceBytes).substring(from, to);
referenceBytes = new byte[to - from];
System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
expectedHashCode = 727575887;
}
@Override
public void testToString() throws UnsupportedEncodingException {
String testString = "I love unicode \u1234\u5678 characters";
LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
ByteString chopped = unicode.substring(2, unicode.size() - 6);
assertEquals(classUnderTest + ".substring() must have the expected type",
classUnderTest, getActualClassName(chopped));
String roundTripString = chopped.toString(UTF_8);
assertEquals(classUnderTest + " unicode bytes must match",
testString.substring(2, testString.length() - 6), roundTripString);
}
}

View File

@ -0,0 +1,692 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.ByteString.Output;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
/**
* Test methods with implementations in {@link ByteString}, plus do some top-level "integration"
* tests.
*
* @author carlanton@google.com (Carl Haverl)
*/
public class ByteStringTest extends TestCase {
private static final String UTF_16 = "UTF-16";
static byte[] getTestBytes(int size, long seed) {
Random random = new Random(seed);
byte[] result = new byte[size];
random.nextBytes(result);
return result;
}
private byte[] getTestBytes(int size) {
return getTestBytes(size, 445566L);
}
private byte[] getTestBytes() {
return getTestBytes(1000);
}
// Compare the entire left array with a subset of the right array.
private boolean isArrayRange(byte[] left, byte[] right, int rightOffset, int length) {
boolean stillEqual = (left.length == length);
for (int i = 0; (stillEqual && i < length); ++i) {
stillEqual = (left[i] == right[rightOffset + i]);
}
return stillEqual;
}
// Returns true only if the given two arrays have identical contents.
private boolean isArray(byte[] left, byte[] right) {
return left.length == right.length && isArrayRange(left, right, 0, left.length);
}
public void testSubstring_BeginIndex() {
byte[] bytes = getTestBytes();
ByteString substring = ByteString.copyFrom(bytes).substring(500);
assertTrue("substring must contain the tail of the string",
isArrayRange(substring.toByteArray(), bytes, 500, bytes.length - 500));
}
public void testCopyFrom_BytesOffsetSize() {
byte[] bytes = getTestBytes();
ByteString byteString = ByteString.copyFrom(bytes, 500, 200);
assertTrue("copyFrom sub-range must contain the expected bytes",
isArrayRange(byteString.toByteArray(), bytes, 500, 200));
}
public void testCopyFrom_Bytes() {
byte[] bytes = getTestBytes();
ByteString byteString = ByteString.copyFrom(bytes);
assertTrue("copyFrom must contain the expected bytes",
isArray(byteString.toByteArray(), bytes));
}
public void testCopyFrom_ByteBufferSize() {
byte[] bytes = getTestBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
byteBuffer.put(bytes);
byteBuffer.position(500);
ByteString byteString = ByteString.copyFrom(byteBuffer, 200);
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
isArrayRange(byteString.toByteArray(), bytes, 500, 200));
}
public void testCopyFrom_ByteBuffer() {
byte[] bytes = getTestBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
byteBuffer.put(bytes);
byteBuffer.position(500);
ByteString byteString = ByteString.copyFrom(byteBuffer);
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
isArrayRange(byteString.toByteArray(), bytes, 500, bytes.length - 500));
}
public void testCopyFrom_StringEncoding() throws UnsupportedEncodingException {
String testString = "I love unicode \u1234\u5678 characters";
ByteString byteString = ByteString.copyFrom(testString, UTF_16);
byte[] testBytes = testString.getBytes(UTF_16);
assertTrue("copyFrom string must respect the charset",
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
}
public void testCopyFrom_Utf8() throws UnsupportedEncodingException {
String testString = "I love unicode \u1234\u5678 characters";
ByteString byteString = ByteString.copyFromUtf8(testString);
byte[] testBytes = testString.getBytes("UTF-8");
assertTrue("copyFromUtf8 string must respect the charset",
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
}
public void testCopyFrom_Iterable() {
byte[] testBytes = getTestBytes(77777, 113344L);
final List<ByteString> pieces = makeConcretePieces(testBytes);
// Call copyFrom() on a Collection
ByteString byteString = ByteString.copyFrom(pieces);
assertTrue("copyFrom a List must contain the expected bytes",
isArrayRange(byteString.toByteArray(), testBytes, 0, testBytes.length));
// Call copyFrom on an iteration that's not a collection
ByteString byteStringAlt = ByteString.copyFrom(new Iterable<ByteString>() {
public Iterator<ByteString> iterator() {
return pieces.iterator();
}
});
assertEquals("copyFrom from an Iteration must contain the expected bytes",
byteString, byteStringAlt);
}
public void testCopyTo_TargetOffset() {
byte[] bytes = getTestBytes();
ByteString byteString = ByteString.copyFrom(bytes);
byte[] target = new byte[bytes.length + 1000];
byteString.copyTo(target, 400);
assertTrue("copyFrom byteBuffer sub-range must contain the expected bytes",
isArrayRange(bytes, target, 400, bytes.length));
}
public void testReadFrom_emptyStream() throws IOException {
ByteString byteString =
ByteString.readFrom(new ByteArrayInputStream(new byte[0]));
assertSame("reading an empty stream must result in the EMPTY constant "
+ "byte string", ByteString.EMPTY, byteString);
}
public void testReadFrom_smallStream() throws IOException {
assertReadFrom(getTestBytes(10));
}
public void testReadFrom_mutating() throws IOException {
byte[] capturedArray = null;
EvilInputStream eis = new EvilInputStream();
ByteString byteString = ByteString.readFrom(eis);
capturedArray = eis.capturedArray;
byte[] originalValue = byteString.toByteArray();
for (int x = 0; x < capturedArray.length; ++x) {
capturedArray[x] = (byte) 0;
}
byte[] newValue = byteString.toByteArray();
assertTrue("copyFrom byteBuffer must not grant access to underlying array",
Arrays.equals(originalValue, newValue));
}
// Tests sizes that are near the rope copy-out threshold.
public void testReadFrom_mediumStream() throws IOException {
assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE - 1));
assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE));
assertReadFrom(getTestBytes(ByteString.CONCATENATE_BY_COPY_SIZE + 1));
assertReadFrom(getTestBytes(200));
}
// Tests sizes that are over multi-segment rope threshold.
public void testReadFrom_largeStream() throws IOException {
assertReadFrom(getTestBytes(0x100));
assertReadFrom(getTestBytes(0x101));
assertReadFrom(getTestBytes(0x110));
assertReadFrom(getTestBytes(0x1000));
assertReadFrom(getTestBytes(0x1001));
assertReadFrom(getTestBytes(0x1010));
assertReadFrom(getTestBytes(0x10000));
assertReadFrom(getTestBytes(0x10001));
assertReadFrom(getTestBytes(0x10010));
}
// Tests sizes that are near the read buffer size.
public void testReadFrom_byteBoundaries() throws IOException {
final int min = ByteString.MIN_READ_FROM_CHUNK_SIZE;
final int max = ByteString.MAX_READ_FROM_CHUNK_SIZE;
assertReadFrom(getTestBytes(min - 1));
assertReadFrom(getTestBytes(min));
assertReadFrom(getTestBytes(min + 1));
assertReadFrom(getTestBytes(min * 2 - 1));
assertReadFrom(getTestBytes(min * 2));
assertReadFrom(getTestBytes(min * 2 + 1));
assertReadFrom(getTestBytes(min * 4 - 1));
assertReadFrom(getTestBytes(min * 4));
assertReadFrom(getTestBytes(min * 4 + 1));
assertReadFrom(getTestBytes(min * 8 - 1));
assertReadFrom(getTestBytes(min * 8));
assertReadFrom(getTestBytes(min * 8 + 1));
assertReadFrom(getTestBytes(max - 1));
assertReadFrom(getTestBytes(max));
assertReadFrom(getTestBytes(max + 1));
assertReadFrom(getTestBytes(max * 2 - 1));
assertReadFrom(getTestBytes(max * 2));
assertReadFrom(getTestBytes(max * 2 + 1));
}
// Tests that IOExceptions propagate through ByteString.readFrom().
public void testReadFrom_IOExceptions() {
try {
ByteString.readFrom(new FailStream());
fail("readFrom must throw the underlying IOException");
} catch (IOException e) {
assertEquals("readFrom must throw the expected exception",
"synthetic failure", e.getMessage());
}
}
// Tests that ByteString.readFrom works with streams that don't
// always fill their buffers.
public void testReadFrom_reluctantStream() throws IOException {
final byte[] data = getTestBytes(0x1000);
ByteString byteString = ByteString.readFrom(new ReluctantStream(data));
assertTrue("readFrom byte stream must contain the expected bytes",
isArray(byteString.toByteArray(), data));
// Same test as above, but with some specific chunk sizes.
assertReadFromReluctantStream(data, 100);
assertReadFromReluctantStream(data, 248);
assertReadFromReluctantStream(data, 249);
assertReadFromReluctantStream(data, 250);
assertReadFromReluctantStream(data, 251);
assertReadFromReluctantStream(data, 0x1000);
assertReadFromReluctantStream(data, 0x1001);
}
// Fails unless ByteString.readFrom reads the bytes correctly from a
// reluctant stream with the given chunkSize parameter.
private void assertReadFromReluctantStream(byte[] bytes, int chunkSize)
throws IOException {
ByteString b = ByteString.readFrom(new ReluctantStream(bytes), chunkSize);
assertTrue("readFrom byte stream must contain the expected bytes",
isArray(b.toByteArray(), bytes));
}
// Tests that ByteString.readFrom works with streams that implement
// available().
public void testReadFrom_available() throws IOException {
final byte[] data = getTestBytes(0x1001);
ByteString byteString = ByteString.readFrom(new AvailableStream(data));
assertTrue("readFrom byte stream must contain the expected bytes",
isArray(byteString.toByteArray(), data));
}
// Fails unless ByteString.readFrom reads the bytes correctly.
private void assertReadFrom(byte[] bytes) throws IOException {
ByteString byteString =
ByteString.readFrom(new ByteArrayInputStream(bytes));
assertTrue("readFrom byte stream must contain the expected bytes",
isArray(byteString.toByteArray(), bytes));
}
// A stream that fails when read.
private static final class FailStream extends InputStream {
@Override public int read() throws IOException {
throw new IOException("synthetic failure");
}
}
// A stream that simulates blocking by only producing 250 characters
// per call to read(byte[]).
private static class ReluctantStream extends InputStream {
protected final byte[] data;
protected int pos = 0;
public ReluctantStream(byte[] data) {
this.data = data;
}
@Override public int read() {
if (pos == data.length) {
return -1;
} else {
return data[pos++];
}
}
@Override public int read(byte[] buf) {
return read(buf, 0, buf.length);
}
@Override public int read(byte[] buf, int offset, int size) {
if (pos == data.length) {
return -1;
}
int count = Math.min(Math.min(size, data.length - pos), 250);
System.arraycopy(data, pos, buf, offset, count);
pos += count;
return count;
}
}
// Same as above, but also implements available().
private static final class AvailableStream extends ReluctantStream {
public AvailableStream(byte[] data) {
super(data);
}
@Override public int available() {
return Math.min(250, data.length - pos);
}
}
// A stream which exposes the byte array passed into read(byte[], int, int).
private static class EvilInputStream extends InputStream {
public byte[] capturedArray = null;
@Override
public int read(byte[] buf, int off, int len) {
if (capturedArray != null) {
return -1;
} else {
capturedArray = buf;
for (int x = 0; x < len; ++x) {
buf[x] = (byte) x;
}
return len;
}
}
@Override
public int read() {
// Purposefully do nothing.
return -1;
}
}
// A stream which exposes the byte array passed into write(byte[], int, int).
private static class EvilOutputStream extends OutputStream {
public byte[] capturedArray = null;
@Override
public void write(byte[] buf, int off, int len) {
if (capturedArray == null) {
capturedArray = buf;
}
}
@Override
public void write(int ignored) {
// Purposefully do nothing.
}
}
public void testToStringUtf8() throws UnsupportedEncodingException {
String testString = "I love unicode \u1234\u5678 characters";
byte[] testBytes = testString.getBytes("UTF-8");
ByteString byteString = ByteString.copyFrom(testBytes);
assertEquals("copyToStringUtf8 must respect the charset",
testString, byteString.toStringUtf8());
}
public void testNewOutput_InitialCapacity() throws IOException {
byte[] bytes = getTestBytes();
ByteString.Output output = ByteString.newOutput(bytes.length + 100);
output.write(bytes);
ByteString byteString = output.toByteString();
assertTrue(
"String built from newOutput(int) must contain the expected bytes",
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
}
// Test newOutput() using a variety of buffer sizes and a variety of (fixed)
// write sizes
public void testNewOutput_ArrayWrite() throws IOException {
byte[] bytes = getTestBytes();
int length = bytes.length;
int[] bufferSizes = {128, 256, length / 2, length - 1, length, length + 1,
2 * length, 3 * length};
int[] writeSizes = {1, 4, 5, 7, 23, bytes.length};
for (int bufferSize : bufferSizes) {
for (int writeSize : writeSizes) {
// Test writing the entire output writeSize bytes at a time.
ByteString.Output output = ByteString.newOutput(bufferSize);
for (int i = 0; i < length; i += writeSize) {
output.write(bytes, i, Math.min(writeSize, length - i));
}
ByteString byteString = output.toByteString();
assertTrue("String built from newOutput() must contain the expected bytes",
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
}
}
}
// Test newOutput() using a variety of buffer sizes, but writing all the
// characters using write(byte);
public void testNewOutput_WriteChar() throws IOException {
byte[] bytes = getTestBytes();
int length = bytes.length;
int[] bufferSizes = {0, 1, 128, 256, length / 2,
length - 1, length, length + 1,
2 * length, 3 * length};
for (int bufferSize : bufferSizes) {
ByteString.Output output = ByteString.newOutput(bufferSize);
for (byte byteValue : bytes) {
output.write(byteValue);
}
ByteString byteString = output.toByteString();
assertTrue("String built from newOutput() must contain the expected bytes",
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
}
}
// Test newOutput() in which we write the bytes using a variety of methods
// and sizes, and in which we repeatedly call toByteString() in the middle.
public void testNewOutput_Mixed() throws IOException {
Random rng = new Random(1);
byte[] bytes = getTestBytes();
int length = bytes.length;
int[] bufferSizes = {0, 1, 128, 256, length / 2,
length - 1, length, length + 1,
2 * length, 3 * length};
for (int bufferSize : bufferSizes) {
// Test writing the entire output using a mixture of write sizes and
// methods;
ByteString.Output output = ByteString.newOutput(bufferSize);
int position = 0;
while (position < bytes.length) {
if (rng.nextBoolean()) {
int count = 1 + rng.nextInt(bytes.length - position);
output.write(bytes, position, count);
position += count;
} else {
output.write(bytes[position]);
position++;
}
assertEquals("size() returns the right value", position, output.size());
assertTrue("newOutput() substring must have correct bytes",
isArrayRange(output.toByteString().toByteArray(),
bytes, 0, position));
}
ByteString byteString = output.toByteString();
assertTrue("String built from newOutput() must contain the expected bytes",
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
}
}
public void testNewOutputEmpty() throws IOException {
// Make sure newOutput() correctly builds empty byte strings
ByteString byteString = ByteString.newOutput().toByteString();
assertEquals(ByteString.EMPTY, byteString);
}
public void testNewOutput_Mutating() throws IOException {
Output os = ByteString.newOutput(5);
os.write(new byte[] {1, 2, 3, 4, 5});
EvilOutputStream eos = new EvilOutputStream();
os.writeTo(eos);
byte[] capturedArray = eos.capturedArray;
ByteString byteString = os.toByteString();
byte[] oldValue = byteString.toByteArray();
Arrays.fill(capturedArray, (byte) 0);
byte[] newValue = byteString.toByteArray();
assertTrue("Output must not provide access to the underlying byte array",
Arrays.equals(oldValue, newValue));
}
public void testNewCodedBuilder() throws IOException {
byte[] bytes = getTestBytes();
ByteString.CodedBuilder builder = ByteString.newCodedBuilder(bytes.length);
builder.getCodedOutput().writeRawBytes(bytes);
ByteString byteString = builder.build();
assertTrue("String built from newCodedBuilder() must contain the expected bytes",
isArrayRange(bytes, byteString.toByteArray(), 0, bytes.length));
}
public void testSubstringParity() {
byte[] bigBytes = getTestBytes(2048 * 1024, 113344L);
int start = 512 * 1024 - 3333;
int end = 512 * 1024 + 7777;
ByteString concreteSubstring = ByteString.copyFrom(bigBytes).substring(start, end);
boolean ok = true;
for (int i = start; ok && i < end; ++i) {
ok = (bigBytes[i] == concreteSubstring.byteAt(i - start));
}
assertTrue("Concrete substring didn't capture the right bytes", ok);
ByteString literalString = ByteString.copyFrom(bigBytes, start, end - start);
assertTrue("Substring must be equal to literal string",
concreteSubstring.equals(literalString));
assertEquals("Substring must have same hashcode as literal string",
literalString.hashCode(), concreteSubstring.hashCode());
}
public void testCompositeSubstring() {
byte[] referenceBytes = getTestBytes(77748, 113344L);
List<ByteString> pieces = makeConcretePieces(referenceBytes);
ByteString listString = ByteString.copyFrom(pieces);
int from = 1000;
int to = 40000;
ByteString compositeSubstring = listString.substring(from, to);
byte[] substringBytes = compositeSubstring.toByteArray();
boolean stillEqual = true;
for (int i = 0; stillEqual && i < to - from; ++i) {
stillEqual = referenceBytes[from + i] == substringBytes[i];
}
assertTrue("Substring must return correct bytes", stillEqual);
stillEqual = true;
for (int i = 0; stillEqual && i < to - from; ++i) {
stillEqual = referenceBytes[from + i] == compositeSubstring.byteAt(i);
}
assertTrue("Substring must support byteAt() correctly", stillEqual);
ByteString literalSubstring = ByteString.copyFrom(referenceBytes, from, to - from);
assertTrue("Composite substring must equal a literal substring over the same bytes",
compositeSubstring.equals(literalSubstring));
assertTrue("Literal substring must equal a composite substring over the same bytes",
literalSubstring.equals(compositeSubstring));
assertEquals("We must get the same hashcodes for composite and literal substrings",
literalSubstring.hashCode(), compositeSubstring.hashCode());
assertFalse("We can't be equal to a proper substring",
compositeSubstring.equals(literalSubstring.substring(0, literalSubstring.size() - 1)));
}
public void testCopyFromList() {
byte[] referenceBytes = getTestBytes(77748, 113344L);
ByteString literalString = ByteString.copyFrom(referenceBytes);
List<ByteString> pieces = makeConcretePieces(referenceBytes);
ByteString listString = ByteString.copyFrom(pieces);
assertTrue("Composite string must be equal to literal string",
listString.equals(literalString));
assertEquals("Composite string must have same hashcode as literal string",
literalString.hashCode(), listString.hashCode());
}
public void testConcat() {
byte[] referenceBytes = getTestBytes(77748, 113344L);
ByteString literalString = ByteString.copyFrom(referenceBytes);
List<ByteString> pieces = makeConcretePieces(referenceBytes);
Iterator<ByteString> iter = pieces.iterator();
ByteString concatenatedString = iter.next();
while (iter.hasNext()) {
concatenatedString = concatenatedString.concat(iter.next());
}
assertTrue("Concatenated string must be equal to literal string",
concatenatedString.equals(literalString));
assertEquals("Concatenated string must have same hashcode as literal string",
literalString.hashCode(), concatenatedString.hashCode());
}
/**
* Test the Rope implementation can deal with Empty nodes, even though we
* guard against them. See also {@link LiteralByteStringTest#testConcat_empty()}.
*/
public void testConcat_empty() {
byte[] referenceBytes = getTestBytes(7748, 113344L);
ByteString literalString = ByteString.copyFrom(referenceBytes);
ByteString duo = RopeByteString.newInstanceForTest(literalString, literalString);
ByteString temp = RopeByteString.newInstanceForTest(
RopeByteString.newInstanceForTest(literalString, ByteString.EMPTY),
RopeByteString.newInstanceForTest(ByteString.EMPTY, literalString));
ByteString quintet = RopeByteString.newInstanceForTest(temp, ByteString.EMPTY);
assertTrue("String with concatenated nulls must equal simple concatenate",
duo.equals(quintet));
assertEquals("String with concatenated nulls have same hashcode as simple concatenate",
duo.hashCode(), quintet.hashCode());
ByteString.ByteIterator duoIter = duo.iterator();
ByteString.ByteIterator quintetIter = quintet.iterator();
boolean stillEqual = true;
while (stillEqual && quintetIter.hasNext()) {
stillEqual = (duoIter.nextByte() == quintetIter.nextByte());
}
assertTrue("We must get the same characters by iterating", stillEqual);
assertFalse("Iterator must be exhausted", duoIter.hasNext());
try {
duoIter.nextByte();
fail("Should have thrown an exception.");
} catch (NoSuchElementException e) {
// This is success
}
try {
quintetIter.nextByte();
fail("Should have thrown an exception.");
} catch (NoSuchElementException e) {
// This is success
}
// Test that even if we force empty strings in as rope leaves in this
// configuration, we always get a (possibly Bounded) LiteralByteString
// for a length 1 substring.
//
// It is possible, using the testing factory method to create deeply nested
// trees of empty leaves, to make a string that will fail this test.
for (int i = 1; i < duo.size(); ++i) {
assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
duo.substring(i - 1, i) instanceof LiteralByteString);
}
for (int i = 1; i < quintet.size(); ++i) {
assertTrue("Substrings of size() < 2 must not be RopeByteStrings",
quintet.substring(i - 1, i) instanceof LiteralByteString);
}
}
public void testStartsWith() {
byte[] bytes = getTestBytes(1000, 1234L);
ByteString string = ByteString.copyFrom(bytes);
ByteString prefix = ByteString.copyFrom(bytes, 0, 500);
ByteString suffix = ByteString.copyFrom(bytes, 400, 600);
assertTrue(string.startsWith(ByteString.EMPTY));
assertTrue(string.startsWith(string));
assertTrue(string.startsWith(prefix));
assertFalse(string.startsWith(suffix));
assertFalse(prefix.startsWith(suffix));
assertFalse(suffix.startsWith(prefix));
assertFalse(ByteString.EMPTY.startsWith(prefix));
assertTrue(ByteString.EMPTY.startsWith(ByteString.EMPTY));
}
static List<ByteString> makeConcretePieces(byte[] referenceBytes) {
List<ByteString> pieces = new ArrayList<ByteString>();
// Starting length should be small enough that we'll do some concatenating by
// copying if we just concatenate all these pieces together.
for (int start = 0, length = 16; start < referenceBytes.length; start += length) {
length = (length << 1) - 1;
if (start + length > referenceBytes.length) {
length = referenceBytes.length - start;
}
pieces.add(ByteString.copyFrom(referenceBytes, start, length));
}
return pieces;
}
}

View File

@ -0,0 +1,528 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestRecursiveMessage;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
/**
* Unit test for {@link CodedInputStream}.
*
* @author kenton@google.com Kenton Varda
*/
public class CodedInputStreamTest extends TestCase {
/**
* Helper to construct a byte array from a bunch of bytes. The inputs are
* actually ints so that I can use hex notation and not get stupid errors
* about precision.
*/
private byte[] bytes(int... bytesAsInts) {
byte[] bytes = new byte[bytesAsInts.length];
for (int i = 0; i < bytesAsInts.length; i++) {
bytes[i] = (byte) bytesAsInts[i];
}
return bytes;
}
/**
* An InputStream which limits the number of bytes it reads at a time.
* We use this to make sure that CodedInputStream doesn't screw up when
* reading in small blocks.
*/
private static final class SmallBlockInputStream extends FilterInputStream {
private final int blockSize;
public SmallBlockInputStream(byte[] data, int blockSize) {
this(new ByteArrayInputStream(data), blockSize);
}
public SmallBlockInputStream(InputStream in, int blockSize) {
super(in);
this.blockSize = blockSize;
}
public int read(byte[] b) throws IOException {
return super.read(b, 0, Math.min(b.length, blockSize));
}
public int read(byte[] b, int off, int len) throws IOException {
return super.read(b, off, Math.min(len, blockSize));
}
}
/**
* Parses the given bytes using readRawVarint32() and readRawVarint64() and
* checks that the result matches the given value.
*/
private void assertReadVarint(byte[] data, long value) throws Exception {
CodedInputStream input = CodedInputStream.newInstance(data);
assertEquals((int)value, input.readRawVarint32());
input = CodedInputStream.newInstance(data);
assertEquals(value, input.readRawVarint64());
assertTrue(input.isAtEnd());
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
assertEquals((int)value, input.readRawVarint32());
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
assertEquals(value, input.readRawVarint64());
assertTrue(input.isAtEnd());
}
// Try reading direct from an InputStream. We want to verify that it
// doesn't read past the end of the input, so we copy to a new, bigger
// array first.
byte[] longerData = new byte[data.length + 1];
System.arraycopy(data, 0, longerData, 0, data.length);
InputStream rawInput = new ByteArrayInputStream(longerData);
assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput));
assertEquals(1, rawInput.available());
}
/**
* Parses the given bytes using readRawVarint32() and readRawVarint64() and
* expects them to fail with an InvalidProtocolBufferException whose
* description matches the given one.
*/
private void assertReadVarintFailure(
InvalidProtocolBufferException expected, byte[] data)
throws Exception {
CodedInputStream input = CodedInputStream.newInstance(data);
try {
input.readRawVarint32();
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals(expected.getMessage(), e.getMessage());
}
input = CodedInputStream.newInstance(data);
try {
input.readRawVarint64();
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals(expected.getMessage(), e.getMessage());
}
// Make sure we get the same error when reading direct from an InputStream.
try {
CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals(expected.getMessage(), e.getMessage());
}
}
/** Tests readRawVarint32() and readRawVarint64(). */
public void testReadVarint() throws Exception {
assertReadVarint(bytes(0x00), 0);
assertReadVarint(bytes(0x01), 1);
assertReadVarint(bytes(0x7f), 127);
// 14882
assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
// 2961488830
assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
(0x0bL << 28));
// 64-bit
// 7256456126
assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
(0x1bL << 28));
// 41256202580718336
assertReadVarint(
bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
(0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
// 11964378330978735131
assertReadVarint(
bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
(0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
(0x05L << 49) | (0x26L << 56) | (0x01L << 63));
// Failures
assertReadVarintFailure(
InvalidProtocolBufferException.malformedVarint(),
bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x00));
assertReadVarintFailure(
InvalidProtocolBufferException.truncatedMessage(),
bytes(0x80));
}
/**
* Parses the given bytes using readRawLittleEndian32() and checks
* that the result matches the given value.
*/
private void assertReadLittleEndian32(byte[] data, int value)
throws Exception {
CodedInputStream input = CodedInputStream.newInstance(data);
assertEquals(value, input.readRawLittleEndian32());
assertTrue(input.isAtEnd());
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
assertEquals(value, input.readRawLittleEndian32());
assertTrue(input.isAtEnd());
}
}
/**
* Parses the given bytes using readRawLittleEndian64() and checks
* that the result matches the given value.
*/
private void assertReadLittleEndian64(byte[] data, long value)
throws Exception {
CodedInputStream input = CodedInputStream.newInstance(data);
assertEquals(value, input.readRawLittleEndian64());
assertTrue(input.isAtEnd());
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
input = CodedInputStream.newInstance(
new SmallBlockInputStream(data, blockSize));
assertEquals(value, input.readRawLittleEndian64());
assertTrue(input.isAtEnd());
}
}
/** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
public void testReadLittleEndian() throws Exception {
assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
assertReadLittleEndian64(
bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
assertReadLittleEndian64(
bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
0x9abcdef012345678L);
}
/** Test decodeZigZag32() and decodeZigZag64(). */
public void testDecodeZigZag() throws Exception {
assertEquals( 0, CodedInputStream.decodeZigZag32(0));
assertEquals(-1, CodedInputStream.decodeZigZag32(1));
assertEquals( 1, CodedInputStream.decodeZigZag32(2));
assertEquals(-2, CodedInputStream.decodeZigZag32(3));
assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
assertEquals( 0, CodedInputStream.decodeZigZag64(0));
assertEquals(-1, CodedInputStream.decodeZigZag64(1));
assertEquals( 1, CodedInputStream.decodeZigZag64(2));
assertEquals(-2, CodedInputStream.decodeZigZag64(3));
assertEquals(0x000000003FFFFFFFL,
CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
assertEquals(0xFFFFFFFFC0000000L,
CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
assertEquals(0x000000007FFFFFFFL,
CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
assertEquals(0xFFFFFFFF80000000L,
CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
assertEquals(0x7FFFFFFFFFFFFFFFL,
CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
assertEquals(0x8000000000000000L,
CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
}
/** Tests reading and parsing a whole message with every field type. */
public void testReadWholeMessage() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
byte[] rawBytes = message.toByteArray();
assertEquals(rawBytes.length, message.getSerializedSize());
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
// Try different block sizes.
for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
message2 = TestAllTypes.parseFrom(
new SmallBlockInputStream(rawBytes, blockSize));
TestUtil.assertAllFieldsSet(message2);
}
}
/** Tests skipField(). */
public void testSkipWholeMessage() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
byte[] rawBytes = message.toByteArray();
// Create two parallel inputs. Parse one as unknown fields while using
// skipField() to skip each field on the other. Expect the same tags.
CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
while (true) {
int tag = input1.readTag();
assertEquals(tag, input2.readTag());
if (tag == 0) {
break;
}
unknownFields.mergeFieldFrom(tag, input1);
input2.skipField(tag);
}
}
/**
* Test that a bug in skipRawBytes() has been fixed: if the skip skips
* exactly up to a limit, this should not break things.
*/
public void testSkipRawBytesBug() throws Exception {
byte[] rawBytes = new byte[] { 1, 2 };
CodedInputStream input = CodedInputStream.newInstance(rawBytes);
int limit = input.pushLimit(1);
input.skipRawBytes(1);
input.popLimit(limit);
assertEquals(2, input.readRawByte());
}
/**
* Test that a bug in skipRawBytes() has been fixed: if the skip skips
* past the end of a buffer with a limit that has been set past the end of
* that buffer, this should not break things.
*/
public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
CodedInputStream input = CodedInputStream.newInstance(
new SmallBlockInputStream(rawBytes, 3));
int limit = input.pushLimit(4);
// In order to expose the bug we need to read at least one byte to prime the
// buffer inside the CodedInputStream.
assertEquals(1, input.readRawByte());
// Skip to the end of the limit.
input.skipRawBytes(3);
assertTrue(input.isAtEnd());
input.popLimit(limit);
assertEquals(5, input.readRawByte());
}
public void testReadHugeBlob() throws Exception {
// Allocate and initialize a 1MB blob.
byte[] blob = new byte[1 << 20];
for (int i = 0; i < blob.length; i++) {
blob[i] = (byte)i;
}
// Make a message containing it.
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder);
builder.setOptionalBytes(ByteString.copyFrom(blob));
TestAllTypes message = builder.build();
// Serialize and parse it. Make sure to parse from an InputStream, not
// directly from a ByteString, so that CodedInputStream uses buffered
// reading.
TestAllTypes message2 =
TestAllTypes.parseFrom(message.toByteString().newInput());
assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
// Make sure all the other fields were parsed correctly.
TestAllTypes message3 = TestAllTypes.newBuilder(message2)
.setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
.build();
TestUtil.assertAllFieldsSet(message3);
}
public void testReadMaliciouslyLargeBlob() throws Exception {
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
output.writeRawVarint32(tag);
output.writeRawVarint32(0x7FFFFFFF);
output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
output.flush();
CodedInputStream input = rawOutput.toByteString().newCodedInput();
assertEquals(tag, input.readTag());
try {
input.readBytes();
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
}
private TestRecursiveMessage makeRecursiveMessage(int depth) {
if (depth == 0) {
return TestRecursiveMessage.newBuilder().setI(5).build();
} else {
return TestRecursiveMessage.newBuilder()
.setA(makeRecursiveMessage(depth - 1)).build();
}
}
private void assertMessageDepth(TestRecursiveMessage message, int depth) {
if (depth == 0) {
assertFalse(message.hasA());
assertEquals(5, message.getI());
} else {
assertTrue(message.hasA());
assertMessageDepth(message.getA(), depth - 1);
}
}
public void testMaliciousRecursion() throws Exception {
ByteString data64 = makeRecursiveMessage(64).toByteString();
ByteString data65 = makeRecursiveMessage(65).toByteString();
assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64);
try {
TestRecursiveMessage.parseFrom(data65);
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
CodedInputStream input = data64.newCodedInput();
input.setRecursionLimit(8);
try {
TestRecursiveMessage.parseFrom(input);
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
}
public void testSizeLimit() throws Exception {
CodedInputStream input = CodedInputStream.newInstance(
TestUtil.getAllSet().toByteString().newInput());
input.setSizeLimit(16);
try {
TestAllTypes.parseFrom(input);
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
}
public void testResetSizeCounter() throws Exception {
CodedInputStream input = CodedInputStream.newInstance(
new SmallBlockInputStream(new byte[256], 8));
input.setSizeLimit(16);
input.readRawBytes(16);
assertEquals(16, input.getTotalBytesRead());
try {
input.readRawByte();
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
input.resetSizeCounter();
assertEquals(0, input.getTotalBytesRead());
input.readRawByte(); // No exception thrown.
input.resetSizeCounter();
assertEquals(0, input.getTotalBytesRead());
try {
input.readRawBytes(16); // Hits limit again.
fail("Should have thrown an exception!");
} catch (InvalidProtocolBufferException e) {
// success.
}
}
/**
* Tests that if we read an string that contains invalid UTF-8, no exception
* is thrown. Instead, the invalid bytes are replaced with the Unicode
* "replacement character" U+FFFD.
*/
public void testReadInvalidUtf8() throws Exception {
ByteString.Output rawOutput = ByteString.newOutput();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
output.writeRawVarint32(tag);
output.writeRawVarint32(1);
output.writeRawBytes(new byte[] { (byte)0x80 });
output.flush();
CodedInputStream input = rawOutput.toByteString().newCodedInput();
assertEquals(tag, input.readTag());
String text = input.readString();
assertEquals(0xfffd, text.charAt(0));
}
public void testReadFromSlice() throws Exception {
byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
assertEquals(0, in.getTotalBytesRead());
for (int i = 3; i < 8; i++) {
assertEquals(i, in.readRawByte());
assertEquals(i-2, in.getTotalBytesRead());
}
// eof
assertEquals(0, in.readTag());
assertEquals(5, in.getTotalBytesRead());
}
public void testInvalidTag() throws Exception {
// Any tag number which corresponds to field number zero is invalid and
// should throw InvalidProtocolBufferException.
for (int i = 0; i < 8; i++) {
try {
CodedInputStream.newInstance(bytes(i)).readTag();
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
e.getMessage());
}
}
}
}

View File

@ -0,0 +1,317 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.SparseEnumMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestSparseEnum;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Unit test for {@link CodedOutputStream}.
*
* @author kenton@google.com Kenton Varda
*/
public class CodedOutputStreamTest extends TestCase {
/**
* Helper to construct a byte array from a bunch of bytes. The inputs are
* actually ints so that I can use hex notation and not get stupid errors
* about precision.
*/
private byte[] bytes(int... bytesAsInts) {
byte[] bytes = new byte[bytesAsInts.length];
for (int i = 0; i < bytesAsInts.length; i++) {
bytes[i] = (byte) bytesAsInts[i];
}
return bytes;
}
/** Arrays.asList() does not work with arrays of primitives. :( */
private List<Byte> toList(byte[] bytes) {
List<Byte> result = new ArrayList<Byte>();
for (byte b : bytes) {
result.add(b);
}
return result;
}
private void assertEqualBytes(byte[] a, byte[] b) {
assertEquals(toList(a), toList(b));
}
/**
* Writes the given value using writeRawVarint32() and writeRawVarint64() and
* checks that the result matches the given bytes.
*/
private void assertWriteVarint(byte[] data, long value) throws Exception {
// Only do 32-bit write if the value fits in 32 bits.
if ((value >>> 32) == 0) {
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawVarint32((int) value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
// Also try computing size.
assertEquals(data.length,
CodedOutputStream.computeRawVarint32Size((int) value));
}
{
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawVarint64(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
// Also try computing size.
assertEquals(data.length,
CodedOutputStream.computeRawVarint64Size(value));
}
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
// Only do 32-bit write if the value fits in 32 bits.
if ((value >>> 32) == 0) {
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output =
CodedOutputStream.newInstance(rawOutput, blockSize);
output.writeRawVarint32((int) value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
}
{
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output =
CodedOutputStream.newInstance(rawOutput, blockSize);
output.writeRawVarint64(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
}
}
}
/** Tests writeRawVarint32() and writeRawVarint64(). */
public void testWriteVarint() throws Exception {
assertWriteVarint(bytes(0x00), 0);
assertWriteVarint(bytes(0x01), 1);
assertWriteVarint(bytes(0x7f), 127);
// 14882
assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
// 2961488830
assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
(0x0bL << 28));
// 64-bit
// 7256456126
assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
(0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
(0x1bL << 28));
// 41256202580718336
assertWriteVarint(
bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
(0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
(0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
// 11964378330978735131
assertWriteVarint(
bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
(0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
(0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
(0x05L << 49) | (0x26L << 56) | (0x01L << 63));
}
/**
* Parses the given bytes using writeRawLittleEndian32() and checks
* that the result matches the given value.
*/
private void assertWriteLittleEndian32(byte[] data, int value)
throws Exception {
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawLittleEndian32(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
rawOutput = new ByteArrayOutputStream();
output = CodedOutputStream.newInstance(rawOutput, blockSize);
output.writeRawLittleEndian32(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
}
}
/**
* Parses the given bytes using writeRawLittleEndian64() and checks
* that the result matches the given value.
*/
private void assertWriteLittleEndian64(byte[] data, long value)
throws Exception {
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
output.writeRawLittleEndian64(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
// Try different block sizes.
for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
rawOutput = new ByteArrayOutputStream();
output = CodedOutputStream.newInstance(rawOutput, blockSize);
output.writeRawLittleEndian64(value);
output.flush();
assertEqualBytes(data, rawOutput.toByteArray());
}
}
/** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
public void testWriteLittleEndian() throws Exception {
assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
assertWriteLittleEndian64(
bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
0x123456789abcdef0L);
assertWriteLittleEndian64(
bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
0x9abcdef012345678L);
}
/** Test encodeZigZag32() and encodeZigZag64(). */
public void testEncodeZigZag() throws Exception {
assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
assertEquals(2, CodedOutputStream.encodeZigZag32( 1));
assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
assertEquals(2, CodedOutputStream.encodeZigZag64( 1));
assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
assertEquals(0x000000007FFFFFFEL,
CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
assertEquals(0x000000007FFFFFFFL,
CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
assertEquals(0x00000000FFFFFFFEL,
CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
assertEquals(0x00000000FFFFFFFFL,
CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
assertEquals(0xFFFFFFFFFFFFFFFEL,
CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
assertEquals(0xFFFFFFFFFFFFFFFFL,
CodedOutputStream.encodeZigZag64(0x8000000000000000L));
// Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1)
// were chosen semi-randomly via keyboard bashing.
assertEquals(0,
CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
assertEquals(1,
CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
assertEquals(-1,
CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
assertEquals(14927,
CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
assertEquals(-3612,
CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
assertEquals(0,
CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
assertEquals(1,
CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
assertEquals(-1,
CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
assertEquals(14927,
CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
assertEquals(-3612,
CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
assertEquals(856912304801416L,
CodedOutputStream.encodeZigZag64(
CodedInputStream.decodeZigZag64(
856912304801416L)));
assertEquals(-75123905439571256L,
CodedOutputStream.encodeZigZag64(
CodedInputStream.decodeZigZag64(
-75123905439571256L)));
}
/** Tests writing a whole message with every field type. */
public void testWriteWholeMessage() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
byte[] rawBytes = message.toByteArray();
assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
// Try different block sizes.
for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
CodedOutputStream output =
CodedOutputStream.newInstance(rawOutput, blockSize);
message.writeTo(output);
output.flush();
assertEqualBytes(rawBytes, rawOutput.toByteArray());
}
}
/** Tests writing a whole message with every packed field type. Ensures the
* wire format of packed fields is compatible with C++. */
public void testWriteWholePackedFieldsMessage() throws Exception {
TestPackedTypes message = TestUtil.getPackedSet();
byte[] rawBytes = message.toByteArray();
assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
rawBytes);
}
/** Test writing a message containing a negative enum value. This used to
* fail because the size was not properly computed as a sign-extended varint.
*/
public void testWriteMessageWithNegativeEnumValue() throws Exception {
SparseEnumMessage message = SparseEnumMessage.newBuilder()
.setSparseEnum(TestSparseEnum.SPARSE_E) .build();
assertTrue(message.getSparseEnum().getNumber() < 0);
byte[] rawBytes = message.toByteArray();
SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes);
assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum());
}
}

View File

@ -0,0 +1,80 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestDeprecatedFields;
import junit.framework.TestCase;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
/**
* Test field deprecation
*
* @author birdo@google.com (Roberto Scaramuzzi)
*/
public class DeprecatedFieldTest extends TestCase {
private String[] deprecatedGetterNames = {
"hasDeprecatedInt32",
"getDeprecatedInt32"};
private String[] deprecatedBuilderGetterNames = {
"hasDeprecatedInt32",
"getDeprecatedInt32",
"clearDeprecatedInt32"};
private String[] deprecatedBuilderSetterNames = {
"setDeprecatedInt32"};
public void testDeprecatedField() throws Exception {
Class<?> deprecatedFields = TestDeprecatedFields.class;
Class<?> deprecatedFieldsBuilder = TestDeprecatedFields.Builder.class;
for (String name : deprecatedGetterNames) {
Method method = deprecatedFields.getMethod(name);
assertTrue("Method " + name + " should be deprecated",
isDeprecated(method));
}
for (String name : deprecatedBuilderGetterNames) {
Method method = deprecatedFieldsBuilder.getMethod(name);
assertTrue("Method " + name + " should be deprecated",
isDeprecated(method));
}
for (String name : deprecatedBuilderSetterNames) {
Method method = deprecatedFieldsBuilder.getMethod(name, int.class);
assertTrue("Method " + name + " should be deprecated",
isDeprecated(method));
}
}
private boolean isDeprecated(AnnotatedElement annotated) {
return annotated.isAnnotationPresent(Deprecated.class);
}
}

View File

@ -0,0 +1,648 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.test.UnittestImport;
import com.google.protobuf.test.UnittestImport.ImportEnum;
import com.google.protobuf.test.UnittestImport.ImportMessage;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestService;
import protobuf_unittest.UnittestCustomOptions;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Unit test for {@link Descriptors}.
*
* @author kenton@google.com Kenton Varda
*/
public class DescriptorsTest extends TestCase {
// Regression test for bug where referencing a FieldDescriptor.Type value
// before a FieldDescriptorProto.Type value would yield a
// ExceptionInInitializerError.
@SuppressWarnings("unused")
private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
public void testFieldTypeEnumMapping() throws Exception {
assertEquals(FieldDescriptor.Type.values().length,
FieldDescriptorProto.Type.values().length);
for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
FieldDescriptorProto.Type protoType = type.toProto();
assertEquals("TYPE_" + type.name(), protoType.name());
assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
}
}
public void testFileDescriptor() throws Exception {
FileDescriptor file = UnittestProto.getDescriptor();
assertEquals("google/protobuf/unittest.proto", file.getName());
assertEquals("protobuf_unittest", file.getPackage());
assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
assertEquals("google/protobuf/unittest.proto",
file.toProto().getName());
assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
file.getDependencies());
Descriptor messageType = TestAllTypes.getDescriptor();
assertEquals(messageType, file.getMessageTypes().get(0));
assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
assertNull(file.findMessageTypeByName("NoSuchType"));
assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
for (int i = 0; i < file.getMessageTypes().size(); i++) {
assertEquals(i, file.getMessageTypes().get(i).getIndex());
}
EnumDescriptor enumType = ForeignEnum.getDescriptor();
assertEquals(enumType, file.getEnumTypes().get(0));
assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
assertNull(file.findEnumTypeByName("NoSuchType"));
assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
UnittestImport.getDescriptor().getEnumTypes());
for (int i = 0; i < file.getEnumTypes().size(); i++) {
assertEquals(i, file.getEnumTypes().get(i).getIndex());
}
ServiceDescriptor service = TestService.getDescriptor();
assertEquals(service, file.getServices().get(0));
assertEquals(service, file.findServiceByName("TestService"));
assertNull(file.findServiceByName("NoSuchType"));
assertNull(file.findServiceByName("protobuf_unittest.TestService"));
assertEquals(Collections.emptyList(),
UnittestImport.getDescriptor().getServices());
for (int i = 0; i < file.getServices().size(); i++) {
assertEquals(i, file.getServices().get(i).getIndex());
}
FieldDescriptor extension =
UnittestProto.optionalInt32Extension.getDescriptor();
assertEquals(extension, file.getExtensions().get(0));
assertEquals(extension,
file.findExtensionByName("optional_int32_extension"));
assertNull(file.findExtensionByName("no_such_ext"));
assertNull(file.findExtensionByName(
"protobuf_unittest.optional_int32_extension"));
assertEquals(Collections.emptyList(),
UnittestImport.getDescriptor().getExtensions());
for (int i = 0; i < file.getExtensions().size(); i++) {
assertEquals(i, file.getExtensions().get(i).getIndex());
}
}
public void testDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor();
Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
assertEquals("TestAllTypes", messageType.getName());
assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
assertNull(messageType.getContainingType());
assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
messageType.getOptions());
assertEquals("TestAllTypes", messageType.toProto().getName());
assertEquals("NestedMessage", nestedType.getName());
assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(messageType, nestedType.getContainingType());
FieldDescriptor field = messageType.getFields().get(0);
assertEquals("optional_int32", field.getName());
assertEquals(field, messageType.findFieldByName("optional_int32"));
assertNull(messageType.findFieldByName("no_such_field"));
assertEquals(field, messageType.findFieldByNumber(1));
assertNull(messageType.findFieldByNumber(571283));
for (int i = 0; i < messageType.getFields().size(); i++) {
assertEquals(i, messageType.getFields().get(i).getIndex());
}
assertEquals(nestedType, messageType.getNestedTypes().get(0));
assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
assertNull(messageType.findNestedTypeByName("NoSuchType"));
for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
}
EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
assertEquals(enumType, messageType.getEnumTypes().get(0));
assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
assertNull(messageType.findEnumTypeByName("NoSuchType"));
for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
}
}
public void testFieldDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor();
FieldDescriptor primitiveField =
messageType.findFieldByName("optional_int32");
FieldDescriptor enumField =
messageType.findFieldByName("optional_nested_enum");
FieldDescriptor messageField =
messageType.findFieldByName("optional_foreign_message");
FieldDescriptor cordField =
messageType.findFieldByName("optional_cord");
FieldDescriptor extension =
UnittestProto.optionalInt32Extension.getDescriptor();
FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
assertEquals("optional_int32", primitiveField.getName());
assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
primitiveField.getFullName());
assertEquals(1, primitiveField.getNumber());
assertEquals(messageType, primitiveField.getContainingType());
assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
primitiveField.getOptions());
assertFalse(primitiveField.isExtension());
assertEquals("optional_int32", primitiveField.toProto().getName());
assertEquals("optional_nested_enum", enumField.getName());
assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
enumField.getEnumType());
assertEquals("optional_foreign_message", messageField.getName());
assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
assertEquals("optional_cord", cordField.getName());
assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
cordField.getOptions().getCtype());
assertEquals("optional_int32_extension", extension.getName());
assertEquals("protobuf_unittest.optional_int32_extension",
extension.getFullName());
assertEquals(1, extension.getNumber());
assertEquals(TestAllExtensions.getDescriptor(),
extension.getContainingType());
assertEquals(UnittestProto.getDescriptor(), extension.getFile());
assertEquals(FieldDescriptor.Type.INT32, extension.getType());
assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
extension.getOptions());
assertTrue(extension.isExtension());
assertEquals(null, extension.getExtensionScope());
assertEquals("optional_int32_extension", extension.toProto().getName());
assertEquals("single", nestedExtension.getName());
assertEquals("protobuf_unittest.TestRequired.single",
nestedExtension.getFullName());
assertEquals(TestRequired.getDescriptor(),
nestedExtension.getExtensionScope());
}
public void testFieldDescriptorLabel() throws Exception {
FieldDescriptor requiredField =
TestRequired.getDescriptor().findFieldByName("a");
FieldDescriptor optionalField =
TestAllTypes.getDescriptor().findFieldByName("optional_int32");
FieldDescriptor repeatedField =
TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
assertTrue(requiredField.isRequired());
assertFalse(requiredField.isRepeated());
assertFalse(optionalField.isRequired());
assertFalse(optionalField.isRepeated());
assertFalse(repeatedField.isRequired());
assertTrue(repeatedField.isRepeated());
}
public void testFieldDescriptorDefault() throws Exception {
Descriptor d = TestAllTypes.getDescriptor();
assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
d = TestExtremeDefaultValues.getDescriptor();
assertEquals(
ByteString.copyFrom(
"\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
d.findFieldByName("escaped_bytes").getDefaultValue());
assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
}
public void testEnumDescriptor() throws Exception {
EnumDescriptor enumType = ForeignEnum.getDescriptor();
EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
assertEquals("ForeignEnum", enumType.getName());
assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
assertNull(enumType.getContainingType());
assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
enumType.getOptions());
assertEquals("NestedEnum", nestedType.getName());
assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
nestedType.getFullName());
assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
assertEquals(value, enumType.getValues().get(0));
assertEquals("FOREIGN_FOO", value.getName());
assertEquals(4, value.getNumber());
assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
assertEquals(value, enumType.findValueByNumber(4));
assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
for (int i = 0; i < enumType.getValues().size(); i++) {
assertEquals(i, enumType.getValues().get(i).getIndex());
}
}
public void testServiceDescriptor() throws Exception {
ServiceDescriptor service = TestService.getDescriptor();
assertEquals("TestService", service.getName());
assertEquals("protobuf_unittest.TestService", service.getFullName());
assertEquals(UnittestProto.getDescriptor(), service.getFile());
assertEquals(2, service.getMethods().size());
MethodDescriptor fooMethod = service.getMethods().get(0);
assertEquals("Foo", fooMethod.getName());
assertEquals(UnittestProto.FooRequest.getDescriptor(),
fooMethod.getInputType());
assertEquals(UnittestProto.FooResponse.getDescriptor(),
fooMethod.getOutputType());
assertEquals(fooMethod, service.findMethodByName("Foo"));
MethodDescriptor barMethod = service.getMethods().get(1);
assertEquals("Bar", barMethod.getName());
assertEquals(UnittestProto.BarRequest.getDescriptor(),
barMethod.getInputType());
assertEquals(UnittestProto.BarResponse.getDescriptor(),
barMethod.getOutputType());
assertEquals(barMethod, service.findMethodByName("Bar"));
assertNull(service.findMethodByName("NoSuchMethod"));
for (int i = 0; i < service.getMethods().size(); i++) {
assertEquals(i, service.getMethods().get(i).getIndex());
}
}
public void testCustomOptions() throws Exception {
Descriptor descriptor =
UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
assertTrue(
descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
assertEquals(Integer.valueOf(-56),
descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
FieldDescriptor field = descriptor.findFieldByName("field1");
assertNotNull(field);
assertTrue(
field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
assertEquals(Long.valueOf(8765432109L),
field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
EnumDescriptor enumType =
UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
assertTrue(
enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
assertEquals(Integer.valueOf(-789),
enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
ServiceDescriptor service =
UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
assertTrue(
service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
assertEquals(Long.valueOf(-9876543210L),
service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
MethodDescriptor method = service.findMethodByName("Foo");
assertNotNull(method);
assertTrue(
method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
}
/**
* Test that the FieldDescriptor.Type enum is the same as the
* WireFormat.FieldType enum.
*/
public void testFieldTypeTablesMatch() throws Exception {
FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
assertEquals(values1.length, values2.length);
for (int i = 0; i < values1.length; i++) {
assertEquals(values1[i].toString(), values2[i].toString());
}
}
/**
* Test that the FieldDescriptor.JavaType enum is the same as the
* WireFormat.JavaType enum.
*/
public void testJavaTypeTablesMatch() throws Exception {
FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
assertEquals(values1.length, values2.length);
for (int i = 0; i < values1.length; i++) {
assertEquals(values1[i].toString(), values2[i].toString());
}
}
public void testEnormousDescriptor() throws Exception {
// The descriptor for this file is larger than 64k, yet it did not cause
// a compiler error due to an over-long string literal.
assertTrue(
UnittestEnormousDescriptor.getDescriptor()
.toProto().getSerializedSize() > 65536);
}
/**
* Tests that the DescriptorValidationException works as intended.
*/
public void testDescriptorValidatorException() throws Exception {
FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addMessageType(DescriptorProto.newBuilder()
.setName("Foo")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.setName("foo")
.setNumber(1)
.setDefaultValue("invalid")
.build())
.build())
.build();
try {
Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
new FileDescriptor[0]);
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
// Expected; check that the error message contains some useful hints
assertTrue(e.getMessage().indexOf("foo") != -1);
assertTrue(e.getMessage().indexOf("Foo") != -1);
assertTrue(e.getMessage().indexOf("invalid") != -1);
assertTrue(e.getCause() instanceof NumberFormatException);
assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
}
}
/**
* Tests the translate/crosslink for an example where a message field's name
* and type name are the same.
*/
public void testDescriptorComplexCrosslink() throws Exception {
FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addMessageType(DescriptorProto.newBuilder()
.setName("Foo")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setType(FieldDescriptorProto.Type.TYPE_INT32)
.setName("foo")
.setNumber(1)
.build())
.build())
.addMessageType(DescriptorProto.newBuilder()
.setName("Bar")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Foo")
.setName("Foo")
.setNumber(1)
.build())
.build())
.build();
// translate and crosslink
FileDescriptor file =
Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
new FileDescriptor[0]);
// verify resulting descriptors
assertNotNull(file);
List<Descriptor> msglist = file.getMessageTypes();
assertNotNull(msglist);
assertTrue(msglist.size() == 2);
boolean barFound = false;
for (Descriptor desc : msglist) {
if (desc.getName().equals("Bar")) {
barFound = true;
assertNotNull(desc.getFields());
List<FieldDescriptor> fieldlist = desc.getFields();
assertNotNull(fieldlist);
assertTrue(fieldlist.size() == 1);
assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
}
}
assertTrue(barFound);
}
public void testInvalidPublicDependency() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("foo.proto") .build();
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("boo.proto")
.addDependency("foo.proto")
.addPublicDependency(1) // Error, should be 0.
.build();
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
new FileDescriptor[0]);
try {
Descriptors.FileDescriptor.buildFrom(barProto,
new FileDescriptor[] {fooFile});
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
assertTrue(
e.getMessage().indexOf("Invalid public dependency index.") != -1);
}
}
public void testHiddenDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("bar.proto")
.addMessageType(DescriptorProto.newBuilder().setName("Bar"))
.build();
FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
.setName("forward.proto")
.addDependency("bar.proto")
.build();
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addDependency("forward.proto")
.addMessageType(DescriptorProto.newBuilder()
.setName("Foo")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar")
.setName("bar")
.setNumber(1)))
.build();
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
barProto, new FileDescriptor[0]);
FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
forwardProto, new FileDescriptor[] {barFile});
try {
Descriptors.FileDescriptor.buildFrom(
fooProto, new FileDescriptor[] {forwardFile});
fail("DescriptorValidationException expected");
} catch (DescriptorValidationException e) {
assertTrue(e.getMessage().indexOf("Bar") != -1);
assertTrue(e.getMessage().indexOf("is not defined") != -1);
}
}
public void testPublicDependency() throws Exception {
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("bar.proto")
.addMessageType(DescriptorProto.newBuilder().setName("Bar"))
.build();
FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
.setName("forward.proto")
.addDependency("bar.proto")
.addPublicDependency(0)
.build();
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addDependency("forward.proto")
.addMessageType(DescriptorProto.newBuilder()
.setName("Foo")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
.setTypeName("Bar")
.setName("bar")
.setNumber(1)))
.build();
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
barProto, new FileDescriptor[0]);
FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
forwardProto, new FileDescriptor[]{barFile});
Descriptors.FileDescriptor.buildFrom(
fooProto, new FileDescriptor[] {forwardFile});
}
/**
* Tests the translate/crosslink for an example with a more complex namespace
* referencing.
*/
public void testComplexNamespacePublicDependency() throws Exception {
FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
.setName("bar.proto")
.setPackage("a.b.c.d.bar.shared")
.addEnumType(EnumDescriptorProto.newBuilder()
.setName("MyEnum")
.addValue(EnumValueDescriptorProto.newBuilder()
.setName("BLAH")
.setNumber(1)))
.build();
FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
.setName("foo.proto")
.addDependency("bar.proto")
.setPackage("a.b.c.d.foo.shared")
.addMessageType(DescriptorProto.newBuilder()
.setName("MyMessage")
.addField(FieldDescriptorProto.newBuilder()
.setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
.setTypeName("bar.shared.MyEnum")
.setName("MyField")
.setNumber(1)))
.build();
// translate and crosslink
FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
fooProto, new FileDescriptor[0]);
FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
barProto, new FileDescriptor[]{fooFile});
// verify resulting descriptors
assertNotNull(barFile);
List<Descriptor> msglist = barFile.getMessageTypes();
assertNotNull(msglist);
assertTrue(msglist.size() == 1);
Descriptor desc = msglist.get(0);
if (desc.getName().equals("MyMessage")) {
assertNotNull(desc.getFields());
List<FieldDescriptor> fieldlist = desc.getFields();
assertNotNull(fieldlist);
assertTrue(fieldlist.size() == 1);
FieldDescriptor field = fieldlist.get(0);
assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
assertTrue(field.getEnumType().getName().equals("MyEnum"));
assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
assertTrue(field.getEnumType().getFile().getPackage().equals(
"a.b.c.d.bar.shared"));
}
}
}

View File

@ -0,0 +1,264 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import junit.framework.TestCase;
import java.util.Arrays;
/**
* Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which
* tests some {@link DynamicMessage} functionality.
*
* @author kenton@google.com Kenton Varda
*/
public class DynamicMessageTest extends TestCase {
TestUtil.ReflectionTester reflectionTester =
new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
TestUtil.ReflectionTester extensionsReflectionTester =
new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
TestUtil.getExtensionRegistry());
TestUtil.ReflectionTester packedReflectionTester =
new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
public void testDynamicMessageAccessors() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.setAllFieldsViaReflection(builder);
Message message = builder.build();
reflectionTester.assertAllFieldsSetViaReflection(message);
}
public void testSettersAfterBuild() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
Message firstMessage = builder.build();
// double build()
builder.build();
// clear() after build()
builder.clear();
// setters after build()
reflectionTester.setAllFieldsViaReflection(builder);
Message message = builder.build();
reflectionTester.assertAllFieldsSetViaReflection(message);
// repeated setters after build()
reflectionTester.modifyRepeatedFieldsViaReflection(builder);
message = builder.build();
reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
// firstMessage shouldn't have been modified.
reflectionTester.assertClearViaReflection(firstMessage);
}
public void testUnknownFields() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor());
builder.setUnknownFields(UnknownFieldSet.newBuilder()
.addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
.addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build())
.build());
Message message = builder.build();
assertEquals(2, message.getUnknownFields().asMap().size());
// clone() with unknown fields
Message.Builder newBuilder = builder.clone();
assertEquals(2, newBuilder.getUnknownFields().asMap().size());
// clear() with unknown fields
newBuilder.clear();
assertTrue(newBuilder.getUnknownFields().asMap().isEmpty());
// serialize/parse with unknown fields
newBuilder.mergeFrom(message.toByteString());
assertEquals(2, newBuilder.getUnknownFields().asMap().size());
}
public void testDynamicMessageSettersRejectNull() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.assertReflectionSettersRejectNull(builder);
}
public void testDynamicMessageExtensionAccessors() throws Exception {
// We don't need to extensively test DynamicMessage's handling of
// extensions because, frankly, it doesn't do anything special with them.
// It treats them just like any other fields.
Message.Builder builder =
DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
extensionsReflectionTester.setAllFieldsViaReflection(builder);
Message message = builder.build();
extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
}
public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
}
public void testDynamicMessageRepeatedSetters() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.setAllFieldsViaReflection(builder);
reflectionTester.modifyRepeatedFieldsViaReflection(builder);
Message message = builder.build();
reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
}
public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
}
public void testDynamicMessageDefaults() throws Exception {
reflectionTester.assertClearViaReflection(
DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
reflectionTester.assertClearViaReflection(
DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
}
public void testDynamicMessageSerializedSize() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
Message.Builder dynamicBuilder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
Message dynamicMessage = dynamicBuilder.build();
assertEquals(message.getSerializedSize(),
dynamicMessage.getSerializedSize());
}
public void testDynamicMessageSerialization() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.setAllFieldsViaReflection(builder);
Message message = builder.build();
ByteString rawBytes = message.toByteString();
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
// In fact, the serialized forms should be exactly the same, byte-for-byte.
assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
}
public void testDynamicMessageParsing() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder);
TestAllTypes message = builder.build();
ByteString rawBytes = message.toByteString();
Message message2 =
DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
reflectionTester.assertAllFieldsSetViaReflection(message2);
// Test Parser interface.
Message message3 = message2.getParserForType().parseFrom(rawBytes);
reflectionTester.assertAllFieldsSetViaReflection(message3);
}
public void testDynamicMessageExtensionParsing() throws Exception {
ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString();
Message message = DynamicMessage.parseFrom(
TestAllExtensions.getDescriptor(), rawBytes,
TestUtil.getExtensionRegistry());
extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
// Test Parser interface.
Message message2 = message.getParserForType().parseFrom(
rawBytes, TestUtil.getExtensionRegistry());
extensionsReflectionTester.assertAllFieldsSetViaReflection(message2);
}
public void testDynamicMessagePackedSerialization() throws Exception {
Message.Builder builder =
DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
packedReflectionTester.setPackedFieldsViaReflection(builder);
Message message = builder.build();
ByteString rawBytes = message.toByteString();
TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
TestUtil.assertPackedFieldsSet(message2);
// In fact, the serialized forms should be exactly the same, byte-for-byte.
assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
}
public void testDynamicMessagePackedParsing() throws Exception {
TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
TestUtil.setPackedFields(builder);
TestPackedTypes message = builder.build();
ByteString rawBytes = message.toByteString();
Message message2 =
DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
// Test Parser interface.
Message message3 = message2.getParserForType().parseFrom(rawBytes);
packedReflectionTester.assertPackedFieldsSetViaReflection(message3);
}
public void testDynamicMessageCopy() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestUtil.setAllFields(builder);
TestAllTypes message = builder.build();
DynamicMessage copy = DynamicMessage.newBuilder(message).build();
reflectionTester.assertAllFieldsSetViaReflection(copy);
}
public void testToBuilder() throws Exception {
DynamicMessage.Builder builder =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
reflectionTester.setAllFieldsViaReflection(builder);
int unknownFieldNum = 9;
long unknownFieldVal = 90;
builder.setUnknownFields(UnknownFieldSet.newBuilder()
.addField(unknownFieldNum,
UnknownFieldSet.Field.newBuilder()
.addVarint(unknownFieldVal).build())
.build());
DynamicMessage message = builder.build();
DynamicMessage derived = message.toBuilder().build();
reflectionTester.assertAllFieldsSetViaReflection(derived);
assertEquals(Arrays.asList(unknownFieldVal),
derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
}
}

View File

@ -0,0 +1,48 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
/**
* A prerun for a test suite that allows running the full protocol buffer
* tests in a mode that disables the optimization for not using
* {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder} until they are
* requested. This allows us to run all the tests through both code paths
* and ensures that both code paths produce identical results.
*
* @author jonp@google.com (Jon Perlow)
*/
public class ForceFieldBuildersPreRun implements Runnable {
//@Override (Java 1.6 override semantics, but we must support 1.5)
public void run() {
GeneratedMessage.enableAlwaysUseFieldBuildersForTesting();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,180 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.IsValidUtf8TestUtil.Shard;
import junit.framework.TestCase;
import java.io.UnsupportedEncodingException;
/**
* Tests cases for {@link ByteString#isValidUtf8()}. This includes three
* brute force tests that actually test every permutation of one byte, two byte,
* and three byte sequences to ensure that the method produces the right result
* for every possible byte encoding where "right" means it's consistent with
* java's UTF-8 string encoding/decoding such that the method returns true for
* any sequence that will round trip when converted to a String and then back to
* bytes and will return false for any sequence that will not round trip.
* See also {@link IsValidUtf8FourByteTest}. It also includes some
* other more targeted tests.
*
* @author jonp@google.com (Jon Perlow)
* @author martinrb@google.com (Martin Buchholz)
*/
public class IsValidUtf8Test extends TestCase {
/**
* Tests that round tripping of all two byte permutations work.
*/
public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException {
IsValidUtf8TestUtil.testBytes(1,
IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
* Tests that round tripping of all two byte permutations work.
*/
public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException {
IsValidUtf8TestUtil.testBytes(2,
IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
* Tests that round tripping of all three byte permutations work.
*/
public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException {
IsValidUtf8TestUtil.testBytes(3,
IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT);
}
/**
* Tests that round tripping of a sample of four byte permutations work.
* All permutations are prohibitively expensive to test for automated runs;
* {@link IsValidUtf8FourByteTest} is used for full coverage. This method
* tests specific four-byte cases.
*/
public void testIsValidUtf8_4BytesSamples()
throws UnsupportedEncodingException {
// Valid 4 byte.
assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2);
// Bad trailing bytes
assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0x7F);
assertInvalidUtf8(0xF0, 0xA4, 0xAD, 0xC0);
// Special cases for byte2
assertInvalidUtf8(0xF0, 0x8F, 0xAD, 0xA2);
assertInvalidUtf8(0xF4, 0x90, 0xAD, 0xA2);
}
/**
* Tests some hard-coded test cases.
*/
public void testSomeSequences() {
// Empty
assertTrue(asBytes("").isValidUtf8());
// One-byte characters, including control characters
assertTrue(asBytes("\u0000abc\u007f").isValidUtf8());
// Two-byte characters
assertTrue(asBytes("\u00a2\u00a2").isValidUtf8());
// Three-byte characters
assertTrue(asBytes("\u020ac\u020ac").isValidUtf8());
// Four-byte characters
assertTrue(asBytes("\u024B62\u024B62").isValidUtf8());
// Mixed string
assertTrue(
asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62")
.isValidUtf8());
// Not a valid string
assertInvalidUtf8(-1, 0, -1, 0);
}
private byte[] toByteArray(int... bytes) {
byte[] realBytes = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++) {
realBytes[i] = (byte) bytes[i];
}
return realBytes;
}
private ByteString toByteString(int... bytes) {
return ByteString.copyFrom(toByteArray(bytes));
}
private void assertValidUtf8(int[] bytes, boolean not) {
byte[] realBytes = toByteArray(bytes);
assertTrue(not ^ Utf8.isValidUtf8(realBytes));
assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length));
ByteString lit = ByteString.copyFrom(realBytes);
ByteString sub = lit.substring(0, bytes.length);
assertTrue(not ^ lit.isValidUtf8());
assertTrue(not ^ sub.isValidUtf8());
ByteString[] ropes = {
RopeByteString.newInstanceForTest(ByteString.EMPTY, lit),
RopeByteString.newInstanceForTest(ByteString.EMPTY, sub),
RopeByteString.newInstanceForTest(lit, ByteString.EMPTY),
RopeByteString.newInstanceForTest(sub, ByteString.EMPTY),
RopeByteString.newInstanceForTest(sub, lit)
};
for (ByteString rope : ropes) {
assertTrue(not ^ rope.isValidUtf8());
}
}
private void assertValidUtf8(int... bytes) {
assertValidUtf8(bytes, false);
}
private void assertInvalidUtf8(int... bytes) {
assertValidUtf8(bytes, true);
}
private static ByteString asBytes(String s) {
return ByteString.copyFromUtf8(s);
}
public void testShardsHaveExpectedRoundTrippables() {
// A sanity check.
int actual = 0;
for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) {
actual += shard.expected;
}
assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT,
actual);
}
}

View File

@ -0,0 +1,421 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import static junit.framework.Assert.*;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.Charset;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
/**
* Shared testing code for {@link IsValidUtf8Test} and
* {@link IsValidUtf8FourByteTest}.
*
* @author jonp@google.com (Jon Perlow)
* @author martinrb@google.com (Martin Buchholz)
*/
class IsValidUtf8TestUtil {
private static Logger logger = Logger.getLogger(
IsValidUtf8TestUtil.class.getName());
// 128 - [chars 0x0000 to 0x007f]
static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1;
// 128
static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT =
ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 1920 [chars 0x0080 to 0x07FF]
static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1;
// 18,304
static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
// Both bytes are one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) +
// The possible number of two byte characters
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 2048
static long THREE_BYTE_SURROGATES = 2 * 1024;
// 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES;
// 2,650,112
static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
// All one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) +
// One two byte character and a one byte character
2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Three byte characters
THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
// 1,048,576 [chars 0x10000L to 0x10FFFF]
static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1;
// 289,571,839
static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT =
// All one byte characters
(long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) +
// One and three byte characters
2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Two two byte characters
TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Permutations of one and two byte characters
3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS *
ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS *
ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS +
// Four byte characters
FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS;
static class Shard {
final long index;
final long start;
final long lim;
final long expected;
public Shard(long index, long start, long lim, long expected) {
assertTrue(start < lim);
this.index = index;
this.start = start;
this.lim = lim;
this.expected = expected;
}
}
static final long[] FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES =
generateFourByteShardsExpectedRunnables();
private static long[] generateFourByteShardsExpectedRunnables() {
long[] expected = new long[128];
// 0-63 are all 5300224
for (int i = 0; i <= 63; i++) {
expected[i] = 5300224;
}
// 97-111 are all 2342912
for (int i = 97; i <= 111; i++) {
expected[i] = 2342912;
}
// 113-117 are all 1048576
for (int i = 113; i <= 117; i++) {
expected[i] = 1048576;
}
// One offs
expected[112] = 786432;
expected[118] = 786432;
expected[119] = 1048576;
expected[120] = 458752;
expected[121] = 524288;
expected[122] = 65536;
// Anything not assigned was the default 0.
return expected;
}
static final List<Shard> FOUR_BYTE_SHARDS = generateFourByteShards(
128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES);
private static List<Shard> generateFourByteShards(
int numShards, long[] expected) {
assertEquals(numShards, expected.length);
List<Shard> shards = new ArrayList<Shard>(numShards);
long LIM = 1L << 32;
long increment = LIM / numShards;
assertTrue(LIM % numShards == 0);
for (int i = 0; i < numShards; i++) {
shards.add(new Shard(i,
increment * i,
increment * (i + 1),
expected[i]));
}
return shards;
}
/**
* Helper to run the loop to test all the permutations for the number of bytes
* specified.
*
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
*/
static void testBytes(int numBytes, long expectedCount)
throws UnsupportedEncodingException {
testBytes(numBytes, expectedCount, 0, -1);
}
/**
* Helper to run the loop to test all the permutations for the number of bytes
* specified. This overload is useful for debugging to get the loop to start
* at a certain character.
*
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
* @param start the starting bytes encoded as a long as big-endian
* @param lim the limit of bytes to process encoded as a long as big-endian,
* or -1 to mean the max limit for numBytes
*/
static void testBytes(int numBytes, long expectedCount, long start, long lim)
throws UnsupportedEncodingException {
Random rnd = new Random();
byte[] bytes = new byte[numBytes];
if (lim == -1) {
lim = 1L << (numBytes * 8);
}
long count = 0;
long countRoundTripped = 0;
for (long byteChar = start; byteChar < lim; byteChar++) {
long tmpByteChar = byteChar;
for (int i = 0; i < numBytes; i++) {
bytes[bytes.length - i - 1] = (byte) tmpByteChar;
tmpByteChar = tmpByteChar >> 8;
}
ByteString bs = ByteString.copyFrom(bytes);
boolean isRoundTrippable = bs.isValidUtf8();
String s = new String(bytes, "UTF-8");
byte[] bytesReencoded = s.getBytes("UTF-8");
boolean bytesEqual = Arrays.equals(bytes, bytesReencoded);
if (bytesEqual != isRoundTrippable) {
outputFailure(byteChar, bytes, bytesReencoded);
}
// Check agreement with static Utf8 methods.
assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes));
assertEquals(isRoundTrippable, Utf8.isValidUtf8(bytes, 0, numBytes));
// Test partial sequences.
// Partition numBytes into three segments (not necessarily non-empty).
int i = rnd.nextInt(numBytes);
int j = rnd.nextInt(numBytes);
if (j < i) {
int tmp = i; i = j; j = tmp;
}
int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i);
int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j);
int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes);
if (isRoundTrippable != (state3 == Utf8.COMPLETE)) {
System.out.printf("state=%04x %04x %04x i=%d j=%d%n",
state1, state2, state3, i, j);
outputFailure(byteChar, bytes, bytesReencoded);
}
assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE));
// Test ropes built out of small partial sequences
ByteString rope = RopeByteString.newInstanceForTest(
bs.substring(0, i),
RopeByteString.newInstanceForTest(
bs.substring(i, j),
bs.substring(j, numBytes)));
assertSame(RopeByteString.class, rope.getClass());
ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope };
for (ByteString x : byteStrings) {
assertEquals(isRoundTrippable,
x.isValidUtf8());
assertEquals(state3,
x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes));
assertEquals(state1,
x.partialIsValidUtf8(Utf8.COMPLETE, 0, i));
assertEquals(state1,
x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i));
assertEquals(state2,
x.partialIsValidUtf8(state1, i, j - i));
assertEquals(state2,
x.substring(i, j).partialIsValidUtf8(state1, 0, j - i));
assertEquals(state3,
x.partialIsValidUtf8(state2, j, numBytes - j));
assertEquals(state3,
x.substring(j, numBytes)
.partialIsValidUtf8(state2, 0, numBytes - j));
}
// ByteString reduplication should not affect its UTF-8 validity.
ByteString ropeADope =
RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes));
assertEquals(isRoundTrippable, ropeADope.isValidUtf8());
if (isRoundTrippable) {
countRoundTripped++;
}
count++;
if (byteChar != 0 && byteChar % 1000000L == 0) {
logger.info("Processed " + (byteChar / 1000000L) +
" million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
assertEquals(expectedCount, countRoundTripped);
}
/**
* Variation of {@link #testBytes} that does less allocation using the
* low-level encoders/decoders directly. Checked in because it's useful for
* debugging when trying to process bytes faster, but since it doesn't use the
* actual String class, it's possible for incompatibilities to develop
* (although unlikely).
*
* @param numBytes the number of bytes in the byte array
* @param expectedCount the expected number of roundtrippable permutations
* @param start the starting bytes encoded as a long as big-endian
* @param lim the limit of bytes to process encoded as a long as big-endian,
* or -1 to mean the max limit for numBytes
*/
void testBytesUsingByteBuffers(
int numBytes, long expectedCount, long start, long lim)
throws UnsupportedEncodingException {
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE);
byte[] bytes = new byte[numBytes];
int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1;
char[] charsDecoded =
new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1];
int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1;
byte[] bytesReencoded = new byte[maxBytes];
ByteBuffer bb = ByteBuffer.wrap(bytes);
CharBuffer cb = CharBuffer.wrap(charsDecoded);
ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded);
if (lim == -1) {
lim = 1L << (numBytes * 8);
}
long count = 0;
long countRoundTripped = 0;
for (long byteChar = start; byteChar < lim; byteChar++) {
bb.rewind();
bb.limit(bytes.length);
cb.rewind();
cb.limit(charsDecoded.length);
bbReencoded.rewind();
bbReencoded.limit(bytesReencoded.length);
encoder.reset();
decoder.reset();
long tmpByteChar = byteChar;
for (int i = 0; i < bytes.length; i++) {
bytes[bytes.length - i - 1] = (byte) tmpByteChar;
tmpByteChar = tmpByteChar >> 8;
}
boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8();
CoderResult result = decoder.decode(bb, cb, true);
assertFalse(result.isError());
result = decoder.flush(cb);
assertFalse(result.isError());
int charLen = cb.position();
cb.rewind();
cb.limit(charLen);
result = encoder.encode(cb, bbReencoded, true);
assertFalse(result.isError());
result = encoder.flush(bbReencoded);
assertFalse(result.isError());
boolean bytesEqual = true;
int bytesLen = bbReencoded.position();
if (bytesLen != numBytes) {
bytesEqual = false;
} else {
for (int i = 0; i < numBytes; i++) {
if (bytes[i] != bytesReencoded[i]) {
bytesEqual = false;
break;
}
}
}
if (bytesEqual != isRoundTrippable) {
outputFailure(byteChar, bytes, bytesReencoded, bytesLen);
}
count++;
if (isRoundTrippable) {
countRoundTripped++;
}
if (byteChar != 0 && byteChar % 1000000 == 0) {
logger.info("Processed " + (byteChar / 1000000) +
" million characters");
}
}
logger.info("Round tripped " + countRoundTripped + " of " + count);
assertEquals(expectedCount, countRoundTripped);
}
private static void outputFailure(long byteChar, byte[] bytes, byte[] after) {
outputFailure(byteChar, bytes, after, after.length);
}
private static void outputFailure(long byteChar, byte[] bytes, byte[] after,
int len) {
fail("Failure: (" + Long.toHexString(byteChar) + ") " +
toHexString(bytes) + " => " + toHexString(after, len));
}
private static String toHexString(byte[] b) {
return toHexString(b, b.length);
}
private static String toHexString(byte[] b, int len) {
StringBuilder s = new StringBuilder();
s.append("\"");
for (int i = 0; i < len; i++) {
if (i > 0) {
s.append(" ");
}
s.append(String.format("%02x", b[i] & 0xFF));
}
s.append("\"");
return s.toString();
}
}

View File

@ -0,0 +1,162 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link LazyStringArrayList}.
*
* @author jonp@google.com (Jon Perlow)
*/
public class LazyStringArrayListTest extends TestCase {
private static String STRING_A = "A";
private static String STRING_B = "B";
private static String STRING_C = "C";
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
public void testJustStrings() {
LazyStringArrayList list = new LazyStringArrayList();
list.add(STRING_A);
list.add(STRING_B);
list.add(STRING_C);
assertEquals(3, list.size());
assertSame(STRING_A, list.get(0));
assertSame(STRING_B, list.get(1));
assertSame(STRING_C, list.get(2));
list.set(1, STRING_C);
assertSame(STRING_C, list.get(1));
list.remove(1);
assertSame(STRING_A, list.get(0));
assertSame(STRING_C, list.get(1));
}
public void testJustByteString() {
LazyStringArrayList list = new LazyStringArrayList();
list.add(BYTE_STRING_A);
list.add(BYTE_STRING_B);
list.add(BYTE_STRING_C);
assertEquals(3, list.size());
assertSame(BYTE_STRING_A, list.getByteString(0));
assertSame(BYTE_STRING_B, list.getByteString(1));
assertSame(BYTE_STRING_C, list.getByteString(2));
list.remove(1);
assertSame(BYTE_STRING_A, list.getByteString(0));
assertSame(BYTE_STRING_C, list.getByteString(1));
}
public void testConversionBackAndForth() {
LazyStringArrayList list = new LazyStringArrayList();
list.add(STRING_A);
list.add(BYTE_STRING_B);
list.add(BYTE_STRING_C);
// String a should be the same because it was originally a string
assertSame(STRING_A, list.get(0));
// String b and c should be different because the string has to be computed
// from the ByteString
String bPrime = list.get(1);
assertNotSame(STRING_B, bPrime);
assertEquals(STRING_B, bPrime);
String cPrime = list.get(2);
assertNotSame(STRING_C, cPrime);
assertEquals(STRING_C, cPrime);
// String c and c should stay the same once cached.
assertSame(bPrime, list.get(1));
assertSame(cPrime, list.get(2));
// ByteString needs to be computed from string for both a and b
ByteString aPrimeByteString = list.getByteString(0);
assertEquals(BYTE_STRING_A, aPrimeByteString);
ByteString bPrimeByteString = list.getByteString(1);
assertNotSame(BYTE_STRING_B, bPrimeByteString);
assertEquals(BYTE_STRING_B, list.getByteString(1));
// Once cached, ByteString should stay cached.
assertSame(aPrimeByteString, list.getByteString(0));
assertSame(bPrimeByteString, list.getByteString(1));
}
public void testCopyConstructorCopiesByReference() {
LazyStringArrayList list1 = new LazyStringArrayList();
list1.add(STRING_A);
list1.add(BYTE_STRING_B);
list1.add(BYTE_STRING_C);
LazyStringArrayList list2 = new LazyStringArrayList(list1);
assertEquals(3, list2.size());
assertSame(STRING_A, list2.get(0));
assertSame(BYTE_STRING_B, list2.getByteString(1));
assertSame(BYTE_STRING_C, list2.getByteString(2));
}
public void testListCopyConstructor() {
List<String> list1 = new ArrayList<String>();
list1.add(STRING_A);
list1.add(STRING_B);
list1.add(STRING_C);
LazyStringArrayList list2 = new LazyStringArrayList(list1);
assertEquals(3, list2.size());
assertSame(STRING_A, list2.get(0));
assertSame(STRING_B, list2.get(1));
assertSame(STRING_C, list2.get(2));
}
public void testAddAllCopiesByReferenceIfPossible() {
LazyStringArrayList list1 = new LazyStringArrayList();
list1.add(STRING_A);
list1.add(BYTE_STRING_B);
list1.add(BYTE_STRING_C);
LazyStringArrayList list2 = new LazyStringArrayList();
list2.addAll(list1);
assertEquals(3, list2.size());
assertSame(STRING_A, list2.get(0));
assertSame(BYTE_STRING_B, list2.getByteString(1));
assertSame(BYTE_STRING_C, list2.getByteString(2));
}
}

View File

@ -0,0 +1,143 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto;
import junit.framework.TestCase;
import java.io.IOException;
/**
* Tests to make sure the lazy conversion of UTF8-encoded byte arrays to
* strings works correctly.
*
* @author jonp@google.com (Jon Perlow)
*/
public class LazyStringEndToEndTest extends TestCase {
private static ByteString TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8 =
ByteString.copyFrom(new byte[] {
114, 4, -1, 0, -1, 0, -30, 2, 4, -1,
0, -1, 0, -30, 2, 4, -1, 0, -1, 0, });
private ByteString encodedTestAllTypes;
@Override
protected void setUp() throws Exception {
super.setUp();
this.encodedTestAllTypes = UnittestProto.TestAllTypes.newBuilder()
.setOptionalString("foo")
.addRepeatedString("bar")
.addRepeatedString("baz")
.build()
.toByteString();
}
/**
* Tests that an invalid UTF8 string will roundtrip through a parse
* and serialization.
*/
public void testParseAndSerialize() throws InvalidProtocolBufferException {
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
ByteString bytes = tV2.toByteString();
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
tV2.getOptionalString();
bytes = tV2.toByteString();
assertEquals(TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8, bytes);
}
public void testParseAndWrite() throws IOException {
UnittestProto.TestAllTypes tV2 = UnittestProto.TestAllTypes.parseFrom(
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8);
byte[] sink = new byte[TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8.size()];
CodedOutputStream outputStream = CodedOutputStream.newInstance(sink);
tV2.writeTo(outputStream);
outputStream.flush();
assertEquals(
TEST_ALL_TYPES_SERIALIZED_WITH_ILLEGAL_UTF8,
ByteString.copyFrom(sink));
}
public void testCaching() {
String a = "a";
String b = "b";
String c = "c";
UnittestProto.TestAllTypes proto = UnittestProto.TestAllTypes.newBuilder()
.setOptionalString(a)
.addRepeatedString(b)
.addRepeatedString(c)
.build();
// String should be the one we passed it.
assertSame(a, proto.getOptionalString());
assertSame(b, proto.getRepeatedString(0));
assertSame(c, proto.getRepeatedString(1));
// There's no way to directly observe that the ByteString is cached
// correctly on serialization, but we can observe that it had to recompute
// the string after serialization.
proto.toByteString();
String aPrime = proto.getOptionalString();
assertNotSame(a, aPrime);
assertEquals(a, aPrime);
String bPrime = proto.getRepeatedString(0);
assertNotSame(b, bPrime);
assertEquals(b, bPrime);
String cPrime = proto.getRepeatedString(1);
assertNotSame(c, cPrime);
assertEquals(c, cPrime);
// And now the string should stay cached.
assertSame(aPrime, proto.getOptionalString());
assertSame(bPrime, proto.getRepeatedString(0));
assertSame(cPrime, proto.getRepeatedString(1));
}
public void testNoStringCachingIfOnlyBytesAccessed() throws Exception {
UnittestProto.TestAllTypes proto =
UnittestProto.TestAllTypes.parseFrom(encodedTestAllTypes);
ByteString optional = proto.getOptionalStringBytes();
assertSame(optional, proto.getOptionalStringBytes());
assertSame(optional, proto.toBuilder().getOptionalStringBytes());
ByteString repeated0 = proto.getRepeatedStringBytes(0);
ByteString repeated1 = proto.getRepeatedStringBytes(1);
assertSame(repeated0, proto.getRepeatedStringBytes(0));
assertSame(repeated1, proto.getRepeatedStringBytes(1));
assertSame(repeated0, proto.toBuilder().getRepeatedStringBytes(0));
assertSame(repeated1, proto.toBuilder().getRepeatedStringBytes(1));
}
}

View File

@ -0,0 +1,148 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.UnittestLite;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Test lite runtime.
*
* @author kenton@google.com Kenton Varda
*/
public class LiteTest extends TestCase {
public void setUp() throws Exception {
// Test that nested extensions are initialized correctly even if the outer
// class has not been accessed directly. This was once a bug with lite
// messages.
//
// We put this in setUp() rather than in its own test method because we
// need to make sure it runs before any actual tests.
assertTrue(TestNestedExtensionLite.nestedExtension != null);
}
public void testLite() throws Exception {
// Since lite messages are a subset of regular messages, we can mostly
// assume that the functionality of lite messages is already thoroughly
// tested by the regular tests. All this test really verifies is that
// a proto with optimize_for = LITE_RUNTIME compiles correctly when
// linked only against the lite library. That is all tested at compile
// time, leaving not much to do in this method. Let's just do some random
// stuff to make sure the lite message is actually here and usable.
TestAllTypesLite message =
TestAllTypesLite.newBuilder()
.setOptionalInt32(123)
.addRepeatedString("hello")
.setOptionalNestedMessage(
TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
.build();
ByteString data = message.toByteString();
TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
assertEquals(123, message2.getOptionalInt32());
assertEquals(1, message2.getRepeatedStringCount());
assertEquals("hello", message2.getRepeatedString(0));
assertEquals(7, message2.getOptionalNestedMessage().getBb());
}
public void testLiteExtensions() throws Exception {
// TODO(kenton): Unlike other features of the lite library, extensions are
// implemented completely differently from the regular library. We
// should probably test them more thoroughly.
TestAllExtensionsLite message =
TestAllExtensionsLite.newBuilder()
.setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
.addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
.setExtension(UnittestLite.optionalNestedEnumExtensionLite,
TestAllTypesLite.NestedEnum.BAZ)
.setExtension(UnittestLite.optionalNestedMessageExtensionLite,
TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
.build();
// Test copying a message, since coping extensions actually does use a
// different code path between lite and regular libraries, and as of this
// writing, parsing hasn't been implemented yet.
TestAllExtensionsLite message2 = message.toBuilder().build();
assertEquals(123, (int) message2.getExtension(
UnittestLite.optionalInt32ExtensionLite));
assertEquals(1, message2.getExtensionCount(
UnittestLite.repeatedStringExtensionLite));
assertEquals(1, message2.getExtension(
UnittestLite.repeatedStringExtensionLite).size());
assertEquals("hello", message2.getExtension(
UnittestLite.repeatedStringExtensionLite, 0));
assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
UnittestLite.optionalNestedEnumExtensionLite));
assertEquals(7, message2.getExtension(
UnittestLite.optionalNestedMessageExtensionLite).getBb());
}
public void testSerialize() throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
TestAllTypesLite expected =
TestAllTypesLite.newBuilder()
.setOptionalInt32(123)
.addRepeatedString("hello")
.setOptionalNestedMessage(
TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
.build();
ObjectOutputStream out = new ObjectOutputStream(baos);
try {
out.writeObject(expected);
} finally {
out.close();
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
TestAllTypesLite actual = (TestAllTypesLite) in.readObject();
assertEquals(expected.getOptionalInt32(), actual.getOptionalInt32());
assertEquals(expected.getRepeatedStringCount(),
actual.getRepeatedStringCount());
assertEquals(expected.getRepeatedString(0),
actual.getRepeatedString(0));
assertEquals(expected.getOptionalNestedMessage().getBb(),
actual.getOptionalNestedMessage().getBb());
}
}

View File

@ -0,0 +1,396 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
/**
* Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}.
* This class is designed to be extended for testing extensions of {@link LiteralByteString}
* such as {@link BoundedByteString}, see {@link BoundedByteStringTest}.
*
* @author carlanton@google.com (Carl Haverl)
*/
public class LiteralByteStringTest extends TestCase {
protected static final String UTF_8 = "UTF-8";
protected String classUnderTest;
protected byte[] referenceBytes;
protected ByteString stringUnderTest;
protected int expectedHashCode;
@Override
protected void setUp() throws Exception {
classUnderTest = "LiteralByteString";
referenceBytes = ByteStringTest.getTestBytes(1234, 11337766L);
stringUnderTest = ByteString.copyFrom(referenceBytes);
expectedHashCode = 331161852;
}
public void testExpectedType() {
String actualClassName = getActualClassName(stringUnderTest);
assertEquals(classUnderTest + " should match type exactly", classUnderTest, actualClassName);
}
protected String getActualClassName(Object object) {
String actualClassName = object.getClass().getName();
actualClassName = actualClassName.substring(actualClassName.lastIndexOf('.') + 1);
return actualClassName;
}
public void testByteAt() {
boolean stillEqual = true;
for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
stillEqual = (referenceBytes[i] == stringUnderTest.byteAt(i));
}
assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
}
public void testByteIterator() {
boolean stillEqual = true;
ByteString.ByteIterator iter = stringUnderTest.iterator();
for (int i = 0; stillEqual && i < referenceBytes.length; ++i) {
stillEqual = (iter.hasNext() && referenceBytes[i] == iter.nextByte());
}
assertTrue(classUnderTest + " must capture the right bytes", stillEqual);
assertFalse(classUnderTest + " must have exhausted the itertor", iter.hasNext());
try {
iter.nextByte();
fail("Should have thrown an exception.");
} catch (NoSuchElementException e) {
// This is success
}
}
public void testByteIterable() {
boolean stillEqual = true;
int j = 0;
for (byte quantum : stringUnderTest) {
stillEqual = (referenceBytes[j] == quantum);
++j;
}
assertTrue(classUnderTest + " must capture the right bytes as Bytes", stillEqual);
assertEquals(classUnderTest + " iterable character count", referenceBytes.length, j);
}
public void testSize() {
assertEquals(classUnderTest + " must have the expected size", referenceBytes.length,
stringUnderTest.size());
}
public void testGetTreeDepth() {
assertEquals(classUnderTest + " must have depth 0", 0, stringUnderTest.getTreeDepth());
}
public void testIsBalanced() {
assertTrue(classUnderTest + " is technically balanced", stringUnderTest.isBalanced());
}
public void testCopyTo_ByteArrayOffsetLength() {
int destinationOffset = 50;
int length = 100;
byte[] destination = new byte[destinationOffset + length];
int sourceOffset = 213;
stringUnderTest.copyTo(destination, sourceOffset, destinationOffset, length);
boolean stillEqual = true;
for (int i = 0; stillEqual && i < length; ++i) {
stillEqual = referenceBytes[i + sourceOffset] == destination[i + destinationOffset];
}
assertTrue(classUnderTest + ".copyTo(4 arg) must give the expected bytes", stillEqual);
}
public void testCopyTo_ByteArrayOffsetLengthErrors() {
int destinationOffset = 50;
int length = 100;
byte[] destination = new byte[destinationOffset + length];
try {
// Copy one too many bytes
stringUnderTest.copyTo(destination, stringUnderTest.size() + 1 - length,
destinationOffset, length);
fail("Should have thrown an exception when copying too many bytes of a "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
try {
// Copy with illegal negative sourceOffset
stringUnderTest.copyTo(destination, -1, destinationOffset, length);
fail("Should have thrown an exception when given a negative sourceOffset in "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
try {
// Copy with illegal negative destinationOffset
stringUnderTest.copyTo(destination, 0, -1, length);
fail("Should have thrown an exception when given a negative destinationOffset in "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
try {
// Copy with illegal negative size
stringUnderTest.copyTo(destination, 0, 0, -1);
fail("Should have thrown an exception when given a negative size in "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
try {
// Copy with illegal too-large sourceOffset
stringUnderTest.copyTo(destination, 2 * stringUnderTest.size(), 0, length);
fail("Should have thrown an exception when the destinationOffset is too large in "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
try {
// Copy with illegal too-large destinationOffset
stringUnderTest.copyTo(destination, 0, 2 * destination.length, length);
fail("Should have thrown an exception when the destinationOffset is too large in "
+ classUnderTest);
} catch (IndexOutOfBoundsException expected) {
// This is success
}
}
public void testCopyTo_ByteBuffer() {
ByteBuffer myBuffer = ByteBuffer.allocate(referenceBytes.length);
stringUnderTest.copyTo(myBuffer);
assertTrue(classUnderTest + ".copyTo(ByteBuffer) must give back the same bytes",
Arrays.equals(referenceBytes, myBuffer.array()));
}
public void testAsReadOnlyByteBuffer() {
ByteBuffer byteBuffer = stringUnderTest.asReadOnlyByteBuffer();
byte[] roundTripBytes = new byte[referenceBytes.length];
assertTrue(byteBuffer.remaining() == referenceBytes.length);
assertTrue(byteBuffer.isReadOnly());
byteBuffer.get(roundTripBytes);
assertTrue(classUnderTest + ".asReadOnlyByteBuffer() must give back the same bytes",
Arrays.equals(referenceBytes, roundTripBytes));
}
public void testAsReadOnlyByteBufferList() {
List<ByteBuffer> byteBuffers = stringUnderTest.asReadOnlyByteBufferList();
int bytesSeen = 0;
byte[] roundTripBytes = new byte[referenceBytes.length];
for (ByteBuffer byteBuffer : byteBuffers) {
int thisLength = byteBuffer.remaining();
assertTrue(byteBuffer.isReadOnly());
assertTrue(bytesSeen + thisLength <= referenceBytes.length);
byteBuffer.get(roundTripBytes, bytesSeen, thisLength);
bytesSeen += thisLength;
}
assertTrue(bytesSeen == referenceBytes.length);
assertTrue(classUnderTest + ".asReadOnlyByteBufferTest() must give back the same bytes",
Arrays.equals(referenceBytes, roundTripBytes));
}
public void testToByteArray() {
byte[] roundTripBytes = stringUnderTest.toByteArray();
assertTrue(classUnderTest + ".toByteArray() must give back the same bytes",
Arrays.equals(referenceBytes, roundTripBytes));
}
public void testWriteTo() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
stringUnderTest.writeTo(bos);
byte[] roundTripBytes = bos.toByteArray();
assertTrue(classUnderTest + ".writeTo() must give back the same bytes",
Arrays.equals(referenceBytes, roundTripBytes));
}
public void testWriteTo_mutating() throws IOException {
OutputStream os = new OutputStream() {
@Override
public void write(byte[] b, int off, int len) {
for (int x = 0; x < len; ++x) {
b[off + x] = (byte) 0;
}
}
@Override
public void write(int b) {
// Purposefully left blank.
}
};
stringUnderTest.writeTo(os);
byte[] newBytes = stringUnderTest.toByteArray();
assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array",
Arrays.equals(referenceBytes, newBytes));
}
public void testNewOutput() throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteString.Output output = ByteString.newOutput();
stringUnderTest.writeTo(output);
assertEquals("Output Size returns correct result",
output.size(), stringUnderTest.size());
output.writeTo(bos);
assertTrue("Output.writeTo() must give back the same bytes",
Arrays.equals(referenceBytes, bos.toByteArray()));
// write the output stream to itself! This should cause it to double
output.writeTo(output);
assertEquals("Writing an output stream to itself is successful",
stringUnderTest.concat(stringUnderTest), output.toByteString());
output.reset();
assertEquals("Output.reset() resets the output", 0, output.size());
assertEquals("Output.reset() resets the output",
ByteString.EMPTY, output.toByteString());
}
public void testToString() throws UnsupportedEncodingException {
String testString = "I love unicode \u1234\u5678 characters";
LiteralByteString unicode = new LiteralByteString(testString.getBytes(UTF_8));
String roundTripString = unicode.toString(UTF_8);
assertEquals(classUnderTest + " unicode must match", testString, roundTripString);
}
public void testEquals() {
assertEquals(classUnderTest + " must not equal null", false, stringUnderTest.equals(null));
assertEquals(classUnderTest + " must equal self", stringUnderTest, stringUnderTest);
assertFalse(classUnderTest + " must not equal the empty string",
stringUnderTest.equals(ByteString.EMPTY));
assertEquals(classUnderTest + " empty strings must be equal",
new LiteralByteString(new byte[]{}), stringUnderTest.substring(55, 55));
assertEquals(classUnderTest + " must equal another string with the same value",
stringUnderTest, new LiteralByteString(referenceBytes));
byte[] mungedBytes = new byte[referenceBytes.length];
System.arraycopy(referenceBytes, 0, mungedBytes, 0, referenceBytes.length);
mungedBytes[mungedBytes.length - 5] ^= 0xFF;
assertFalse(classUnderTest + " must not equal every string with the same length",
stringUnderTest.equals(new LiteralByteString(mungedBytes)));
}
public void testHashCode() {
int hash = stringUnderTest.hashCode();
assertEquals(classUnderTest + " must have expected hashCode", expectedHashCode, hash);
}
public void testPeekCachedHashCode() {
assertEquals(classUnderTest + ".peekCachedHashCode() should return zero at first", 0,
stringUnderTest.peekCachedHashCode());
stringUnderTest.hashCode();
assertEquals(classUnderTest + ".peekCachedHashCode should return zero at first",
expectedHashCode, stringUnderTest.peekCachedHashCode());
}
public void testPartialHash() {
// partialHash() is more strenuously tested elsewhere by testing hashes of substrings.
// This test would fail if the expected hash were 1. It's not.
int hash = stringUnderTest.partialHash(stringUnderTest.size(), 0, stringUnderTest.size());
assertEquals(classUnderTest + ".partialHash() must yield expected hashCode",
expectedHashCode, hash);
}
public void testNewInput() throws IOException {
InputStream input = stringUnderTest.newInput();
assertEquals("InputStream.available() returns correct value",
stringUnderTest.size(), input.available());
boolean stillEqual = true;
for (byte referenceByte : referenceBytes) {
int expectedInt = (referenceByte & 0xFF);
stillEqual = (expectedInt == input.read());
}
assertEquals("InputStream.available() returns correct value",
0, input.available());
assertTrue(classUnderTest + " must give the same bytes from the InputStream", stillEqual);
assertEquals(classUnderTest + " InputStream must now be exhausted", -1, input.read());
}
public void testNewInput_skip() throws IOException {
InputStream input = stringUnderTest.newInput();
int stringSize = stringUnderTest.size();
int nearEndIndex = stringSize * 2 / 3;
long skipped1 = input.skip(nearEndIndex);
assertEquals("InputStream.skip()", skipped1, nearEndIndex);
assertEquals("InputStream.available()",
stringSize - skipped1, input.available());
assertTrue("InputStream.mark() is available", input.markSupported());
input.mark(0);
assertEquals("InputStream.skip(), read()",
stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
assertEquals("InputStream.available()",
stringSize - skipped1 - 1, input.available());
long skipped2 = input.skip(stringSize);
assertEquals("InputStream.skip() incomplete",
skipped2, stringSize - skipped1 - 1);
assertEquals("InputStream.skip(), no more input", 0, input.available());
assertEquals("InputStream.skip(), no more input", -1, input.read());
input.reset();
assertEquals("InputStream.reset() succeded",
stringSize - skipped1, input.available());
assertEquals("InputStream.reset(), read()",
stringUnderTest.byteAt(nearEndIndex) & 0xFF, input.read());
}
public void testNewCodedInput() throws IOException {
CodedInputStream cis = stringUnderTest.newCodedInput();
byte[] roundTripBytes = cis.readRawBytes(referenceBytes.length);
assertTrue(classUnderTest + " must give the same bytes back from the CodedInputStream",
Arrays.equals(referenceBytes, roundTripBytes));
assertTrue(classUnderTest + " CodedInputStream must now be exhausted", cis.isAtEnd());
}
/**
* Make sure we keep things simple when concatenating with empty. See also
* {@link ByteStringTest#testConcat_empty()}.
*/
public void testConcat_empty() {
assertSame(classUnderTest + " concatenated with empty must give " + classUnderTest,
stringUnderTest.concat(ByteString.EMPTY), stringUnderTest);
assertSame("empty concatenated with " + classUnderTest + " must give " + classUnderTest,
ByteString.EMPTY.concat(stringUnderTest), stringUnderTest);
}
}

View File

@ -0,0 +1,353 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestRequiredForeign;
import protobuf_unittest.UnittestProto.ForeignMessage;
import junit.framework.TestCase;
import java.util.List;
/**
* Misc. unit tests for message operations that apply to both generated
* and dynamic messages.
*
* @author kenton@google.com Kenton Varda
*/
public class MessageTest extends TestCase {
// =================================================================
// Message-merging tests.
static final TestAllTypes MERGE_SOURCE =
TestAllTypes.newBuilder()
.setOptionalInt32(1)
.setOptionalString("foo")
.setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
.addRepeatedString("bar")
.build();
static final TestAllTypes MERGE_DEST =
TestAllTypes.newBuilder()
.setOptionalInt64(2)
.setOptionalString("baz")
.setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
.addRepeatedString("qux")
.build();
static final String MERGE_RESULT_TEXT =
"optional_int32: 1\n" +
"optional_int64: 2\n" +
"optional_string: \"foo\"\n" +
"optional_foreign_message {\n" +
" c: 3\n" +
"}\n" +
"repeated_string: \"qux\"\n" +
"repeated_string: \"bar\"\n";
public void testMergeFrom() throws Exception {
TestAllTypes result =
TestAllTypes.newBuilder(MERGE_DEST)
.mergeFrom(MERGE_SOURCE).build();
assertEquals(MERGE_RESULT_TEXT, result.toString());
}
/**
* Test merging a DynamicMessage into a GeneratedMessage. As long as they
* have the same descriptor, this should work, but it is an entirely different
* code path.
*/
public void testMergeFromDynamic() throws Exception {
TestAllTypes result =
TestAllTypes.newBuilder(MERGE_DEST)
.mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
.build();
assertEquals(MERGE_RESULT_TEXT, result.toString());
}
/** Test merging two DynamicMessages. */
public void testDynamicMergeFrom() throws Exception {
DynamicMessage result =
DynamicMessage.newBuilder(MERGE_DEST)
.mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
.build();
assertEquals(MERGE_RESULT_TEXT, result.toString());
}
// =================================================================
// Required-field-related tests.
private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
TestRequired.getDefaultInstance();
private static final TestRequired TEST_REQUIRED_INITIALIZED =
TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
public void testRequired() throws Exception {
TestRequired.Builder builder = TestRequired.newBuilder();
assertFalse(builder.isInitialized());
builder.setA(1);
assertFalse(builder.isInitialized());
builder.setB(1);
assertFalse(builder.isInitialized());
builder.setC(1);
assertTrue(builder.isInitialized());
}
public void testRequiredForeign() throws Exception {
TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
assertTrue(builder.isInitialized());
builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
}
public void testRequiredExtension() throws Exception {
TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
assertTrue(builder.isInitialized());
builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
}
public void testRequiredDynamic() throws Exception {
Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
assertFalse(builder.isInitialized());
builder.setField(descriptor.findFieldByName("a"), 1);
assertFalse(builder.isInitialized());
builder.setField(descriptor.findFieldByName("b"), 1);
assertFalse(builder.isInitialized());
builder.setField(descriptor.findFieldByName("c"), 1);
assertTrue(builder.isInitialized());
}
public void testRequiredDynamicForeign() throws Exception {
Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
assertTrue(builder.isInitialized());
builder.setField(descriptor.findFieldByName("optional_message"),
TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setField(descriptor.findFieldByName("optional_message"),
TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
TEST_REQUIRED_UNINITIALIZED);
assertFalse(builder.isInitialized());
builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
TEST_REQUIRED_INITIALIZED);
assertTrue(builder.isInitialized());
}
public void testUninitializedException() throws Exception {
try {
TestRequired.newBuilder().build();
fail("Should have thrown an exception.");
} catch (UninitializedMessageException e) {
assertEquals("Message missing required fields: a, b, c", e.getMessage());
}
}
public void testBuildPartial() throws Exception {
// We're mostly testing that no exception is thrown.
TestRequired message = TestRequired.newBuilder().buildPartial();
assertFalse(message.isInitialized());
}
public void testNestedUninitializedException() throws Exception {
try {
TestRequiredForeign.newBuilder()
.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.build();
fail("Should have thrown an exception.");
} catch (UninitializedMessageException e) {
assertEquals(
"Message missing required fields: " +
"optional_message.a, " +
"optional_message.b, " +
"optional_message.c, " +
"repeated_message[0].a, " +
"repeated_message[0].b, " +
"repeated_message[0].c, " +
"repeated_message[1].a, " +
"repeated_message[1].b, " +
"repeated_message[1].c",
e.getMessage());
}
}
public void testBuildNestedPartial() throws Exception {
// We're mostly testing that no exception is thrown.
TestRequiredForeign message =
TestRequiredForeign.newBuilder()
.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.buildPartial();
assertFalse(message.isInitialized());
}
public void testParseUnititialized() throws Exception {
try {
TestRequired.parseFrom(ByteString.EMPTY);
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals("Message missing required fields: a, b, c", e.getMessage());
}
}
public void testParseNestedUnititialized() throws Exception {
ByteString data =
TestRequiredForeign.newBuilder()
.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
.buildPartial().toByteString();
try {
TestRequiredForeign.parseFrom(data);
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals(
"Message missing required fields: " +
"optional_message.a, " +
"optional_message.b, " +
"optional_message.c, " +
"repeated_message[0].a, " +
"repeated_message[0].b, " +
"repeated_message[0].c, " +
"repeated_message[1].a, " +
"repeated_message[1].b, " +
"repeated_message[1].c",
e.getMessage());
}
}
public void testDynamicUninitializedException() throws Exception {
try {
DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
fail("Should have thrown an exception.");
} catch (UninitializedMessageException e) {
assertEquals("Message missing required fields: a, b, c", e.getMessage());
}
}
public void testDynamicBuildPartial() throws Exception {
// We're mostly testing that no exception is thrown.
DynamicMessage message =
DynamicMessage.newBuilder(TestRequired.getDescriptor())
.buildPartial();
assertFalse(message.isInitialized());
}
public void testDynamicParseUnititialized() throws Exception {
try {
Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
fail("Should have thrown an exception.");
} catch (InvalidProtocolBufferException e) {
assertEquals("Message missing required fields: a, b, c", e.getMessage());
}
}
/** Test reading unset repeated message from DynamicMessage. */
public void testDynamicRepeatedMessageNull() throws Exception {
Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
DynamicMessage result =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
.mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
.build();
assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>);
assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")), 0);
}
/** Test reading repeated message from DynamicMessage. */
public void testDynamicRepeatedMessageNotNull() throws Exception {
TestAllTypes REPEATED_NESTED =
TestAllTypes.newBuilder()
.setOptionalInt32(1)
.setOptionalString("foo")
.setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
.addRepeatedString("bar")
.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
.addRepeatedForeignMessage(ForeignMessage.getDefaultInstance())
.build();
Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
DynamicMessage result =
DynamicMessage.newBuilder(TestAllTypes.getDescriptor())
.mergeFrom(DynamicMessage.newBuilder(REPEATED_NESTED).build())
.build();
assertTrue(result.getField(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")) instanceof List<?>);
assertEquals(result.getRepeatedFieldCount(result.getDescriptorForType()
.findFieldByName("repeated_foreign_message")), 2);
}
}

View File

@ -0,0 +1,185 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.Vehicle;
import protobuf_unittest.Wheel;
import junit.framework.TestCase;
import java.util.List;
import java.util.ArrayList;
/**
* Test cases that exercise end-to-end use cases involving
* {@link SingleFieldBuilder} and {@link RepeatedFieldBuilder}.
*
* @author jonp@google.com (Jon Perlow)
*/
public class NestedBuildersTest extends TestCase {
public void testMessagesAndBuilders() {
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
vehicleBuilder.addWheelBuilder()
.setRadius(4)
.setWidth(1);
vehicleBuilder.addWheelBuilder()
.setRadius(4)
.setWidth(2);
vehicleBuilder.addWheelBuilder()
.setRadius(4)
.setWidth(3);
vehicleBuilder.addWheelBuilder()
.setRadius(4)
.setWidth(4);
vehicleBuilder.getEngineBuilder()
.setLiters(10);
Vehicle vehicle = vehicleBuilder.build();
assertEquals(4, vehicle.getWheelCount());
for (int i = 0; i < 4; i++) {
Wheel wheel = vehicle.getWheel(i);
assertEquals(4, wheel.getRadius());
assertEquals(i + 1, wheel.getWidth());
}
assertEquals(10, vehicle.getEngine().getLiters());
for (int i = 0; i < 4; i++) {
vehicleBuilder.getWheelBuilder(i)
.setRadius(5)
.setWidth(i + 10);
}
vehicleBuilder.getEngineBuilder().setLiters(20);
vehicle = vehicleBuilder.build();
for (int i = 0; i < 4; i++) {
Wheel wheel = vehicle.getWheel(i);
assertEquals(5, wheel.getRadius());
assertEquals(i + 10, wheel.getWidth());
}
assertEquals(20, vehicle.getEngine().getLiters());
assertTrue(vehicle.hasEngine());
}
public void testMessagesAreCached() {
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
vehicleBuilder.addWheelBuilder()
.setRadius(1)
.setWidth(2);
vehicleBuilder.addWheelBuilder()
.setRadius(3)
.setWidth(4);
vehicleBuilder.addWheelBuilder()
.setRadius(5)
.setWidth(6);
vehicleBuilder.addWheelBuilder()
.setRadius(7)
.setWidth(8);
// Make sure messages are cached.
List<Wheel> wheels = new ArrayList<Wheel>(vehicleBuilder.getWheelList());
for (int i = 0; i < wheels.size(); i++) {
assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
}
// Now get builders and check they didn't change.
for (int i = 0; i < wheels.size(); i++) {
vehicleBuilder.getWheel(i);
}
for (int i = 0; i < wheels.size(); i++) {
assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
}
// Change just one
vehicleBuilder.getWheelBuilder(3)
.setRadius(20).setWidth(20);
// Now get wheels and check that only that one changed
for (int i = 0; i < wheels.size(); i++) {
if (i < 3) {
assertSame(wheels.get(i), vehicleBuilder.getWheel(i));
} else {
assertNotSame(wheels.get(i), vehicleBuilder.getWheel(i));
}
}
}
public void testRemove_WithNestedBuilders() {
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
vehicleBuilder.addWheelBuilder()
.setRadius(1)
.setWidth(1);
vehicleBuilder.addWheelBuilder()
.setRadius(2)
.setWidth(2);
vehicleBuilder.removeWheel(0);
assertEquals(1, vehicleBuilder.getWheelCount());
assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
}
public void testRemove_WithNestedMessages() {
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
vehicleBuilder.addWheel(Wheel.newBuilder()
.setRadius(1)
.setWidth(1));
vehicleBuilder.addWheel(Wheel.newBuilder()
.setRadius(2)
.setWidth(2));
vehicleBuilder.removeWheel(0);
assertEquals(1, vehicleBuilder.getWheelCount());
assertEquals(2, vehicleBuilder.getWheel(0).getRadius());
}
public void testMerge() {
Vehicle vehicle1 = Vehicle.newBuilder()
.addWheel(Wheel.newBuilder().setRadius(1).build())
.addWheel(Wheel.newBuilder().setRadius(2).build())
.build();
Vehicle vehicle2 = Vehicle.newBuilder()
.mergeFrom(vehicle1)
.build();
// List should be the same -- no allocation
assertSame(vehicle1.getWheelList(), vehicle2.getWheelList());
Vehicle vehicle3 = vehicle1.toBuilder().build();
assertSame(vehicle1.getWheelList(), vehicle3.getWheelList());
}
public void testGettingBuilderMarksFieldAsHaving() {
Vehicle.Builder vehicleBuilder = Vehicle.newBuilder();
vehicleBuilder.getEngineBuilder();
Vehicle vehicle = vehicleBuilder.buildPartial();
assertTrue(vehicle.hasEngine());
}
}

View File

@ -0,0 +1,375 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.UnittestLite.TestAllTypesLite;
import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
import com.google.protobuf.UnittestLite.TestParsingMergeLite;
import com.google.protobuf.UnittestLite;
import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
import protobuf_unittest.UnittestOptimizeFor;
import protobuf_unittest.UnittestProto.ForeignMessage;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestParsingMerge;
import protobuf_unittest.UnittestProto;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Unit test for {@link Parser}.
*
* @author liujisi@google.com (Pherl Liu)
*/
public class ParserTest extends TestCase {
public void testGeneratedMessageParserSingleton() throws Exception {
for (int i = 0; i < 10; i++) {
assertEquals(TestAllTypes.PARSER,
TestUtil.getAllSet().getParserForType());
}
}
private void assertRoundTripEquals(MessageLite message,
ExtensionRegistryLite registry)
throws Exception {
final byte[] data = message.toByteArray();
final int offset = 20;
final int length = data.length;
final int padding = 30;
Parser<? extends MessageLite> parser = message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data, registry));
assertMessageEquals(message, parser.parseFrom(
generatePaddingArray(data, offset, padding),
offset, length, registry));
assertMessageEquals(message, parser.parseFrom(
message.toByteString(), registry));
assertMessageEquals(message, parser.parseFrom(
new ByteArrayInputStream(data), registry));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data), registry));
}
private void assertRoundTripEquals(MessageLite message) throws Exception {
final byte[] data = message.toByteArray();
final int offset = 20;
final int length = data.length;
final int padding = 30;
Parser<? extends MessageLite> parser = message.getParserForType();
assertMessageEquals(message, parser.parseFrom(data));
assertMessageEquals(message, parser.parseFrom(
generatePaddingArray(data, offset, padding),
offset, length));
assertMessageEquals(message, parser.parseFrom(message.toByteString()));
assertMessageEquals(message, parser.parseFrom(
new ByteArrayInputStream(data)));
assertMessageEquals(message, parser.parseFrom(
CodedInputStream.newInstance(data)));
}
private void assertMessageEquals(MessageLite expected, MessageLite actual)
throws Exception {
if (expected instanceof Message) {
assertEquals(expected, actual);
} else {
assertEquals(expected.toByteString(), actual.toByteString());
}
}
private byte[] generatePaddingArray(byte[] data, int offset, int padding) {
byte[] result = new byte[offset + data.length + padding];
System.arraycopy(data, 0, result, offset, data.length);
return result;
}
public void testNormalMessage() throws Exception {
assertRoundTripEquals(TestUtil.getAllSet());
}
public void testParsePartial() throws Exception {
Parser<TestRequired> parser = TestRequired.PARSER;
final String errorString =
"Should throw exceptions when the parsed message isn't initialized.";
// TestRequired.b and TestRequired.c are not set.
TestRequired partialMessage = TestRequired.newBuilder()
.setA(1).buildPartial();
// parsePartialFrom should pass.
byte[] data = partialMessage.toByteArray();
assertEquals(partialMessage, parser.parsePartialFrom(data));
assertEquals(partialMessage, parser.parsePartialFrom(
partialMessage.toByteString()));
assertEquals(partialMessage, parser.parsePartialFrom(
new ByteArrayInputStream(data)));
assertEquals(partialMessage, parser.parsePartialFrom(
CodedInputStream.newInstance(data)));
// parseFrom(ByteArray)
try {
parser.parseFrom(partialMessage.toByteArray());
fail(errorString);
} catch (InvalidProtocolBufferException e) {
// pass.
}
// parseFrom(ByteString)
try {
parser.parseFrom(partialMessage.toByteString());
fail(errorString);
} catch (InvalidProtocolBufferException e) {
// pass.
}
// parseFrom(InputStream)
try {
parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray()));
fail(errorString);
} catch (IOException e) {
// pass.
}
// parseFrom(CodedInputStream)
try {
parser.parseFrom(CodedInputStream.newInstance(
partialMessage.toByteArray()));
fail(errorString);
} catch (IOException e) {
// pass.
}
}
public void testParseExtensions() throws Exception {
assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
TestUtil.getExtensionRegistry());
assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(),
TestUtil.getExtensionRegistryLite());
}
public void testParsePacked() throws Exception {
assertRoundTripEquals(TestUtil.getPackedSet());
assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
TestUtil.getExtensionRegistry());
assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(),
TestUtil.getExtensionRegistryLite());
}
public void testParseDelimitedTo() throws Exception {
// Write normal Message.
TestAllTypes normalMessage = TestUtil.getAllSet();
ByteArrayOutputStream output = new ByteArrayOutputStream();
normalMessage.writeDelimitedTo(output);
// Write MessageLite with packed extension fields.
TestPackedExtensionsLite packedMessage =
TestUtil.getLitePackedExtensionsSet();
packedMessage.writeDelimitedTo(output);
InputStream input = new ByteArrayInputStream(output.toByteArray());
assertMessageEquals(
normalMessage,
normalMessage.getParserForType().parseDelimitedFrom(input));
assertMessageEquals(
packedMessage,
packedMessage.getParserForType().parseDelimitedFrom(
input, TestUtil.getExtensionRegistryLite()));
}
public void testParseUnknownFields() throws Exception {
// All fields will be treated as unknown fields in emptyMessage.
TestEmptyMessage emptyMessage = TestEmptyMessage.PARSER.parseFrom(
TestUtil.getAllSet().toByteString());
assertEquals(
TestUtil.getAllSet().toByteString(),
emptyMessage.toByteString());
}
public void testOptimizeForSize() throws Exception {
TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build());
builder.setExtension(TestOptimizedForSize.testExtension, 56);
builder.setExtension(TestOptimizedForSize.testExtension2,
TestRequiredOptimizedForSize.newBuilder().setX(78).build());
TestOptimizedForSize message = builder.build();
ExtensionRegistry registry = ExtensionRegistry.newInstance();
UnittestOptimizeFor.registerAllExtensions(registry);
assertRoundTripEquals(message, registry);
}
/** Helper method for {@link #testParsingMerge()}.*/
private void assertMessageMerged(TestAllTypes allTypes)
throws Exception {
assertEquals(3, allTypes.getOptionalInt32());
assertEquals(2, allTypes.getOptionalInt64());
assertEquals("hello", allTypes.getOptionalString());
}
/** Helper method for {@link #testParsingMergeLite()}.*/
private void assertMessageMerged(TestAllTypesLite allTypes)
throws Exception {
assertEquals(3, allTypes.getOptionalInt32());
assertEquals(2, allTypes.getOptionalInt64());
assertEquals("hello", allTypes.getOptionalString());
}
public void testParsingMerge() throws Exception {
// Build messages.
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TestAllTypes msg1 = builder.setOptionalInt32(1).build();
builder.clear();
TestAllTypes msg2 = builder.setOptionalInt64(2).build();
builder.clear();
TestAllTypes msg3 = builder.setOptionalInt32(3)
.setOptionalString("hello").build();
// Build groups.
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 =
TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg3).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg1).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg2).build();
TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 =
TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg3).build();
// Assign and serialize RepeatedFieldsGenerator.
ByteString data = TestParsingMerge.RepeatedFieldsGenerator.newBuilder()
.addField1(msg1).addField1(msg2).addField1(msg3)
.addField2(msg1).addField2(msg2).addField2(msg3)
.addField3(msg1).addField3(msg2).addField3(msg3)
.addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
.addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
.addExt1(msg1).addExt1(msg2).addExt1(msg3)
.addExt2(msg1).addExt2(msg2).addExt2(msg3)
.build().toByteString();
// Parse TestParsingMerge.
ExtensionRegistry registry = ExtensionRegistry.newInstance();
UnittestProto.registerAllExtensions(registry);
TestParsingMerge parsingMerge =
TestParsingMerge.PARSER.parseFrom(data, registry);
// Required and optional fields should be merged.
assertMessageMerged(parsingMerge.getRequiredAllTypes());
assertMessageMerged(parsingMerge.getOptionalAllTypes());
assertMessageMerged(
parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
assertMessageMerged(parsingMerge.getExtension(
TestParsingMerge.optionalExt));
// Repeated fields should not be merged.
assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
assertEquals(3, parsingMerge.getRepeatedGroupCount());
assertEquals(3, parsingMerge.getExtensionCount(
TestParsingMerge.repeatedExt));
}
public void testParsingMergeLite() throws Exception {
// Build messages.
TestAllTypesLite.Builder builder =
TestAllTypesLite.newBuilder();
TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
builder.clear();
TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
builder.clear();
TestAllTypesLite msg3 = builder.setOptionalInt32(3)
.setOptionalString("hello").build();
// Build groups.
TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG1 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg1).build();
TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG2 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg2).build();
TestParsingMergeLite.RepeatedFieldsGenerator.Group1 optionalG3 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group1.newBuilder()
.setField1(msg3).build();
TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG1 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg1).build();
TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG2 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg2).build();
TestParsingMergeLite.RepeatedFieldsGenerator.Group2 repeatedG3 =
TestParsingMergeLite.RepeatedFieldsGenerator.Group2.newBuilder()
.setField1(msg3).build();
// Assign and serialize RepeatedFieldsGenerator.
ByteString data = TestParsingMergeLite.RepeatedFieldsGenerator.newBuilder()
.addField1(msg1).addField1(msg2).addField1(msg3)
.addField2(msg1).addField2(msg2).addField2(msg3)
.addField3(msg1).addField3(msg2).addField3(msg3)
.addGroup1(optionalG1).addGroup1(optionalG2).addGroup1(optionalG3)
.addGroup2(repeatedG1).addGroup2(repeatedG2).addGroup2(repeatedG3)
.addExt1(msg1).addExt1(msg2).addExt1(msg3)
.addExt2(msg1).addExt2(msg2).addExt2(msg3)
.build().toByteString();
// Parse TestParsingMergeLite.
ExtensionRegistry registry = ExtensionRegistry.newInstance();
UnittestLite.registerAllExtensions(registry);
TestParsingMergeLite parsingMerge =
TestParsingMergeLite.PARSER.parseFrom(data, registry);
// Required and optional fields should be merged.
assertMessageMerged(parsingMerge.getRequiredAllTypes());
assertMessageMerged(parsingMerge.getOptionalAllTypes());
assertMessageMerged(
parsingMerge.getOptionalGroup().getOptionalGroupAllTypes());
assertMessageMerged(parsingMerge.getExtension(
TestParsingMergeLite.optionalExt));
// Repeated fields should not be merged.
assertEquals(3, parsingMerge.getRepeatedAllTypesCount());
assertEquals(3, parsingMerge.getRepeatedGroupCount());
assertEquals(3, parsingMerge.getExtensionCount(
TestParsingMergeLite.repeatedExt));
}
}

View File

@ -0,0 +1,190 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
import junit.framework.TestCase;
import java.util.Collections;
import java.util.List;
/**
* Tests for {@link RepeatedFieldBuilder}. This tests basic functionality.
* More extensive testing is provided via other tests that exercise the
* builder.
*
* @author jonp@google.com (Jon Perlow)
*/
public class RepeatedFieldBuilderTest extends TestCase {
public void testBasicUse() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
assertEquals(0, builder.getMessage(0).getOptionalInt32());
assertEquals(1, builder.getMessage(1).getOptionalInt32());
List<TestAllTypes> list = builder.build();
assertEquals(2, list.size());
assertEquals(0, list.get(0).getOptionalInt32());
assertEquals(1, list.get(1).getOptionalInt32());
assertIsUnmodifiable(list);
// Make sure it doesn't change.
List<TestAllTypes> list2 = builder.build();
assertSame(list, list2);
assertEquals(0, mockParent.getInvalidationCount());
}
public void testGoingBackAndForth() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
assertEquals(0, builder.getMessage(0).getOptionalInt32());
assertEquals(1, builder.getMessage(1).getOptionalInt32());
// Convert to list
List<TestAllTypes> list = builder.build();
assertEquals(2, list.size());
assertEquals(0, list.get(0).getOptionalInt32());
assertEquals(1, list.get(1).getOptionalInt32());
assertIsUnmodifiable(list);
// Update 0th item
assertEquals(0, mockParent.getInvalidationCount());
builder.getBuilder(0).setOptionalString("foo");
assertEquals(1, mockParent.getInvalidationCount());
list = builder.build();
assertEquals(2, list.size());
assertEquals(0, list.get(0).getOptionalInt32());
assertEquals("foo", list.get(0).getOptionalString());
assertEquals(1, list.get(1).getOptionalInt32());
assertIsUnmodifiable(list);
assertEquals(1, mockParent.getInvalidationCount());
}
public void testVariousMethods() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build());
builder.addBuilder(0, TestAllTypes.getDefaultInstance())
.setOptionalInt32(0);
builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
assertEquals(0, builder.getMessage(0).getOptionalInt32());
assertEquals(1, builder.getMessage(1).getOptionalInt32());
assertEquals(2, builder.getMessage(2).getOptionalInt32());
assertEquals(3, builder.getMessage(3).getOptionalInt32());
assertEquals(0, mockParent.getInvalidationCount());
List<TestAllTypes> messages = builder.build();
assertEquals(4, messages.size());
assertSame(messages, builder.build()); // expect same list
// Remove a message.
builder.remove(2);
assertEquals(1, mockParent.getInvalidationCount());
assertEquals(3, builder.getCount());
assertEquals(0, builder.getMessage(0).getOptionalInt32());
assertEquals(1, builder.getMessage(1).getOptionalInt32());
assertEquals(3, builder.getMessage(2).getOptionalInt32());
// Remove a builder.
builder.remove(0);
assertEquals(1, mockParent.getInvalidationCount());
assertEquals(2, builder.getCount());
assertEquals(1, builder.getMessage(0).getOptionalInt32());
assertEquals(3, builder.getMessage(1).getOptionalInt32());
// Test clear.
builder.clear();
assertEquals(1, mockParent.getInvalidationCount());
assertEquals(0, builder.getCount());
assertTrue(builder.isEmpty());
}
public void testLists() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder = newRepeatedFieldBuilder(mockParent);
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
builder.addMessage(0,
TestAllTypes.newBuilder().setOptionalInt32(0).build());
assertEquals(0, builder.getMessage(0).getOptionalInt32());
assertEquals(1, builder.getMessage(1).getOptionalInt32());
// Use list of builders.
List<TestAllTypes.Builder> builders = builder.getBuilderList();
assertEquals(0, builders.get(0).getOptionalInt32());
assertEquals(1, builders.get(1).getOptionalInt32());
builders.get(0).setOptionalInt32(10);
builders.get(1).setOptionalInt32(11);
// Use list of protos
List<TestAllTypes> protos = builder.getMessageList();
assertEquals(10, protos.get(0).getOptionalInt32());
assertEquals(11, protos.get(1).getOptionalInt32());
// Add an item to the builders and verify it's updated in both
builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
assertEquals(3, builders.size());
assertEquals(3, protos.size());
}
private void assertIsUnmodifiable(List<?> list) {
if (list == Collections.emptyList()) {
// OKAY -- Need to check this b/c EmptyList allows you to call clear.
} else {
try {
list.clear();
fail("List wasn't immutable");
} catch (UnsupportedOperationException e) {
// good
}
}
}
private RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>
newRepeatedFieldBuilder(GeneratedMessage.BuilderParent parent) {
return new RepeatedFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false,
parent, false);
}
}

View File

@ -0,0 +1,97 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
/**
* This class tests {@link RopeByteString#substring(int, int)} by inheriting the tests from
* {@link LiteralByteStringTest}. Only a couple of methods are overridden.
*
* @author carlanton@google.com (Carl Haverl)
*/
public class RopeByteStringSubstringTest extends LiteralByteStringTest {
@Override
protected void setUp() throws Exception {
classUnderTest = "RopeByteString";
byte[] sourceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(sourceBytes).iterator();
ByteString sourceString = iter.next();
while (iter.hasNext()) {
sourceString = sourceString.concat(iter.next());
}
int from = 1130;
int to = sourceBytes.length - 5555;
stringUnderTest = sourceString.substring(from, to);
referenceBytes = new byte[to - from];
System.arraycopy(sourceBytes, from, referenceBytes, 0, to - from);
expectedHashCode = -1259260680;
}
@Override
public void testGetTreeDepth() {
assertEquals(classUnderTest + " must have the expected tree depth",
3, stringUnderTest.getTreeDepth());
}
@Override
public void testToString() throws UnsupportedEncodingException {
String sourceString = "I love unicode \u1234\u5678 characters";
ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
int copies = 250;
// By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
StringBuilder builder = new StringBuilder(copies * sourceString.length());
ByteString unicode = ByteString.EMPTY;
for (int i = 0; i < copies; ++i) {
builder.append(sourceString);
unicode = RopeByteString.concatenate(unicode, sourceByteString);
}
String testString = builder.toString();
// Do the substring part
testString = testString.substring(2, testString.length() - 6);
unicode = unicode.substring(2, unicode.size() - 6);
assertEquals(classUnderTest + " from string must have the expected type",
classUnderTest, getActualClassName(unicode));
String roundTripString = unicode.toString(UTF_8);
assertEquals(classUnderTest + " unicode bytes must match",
testString, roundTripString);
ByteString flatString = ByteString.copyFromUtf8(testString);
assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
flatString.hashCode(), unicode.hashCode());
}
}

View File

@ -0,0 +1,115 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Iterator;
/**
* This class tests {@link RopeByteString} by inheriting the tests from
* {@link LiteralByteStringTest}. Only a couple of methods are overridden.
*
* <p>A full test of the result of {@link RopeByteString#substring(int, int)} is found in the
* separate class {@link RopeByteStringSubstringTest}.
*
* @author carlanton@google.com (Carl Haverl)
*/
public class RopeByteStringTest extends LiteralByteStringTest {
@Override
protected void setUp() throws Exception {
classUnderTest = "RopeByteString";
referenceBytes = ByteStringTest.getTestBytes(22341, 22337766L);
Iterator<ByteString> iter = ByteStringTest.makeConcretePieces(referenceBytes).iterator();
stringUnderTest = iter.next();
while (iter.hasNext()) {
stringUnderTest = stringUnderTest.concat(iter.next());
}
expectedHashCode = -1214197238;
}
@Override
public void testGetTreeDepth() {
assertEquals(classUnderTest + " must have the expected tree depth",
4, stringUnderTest.getTreeDepth());
}
public void testBalance() {
int numberOfPieces = 10000;
int pieceSize = 64;
byte[] testBytes = ByteStringTest.getTestBytes(numberOfPieces * pieceSize, 113377L);
// Build up a big ByteString from smaller pieces to force a rebalance
ByteString concatenated = ByteString.EMPTY;
for (int i = 0; i < numberOfPieces; ++i) {
concatenated = concatenated.concat(ByteString.copyFrom(testBytes, i * pieceSize, pieceSize));
}
assertEquals(classUnderTest + " from string must have the expected type",
classUnderTest, getActualClassName(concatenated));
assertTrue(classUnderTest + " underlying bytes must match after balancing",
Arrays.equals(testBytes, concatenated.toByteArray()));
ByteString testString = ByteString.copyFrom(testBytes);
assertTrue(classUnderTest + " balanced string must equal flat string",
concatenated.equals(testString));
assertTrue(classUnderTest + " flat string must equal balanced string",
testString.equals(concatenated));
assertEquals(classUnderTest + " balanced string must have same hash code as flat string",
testString.hashCode(), concatenated.hashCode());
}
@Override
public void testToString() throws UnsupportedEncodingException {
String sourceString = "I love unicode \u1234\u5678 characters";
ByteString sourceByteString = ByteString.copyFromUtf8(sourceString);
int copies = 250;
// By building the RopeByteString by concatenating, this is actually a fairly strenuous test.
StringBuilder builder = new StringBuilder(copies * sourceString.length());
ByteString unicode = ByteString.EMPTY;
for (int i = 0; i < copies; ++i) {
builder.append(sourceString);
unicode = RopeByteString.concatenate(unicode, sourceByteString);
}
String testString = builder.toString();
assertEquals(classUnderTest + " from string must have the expected type",
classUnderTest, getActualClassName(unicode));
String roundTripString = unicode.toString(UTF_8);
assertEquals(classUnderTest + " unicode bytes must match",
testString, roundTripString);
ByteString flatString = ByteString.copyFromUtf8(testString);
assertEquals(classUnderTest + " string must equal the flat string", flatString, unicode);
assertEquals(classUnderTest + " string must must have same hashCode as the flat string",
flatString.hashCode(), unicode.hashCode());
}
}

View File

@ -0,0 +1,320 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.MethodDescriptor;
import google.protobuf.no_generic_services_test.UnittestNoGenericServices;
import protobuf_unittest.MessageWithNoOuter;
import protobuf_unittest.ServiceWithNoOuter;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestService;
import protobuf_unittest.UnittestProto.FooRequest;
import protobuf_unittest.UnittestProto.FooResponse;
import protobuf_unittest.UnittestProto.BarRequest;
import protobuf_unittest.UnittestProto.BarResponse;
import org.easymock.classextension.EasyMock;
import org.easymock.classextension.IMocksControl;
import org.easymock.IArgumentMatcher;
import java.util.HashSet;
import java.util.Set;
import junit.framework.TestCase;
/**
* Tests services and stubs.
*
* @author kenton@google.com Kenton Varda
*/
public class ServiceTest extends TestCase {
private IMocksControl control;
private RpcController mockController;
private final Descriptors.MethodDescriptor fooDescriptor =
TestService.getDescriptor().getMethods().get(0);
private final Descriptors.MethodDescriptor barDescriptor =
TestService.getDescriptor().getMethods().get(1);
@Override
protected void setUp() throws Exception {
super.setUp();
control = EasyMock.createStrictControl();
mockController = control.createMock(RpcController.class);
}
// =================================================================
/** Tests Service.callMethod(). */
public void testCallMethod() throws Exception {
FooRequest fooRequest = FooRequest.newBuilder().build();
BarRequest barRequest = BarRequest.newBuilder().build();
MockCallback<Message> fooCallback = new MockCallback<Message>();
MockCallback<Message> barCallback = new MockCallback<Message>();
TestService mockService = control.createMock(TestService.class);
mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
this.<FooResponse>wrapsCallback(fooCallback));
mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
this.<BarResponse>wrapsCallback(barCallback));
control.replay();
mockService.callMethod(fooDescriptor, mockController,
fooRequest, fooCallback);
mockService.callMethod(barDescriptor, mockController,
barRequest, barCallback);
control.verify();
}
/** Tests Service.get{Request,Response}Prototype(). */
public void testGetPrototype() throws Exception {
TestService mockService = control.createMock(TestService.class);
assertSame(mockService.getRequestPrototype(fooDescriptor),
FooRequest.getDefaultInstance());
assertSame(mockService.getResponsePrototype(fooDescriptor),
FooResponse.getDefaultInstance());
assertSame(mockService.getRequestPrototype(barDescriptor),
BarRequest.getDefaultInstance());
assertSame(mockService.getResponsePrototype(barDescriptor),
BarResponse.getDefaultInstance());
}
/** Tests generated stubs. */
public void testStub() throws Exception {
FooRequest fooRequest = FooRequest.newBuilder().build();
BarRequest barRequest = BarRequest.newBuilder().build();
MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
RpcChannel mockChannel = control.createMock(RpcChannel.class);
TestService stub = TestService.newStub(mockChannel);
mockChannel.callMethod(
EasyMock.same(fooDescriptor),
EasyMock.same(mockController),
EasyMock.same(fooRequest),
EasyMock.same(FooResponse.getDefaultInstance()),
this.<Message>wrapsCallback(fooCallback));
mockChannel.callMethod(
EasyMock.same(barDescriptor),
EasyMock.same(mockController),
EasyMock.same(barRequest),
EasyMock.same(BarResponse.getDefaultInstance()),
this.<Message>wrapsCallback(barCallback));
control.replay();
stub.foo(mockController, fooRequest, fooCallback);
stub.bar(mockController, barRequest, barCallback);
control.verify();
}
/** Tests generated blocking stubs. */
public void testBlockingStub() throws Exception {
FooRequest fooRequest = FooRequest.newBuilder().build();
BarRequest barRequest = BarRequest.newBuilder().build();
BlockingRpcChannel mockChannel =
control.createMock(BlockingRpcChannel.class);
TestService.BlockingInterface stub =
TestService.newBlockingStub(mockChannel);
FooResponse fooResponse = FooResponse.newBuilder().build();
BarResponse barResponse = BarResponse.newBuilder().build();
EasyMock.expect(mockChannel.callBlockingMethod(
EasyMock.same(fooDescriptor),
EasyMock.same(mockController),
EasyMock.same(fooRequest),
EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
EasyMock.expect(mockChannel.callBlockingMethod(
EasyMock.same(barDescriptor),
EasyMock.same(mockController),
EasyMock.same(barRequest),
EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
control.replay();
assertSame(fooResponse, stub.foo(mockController, fooRequest));
assertSame(barResponse, stub.bar(mockController, barRequest));
control.verify();
}
public void testNewReflectiveService() {
ServiceWithNoOuter.Interface impl =
control.createMock(ServiceWithNoOuter.Interface.class);
RpcController controller = control.createMock(RpcController.class);
Service service = ServiceWithNoOuter.newReflectiveService(impl);
MethodDescriptor fooMethod =
ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
RpcCallback<Message> callback = new RpcCallback<Message>() {
public void run(Message parameter) {
// No reason this should be run.
fail();
}
};
RpcCallback<TestAllTypes> specializedCallback =
RpcUtil.specializeCallback(callback);
impl.foo(EasyMock.same(controller), EasyMock.same(request),
EasyMock.same(specializedCallback));
EasyMock.expectLastCall();
control.replay();
service.callMethod(fooMethod, controller, request, callback);
control.verify();
}
public void testNewReflectiveBlockingService() throws ServiceException {
ServiceWithNoOuter.BlockingInterface impl =
control.createMock(ServiceWithNoOuter.BlockingInterface.class);
RpcController controller = control.createMock(RpcController.class);
BlockingService service =
ServiceWithNoOuter.newReflectiveBlockingService(impl);
MethodDescriptor fooMethod =
ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
.andReturn(expectedResponse);
control.replay();
Message response =
service.callBlockingMethod(fooMethod, controller, request);
assertEquals(expectedResponse, response);
control.verify();
}
public void testNoGenericServices() throws Exception {
// Non-services should be usable.
UnittestNoGenericServices.TestMessage message =
UnittestNoGenericServices.TestMessage.newBuilder()
.setA(123)
.setExtension(UnittestNoGenericServices.testExtension, 456)
.build();
assertEquals(123, message.getA());
assertEquals(1, UnittestNoGenericServices.TestEnum.FOO.getNumber());
// Build a list of the class names nested in UnittestNoGenericServices.
String outerName = "google.protobuf.no_generic_services_test." +
"UnittestNoGenericServices";
Class<?> outerClass = Class.forName(outerName);
Set<String> innerClassNames = new HashSet<String>();
for (Class<?> innerClass : outerClass.getClasses()) {
String fullName = innerClass.getName();
// Figure out the unqualified name of the inner class.
// Note: Surprisingly, the full name of an inner class will be separated
// from the outer class name by a '$' rather than a '.'. This is not
// mentioned in the documentation for java.lang.Class. I don't want to
// make assumptions, so I'm just going to accept any character as the
// separator.
assertTrue(fullName.startsWith(outerName));
if (!Service.class.isAssignableFrom(innerClass) &&
!Message.class.isAssignableFrom(innerClass) &&
!ProtocolMessageEnum.class.isAssignableFrom(innerClass)) {
// Ignore any classes not generated by the base code generator.
continue;
}
innerClassNames.add(fullName.substring(outerName.length() + 1));
}
// No service class should have been generated.
assertTrue(innerClassNames.contains("TestMessage"));
assertTrue(innerClassNames.contains("TestEnum"));
assertFalse(innerClassNames.contains("TestService"));
// But descriptors are there.
FileDescriptor file = UnittestNoGenericServices.getDescriptor();
assertEquals(1, file.getServices().size());
assertEquals("TestService", file.getServices().get(0).getName());
assertEquals(1, file.getServices().get(0).getMethods().size());
assertEquals("Foo",
file.getServices().get(0).getMethods().get(0).getName());
}
// =================================================================
/**
* wrapsCallback() is an EasyMock argument predicate. wrapsCallback(c)
* matches a callback if calling that callback causes c to be called.
* In other words, c wraps the given callback.
*/
private <Type extends Message> RpcCallback<Type> wrapsCallback(
MockCallback<?> callback) {
EasyMock.reportMatcher(new WrapsCallback(callback));
return null;
}
/** The parameter to wrapsCallback() must be a MockCallback. */
private static class MockCallback<Type extends Message>
implements RpcCallback<Type> {
private boolean called = false;
public boolean isCalled() { return called; }
public void reset() { called = false; }
public void run(Type message) { called = true; }
}
/** Implementation of the wrapsCallback() argument matcher. */
private static class WrapsCallback implements IArgumentMatcher {
private MockCallback<?> callback;
public WrapsCallback(MockCallback<?> callback) {
this.callback = callback;
}
@SuppressWarnings("unchecked")
public boolean matches(Object actual) {
if (!(actual instanceof RpcCallback)) {
return false;
}
RpcCallback actualCallback = (RpcCallback)actual;
callback.reset();
actualCallback.run(null);
return callback.isCalled();
}
public void appendTo(StringBuffer buffer) {
buffer.append("wrapsCallback(mockCallback)");
}
}
}

View File

@ -0,0 +1,155 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
import junit.framework.TestCase;
/**
* Tests for {@link SingleFieldBuilder}. This tests basic functionality.
* More extensive testing is provided via other tests that exercise the
* builder.
*
* @author jonp@google.com (Jon Perlow)
*/
public class SingleFieldBuilderTest extends TestCase {
public void testBasicUseAndInvalidations() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder =
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>(
TestAllTypes.getDefaultInstance(),
mockParent,
false);
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
assertEquals(TestAllTypes.getDefaultInstance(),
builder.getBuilder().buildPartial());
assertEquals(0, mockParent.getInvalidationCount());
builder.getBuilder().setOptionalInt32(10);
assertEquals(0, mockParent.getInvalidationCount());
TestAllTypes message = builder.build();
assertEquals(10, message.getOptionalInt32());
// Test that we receive invalidations now that build has been called.
assertEquals(0, mockParent.getInvalidationCount());
builder.getBuilder().setOptionalInt32(20);
assertEquals(1, mockParent.getInvalidationCount());
// Test that we don't keep getting invalidations on every change
builder.getBuilder().setOptionalInt32(30);
assertEquals(1, mockParent.getInvalidationCount());
}
public void testSetMessage() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder =
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>(
TestAllTypes.getDefaultInstance(),
mockParent,
false);
builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
assertEquals(0, builder.getMessage().getOptionalInt32());
// Update message using the builder
builder.getBuilder().setOptionalInt32(1);
assertEquals(0, mockParent.getInvalidationCount());
assertEquals(1, builder.getBuilder().getOptionalInt32());
assertEquals(1, builder.getMessage().getOptionalInt32());
builder.build();
builder.getBuilder().setOptionalInt32(2);
assertEquals(2, builder.getBuilder().getOptionalInt32());
assertEquals(2, builder.getMessage().getOptionalInt32());
// Make sure message stays cached
assertSame(builder.getMessage(), builder.getMessage());
}
public void testClear() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder =
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>(
TestAllTypes.getDefaultInstance(),
mockParent,
false);
builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
builder.clear();
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
builder.getBuilder().setOptionalInt32(1);
assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
builder.clear();
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
}
public void testMerge() {
TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder> builder =
new SingleFieldBuilder<TestAllTypes, TestAllTypes.Builder,
TestAllTypesOrBuilder>(
TestAllTypes.getDefaultInstance(),
mockParent,
false);
// Merge into default field.
builder.mergeFrom(TestAllTypes.getDefaultInstance());
assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
// Merge into non-default field on existing builder.
builder.getBuilder().setOptionalInt32(2);
builder.mergeFrom(TestAllTypes.newBuilder()
.setOptionalDouble(4.0)
.buildPartial());
assertEquals(2, builder.getMessage().getOptionalInt32());
assertEquals(4.0, builder.getMessage().getOptionalDouble());
// Merge into non-default field on existing message
builder.setMessage(TestAllTypes.newBuilder()
.setOptionalInt32(10)
.buildPartial());
builder.mergeFrom(TestAllTypes.newBuilder()
.setOptionalDouble(5.0)
.buildPartial());
assertEquals(10, builder.getMessage().getOptionalInt32());
assertEquals(5.0, builder.getMessage().getOptionalDouble());
}
}

View File

@ -0,0 +1,420 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* @author darick@google.com Darick Tong
*/
public class SmallSortedMapTest extends TestCase {
// java.util.AbstractMap.SimpleEntry is private in JDK 1.5. We re-implement it
// here for JDK 1.5 users.
private static class SimpleEntry<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry) o;
return eq(key, e.getKey()) && eq(value, e.getValue());
}
@Override
public int hashCode() {
return ((key == null) ? 0 : key.hashCode()) ^
((value == null) ? 0 : value.hashCode());
}
}
public void testPutAndGetArrayEntriesOnly() {
runPutAndGetTest(3);
}
public void testPutAndGetOverflowEntries() {
runPutAndGetTest(6);
}
private void runPutAndGetTest(int numElements) {
// Test with even and odd arraySize
SmallSortedMap<Integer, Integer> map1 =
SmallSortedMap.newInstanceForTest(3);
SmallSortedMap<Integer, Integer> map2 =
SmallSortedMap.newInstanceForTest(4);
SmallSortedMap<Integer, Integer> map3 =
SmallSortedMap.newInstanceForTest(3);
SmallSortedMap<Integer, Integer> map4 =
SmallSortedMap.newInstanceForTest(4);
// Test with puts in ascending order.
for (int i = 0; i < numElements; i++) {
assertNull(map1.put(i, i + 1));
assertNull(map2.put(i, i + 1));
}
// Test with puts in descending order.
for (int i = numElements - 1; i >= 0; i--) {
assertNull(map3.put(i, i + 1));
assertNull(map4.put(i, i + 1));
}
assertEquals(Math.min(3, numElements), map1.getNumArrayEntries());
assertEquals(Math.min(4, numElements), map2.getNumArrayEntries());
assertEquals(Math.min(3, numElements), map3.getNumArrayEntries());
assertEquals(Math.min(4, numElements), map4.getNumArrayEntries());
List<SmallSortedMap<Integer, Integer>> allMaps =
new ArrayList<SmallSortedMap<Integer, Integer>>();
allMaps.add(map1);
allMaps.add(map2);
allMaps.add(map3);
allMaps.add(map4);
for (SmallSortedMap<Integer, Integer> map : allMaps) {
assertEquals(numElements, map.size());
for (int i = 0; i < numElements; i++) {
assertEquals(new Integer(i + 1), map.get(i));
}
}
assertEquals(map1, map2);
assertEquals(map2, map3);
assertEquals(map3, map4);
}
public void testReplacingPut() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
assertNull(map.remove(i + 1));
}
for (int i = 0; i < 6; i++) {
assertEquals(new Integer(i + 1), map.put(i, i + 2));
}
}
public void testRemove() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
assertNull(map.remove(i + 1));
}
assertEquals(3, map.getNumArrayEntries());
assertEquals(3, map.getNumOverflowEntries());
assertEquals(6, map.size());
assertEquals(makeSortedKeySet(0, 1, 2, 3, 4, 5), map.keySet());
assertEquals(new Integer(2), map.remove(1));
assertEquals(3, map.getNumArrayEntries());
assertEquals(2, map.getNumOverflowEntries());
assertEquals(5, map.size());
assertEquals(makeSortedKeySet(0, 2, 3, 4, 5), map.keySet());
assertEquals(new Integer(5), map.remove(4));
assertEquals(3, map.getNumArrayEntries());
assertEquals(1, map.getNumOverflowEntries());
assertEquals(4, map.size());
assertEquals(makeSortedKeySet(0, 2, 3, 5), map.keySet());
assertEquals(new Integer(4), map.remove(3));
assertEquals(3, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(3, map.size());
assertEquals(makeSortedKeySet(0, 2, 5), map.keySet());
assertNull(map.remove(3));
assertEquals(3, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(3, map.size());
assertEquals(new Integer(1), map.remove(0));
assertEquals(2, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(2, map.size());
}
public void testClear() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
map.clear();
assertEquals(0, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(0, map.size());
}
public void testGetArrayEntryAndOverflowEntries() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
assertEquals(3, map.getNumArrayEntries());
for (int i = 0; i < 3; i++) {
Map.Entry<Integer, Integer> entry = map.getArrayEntryAt(i);
assertEquals(new Integer(i), entry.getKey());
assertEquals(new Integer(i + 1), entry.getValue());
}
Iterator<Map.Entry<Integer, Integer>> it =
map.getOverflowEntries().iterator();
for (int i = 3; i < 6; i++) {
assertTrue(it.hasNext());
Map.Entry<Integer, Integer> entry = it.next();
assertEquals(new Integer(i), entry.getKey());
assertEquals(new Integer(i + 1), entry.getValue());
}
assertFalse(it.hasNext());
}
public void testEntrySetContains() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
for (int i = 0; i < 6; i++) {
assertTrue(
entrySet.contains(new SimpleEntry<Integer, Integer>(i, i + 1)));
assertFalse(
entrySet.contains(new SimpleEntry<Integer, Integer>(i, i)));
}
}
public void testEntrySetAdd() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
for (int i = 0; i < 6; i++) {
Map.Entry<Integer, Integer> entry =
new SimpleEntry<Integer, Integer>(i, i + 1);
assertTrue(entrySet.add(entry));
assertFalse(entrySet.add(entry));
}
for (int i = 0; i < 6; i++) {
assertEquals(new Integer(i + 1), map.get(i));
}
assertEquals(3, map.getNumArrayEntries());
assertEquals(3, map.getNumOverflowEntries());
assertEquals(6, map.size());
}
public void testEntrySetRemove() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
for (int i = 0; i < 6; i++) {
Map.Entry<Integer, Integer> entry =
new SimpleEntry<Integer, Integer>(i, i + 1);
assertTrue(entrySet.remove(entry));
assertFalse(entrySet.remove(entry));
}
assertTrue(map.isEmpty());
assertEquals(0, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(0, map.size());
}
public void testEntrySetClear() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
map.entrySet().clear();
assertTrue(map.isEmpty());
assertEquals(0, map.getNumArrayEntries());
assertEquals(0, map.getNumOverflowEntries());
assertEquals(0, map.size());
}
public void testEntrySetIteratorNext() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
for (int i = 0; i < 6; i++) {
assertTrue(it.hasNext());
Map.Entry<Integer, Integer> entry = it.next();
assertEquals(new Integer(i), entry.getKey());
assertEquals(new Integer(i + 1), entry.getValue());
}
assertFalse(it.hasNext());
}
public void testEntrySetIteratorRemove() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
for (int i = 0; i < 6; i++) {
assertTrue(map.containsKey(i));
it.next();
it.remove();
assertFalse(map.containsKey(i));
assertEquals(6 - i - 1, map.size());
}
}
public void testMapEntryModification() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
for (int i = 0; i < 6; i++) {
Map.Entry<Integer, Integer> entry = it.next();
entry.setValue(i + 23);
}
for (int i = 0; i < 6; i++) {
assertEquals(new Integer(i + 23), map.get(i));
}
}
public void testMakeImmutable() {
SmallSortedMap<Integer, Integer> map = SmallSortedMap.newInstanceForTest(3);
for (int i = 0; i < 6; i++) {
assertNull(map.put(i, i + 1));
}
map.makeImmutable();
assertEquals(new Integer(1), map.get(0));
assertEquals(6, map.size());
try {
map.put(23, 23);
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
Map<Integer, Integer> other = new HashMap<Integer, Integer>();
other.put(23, 23);
try {
map.putAll(other);
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
try {
map.remove(0);
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
try {
map.clear();
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
try {
entrySet.clear();
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
Iterator<Map.Entry<Integer, Integer>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> entry = it.next();
try {
entry.setValue(0);
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
try {
it.remove();
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
}
Set<Integer> keySet = map.keySet();
try {
keySet.clear();
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
Iterator<Integer> keys = keySet.iterator();
while (keys.hasNext()) {
Integer key = keys.next();
try {
keySet.remove(key);
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
try {
keys.remove();
fail("Expected UnsupportedOperationException");
} catch (UnsupportedOperationException expected) {
}
}
}
private Set<Integer> makeSortedKeySet(Integer... keys) {
return new TreeSet<Integer>(Arrays.<Integer>asList(keys));
}
}

View File

@ -0,0 +1,63 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
/**
* Tests that proto2 api generation doesn't cause compile errors when
* compiling protocol buffers that have names that would otherwise conflict
* if not fully qualified (like @Deprecated and @Override).
*
* @author jonp@google.com (Jon Perlow)
*/
public class TestBadIdentifiers extends TestCase {
public void testCompilation() {
// If this compiles, it means the generation was correct.
TestBadIdentifiersProto.Deprecated.newBuilder();
TestBadIdentifiersProto.Override.newBuilder();
}
public void testGetDescriptor() {
Descriptors.FileDescriptor fileDescriptor =
TestBadIdentifiersProto.getDescriptor();
String descriptorField = TestBadIdentifiersProto.Descriptor
.getDefaultInstance().getDescriptor();
Descriptors.Descriptor protoDescriptor = TestBadIdentifiersProto.Descriptor
.getDefaultInstance().getDescriptorForType();
String nestedDescriptorField = TestBadIdentifiersProto.Descriptor
.NestedDescriptor.getDefaultInstance().getDescriptor();
Descriptors.Descriptor nestedProtoDescriptor = TestBadIdentifiersProto
.Descriptor.NestedDescriptor.getDefaultInstance()
.getDescriptorForType();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,786 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import com.google.protobuf.Descriptors.FieldDescriptor;
import protobuf_unittest.UnittestMset.TestMessageSet;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import protobuf_unittest.UnittestProto.OneString;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import junit.framework.TestCase;
import java.io.StringReader;
/**
* Test case for {@link TextFormat}.
*
* TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
*
* @author wenboz@google.com (Wenbo Zhu)
*/
public class TextFormatTest extends TestCase {
// A basic string with different escapable characters for testing.
private final static String kEscapeTestString =
"\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+ "slashes \\";
// A representation of the above string with all the characters escaped.
private final static String kEscapeTestStringEscaped =
"\\\"A string with \\' characters \\n and \\r newlines "
+ "and \\t tabs and \\001 slashes \\\\";
private static String allFieldsSetText = TestUtil.readTextFromFile(
"text_format_unittest_data.txt");
private static String allExtensionsSetText = TestUtil.readTextFromFile(
"text_format_unittest_extensions_data.txt");
private static String exoticText =
"repeated_int32: -1\n" +
"repeated_int32: -2147483648\n" +
"repeated_int64: -1\n" +
"repeated_int64: -9223372036854775808\n" +
"repeated_uint32: 4294967295\n" +
"repeated_uint32: 2147483648\n" +
"repeated_uint64: 18446744073709551615\n" +
"repeated_uint64: 9223372036854775808\n" +
"repeated_double: 123.0\n" +
"repeated_double: 123.5\n" +
"repeated_double: 0.125\n" +
"repeated_double: .125\n" +
"repeated_double: -.125\n" +
"repeated_double: 1.23E17\n" +
"repeated_double: 1.23E+17\n" +
"repeated_double: -1.23e-17\n" +
"repeated_double: .23e+17\n" +
"repeated_double: -.23E17\n" +
"repeated_double: 1.235E22\n" +
"repeated_double: 1.235E-18\n" +
"repeated_double: 123.456789\n" +
"repeated_double: Infinity\n" +
"repeated_double: -Infinity\n" +
"repeated_double: NaN\n" +
"repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
"\\341\\210\\264\"\n" +
"repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
private static String canonicalExoticText =
exoticText.replace(": .", ": 0.").replace(": -.", ": -0.") // short-form double
.replace("23e", "23E").replace("E+", "E").replace("0.23E17", "2.3E16");
private String messageSetText =
"[protobuf_unittest.TestMessageSetExtension1] {\n" +
" i: 123\n" +
"}\n" +
"[protobuf_unittest.TestMessageSetExtension2] {\n" +
" str: \"foo\"\n" +
"}\n";
/** Print TestAllTypes and compare with golden file. */
public void testPrintMessage() throws Exception {
String javaText = TextFormat.printToString(TestUtil.getAllSet());
// Java likes to add a trailing ".0" to floats and doubles. C printf
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertEquals(allFieldsSetText, javaText);
}
/** Print TestAllTypes as Builder and compare with golden file. */
public void testPrintMessageBuilder() throws Exception {
String javaText = TextFormat.printToString(TestUtil.getAllSetBuilder());
// Java likes to add a trailing ".0" to floats and doubles. C printf
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertEquals(allFieldsSetText, javaText);
}
/** Print TestAllExtensions and compare with golden file. */
public void testPrintExtensions() throws Exception {
String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
// Java likes to add a trailing ".0" to floats and doubles. C printf
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertEquals(allExtensionsSetText, javaText);
}
// Creates an example unknown field set.
private UnknownFieldSet makeUnknownFieldSet() {
return UnknownFieldSet.newBuilder()
.addField(5,
UnknownFieldSet.Field.newBuilder()
.addVarint(1)
.addFixed32(2)
.addFixed64(3)
.addLengthDelimited(ByteString.copyFromUtf8("4"))
.addGroup(
UnknownFieldSet.newBuilder()
.addField(10,
UnknownFieldSet.Field.newBuilder()
.addVarint(5)
.build())
.build())
.build())
.addField(8,
UnknownFieldSet.Field.newBuilder()
.addVarint(1)
.addVarint(2)
.addVarint(3)
.build())
.addField(15,
UnknownFieldSet.Field.newBuilder()
.addVarint(0xABCDEF1234567890L)
.addFixed32(0xABCD1234)
.addFixed64(0xABCDEF1234567890L)
.build())
.build();
}
public void testPrintUnknownFields() throws Exception {
// Test printing of unknown fields in a message.
TestEmptyMessage message =
TestEmptyMessage.newBuilder()
.setUnknownFields(makeUnknownFieldSet())
.build();
assertEquals(
"5: 1\n" +
"5: 0x00000002\n" +
"5: 0x0000000000000003\n" +
"5: \"4\"\n" +
"5 {\n" +
" 10: 5\n" +
"}\n" +
"8: 1\n" +
"8: 2\n" +
"8: 3\n" +
"15: 12379813812177893520\n" +
"15: 0xabcd1234\n" +
"15: 0xabcdef1234567890\n",
TextFormat.printToString(message));
}
public void testPrintField() throws Exception {
final FieldDescriptor dataField =
OneString.getDescriptor().findFieldByName("data");
assertEquals(
"data: \"test data\"\n",
TextFormat.printFieldToString(dataField, "test data"));
final FieldDescriptor optionalField =
TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
final Object value = NestedMessage.newBuilder().setBb(42).build();
assertEquals(
"optional_nested_message {\n bb: 42\n}\n",
TextFormat.printFieldToString(optionalField, value));
}
/**
* Helper to construct a ByteString from a String containing only 8-bit
* characters. The characters are converted directly to bytes, *not*
* encoded using UTF-8.
*/
private ByteString bytes(String str) throws Exception {
return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
}
/**
* Helper to construct a ByteString from a bunch of bytes. The inputs are
* actually ints so that I can use hex notation and not get stupid errors
* about precision.
*/
private ByteString bytes(int... bytesAsInts) {
byte[] bytes = new byte[bytesAsInts.length];
for (int i = 0; i < bytesAsInts.length; i++) {
bytes[i] = (byte) bytesAsInts[i];
}
return ByteString.copyFrom(bytes);
}
public void testPrintExotic() throws Exception {
Message message = TestAllTypes.newBuilder()
// Signed vs. unsigned numbers.
.addRepeatedInt32 (-1)
.addRepeatedUint32(-1)
.addRepeatedInt64 (-1)
.addRepeatedUint64(-1)
.addRepeatedInt32 (1 << 31)
.addRepeatedUint32(1 << 31)
.addRepeatedInt64 (1l << 63)
.addRepeatedUint64(1l << 63)
// Floats of various precisions and exponents.
.addRepeatedDouble(123)
.addRepeatedDouble(123.5)
.addRepeatedDouble(0.125)
.addRepeatedDouble(.125)
.addRepeatedDouble(-.125)
.addRepeatedDouble(123e15)
.addRepeatedDouble(123e15)
.addRepeatedDouble(-1.23e-17)
.addRepeatedDouble(.23e17)
.addRepeatedDouble(-23e15)
.addRepeatedDouble(123.5e20)
.addRepeatedDouble(123.5e-20)
.addRepeatedDouble(123.456789)
.addRepeatedDouble(Double.POSITIVE_INFINITY)
.addRepeatedDouble(Double.NEGATIVE_INFINITY)
.addRepeatedDouble(Double.NaN)
// Strings and bytes that needing escaping.
.addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
.addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
.build();
assertEquals(canonicalExoticText, message.toString());
}
public void testPrintMessageSet() throws Exception {
TestMessageSet messageSet =
TestMessageSet.newBuilder()
.setExtension(
TestMessageSetExtension1.messageSetExtension,
TestMessageSetExtension1.newBuilder().setI(123).build())
.setExtension(
TestMessageSetExtension2.messageSetExtension,
TestMessageSetExtension2.newBuilder().setStr("foo").build())
.build();
assertEquals(messageSetText, messageSet.toString());
}
// =================================================================
public void testParse() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(allFieldsSetText, builder);
TestUtil.assertAllFieldsSet(builder.build());
}
public void testParseReader() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(new StringReader(allFieldsSetText), builder);
TestUtil.assertAllFieldsSet(builder.build());
}
public void testParseExtensions() throws Exception {
TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
TextFormat.merge(allExtensionsSetText,
TestUtil.getExtensionRegistry(),
builder);
TestUtil.assertAllExtensionsSet(builder.build());
}
public void testParseCompatibility() throws Exception {
String original = "repeated_float: inf\n" +
"repeated_float: -inf\n" +
"repeated_float: nan\n" +
"repeated_float: inff\n" +
"repeated_float: -inff\n" +
"repeated_float: nanf\n" +
"repeated_float: 1.0f\n" +
"repeated_float: infinityf\n" +
"repeated_float: -Infinityf\n" +
"repeated_double: infinity\n" +
"repeated_double: -infinity\n" +
"repeated_double: nan\n";
String canonical = "repeated_float: Infinity\n" +
"repeated_float: -Infinity\n" +
"repeated_float: NaN\n" +
"repeated_float: Infinity\n" +
"repeated_float: -Infinity\n" +
"repeated_float: NaN\n" +
"repeated_float: 1.0\n" +
"repeated_float: Infinity\n" +
"repeated_float: -Infinity\n" +
"repeated_double: Infinity\n" +
"repeated_double: -Infinity\n" +
"repeated_double: NaN\n";
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(original, builder);
assertEquals(canonical, builder.build().toString());
}
public void testParseExotic() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(exoticText, builder);
// Too lazy to check things individually. Don't try to debug this
// if testPrintExotic() is failing.
assertEquals(canonicalExoticText, builder.build().toString());
}
public void testParseMessageSet() throws Exception {
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
TestMessageSet.Builder builder = TestMessageSet.newBuilder();
TextFormat.merge(messageSetText, extensionRegistry, builder);
TestMessageSet messageSet = builder.build();
assertTrue(messageSet.hasExtension(
TestMessageSetExtension1.messageSetExtension));
assertEquals(123, messageSet.getExtension(
TestMessageSetExtension1.messageSetExtension).getI());
assertTrue(messageSet.hasExtension(
TestMessageSetExtension2.messageSetExtension));
assertEquals("foo", messageSet.getExtension(
TestMessageSetExtension2.messageSetExtension).getStr());
}
public void testParseNumericEnum() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("optional_nested_enum: 2", builder);
assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
}
public void testParseAngleBrackets() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("OptionalGroup: < a: 1 >", builder);
assertTrue(builder.hasOptionalGroup());
assertEquals(1, builder.getOptionalGroup().getA());
}
public void testParseComment() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(
"# this is a comment\n" +
"optional_int32: 1 # another comment\n" +
"optional_int64: 2\n" +
"# EOF comment", builder);
assertEquals(1, builder.getOptionalInt32());
assertEquals(2, builder.getOptionalInt64());
}
private void assertParseError(String error, String text) {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
try {
TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
fail("Expected parse exception.");
} catch (TextFormat.ParseException e) {
assertEquals(error, e.getMessage());
}
}
public void testParseErrors() throws Exception {
assertParseError(
"1:16: Expected \":\".",
"optional_int32 123");
assertParseError(
"1:23: Expected identifier.",
"optional_nested_enum: ?");
assertParseError(
"1:18: Couldn't parse integer: Number must be positive: -1",
"optional_uint32: -1");
assertParseError(
"1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
"integer: 82301481290849012385230157",
"optional_int32: 82301481290849012385230157");
assertParseError(
"1:16: Expected \"true\" or \"false\".",
"optional_bool: maybe");
assertParseError(
"1:16: Expected \"true\" or \"false\".",
"optional_bool: 2");
assertParseError(
"1:18: Expected string.",
"optional_string: 123");
assertParseError(
"1:18: String missing ending quote.",
"optional_string: \"ueoauaoe");
assertParseError(
"1:18: String missing ending quote.",
"optional_string: \"ueoauaoe\n" +
"optional_int32: 123");
assertParseError(
"1:18: Invalid escape sequence: '\\z'",
"optional_string: \"\\z\"");
assertParseError(
"1:18: String missing ending quote.",
"optional_string: \"ueoauaoe\n" +
"optional_int32: 123");
assertParseError(
"1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
"[nosuchext]: 123");
assertParseError(
"1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
"not extend message type \"protobuf_unittest.TestAllTypes\".",
"[protobuf_unittest.optional_int32_extension]: 123");
assertParseError(
"1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
"named \"nosuchfield\".",
"nosuchfield: 123");
assertParseError(
"1:21: Expected \">\".",
"OptionalGroup < a: 1");
assertParseError(
"1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
"value named \"NO_SUCH_VALUE\".",
"optional_nested_enum: NO_SUCH_VALUE");
assertParseError(
"1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
"value with number 123.",
"optional_nested_enum: 123");
// Delimiters must match.
assertParseError(
"1:22: Expected identifier.",
"OptionalGroup < a: 1 }");
assertParseError(
"1:22: Expected identifier.",
"OptionalGroup { a: 1 >");
}
// =================================================================
public void testEscape() throws Exception {
// Escape sequences.
assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"")));
assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\""));
assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
assertEquals(kEscapeTestStringEscaped,
TextFormat.escapeText(kEscapeTestString));
assertEquals(kEscapeTestString,
TextFormat.unescapeText(kEscapeTestStringEscaped));
// Unicode handling.
assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
assertEquals("\\341\\210\\264",
TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
assertEquals(bytes(0xe1, 0x88, 0xb4),
TextFormat.unescapeBytes("\\341\\210\\264"));
assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
assertEquals(bytes(0xe1, 0x88, 0xb4),
TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
// Handling of strings with unescaped Unicode characters > 255.
final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
ByteString zhByteString = ByteString.copyFromUtf8(zh);
assertEquals(zhByteString, TextFormat.unescapeBytes(zh));
// Errors.
try {
TextFormat.unescapeText("\\x");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
try {
TextFormat.unescapeText("\\z");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
try {
TextFormat.unescapeText("\\");
fail("Should have thrown an exception.");
} catch (TextFormat.InvalidEscapeSequenceException e) {
// success
}
}
public void testParseInteger() throws Exception {
assertEquals( 0, TextFormat.parseInt32( "0"));
assertEquals( 1, TextFormat.parseInt32( "1"));
assertEquals( -1, TextFormat.parseInt32( "-1"));
assertEquals( 12345, TextFormat.parseInt32( "12345"));
assertEquals( -12345, TextFormat.parseInt32( "-12345"));
assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
assertEquals( 0, TextFormat.parseUInt32( "0"));
assertEquals( 1, TextFormat.parseUInt32( "1"));
assertEquals( 12345, TextFormat.parseUInt32( "12345"));
assertEquals( 2147483647, TextFormat.parseUInt32("2147483647"));
assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
assertEquals( 0L, TextFormat.parseInt64( "0"));
assertEquals( 1L, TextFormat.parseInt64( "1"));
assertEquals( -1L, TextFormat.parseInt64( "-1"));
assertEquals( 12345L, TextFormat.parseInt64( "12345"));
assertEquals( -12345L, TextFormat.parseInt64( "-12345"));
assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
assertEquals(9223372036854775807L,
TextFormat.parseInt64("9223372036854775807"));
assertEquals(-9223372036854775808L,
TextFormat.parseInt64("-9223372036854775808"));
assertEquals( 0L, TextFormat.parseUInt64( "0"));
assertEquals( 1L, TextFormat.parseUInt64( "1"));
assertEquals( 12345L, TextFormat.parseUInt64( "12345"));
assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
assertEquals(9223372036854775807L,
TextFormat.parseUInt64("9223372036854775807"));
assertEquals(-9223372036854775808L,
TextFormat.parseUInt64("9223372036854775808"));
assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
// Hex
assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
assertEquals(0x7fffffffffffffffL,
TextFormat.parseInt64("0x7fffffffffffffff"));
// Octal
assertEquals(01234567, TextFormat.parseInt32("01234567"));
// Out-of-range
try {
TextFormat.parseInt32("2147483648");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseInt32("-2147483649");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseUInt32("4294967296");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseUInt32("-1");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseInt64("9223372036854775808");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseInt64("-9223372036854775809");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseUInt64("18446744073709551616");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
try {
TextFormat.parseUInt64("-1");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
// Not a number.
try {
TextFormat.parseInt32("abcd");
fail("Should have thrown an exception.");
} catch (NumberFormatException e) {
// success
}
}
public void testParseString() throws Exception {
final String zh = "\u9999\u6e2f\u4e0a\u6d77\ud84f\udf80\u8c50\u9280\u884c";
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("optional_string: \"" + zh + "\"", builder);
assertEquals(zh, builder.getOptionalString());
}
public void testParseLongString() throws Exception {
String longText =
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890" +
"123456789012345678901234567890123456789012345678901234567890";
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("optional_string: \"" + longText + "\"", builder);
assertEquals(longText, builder.getOptionalString());
}
public void testParseBoolean() throws Exception {
String goodText =
"repeated_bool: t repeated_bool : 0\n" +
"repeated_bool :f repeated_bool:1";
String goodTextCanonical =
"repeated_bool: true\n" +
"repeated_bool: false\n" +
"repeated_bool: false\n" +
"repeated_bool: true\n";
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(goodText, builder);
assertEquals(goodTextCanonical, builder.build().toString());
try {
TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
TextFormat.merge("optional_bool:2", badBuilder);
fail("Should have thrown an exception.");
} catch (TextFormat.ParseException e) {
// success
}
try {
TestAllTypes.Builder badBuilder = TestAllTypes.newBuilder();
TextFormat.merge("optional_bool: foo", badBuilder);
fail("Should have thrown an exception.");
} catch (TextFormat.ParseException e) {
// success
}
}
public void testParseAdjacentStringLiterals() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge("optional_string: \"foo\" 'corge' \"grault\"", builder);
assertEquals("foocorgegrault", builder.getOptionalString());
}
public void testPrintFieldValue() throws Exception {
assertPrintFieldValue("\"Hello\"", "Hello", "repeated_string");
assertPrintFieldValue("123.0", 123f, "repeated_float");
assertPrintFieldValue("123.0", 123d, "repeated_double");
assertPrintFieldValue("123", 123, "repeated_int32");
assertPrintFieldValue("123", 123L, "repeated_int64");
assertPrintFieldValue("true", true, "repeated_bool");
assertPrintFieldValue("4294967295", 0xFFFFFFFF, "repeated_uint32");
assertPrintFieldValue("18446744073709551615", 0xFFFFFFFFFFFFFFFFL,
"repeated_uint64");
assertPrintFieldValue("\"\\001\\002\\003\"",
ByteString.copyFrom(new byte[] {1, 2, 3}), "repeated_bytes");
}
private void assertPrintFieldValue(String expect, Object value,
String fieldName) throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
StringBuilder sb = new StringBuilder();
TextFormat.printFieldValue(
TestAllTypes.getDescriptor().findFieldByName(fieldName),
value, sb);
assertEquals(expect, sb.toString());
}
public void testShortDebugString() {
assertEquals("optional_nested_message { bb: 42 } repeated_int32: 1"
+ " repeated_uint32: 2",
TextFormat.shortDebugString(TestAllTypes.newBuilder()
.addRepeatedInt32(1)
.addRepeatedUint32(2)
.setOptionalNestedMessage(
NestedMessage.newBuilder().setBb(42).build())
.build()));
}
public void testShortDebugString_unknown() {
assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+ " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
+ " 0xabcdef1234567890",
TextFormat.shortDebugString(makeUnknownFieldSet()));
}
public void testPrintToUnicodeString() {
assertEquals(
"optional_string: \"abc\u3042efg\"\n" +
"optional_bytes: \"\\343\\201\\202\"\n" +
"repeated_string: \"\u3093XYZ\"\n",
TextFormat.printToUnicodeString(TestAllTypes.newBuilder()
.setOptionalString("abc\u3042efg")
.setOptionalBytes(bytes(0xe3, 0x81, 0x82))
.addRepeatedString("\u3093XYZ")
.build()));
}
public void testPrintToUnicodeString_unknown() {
assertEquals(
"1: \"\\343\\201\\202\"\n",
TextFormat.printToUnicodeString(UnknownFieldSet.newBuilder()
.addField(1,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(bytes(0xe3, 0x81, 0x82)).build())
.build()));
}
}

View File

@ -0,0 +1,437 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.Map;
/**
* Tests related to unknown field handling.
*
* @author kenton@google.com (Kenton Varda)
*/
public class UnknownFieldSetTest extends TestCase {
public void setUp() throws Exception {
descriptor = TestAllTypes.getDescriptor();
allFields = TestUtil.getAllSet();
allFieldsData = allFields.toByteString();
emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
unknownFields = emptyMessage.getUnknownFields();
}
UnknownFieldSet.Field getField(String name) {
Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
assertNotNull(field);
return unknownFields.getField(field.getNumber());
}
// Constructs a protocol buffer which contains fields with all the same
// numbers as allFieldsData except that each field is some other wire
// type.
ByteString getBizarroData() throws Exception {
UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
UnknownFieldSet.Field varintField =
UnknownFieldSet.Field.newBuilder().addVarint(1).build();
UnknownFieldSet.Field fixed32Field =
UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
unknownFields.asMap().entrySet()) {
if (entry.getValue().getVarintList().isEmpty()) {
// Original field is not a varint, so use a varint.
bizarroFields.addField(entry.getKey(), varintField);
} else {
// Original field *is* a varint, so use something else.
bizarroFields.addField(entry.getKey(), fixed32Field);
}
}
return bizarroFields.build().toByteString();
}
Descriptors.Descriptor descriptor;
TestAllTypes allFields;
ByteString allFieldsData;
// An empty message that has been parsed from allFieldsData. So, it has
// unknown fields of every type.
TestEmptyMessage emptyMessage;
UnknownFieldSet unknownFields;
// =================================================================
public void testVarint() throws Exception {
UnknownFieldSet.Field field = getField("optional_int32");
assertEquals(1, field.getVarintList().size());
assertEquals(allFields.getOptionalInt32(),
(long) field.getVarintList().get(0));
}
public void testFixed32() throws Exception {
UnknownFieldSet.Field field = getField("optional_fixed32");
assertEquals(1, field.getFixed32List().size());
assertEquals(allFields.getOptionalFixed32(),
(int) field.getFixed32List().get(0));
}
public void testFixed64() throws Exception {
UnknownFieldSet.Field field = getField("optional_fixed64");
assertEquals(1, field.getFixed64List().size());
assertEquals(allFields.getOptionalFixed64(),
(long) field.getFixed64List().get(0));
}
public void testLengthDelimited() throws Exception {
UnknownFieldSet.Field field = getField("optional_bytes");
assertEquals(1, field.getLengthDelimitedList().size());
assertEquals(allFields.getOptionalBytes(),
field.getLengthDelimitedList().get(0));
}
public void testGroup() throws Exception {
Descriptors.FieldDescriptor nestedFieldDescriptor =
TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
assertNotNull(nestedFieldDescriptor);
UnknownFieldSet.Field field = getField("optionalgroup");
assertEquals(1, field.getGroupList().size());
UnknownFieldSet group = field.getGroupList().get(0);
assertEquals(1, group.asMap().size());
assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
UnknownFieldSet.Field nestedField =
group.getField(nestedFieldDescriptor.getNumber());
assertEquals(1, nestedField.getVarintList().size());
assertEquals(allFields.getOptionalGroup().getA(),
(long) nestedField.getVarintList().get(0));
}
public void testSerialize() throws Exception {
// Check that serializing the UnknownFieldSet produces the original data
// again.
ByteString data = emptyMessage.toByteString();
assertEquals(allFieldsData, data);
}
public void testCopyFrom() throws Exception {
TestEmptyMessage message =
TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
assertEquals(emptyMessage.toString(), message.toString());
}
public void testMergeFrom() throws Exception {
TestEmptyMessage source =
TestEmptyMessage.newBuilder()
.setUnknownFields(
UnknownFieldSet.newBuilder()
.addField(2,
UnknownFieldSet.Field.newBuilder()
.addVarint(2).build())
.addField(3,
UnknownFieldSet.Field.newBuilder()
.addVarint(4).build())
.build())
.build();
TestEmptyMessage destination =
TestEmptyMessage.newBuilder()
.setUnknownFields(
UnknownFieldSet.newBuilder()
.addField(1,
UnknownFieldSet.Field.newBuilder()
.addVarint(1).build())
.addField(3,
UnknownFieldSet.Field.newBuilder()
.addVarint(3).build())
.build())
.mergeFrom(source)
.build();
assertEquals(
"1: 1\n" +
"2: 2\n" +
"3: 3\n" +
"3: 4\n",
destination.toString());
}
public void testClear() throws Exception {
UnknownFieldSet fields =
UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
assertTrue(fields.asMap().isEmpty());
}
public void testClearMessage() throws Exception {
TestEmptyMessage message =
TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
assertEquals(0, message.getSerializedSize());
}
public void testParseKnownAndUnknown() throws Exception {
// Test mixing known and unknown fields when parsing.
UnknownFieldSet fields =
UnknownFieldSet.newBuilder(unknownFields)
.addField(123456,
UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
.build();
ByteString data = fields.toByteString();
TestAllTypes destination = TestAllTypes.parseFrom(data);
TestUtil.assertAllFieldsSet(destination);
assertEquals(1, destination.getUnknownFields().asMap().size());
UnknownFieldSet.Field field =
destination.getUnknownFields().getField(123456);
assertEquals(1, field.getVarintList().size());
assertEquals(654321, (long) field.getVarintList().get(0));
}
public void testWrongTypeTreatedAsUnknown() throws Exception {
// Test that fields of the wrong wire type are treated like unknown fields
// when parsing.
ByteString bizarroData = getBizarroData();
TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
// All fields should have been interpreted as unknown, so the debug strings
// should be the same.
assertEquals(emptyMessage.toString(), allTypesMessage.toString());
}
public void testUnknownExtensions() throws Exception {
// Make sure fields are properly parsed to the UnknownFieldSet even when
// they are declared as extension numbers.
TestEmptyMessageWithExtensions message =
TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
assertEquals(unknownFields.asMap().size(),
message.getUnknownFields().asMap().size());
assertEquals(allFieldsData, message.toByteString());
}
public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
// Test that fields of the wrong wire type are treated like unknown fields
// when parsing extensions.
ByteString bizarroData = getBizarroData();
TestAllExtensions allExtensionsMessage =
TestAllExtensions.parseFrom(bizarroData);
TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
// All fields should have been interpreted as unknown, so the debug strings
// should be the same.
assertEquals(emptyMessage.toString(),
allExtensionsMessage.toString());
}
public void testParseUnknownEnumValue() throws Exception {
Descriptors.FieldDescriptor singularField =
TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
Descriptors.FieldDescriptor repeatedField =
TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
assertNotNull(singularField);
assertNotNull(repeatedField);
ByteString data =
UnknownFieldSet.newBuilder()
.addField(singularField.getNumber(),
UnknownFieldSet.Field.newBuilder()
.addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
.addVarint(5) // not valid
.build())
.addField(repeatedField.getNumber(),
UnknownFieldSet.Field.newBuilder()
.addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
.addVarint(4) // not valid
.addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
.addVarint(6) // not valid
.build())
.build()
.toByteString();
{
TestAllTypes message = TestAllTypes.parseFrom(data);
assertEquals(TestAllTypes.NestedEnum.BAR,
message.getOptionalNestedEnum());
assertEquals(
Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
message.getRepeatedNestedEnumList());
assertEquals(Arrays.asList(5L),
message.getUnknownFields()
.getField(singularField.getNumber())
.getVarintList());
assertEquals(Arrays.asList(4L, 6L),
message.getUnknownFields()
.getField(repeatedField.getNumber())
.getVarintList());
}
{
TestAllExtensions message =
TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
assertEquals(TestAllTypes.NestedEnum.BAR,
message.getExtension(UnittestProto.optionalNestedEnumExtension));
assertEquals(
Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
message.getExtension(UnittestProto.repeatedNestedEnumExtension));
assertEquals(Arrays.asList(5L),
message.getUnknownFields()
.getField(singularField.getNumber())
.getVarintList());
assertEquals(Arrays.asList(4L, 6L),
message.getUnknownFields()
.getField(repeatedField.getNumber())
.getVarintList());
}
}
public void testLargeVarint() throws Exception {
ByteString data =
UnknownFieldSet.newBuilder()
.addField(1,
UnknownFieldSet.Field.newBuilder()
.addVarint(0x7FFFFFFFFFFFFFFFL)
.build())
.build()
.toByteString();
UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
UnknownFieldSet.Field field = parsed.getField(1);
assertEquals(1, field.getVarintList().size());
assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
}
public void testEqualsAndHashCode() {
UnknownFieldSet.Field fixed32Field =
UnknownFieldSet.Field.newBuilder()
.addFixed32(1)
.build();
UnknownFieldSet.Field fixed64Field =
UnknownFieldSet.Field.newBuilder()
.addFixed64(1)
.build();
UnknownFieldSet.Field varIntField =
UnknownFieldSet.Field.newBuilder()
.addVarint(1)
.build();
UnknownFieldSet.Field lengthDelimitedField =
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(ByteString.EMPTY)
.build();
UnknownFieldSet.Field groupField =
UnknownFieldSet.Field.newBuilder()
.addGroup(unknownFields)
.build();
UnknownFieldSet a =
UnknownFieldSet.newBuilder()
.addField(1, fixed32Field)
.build();
UnknownFieldSet b =
UnknownFieldSet.newBuilder()
.addField(1, fixed64Field)
.build();
UnknownFieldSet c =
UnknownFieldSet.newBuilder()
.addField(1, varIntField)
.build();
UnknownFieldSet d =
UnknownFieldSet.newBuilder()
.addField(1, lengthDelimitedField)
.build();
UnknownFieldSet e =
UnknownFieldSet.newBuilder()
.addField(1, groupField)
.build();
checkEqualsIsConsistent(a);
checkEqualsIsConsistent(b);
checkEqualsIsConsistent(c);
checkEqualsIsConsistent(d);
checkEqualsIsConsistent(e);
checkNotEqual(a, b);
checkNotEqual(a, c);
checkNotEqual(a, d);
checkNotEqual(a, e);
checkNotEqual(b, c);
checkNotEqual(b, d);
checkNotEqual(b, e);
checkNotEqual(c, d);
checkNotEqual(c, e);
checkNotEqual(d, e);
}
/**
* Asserts that the given field sets are not equal and have different
* hash codes.
*
* @warning It's valid for non-equal objects to have the same hash code, so
* this test is stricter than it needs to be. However, this should happen
* relatively rarely.
*/
private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
String equalsError = String.format("%s should not be equal to %s", s1, s2);
assertFalse(equalsError, s1.equals(s2));
assertFalse(equalsError, s2.equals(s1));
assertFalse(
String.format("%s should have a different hash code from %s", s1, s2),
s1.hashCode() == s2.hashCode());
}
/**
* Asserts that the given field sets are equal and have identical hash codes.
*/
private void checkEqualsIsConsistent(UnknownFieldSet set) {
// Object should be equal to itself.
assertEquals(set, set);
// Object should be equal to a copy of itself.
UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
assertEquals(set, copy);
assertEquals(copy, set);
assertEquals(set.hashCode(), copy.hashCode());
}
}

View File

@ -0,0 +1,152 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
import java.util.Iterator;
import java.util.ListIterator;
/**
* Tests for {@link UnmodifiableLazyStringList}.
*
* @author jonp@google.com (Jon Perlow)
*/
public class UnmodifiableLazyStringListTest extends TestCase {
private static String STRING_A = "A";
private static String STRING_B = "B";
private static String STRING_C = "C";
private static ByteString BYTE_STRING_A = ByteString.copyFromUtf8("A");
private static ByteString BYTE_STRING_B = ByteString.copyFromUtf8("B");
private static ByteString BYTE_STRING_C = ByteString.copyFromUtf8("C");
public void testReadOnlyMethods() {
LazyStringArrayList rawList = createSampleList();
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
assertEquals(3, list.size());
assertSame(STRING_A, list.get(0));
assertSame(STRING_B, list.get(1));
assertSame(STRING_C, list.get(2));
assertEquals(BYTE_STRING_A, list.getByteString(0));
assertEquals(BYTE_STRING_B, list.getByteString(1));
assertEquals(BYTE_STRING_C, list.getByteString(2));
}
public void testModifyMethods() {
LazyStringArrayList rawList = createSampleList();
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
try {
list.remove(0);
fail();
} catch (UnsupportedOperationException e) {
// expected
}
assertEquals(3, list.size());
try {
list.add(STRING_B);
fail();
} catch (UnsupportedOperationException e) {
// expected
}
assertEquals(3, list.size());
try {
list.set(1, STRING_B);
fail();
} catch (UnsupportedOperationException e) {
// expected
}
}
public void testIterator() {
LazyStringArrayList rawList = createSampleList();
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
Iterator<String> iter = list.iterator();
int count = 0;
while (iter.hasNext()) {
iter.next();
count++;
try {
iter.remove();
fail();
} catch (UnsupportedOperationException e) {
// expected
}
}
assertEquals(3, count);
}
public void testListIterator() {
LazyStringArrayList rawList = createSampleList();
UnmodifiableLazyStringList list = new UnmodifiableLazyStringList(rawList);
ListIterator<String> iter = list.listIterator();
int count = 0;
while (iter.hasNext()) {
iter.next();
count++;
try {
iter.remove();
fail();
} catch (UnsupportedOperationException e) {
// expected
}
try {
iter.set("bar");
fail();
} catch (UnsupportedOperationException e) {
// expected
}
try {
iter.add("bar");
fail();
} catch (UnsupportedOperationException e) {
// expected
}
}
assertEquals(3, count);
}
private LazyStringArrayList createSampleList() {
LazyStringArrayList rawList = new LazyStringArrayList();
rawList.add(STRING_A);
rawList.add(STRING_B);
rawList.add(STRING_C);
return rawList;
}
}

View File

@ -0,0 +1,580 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.List;
import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestFieldOrderings;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestMset.TestMessageSet;
import protobuf_unittest.UnittestMset.RawMessageSet;
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
/**
* Tests related to parsing and serialization.
*
* @author kenton@google.com (Kenton Varda)
*/
public class WireFormatTest extends TestCase {
public void testSerialization() throws Exception {
TestAllTypes message = TestUtil.getAllSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
}
public void testSerializationPacked() throws Exception {
TestPackedTypes message = TestUtil.getPackedSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
TestUtil.assertPackedFieldsSet(message2);
}
public void testSerializeExtensions() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllExtensions then parse it as TestAllTypes
// it should work.
TestAllExtensions message = TestUtil.getAllExtensionsSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
}
public void testSerializePackedExtensions() throws Exception {
// TestPackedTypes and TestPackedExtensions should have compatible wire
// formats; check that they serialize to the same string.
TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
ByteString rawBytes = message.toByteString();
TestPackedTypes message2 = TestUtil.getPackedSet();
ByteString rawBytes2 = message2.toByteString();
assertEquals(rawBytes, rawBytes2);
}
public void testSerializationPackedWithoutGetSerializedSize()
throws Exception {
// Write directly to an OutputStream, without invoking getSerializedSize()
// This used to be a bug where the size of a packed field was incorrect,
// since getSerializedSize() was never invoked.
TestPackedTypes message = TestUtil.getPackedSet();
// Directly construct a CodedOutputStream around the actual OutputStream,
// in case writeTo(OutputStream output) invokes getSerializedSize();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream);
message.writeTo(codedOutput);
codedOutput.flush();
TestPackedTypes message2 = TestPackedTypes.parseFrom(
outputStream.toByteArray());
TestUtil.assertPackedFieldsSet(message2);
}
public void testSerializeExtensionsLite() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllExtensions then parse it as TestAllTypes
// it should work.
TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
ByteString rawBytes = message.toByteString();
assertEquals(rawBytes.size(), message.getSerializedSize());
TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
TestUtil.assertAllFieldsSet(message2);
}
public void testSerializePackedExtensionsLite() throws Exception {
// TestPackedTypes and TestPackedExtensions should have compatible wire
// formats; check that they serialize to the same string.
TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
TestPackedTypes message2 = TestUtil.getPackedSet();
ByteString rawBytes2 = message2.toByteString();
assertEquals(rawBytes, rawBytes2);
}
public void testParseExtensions() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllTypes then parse it as TestAllExtensions
// it should work.
TestAllTypes message = TestUtil.getAllSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistry registry = TestUtil.getExtensionRegistry();
TestAllExtensions message2 =
TestAllExtensions.parseFrom(rawBytes, registry);
TestUtil.assertAllExtensionsSet(message2);
}
public void testParsePackedExtensions() throws Exception {
// Ensure that packed extensions can be properly parsed.
TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistry registry = TestUtil.getExtensionRegistry();
TestPackedExtensions message2 =
TestPackedExtensions.parseFrom(rawBytes, registry);
TestUtil.assertPackedExtensionsSet(message2);
}
public void testParseExtensionsLite() throws Exception {
// TestAllTypes and TestAllExtensions should have compatible wire formats,
// so if we serialize a TestAllTypes then parse it as TestAllExtensions
// it should work.
TestAllTypes message = TestUtil.getAllSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
TestAllExtensionsLite message2 =
TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
TestUtil.assertAllExtensionsSet(message2);
// Try again using a full extension registry.
ExtensionRegistry registry = TestUtil.getExtensionRegistry();
TestAllExtensionsLite message3 =
TestAllExtensionsLite.parseFrom(rawBytes, registry);
TestUtil.assertAllExtensionsSet(message3);
}
public void testParsePackedExtensionsLite() throws Exception {
// Ensure that packed extensions can be properly parsed.
TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
ByteString rawBytes = message.toByteString();
ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
TestPackedExtensionsLite message2 =
TestPackedExtensionsLite.parseFrom(rawBytes, registry);
TestUtil.assertPackedExtensionsSet(message2);
}
public void testExtensionsSerializedSize() throws Exception {
assertEquals(TestUtil.getAllSet().getSerializedSize(),
TestUtil.getAllExtensionsSet().getSerializedSize());
}
public void testSerializeDelimited() throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
TestUtil.getAllSet().writeDelimitedTo(output);
output.write(12);
TestUtil.getPackedSet().writeDelimitedTo(output);
output.write(34);
ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
assertEquals(12, input.read());
TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
assertEquals(34, input.read());
assertEquals(-1, input.read());
// We're at EOF, so parsing again should return null.
assertTrue(TestAllTypes.parseDelimitedFrom(input) == null);
}
private void assertFieldsInOrder(ByteString data) throws Exception {
CodedInputStream input = data.newCodedInput();
int previousTag = 0;
while (true) {
int tag = input.readTag();
if (tag == 0) {
break;
}
assertTrue(tag > previousTag);
previousTag = tag;
input.skipField(tag);
}
}
public void testInterleavedFieldsAndExtensions() throws Exception {
// Tests that fields are written in order even when extension ranges
// are interleaved with field numbers.
ByteString data =
TestFieldOrderings.newBuilder()
.setMyInt(1)
.setMyString("foo")
.setMyFloat(1.0F)
.setExtension(UnittestProto.myExtensionInt, 23)
.setExtension(UnittestProto.myExtensionString, "bar")
.build().toByteString();
assertFieldsInOrder(data);
Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
ByteString dynamic_data =
DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
.setField(descriptor.findFieldByName("my_int"), 1L)
.setField(descriptor.findFieldByName("my_string"), "foo")
.setField(descriptor.findFieldByName("my_float"), 1.0F)
.setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
.setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
.build().toByteString();
assertFieldsInOrder(dynamic_data);
}
private ExtensionRegistry getTestFieldOrderingsRegistry() {
ExtensionRegistry result = ExtensionRegistry.newInstance();
result.add(UnittestProto.myExtensionInt);
result.add(UnittestProto.myExtensionString);
return result;
}
public void testParseMultipleExtensionRanges() throws Exception {
// Make sure we can parse a message that contains multiple extensions
// ranges.
TestFieldOrderings source =
TestFieldOrderings.newBuilder()
.setMyInt(1)
.setMyString("foo")
.setMyFloat(1.0F)
.setExtension(UnittestProto.myExtensionInt, 23)
.setExtension(UnittestProto.myExtensionString, "bar")
.build();
TestFieldOrderings dest =
TestFieldOrderings.parseFrom(source.toByteString(),
getTestFieldOrderingsRegistry());
assertEquals(source, dest);
}
public void testParseMultipleExtensionRangesDynamic() throws Exception {
// Same as above except with DynamicMessage.
Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
DynamicMessage source =
DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
.setField(descriptor.findFieldByName("my_int"), 1L)
.setField(descriptor.findFieldByName("my_string"), "foo")
.setField(descriptor.findFieldByName("my_float"), 1.0F)
.setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
.setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
.build();
DynamicMessage dest =
DynamicMessage.parseFrom(descriptor, source.toByteString(),
getTestFieldOrderingsRegistry());
assertEquals(source, dest);
}
private static final int UNKNOWN_TYPE_ID = 1550055;
private static final int TYPE_ID_1 =
TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
private static final int TYPE_ID_2 =
TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
public void testSerializeMessageSetEagerly() throws Exception {
testSerializeMessageSetWithFlag(true);
}
public void testSerializeMessageSetNotEagerly() throws Exception {
testSerializeMessageSetWithFlag(false);
}
private void testSerializeMessageSetWithFlag(boolean eagerParsing)
throws Exception {
ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
// Set up a TestMessageSet with two known messages and an unknown one.
TestMessageSet messageSet =
TestMessageSet.newBuilder()
.setExtension(
TestMessageSetExtension1.messageSetExtension,
TestMessageSetExtension1.newBuilder().setI(123).build())
.setExtension(
TestMessageSetExtension2.messageSetExtension,
TestMessageSetExtension2.newBuilder().setStr("foo").build())
.setUnknownFields(
UnknownFieldSet.newBuilder()
.addField(UNKNOWN_TYPE_ID,
UnknownFieldSet.Field.newBuilder()
.addLengthDelimited(ByteString.copyFromUtf8("bar"))
.build())
.build())
.build();
ByteString data = messageSet.toByteString();
// Parse back using RawMessageSet and check the contents.
RawMessageSet raw = RawMessageSet.parseFrom(data);
assertTrue(raw.getUnknownFields().asMap().isEmpty());
assertEquals(3, raw.getItemCount());
assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
TestMessageSetExtension1 message1 =
TestMessageSetExtension1.parseFrom(
raw.getItem(0).getMessage().toByteArray());
assertEquals(123, message1.getI());
TestMessageSetExtension2 message2 =
TestMessageSetExtension2.parseFrom(
raw.getItem(1).getMessage().toByteArray());
assertEquals("foo", message2.getStr());
assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
}
public void testParseMessageSetEagerly() throws Exception {
testParseMessageSetWithFlag(true);
}
public void testParseMessageSetNotEagerly()throws Exception {
testParseMessageSetWithFlag(false);
}
private void testParseMessageSetWithFlag(boolean eagerParsing)
throws Exception {
ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
// Set up a RawMessageSet with two known messages and an unknown one.
RawMessageSet raw =
RawMessageSet.newBuilder()
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(TYPE_ID_1)
.setMessage(
TestMessageSetExtension1.newBuilder()
.setI(123)
.build().toByteString())
.build())
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(TYPE_ID_2)
.setMessage(
TestMessageSetExtension2.newBuilder()
.setStr("foo")
.build().toByteString())
.build())
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(UNKNOWN_TYPE_ID)
.setMessage(ByteString.copyFromUtf8("bar"))
.build())
.build();
ByteString data = raw.toByteString();
// Parse as a TestMessageSet and check the contents.
TestMessageSet messageSet =
TestMessageSet.parseFrom(data, extensionRegistry);
assertEquals(123, messageSet.getExtension(
TestMessageSetExtension1.messageSetExtension).getI());
assertEquals("foo", messageSet.getExtension(
TestMessageSetExtension2.messageSetExtension).getStr());
// Check for unknown field with type LENGTH_DELIMITED,
// number UNKNOWN_TYPE_ID, and contents "bar".
UnknownFieldSet unknownFields = messageSet.getUnknownFields();
assertEquals(1, unknownFields.asMap().size());
assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
assertEquals(1, field.getLengthDelimitedList().size());
assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
}
public void testParseMessageSetExtensionEagerly() throws Exception {
testParseMessageSetExtensionWithFlag(true);
}
public void testParseMessageSetExtensionNotEagerly() throws Exception {
testParseMessageSetExtensionWithFlag(false);
}
private void testParseMessageSetExtensionWithFlag(boolean eagerParsing)
throws Exception {
ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
// Set up a RawMessageSet with a known messages.
int TYPE_ID_1 =
TestMessageSetExtension1
.getDescriptor().getExtensions().get(0).getNumber();
RawMessageSet raw =
RawMessageSet.newBuilder()
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(TYPE_ID_1)
.setMessage(
TestMessageSetExtension1.newBuilder()
.setI(123)
.build().toByteString())
.build())
.build();
ByteString data = raw.toByteString();
// Parse as a TestMessageSet and check the contents.
TestMessageSet messageSet =
TestMessageSet.parseFrom(data, extensionRegistry);
assertEquals(123, messageSet.getExtension(
TestMessageSetExtension1.messageSetExtension).getI());
}
public void testMergeLazyMessageSetExtensionEagerly() throws Exception {
testMergeLazyMessageSetExtensionWithFlag(true);
}
public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception {
testMergeLazyMessageSetExtensionWithFlag(false);
}
private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)
throws Exception {
ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
// Set up a RawMessageSet with a known messages.
int TYPE_ID_1 =
TestMessageSetExtension1
.getDescriptor().getExtensions().get(0).getNumber();
RawMessageSet raw =
RawMessageSet.newBuilder()
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(TYPE_ID_1)
.setMessage(
TestMessageSetExtension1.newBuilder()
.setI(123)
.build().toByteString())
.build())
.build();
ByteString data = raw.toByteString();
// Parse as a TestMessageSet and store value into lazy field
TestMessageSet messageSet =
TestMessageSet.parseFrom(data, extensionRegistry);
// Merge lazy field check the contents.
messageSet =
messageSet.toBuilder().mergeFrom(data, extensionRegistry).build();
assertEquals(123, messageSet.getExtension(
TestMessageSetExtension1.messageSetExtension).getI());
}
public void testMergeMessageSetExtensionEagerly() throws Exception {
testMergeMessageSetExtensionWithFlag(true);
}
public void testMergeMessageSetExtensionNotEagerly() throws Exception {
testMergeMessageSetExtensionWithFlag(false);
}
private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing)
throws Exception {
ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing);
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
// Set up a RawMessageSet with a known messages.
int TYPE_ID_1 =
TestMessageSetExtension1
.getDescriptor().getExtensions().get(0).getNumber();
RawMessageSet raw =
RawMessageSet.newBuilder()
.addItem(
RawMessageSet.Item.newBuilder()
.setTypeId(TYPE_ID_1)
.setMessage(
TestMessageSetExtension1.newBuilder()
.setI(123)
.build().toByteString())
.build())
.build();
// Serialize RawMessageSet unnormally (message value before type id)
ByteString.CodedBuilder out = ByteString.newCodedBuilder(
raw.getSerializedSize());
CodedOutputStream output = out.getCodedOutput();
List<RawMessageSet.Item> items = raw.getItemList();
for (int i = 0; i < items.size(); i++) {
RawMessageSet.Item item = items.get(i);
output.writeTag(1, WireFormat.WIRETYPE_START_GROUP);
output.writeBytes(3, item.getMessage());
output.writeInt32(2, item.getTypeId());
output.writeTag(1, WireFormat.WIRETYPE_END_GROUP);
}
ByteString data = out.build();
// Merge bytes into TestMessageSet and check the contents.
TestMessageSet messageSet =
TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build();
assertEquals(123, messageSet.getExtension(
TestMessageSetExtension1.messageSetExtension).getI());
}
}

View File

@ -0,0 +1,71 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
//
// A proto file which tests the java_multiple_files option.
// Some generic_services option(s) added automatically.
// See: http://go/proto2-generic-services-default
option java_generic_services = true; // auto-added
import "google/protobuf/unittest.proto";
package protobuf_unittest;
option java_multiple_files = true;
option java_outer_classname = "MultipleFilesTestProto";
message MessageWithNoOuter {
message NestedMessage {
optional int32 i = 1;
}
enum NestedEnum {
BAZ = 3;
}
optional NestedMessage nested = 1;
repeated TestAllTypes foreign = 2;
optional NestedEnum nested_enum = 3;
optional EnumWithNoOuter foreign_enum = 4;
}
enum EnumWithNoOuter {
FOO = 1;
BAR = 2;
}
service ServiceWithNoOuter {
rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
}
extend TestAllExtensions {
optional int32 extension_with_outer = 1234567;
}

View File

@ -0,0 +1,53 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: jonp@google.com (Jon Perlow)
//
package protobuf_unittest;
option java_multiple_files = true;
option java_outer_classname = "NestedBuilders";
message Vehicle {
optional Engine engine = 1;
repeated Wheel wheel = 2;
}
message Engine {
optional int32 cylinder = 1;
optional int32 liters = 2;
}
message Wheel {
optional int32 radius = 1;
optional int32 width = 2;
}

View File

@ -0,0 +1,45 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: Darick Tong (darick@google.com)
//
// A proto file with nested extensions. Note that this must be defined in
// a separate file to properly test the initialization of the outer class.
import "com/google/protobuf/non_nested_extension.proto";
package protobuf_unittest;
message MyNestedExtension {
extend MessageToBeExtended {
optional MessageToBeExtended recursiveExtension = 2;
}
}

View File

@ -0,0 +1,48 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: Darick Tong (darick@google.com)
//
// A proto file with nested extensions for a MessageLite messages. Note that
// this must be defined in a separate file to properly test the initialization
// of the outer class.
package protobuf_unittest;
option optimize_for = LITE_RUNTIME;
import "com/google/protobuf/non_nested_extension_lite.proto";
message MyNestedExtensionLite {
extend MessageLiteToBeExtended {
optional MessageLiteToBeExtended recursiveExtensionLite = 3;
}
}

View File

@ -0,0 +1,48 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: Darick Tong (darick@google.com)
//
// A proto file with extensions.
package protobuf_unittest;
message MessageToBeExtended {
extensions 1 to max;
}
message MyNonNestedExtension {
}
extend MessageToBeExtended {
optional MyNonNestedExtension nonNestedExtension = 1;
}

View File

@ -0,0 +1,50 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: Darick Tong (darick@google.com)
//
// A proto file with extensions for a MessageLite messages.
package protobuf_unittest;
option optimize_for = LITE_RUNTIME;
message MessageLiteToBeExtended {
extensions 1 to max;
}
message MyNonNestedExtensionLite {
}
extend MessageLiteToBeExtended {
optional MyNonNestedExtensionLite nonNestedExtensionLite = 1;
}

View File

@ -0,0 +1,108 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: jonp@google.com (Jon Perlow)
// This file tests that various identifiers work as field and type names even
// though the same identifiers are used internally by the java code generator.
// Some generic_services option(s) added automatically.
// See: http://go/proto2-generic-services-default
option java_generic_services = true; // auto-added
package io_protocol_tests;
option java_package = "com.google.protobuf";
option java_outer_classname = "TestBadIdentifiersProto";
message TestMessage {
}
message Descriptor {
option no_standard_descriptor_accessor = true;
optional string descriptor = 1;
message NestedDescriptor {
option no_standard_descriptor_accessor = true;
optional string descriptor = 1;
}
optional NestedDescriptor nested_descriptor = 2;
}
message Parser {
enum ParserEnum {
PARSER = 1;
}
optional ParserEnum parser = 1;
}
message Deprecated {
enum TestEnum {
FOO = 1;
}
optional int32 field1 = 1 [deprecated=true];
optional TestEnum field2 = 2 [deprecated=true];
optional TestMessage field3 = 3 [deprecated=true];
}
message Override {
optional int32 override = 1;
}
message Object {
optional int32 object = 1;
optional string string_object = 2;
}
message String {
optional string string = 1;
}
message Integer {
optional int32 integer = 1;
}
message Long {
optional int32 long = 1;
}
message Float {
optional float float = 1;
}
message Double {
optional double double = 1;
}
service TestConflictingMethodNames {
rpc Override(TestMessage) returns (TestMessage);
}

444
third_party/protobuf/protobuf.gyp vendored Normal file
View File

@ -0,0 +1,444 @@
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'conditions': [
['use_system_protobuf==0', {
'conditions': [
['OS!="win"', {
'variables': {
'config_h_dir':
'.', # crafted for gcc/linux.
},
}, { # else, OS=="win"
'variables': {
'config_h_dir':
'vsprojects', # crafted for msvc.
},
'target_defaults': {
'msvs_disabled_warnings': [
4018, # signed/unsigned mismatch in comparison
4244, # implicit conversion, possible loss of data
4355, # 'this' used in base member initializer list
4267, # size_t to int truncation
4291, # no matching operator delete for a placement new
],
'defines!': [
'WIN32_LEAN_AND_MEAN', # Protobuf defines this itself.
],
},
}],
['OS=="ios" and "<(GENERATOR)"!="ninja"', {
'variables': {
'ninja_output_dir': 'ninja-protoc',
'ninja_product_dir':
'<(DEPTH)/xcodebuild/<(ninja_output_dir)/<(CONFIGURATION_NAME)',
# Gyp to rerun
're_run_targets': [
'third_party/protobuf/protobuf.gyp',
],
},
'targets': [
{
# On iOS, generating protoc is done via two actions: (1) compiling
# the executable with ninja, and (2) copying the executable into a
# location that is shared with other projects. These actions are
# separated into two targets in order to be able to specify that the
# second action should not run until the first action finishes (since
# the ordering of multiple actions in one target is defined only by
# inputs and outputs, and it's impossible to set correct inputs for
# the ninja build, so setting all the inputs and outputs isn't an
# option). The first target is given here; the second target is the
# normal protoc target under the condition that "OS==iOS".
'target_name': 'compile_protoc',
'type': 'none',
'includes': ['../../build/ios/mac_build.gypi'],
'actions': [
{
'action_name': 'compile protoc',
'inputs': [],
'outputs': [],
'action': [
'<@(ninja_cmd)',
'protoc',
],
'message': 'Generating the C++ protocol buffers compiler',
},
],
},
],
}],
['OS=="android"', {
'targets': [
{
'target_name': 'protobuf_lite_javalib',
'type' : 'none',
'dependencies': [
'protoc#host',
],
'variables': {
'script_descriptors': './protobuf_lite_java_descriptor_proto.py',
'script_pom': './protobuf_lite_java_parse_pom.py',
'protoc': '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
# Variables needed by java.gypi below.
'java_out_dir': '<(PRODUCT_DIR)/java_proto/protobuf_lite_java_descriptor_proto',
'generated_src_dirs': ['<(java_out_dir)'],
'java_in_dir': 'java',
'maven_pom': '<(java_in_dir)/pom.xml',
'javac_includes': ['<!@(<(script_pom) <(maven_pom))'],
'additional_input_paths': [
'<(java_out_dir)/com/google/protobuf/DescriptorProtos.java'
],
},
'actions': [
{
'action_name': 'protobuf_lite_java_gen_descriptor_proto',
'inputs': [
'<(script_descriptors)',
'<(protoc)',
'src/google/protobuf/descriptor.proto',
],
'outputs': [
'<(java_out_dir)/com/google/protobuf/DescriptorProtos.java',
],
'action': [
'<(script_descriptors)',
'<(protoc)',
'<(java_out_dir)',
'src',
'src/google/protobuf/descriptor.proto',
],
'message': 'Generating descriptor protos for Java',
},
],
# Now that we have generated DescriptorProtos.java, build jar.
'includes': ['../../build/java.gypi'],
},
]
}],
],
'targets': [
# The "lite" lib is about 1/7th the size of the heavy lib,
# but it doesn't support some of the more exotic features of
# protobufs, like reflection. To generate C++ code that can link
# against the lite version of the library, add the option line:
#
# option optimize_for = LITE_RUNTIME;
#
# to your .proto file.
{
'target_name': 'protobuf_lite',
'type': '<(component)',
'toolsets': ['host', 'target'],
'includes': [
'protobuf_lite.gypi',
],
# Required for component builds. See http://crbug.com/172800.
'defines': [
'LIBPROTOBUF_EXPORTS',
'PROTOBUF_USE_DLLS',
],
'direct_dependent_settings': {
'defines': [
'PROTOBUF_USE_DLLS',
],
},
},
# This is the full, heavy protobuf lib that's needed for c++ .protos
# that don't specify the LITE_RUNTIME option. The protocol
# compiler itself (protoc) falls into that category.
#
# DO NOT LINK AGAINST THIS TARGET IN CHROME CODE --agl
{
'target_name': 'protobuf_full_do_not_use',
'type': 'static_library',
'toolsets': ['host','target'],
'includes': [
'protobuf_lite.gypi',
],
'sources': [
'src/google/protobuf/descriptor.h',
'src/google/protobuf/descriptor.pb.h',
'src/google/protobuf/descriptor_database.h',
'src/google/protobuf/dynamic_message.h',
'src/google/protobuf/generated_enum_reflection.h',
'src/google/protobuf/generated_message_reflection.h',
'src/google/protobuf/message.h',
'src/google/protobuf/reflection_ops.h',
'src/google/protobuf/service.h',
'src/google/protobuf/text_format.h',
'src/google/protobuf/wire_format.h',
'src/google/protobuf/io/gzip_stream.h',
'src/google/protobuf/io/printer.h',
'src/google/protobuf/io/tokenizer.h',
'src/google/protobuf/io/zero_copy_stream_impl.h',
'src/google/protobuf/compiler/code_generator.h',
'src/google/protobuf/compiler/command_line_interface.h',
'src/google/protobuf/compiler/importer.h',
'src/google/protobuf/compiler/java/java_doc_comment.cc',
'src/google/protobuf/compiler/java/java_doc_comment.h',
'src/google/protobuf/compiler/parser.h',
'src/google/protobuf/stubs/strutil.cc',
'src/google/protobuf/stubs/strutil.h',
'src/google/protobuf/stubs/substitute.cc',
'src/google/protobuf/stubs/substitute.h',
'src/google/protobuf/stubs/stl_util.h',
'src/google/protobuf/stubs/stringprintf.cc',
'src/google/protobuf/stubs/stringprintf.h',
'src/google/protobuf/stubs/structurally_valid.cc',
'src/google/protobuf/stubs/template_util.h',
'src/google/protobuf/stubs/type_traits.h',
'src/google/protobuf/descriptor.cc',
'src/google/protobuf/descriptor.pb.cc',
'src/google/protobuf/descriptor_database.cc',
'src/google/protobuf/dynamic_message.cc',
'src/google/protobuf/extension_set.cc',
'src/google/protobuf/extension_set.h',
'src/google/protobuf/extension_set_heavy.cc',
'src/google/protobuf/generated_message_reflection.cc',
'src/google/protobuf/message.cc',
'src/google/protobuf/reflection_ops.cc',
'src/google/protobuf/service.cc',
'src/google/protobuf/text_format.cc',
'src/google/protobuf/wire_format.cc',
# This file pulls in zlib, but it's not actually used by protoc, so
# instead of compiling zlib for the host, let's just exclude this.
# 'src/src/google/protobuf/io/gzip_stream.cc',
'src/google/protobuf/io/printer.cc',
'src/google/protobuf/io/tokenizer.cc',
'src/google/protobuf/io/zero_copy_stream_impl.cc',
'src/google/protobuf/compiler/importer.cc',
'src/google/protobuf/compiler/parser.cc',
],
},
{
'target_name': 'protoc',
'conditions': [
['OS!="ios" or "<(GENERATOR)"=="ninja"', {
'type': 'executable',
'toolsets': ['host'],
'sources': [
'src/google/protobuf/compiler/code_generator.cc',
'src/google/protobuf/compiler/command_line_interface.cc',
'src/google/protobuf/compiler/plugin.cc',
'src/google/protobuf/compiler/plugin.pb.cc',
'src/google/protobuf/compiler/subprocess.cc',
'src/google/protobuf/compiler/subprocess.h',
'src/google/protobuf/compiler/zip_writer.cc',
'src/google/protobuf/compiler/zip_writer.h',
'src/google/protobuf/compiler/cpp/cpp_enum.cc',
'src/google/protobuf/compiler/cpp/cpp_enum.h',
'src/google/protobuf/compiler/cpp/cpp_enum_field.cc',
'src/google/protobuf/compiler/cpp/cpp_enum_field.h',
'src/google/protobuf/compiler/cpp/cpp_extension.cc',
'src/google/protobuf/compiler/cpp/cpp_extension.h',
'src/google/protobuf/compiler/cpp/cpp_field.cc',
'src/google/protobuf/compiler/cpp/cpp_field.h',
'src/google/protobuf/compiler/cpp/cpp_file.cc',
'src/google/protobuf/compiler/cpp/cpp_file.h',
'src/google/protobuf/compiler/cpp/cpp_generator.cc',
'src/google/protobuf/compiler/cpp/cpp_helpers.cc',
'src/google/protobuf/compiler/cpp/cpp_helpers.h',
'src/google/protobuf/compiler/cpp/cpp_message.cc',
'src/google/protobuf/compiler/cpp/cpp_message.h',
'src/google/protobuf/compiler/cpp/cpp_message_field.cc',
'src/google/protobuf/compiler/cpp/cpp_message_field.h',
'src/google/protobuf/compiler/cpp/cpp_primitive_field.cc',
'src/google/protobuf/compiler/cpp/cpp_primitive_field.h',
'src/google/protobuf/compiler/cpp/cpp_service.cc',
'src/google/protobuf/compiler/cpp/cpp_service.h',
'src/google/protobuf/compiler/cpp/cpp_string_field.cc',
'src/google/protobuf/compiler/cpp/cpp_string_field.h',
'src/google/protobuf/compiler/java/java_enum.cc',
'src/google/protobuf/compiler/java/java_enum.h',
'src/google/protobuf/compiler/java/java_enum_field.cc',
'src/google/protobuf/compiler/java/java_enum_field.h',
'src/google/protobuf/compiler/java/java_extension.cc',
'src/google/protobuf/compiler/java/java_extension.h',
'src/google/protobuf/compiler/java/java_field.cc',
'src/google/protobuf/compiler/java/java_field.h',
'src/google/protobuf/compiler/java/java_file.cc',
'src/google/protobuf/compiler/java/java_file.h',
'src/google/protobuf/compiler/java/java_generator.cc',
'src/google/protobuf/compiler/java/java_helpers.cc',
'src/google/protobuf/compiler/java/java_helpers.h',
'src/google/protobuf/compiler/java/java_message.cc',
'src/google/protobuf/compiler/java/java_message.h',
'src/google/protobuf/compiler/java/java_message_field.cc',
'src/google/protobuf/compiler/java/java_message_field.h',
'src/google/protobuf/compiler/java/java_primitive_field.cc',
'src/google/protobuf/compiler/java/java_primitive_field.h',
'src/google/protobuf/compiler/java/java_service.cc',
'src/google/protobuf/compiler/java/java_service.h',
'src/google/protobuf/compiler/java/java_string_field.cc',
'src/google/protobuf/compiler/java/java_string_field.h',
'src/google/protobuf/compiler/python/python_generator.cc',
'src/google/protobuf/compiler/main.cc',
],
'dependencies': [
'protobuf_full_do_not_use',
],
'include_dirs': [
'<(config_h_dir)',
'src/src',
],
}, { # else, OS=="ios" and "<(GENERATOR)"!="ninja"
'type': 'none',
'dependencies': [
'compile_protoc',
],
'actions': [
{
'action_name': 'copy protoc',
'inputs': [
'<(ninja_product_dir)/protoc',
],
'outputs': [
'<(PRODUCT_DIR)/protoc',
],
'action': [
'cp',
'<(ninja_product_dir)/protoc',
'<(PRODUCT_DIR)/protoc',
],
},
],
}],
],
},
{
# Generate the python module needed by all protoc-generated Python code.
'target_name': 'py_proto',
'type': 'none',
'copies': [
{
'destination': '<(PRODUCT_DIR)/pyproto/google/',
'files': [
# google/ module gets an empty __init__.py.
'__init__.py',
],
},
{
'destination': '<(PRODUCT_DIR)/pyproto/google/protobuf',
'files': [
'python/google/protobuf/__init__.py',
'python/google/protobuf/descriptor.py',
'python/google/protobuf/descriptor_database.py',
'python/google/protobuf/descriptor_pool.py',
'python/google/protobuf/message.py',
'python/google/protobuf/message_factory.py',
'python/google/protobuf/reflection.py',
'python/google/protobuf/service.py',
'python/google/protobuf/service_reflection.py',
'python/google/protobuf/text_format.py',
# TODO(ncarter): protoc's python generator treats
# descriptor.proto specially, but it's not possible to trigger
# the special treatment unless you run protoc from ./src/src
# (the treatment is based on the path to the .proto file
# matching a constant exactly). I'm not sure how to convince
# gyp to execute a rule from a different directory. Until this
# is resolved, use a copy of descriptor_pb2.py that I manually
# generated.
'descriptor_pb2.py',
],
},
{
'destination': '<(PRODUCT_DIR)/pyproto/google/protobuf/internal',
'files': [
'python/google/protobuf/internal/__init__.py',
'python/google/protobuf/internal/api_implementation.py',
'python/google/protobuf/internal/containers.py',
'python/google/protobuf/internal/cpp_message.py',
'python/google/protobuf/internal/decoder.py',
'python/google/protobuf/internal/encoder.py',
'python/google/protobuf/internal/enum_type_wrapper.py',
'python/google/protobuf/internal/generator_test.py',
'python/google/protobuf/internal/message_listener.py',
'python/google/protobuf/internal/python_message.py',
'python/google/protobuf/internal/type_checkers.py',
'python/google/protobuf/internal/wire_format.py',
],
},
],
# # We can't generate a proper descriptor_pb2.py -- see earlier comment.
# 'rules': [
# {
# 'rule_name': 'genproto',
# 'extension': 'proto',
# 'inputs': [
# '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
# ],
# 'variables': {
# # The protoc compiler requires a proto_path argument with the
# # directory containing the .proto file.
# 'rule_input_relpath': 'src/google/protobuf',
# },
# 'outputs': [
# '<(PRODUCT_DIR)/pyproto/google/protobuf/<(RULE_INPUT_ROOT)_pb2.py',
# ],
# 'action': [
# '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)protoc<(EXECUTABLE_SUFFIX)',
# '-I./src',
# '-I.',
# '--python_out=<(PRODUCT_DIR)/pyproto/google/protobuf',
# 'google/protobuf/descriptor.proto',
# ],
# 'message': 'Generating Python code from <(RULE_INPUT_PATH)',
# },
# ],
# 'dependencies': [
# 'protoc#host',
# ],
# 'sources': [
# 'src/google/protobuf/descriptor.proto',
# ],
},
],
}, { # use_system_protobuf==1
'targets': [
{
'target_name': 'protobuf_lite',
'type': 'none',
'direct_dependent_settings': {
'cflags': [
# Use full protobuf, because vanilla protobuf doesn't have
# our custom patch to retain unknown fields in lite mode.
'<!@(pkg-config --cflags protobuf)',
],
'defines': [
'USE_SYSTEM_PROTOBUF',
# This macro must be defined to suppress the use
# of dynamic_cast<>, which requires RTTI.
'GOOGLE_PROTOBUF_NO_RTTI',
'GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER',
],
},
'link_settings': {
# Use full protobuf, because vanilla protobuf doesn't have
# our custom patch to retain unknown fields in lite mode.
'ldflags': [
'<!@(pkg-config --libs-only-L --libs-only-other protobuf)',
],
'libraries': [
'<!@(pkg-config --libs-only-l protobuf)',
],
},
},
{
'target_name': 'protoc',
'type': 'none',
'toolsets': ['host', 'target'],
},
{
'target_name': 'py_proto',
'type': 'none',
},
],
}],
],
}

68
third_party/protobuf/protobuf_lite.gypi vendored Normal file
View File

@ -0,0 +1,68 @@
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
{
'sources': [
'src/google/protobuf/stubs/atomicops.h',
'src/google/protobuf/stubs/atomicops_internals_arm_gcc.h',
'src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h',
'src/google/protobuf/stubs/atomicops_internals_macosx.h',
'src/google/protobuf/stubs/atomicops_internals_mips_gcc.h',
'src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc',
'src/google/protobuf/stubs/atomicops_internals_x86_gcc.h',
'src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc',
'src/google/protobuf/stubs/atomicops_internals_x86_msvc.h',
'src/google/protobuf/stubs/common.h',
'src/google/protobuf/stubs/once.h',
'src/google/protobuf/stubs/platform_macros.h',
'src/google/protobuf/extension_set.h',
'src/google/protobuf/generated_message_util.h',
'src/google/protobuf/message_lite.h',
'src/google/protobuf/repeated_field.h',
'src/google/protobuf/unknown_field_set.cc',
'src/google/protobuf/unknown_field_set.h',
'src/google/protobuf/wire_format_lite.h',
'src/google/protobuf/wire_format_lite_inl.h',
'src/google/protobuf/io/coded_stream.h',
'src/google/protobuf/io/zero_copy_stream.h',
'src/google/protobuf/io/zero_copy_stream_impl_lite.h',
'src/google/protobuf/stubs/common.cc',
'src/google/protobuf/stubs/once.cc',
'src/google/protobuf/stubs/hash.h',
'src/google/protobuf/stubs/map-util.h',
'src/google/protobuf/extension_set.cc',
'src/google/protobuf/generated_message_util.cc',
'src/google/protobuf/message_lite.cc',
'src/google/protobuf/repeated_field.cc',
'src/google/protobuf/wire_format_lite.cc',
'src/google/protobuf/io/coded_stream.cc',
'src/google/protobuf/io/coded_stream_inl.h',
'src/google/protobuf/io/zero_copy_stream.cc',
'src/google/protobuf/io/zero_copy_stream_impl_lite.cc',
'<(config_h_dir)/config.h',
],
'include_dirs': [
'<(config_h_dir)',
'src',
],
# This macro must be defined to suppress the use of dynamic_cast<>,
# which requires RTTI.
'defines': [
'GOOGLE_PROTOBUF_NO_RTTI',
'GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER',
],
'direct_dependent_settings': {
'include_dirs': [
'<(config_h_dir)',
'src',
],
'defines': [
'GOOGLE_PROTOBUF_NO_RTTI',
'GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER',
],
# TODO(jschuh): http://crbug.com/167187 size_t -> int.
'msvs_disabled_warnings': [ 4267 ],
},
}

View File

@ -0,0 +1,49 @@
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generate java DescriptorProto file.
Usage:
protobuf_lite_java_descriptor_proto.py {protoc} {java_out} {include} {proto_files}
This is a helper file for the protobuf_lite_java_gen_descriptor_proto action in
protobuf.gyp.
It performs the following steps:
1. Recursively deletes old java_out directory.
2. Creates java_out directory.
3. Generates Java descriptor proto file using protoc.
"""
import os
import shutil
import subprocess
import sys
def main(argv):
if len(argv) < 4:
usage()
return 1
protoc_path, java_out, include = argv[1:4]
proto_files = argv[4:]
# Delete all old sources
if os.path.exists(java_out):
shutil.rmtree(java_out)
# Create source directory
os.makedirs(java_out)
# Generate Java files using protoc
return subprocess.call(
[protoc_path, '--java_out', java_out, '-I' + include]
+ proto_files)
def usage():
print(__doc__);
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@ -0,0 +1,57 @@
#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Parses the Maven pom.xml file for which files to include in a lite build.
Usage:
protobuf_lite_java_parse_pom.py {path to pom.xml}
This is a helper file for the protobuf_lite_java target in protobuf.gyp.
It parses the pom.xml file, and looks for all the includes specified in the
'lite' profile. It does not return and test includes.
The result is printed as one line per entry.
"""
import sys
from xml.etree import ElementTree
def main(argv):
if (len(argv) < 2):
usage()
return 1
# Setup all file and XML query paths.
pom_path = argv[1]
namespace = "{http://maven.apache.org/POM/4.0.0}"
profile_path = '{0}profiles/{0}profile'.format(namespace)
id_path = '{0}id'.format(namespace)
plugin_path = \
'{0}build/{0}plugins/{0}plugin'.format(namespace)
artifact_path = '{0}artifactId'.format(namespace)
include_path = '{0}configuration/{0}includes/{0}include'.format(namespace)
# Parse XML file and store result in includes list.
includes = []
for profile in ElementTree.parse(pom_path).getroot().findall(profile_path):
id_element = profile.find(id_path)
if (id_element is not None and id_element.text == 'lite'):
for plugin in profile.findall(plugin_path):
artifact_element = plugin.find(artifact_path)
if (artifact_element is not None and
artifact_element.text == 'maven-compiler-plugin'):
for include in plugin.findall(include_path):
includes.append(include.text)
# Print result to stdout, one item on each line.
print '\n'.join(includes)
def usage():
print(__doc__);
if __name__ == '__main__':
sys.exit(main(sys.argv))

100
third_party/protobuf/python/README.txt vendored Normal file
View File

@ -0,0 +1,100 @@
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc.
This directory contains the Python Protocol Buffers runtime library.
Normally, this directory comes as part of the protobuf package, available
from:
http://code.google.com/p/protobuf
The complete package includes the C++ source code, which includes the
Protocol Compiler (protoc). If you downloaded this package from PyPI
or some other Python-specific source, you may have received only the
Python part of the code. In this case, you will need to obtain the
Protocol Compiler from some other source before you can use this
package.
Development Warning
===================
The Python implementation of Protocol Buffers is not as mature as the C++
and Java implementations. It may be more buggy, and it is known to be
pretty slow at this time. If you would like to help fix these issues,
join the Protocol Buffers discussion list and let us know!
Installation
============
1) Make sure you have Python 2.4 or newer. If in doubt, run:
$ python -V
2) If you do not have setuptools installed, note that it will be
downloaded and installed automatically as soon as you run setup.py.
If you would rather install it manually, you may do so by following
the instructions on this page:
http://peak.telecommunity.com/DevCenter/EasyInstall#installation-instructions
3) Build the C++ code, or install a binary distribution of protoc. If
you install a binary distribution, make sure that it is the same
version as this package. If in doubt, run:
$ protoc --version
4) Run the tests:
$ python setup.py test
If some tests fail, this library may not work correctly on your
system. Continue at your own risk.
Please note that there is a known problem with some versions of
Python on Cygwin which causes the tests to fail after printing the
error: "sem_init: Resource temporarily unavailable". This appears
to be a bug either in Cygwin or in Python:
http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html
We do not know if or when it might me fixed. We also do not know
how likely it is that this bug will affect users in practice.
5) Install:
$ python setup.py install
This step may require superuser privileges.
NOTE: To use C++ implementation, you need to install C++ protobuf runtime
library of the same version and export the environment variable before this
step. See the "C++ Implementation" section below for more details.
Usage
=====
The complete documentation for Protocol Buffers is available via the
web at:
http://code.google.com/apis/protocolbuffers/
C++ Implementation
==================
WARNING: This is EXPERIMENTAL and only available for CPython platforms.
The C++ implementation for Python messages is built as a Python extension to
improve the overall protobuf Python performance.
To use the C++ implementation, you need to:
1) Install the C++ protobuf runtime library, please see instructions in the
parent directory.
2) Export an environment variable:
$ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp
You need to export this variable before running setup.py script to build and
install the extension. You must also set the variable at runtime, otherwise
the pure-Python implementation will be used. In a future release, we will
change the default so that C++ implementation is used whenever it is available.
It is strongly recommended to run `python setup.py test` after setting the
variable to "cpp", so the tests will be against C++ implemented Python
messages.

283
third_party/protobuf/python/ez_setup.py vendored Executable file
View File

@ -0,0 +1,283 @@
#!python
# This file was obtained from:
# http://peak.telecommunity.com/dist/ez_setup.py
# on 2011/1/21.
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c11"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
}
import sys, os
try: from hashlib import md5
except ImportError: from md5 import md5
def _validate_md5(egg_name, data):
if egg_name in md5_data:
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
def do_download():
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
try:
import pkg_resources
except ImportError:
return do_download()
try:
pkg_resources.require("setuptools>="+version); return
except pkg_resources.VersionConflict, e:
if was_imported:
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first, using 'easy_install -U setuptools'."
"\n\n(Currently using %r)"
) % (version, e.args[0])
sys.exit(2)
except pkg_resources.DistributionNotFound:
pass
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return do_download()
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
egg = None
try:
egg = download_setuptools(version, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
if egg and os.path.exists(egg):
os.unlink(egg)
else:
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])

View File

@ -0,0 +1 @@
__import__('pkg_resources').declare_namespace(__name__)

Some files were not shown because too many files have changed in this diff Show More