diff options
author | Wink Saville <wink@google.com> | 2010-05-29 13:13:38 -0700 |
---|---|---|
committer | Wink Saville <wink@google.com> | 2010-05-29 13:13:38 -0700 |
commit | e2d542951c059563a3b7f74c257dac4f222d9dc5 (patch) | |
tree | 2025d0dd0c8963081fef2e340a2789ae6e24f652 | |
parent | d0332953cda33fb4f8e24ebff9c49159b69c43d6 (diff) | |
download | external_protobuf-e2d542951c059563a3b7f74c257dac4f222d9dc5.zip external_protobuf-e2d542951c059563a3b7f74c257dac4f222d9dc5.tar.gz external_protobuf-e2d542951c059563a3b7f74c257dac4f222d9dc5.tar.bz2 |
Add support for Java micro protobuf's to protobuf-2.3.0.
See README.android for additional information.
Change-Id: I6693e405c0d651eacacd3227a876129865dd0d3c
38 files changed, 9888 insertions, 1 deletions
diff --git a/java/README.txt b/java/README.txt index 3ed06a1..4a2839a 100644 --- a/java/README.txt +++ b/java/README.txt @@ -87,6 +87,180 @@ running unit tests. 4) Install the classes wherever you prefer. +Micro version +============================ + +The runtime and generated code for MICRO_RUNTIME is smaller +because it does not include support for the descriptor, +reflection or extensions. Also, not currently supported +are packed repeated elements nor testing of java_multiple_files. + +To create a jar file for the runtime and run tests invoke +"mvn package -P micro" from the <protobuf-root>/java +directory. The generated jar file is +<protobuf-root>java/target/protobuf-java-2.2.0-micro.jar. + +If you wish to compile the MICRO_RUTIME your self, place +the 7 files below, in <root>/com/google/protobuf and +create a jar file for use with your code and the generated +code: + +ByteStringMicro.java +CodedInputStreamMicro.java +CodedOutputStreamMicro.java +InvalidProtocolBufferException.java +MessageMicro.java +StringUtf8Micro.java +WireFormatMicro.java + +If you wish to change on the code generator it is located +in /src/google/protobuf/compiler/javamicro. + +To generate code for the MICRO_RUNTIME invoke protoc with +--javamicro_out command line parameter. javamciro_out takes +a series of optional sub-parameters separated by comma's +and a final parameter, with a colon separator, which defines +the source directory. Sub-paraemeters begin with a name +followed by an equal and if that sub-parameter has multiple +parameters they are seperated by "|". The command line options +are: + +opt -> speed or space +java_use_vector -> true or false +java_package -> <file-name>|<package-name> +java_outer_classname -> <file-name>|<package-name> + +opt: + This change the code generation to optimize for speed, + opt=speed, or space, opt=space. When opt=speed this + changes the code generation for strings to use + StringUtf8Micro which eliminates multiple conversions + of the string to utf8. The default value is opt=space. + +java_use_vector: + Is a boolean flag either java_use_vector=true or + java_use_vector=false. When java_use_vector=true the + code generated for repeated elements uses + java.util.Vector and when java_use_vector=false the + java.util.ArrayList<> is used. When java.util.Vector + is used the code must be compiled with Java 1.3 and + when ArrayList is used Java 1.5 or above must be used. + The using javac the source parameter maybe used to + control the version of the srouce: "javac -source 1.3". + You can also change the <source> xml element for the + maven-compiler-plugin. Below is for 1.5 sources: + + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.5</source> + <target>1.5</target> + </configuration> + </plugin> + + When compiling for 1.5 java_use_vector=false or not + present where the default value is false. + + And below would be for 1.3 sources note when changing + to 1.3 you must also set java_use_vector=true: + + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.3</source> + <target>1.5</target> + </configuration> + </plugin> + +java_package: + The allows setting/overriding the java_package option + and associates allows a package name for a file to + be specified on the command line. Overriding any + "option java_package xxxx" in the file. The default + if not present is to use the value from the package + statment or "option java_package xxxx" in the file. + +java_outer_classname: + This allows the setting/overriding of the outer + class name option and associates a class name + to a file. An outer class name is required and + must be specified if there are multiple messages + in a single proto file either in the proto source + file or on the command line. If not present the + no outer class name will be used. + +Below are a series of examples for clarification of the +various javamicro_out parameters using +src/test/proto/simple-data.proto: + +package testprotobuf; + +message SimpleData { + optional fixed64 id = 1; + optional string description = 2; + optional bool ok = 3 [default = false]; +}; + + +Assuming you've only compiled and not installed protoc and +your current working directory java/, then a simple +command line to compile simple-data would be: + +../src/protoc --javamicro_out=. src/test/proto/simple-data.proto + +This will create testprotobuf/SimpleData.java + +The directory testprotobuf is created because on line 1 +of simple-data.proto is "package testprotobuf;". If you +wanted a different package name you could use the +java_package option command line sub-parameter: + +../src/protoc '--javamicro_out=java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto + +Here you see the new java_package sub-parameter which +itself needs two parameters the file name and the +package name, these are separated by "|". Now you'll +find my_package/SimpleData.java. + +If you wanted to also change the optimization for +speed you'd add opt=speed with the comma seperator +as follows: + +../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto + +Finally if you also wanted an outer class name you'd +do the following: + +../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package,java_outer_classname=src/test/proto/simple-data.proto|OuterName:.' src/test/proto/simple-data.proto + +Now you'll find my_packate/OuterName.java. + +As mentioned java_package and java_outer_classname +may also be specified in the file. In the example +below we must define java_outer_classname because +there are multiple messages in +src/test/proto/two-messages.proto + +package testmicroruntime; + +option java_package = "com.example"; +option java_outer_classname = "TestMessages"; + +message TestMessage1 { + required int32 id = 1; +} + +message TestMessage2 { + required int32 id = 1; +} + +This could be compiled using: + +../src/protoc --javamicro_out=. src/test/proto/two-message.proto + +With the result will be com/example/TestMessages.java + + Usage ===== diff --git a/java/pom.xml b/java/pom.xml index b07f29b..a71a69a 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -96,6 +96,8 @@ <configuration> <tasks> <mkdir dir="target/generated-test-sources" /> + <!--mkdir dir="target/generated-test-sources/opt-space" /--> + <!--mkdir dir="target/generated-test-sources/opt-speed" /--> <exec executable="../src/protoc"> <arg value="--java_out=target/generated-test-sources" /> <arg value="--proto_path=../src" /> @@ -115,8 +117,20 @@ <arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" /> <arg value="../src/google/protobuf/unittest_no_generic_services.proto" /> </exec> + <exec executable="../src/protoc"> + <arg value="--javamicro_out=opt=speed,java_use_vector=false,java_package=google/protobuf/unittest_import_micro.proto|com.google.protobuf.micro,java_outer_classname=google/protobuf/unittest_import_micro.proto|UnittestImportMicro:target/generated-test-sources" /> + <arg value="--proto_path=../src" /> + <arg value="--proto_path=src/test/java" /> + <arg value="../src/google/protobuf/unittest_micro.proto" /> + <arg value="../src/google/protobuf/unittest_simple_micro.proto" /> + <arg value="../src/google/protobuf/unittest_stringutf8_micro.proto" /> + <arg value="../src/google/protobuf/unittest_recursive_micro.proto" /> + <arg value="../src/google/protobuf/unittest_import_micro.proto" /> + </exec> </tasks> <testSourceRoot>target/generated-test-sources</testSourceRoot> + <!--testSourceRoot>target/generated-test-sources/opt-space</testSourceRoot--> + <!--testSourceRoot>target/generated-test-sources/opt-speed</testSourceRoot--> </configuration> <goals> <goal>run</goal> @@ -171,5 +185,48 @@ </plugins> </build> </profile> + <profile> + <id>micro</id> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <includes> + <include>**/MessageMicro.java</include> + <include>**/ByteStringMicro.java</include> + <include>**/CodedInputStreamMicro.java</include> + <include>**/CodedOutputStreamMicro.java</include> + <include>**/InvalidProtocolBufferMicroException.java</include> + <include>**/StringUtf8Micro.java</include> + <include>**/WireFormatMicro.java</include> + </includes> + <testIncludes> + <testInclude>**/MicroTest.java</testInclude> + <testInclude>**/MicroOuterClass.java</testInclude> + <testInclude>**/SimpleMessageMicro.java</testInclude> + <testInclude>**/StringUtf8.java</testInclude> + <testInclude>**/RecursiveMessageMicro.java</testInclude> + <testInclude>**/UnittestImportMicro.java</testInclude> + </testIncludes> + </configuration> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <includes> + <include>**/MicroTest.java</include> + </includes> + </configuration> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <configuration> + <classifier>micro</classifier> + </configuration> + </plugin> + </plugins> + </build> + </profile> </profiles> </project> diff --git a/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java b/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java new file mode 100644 index 0000000..6e87dc9 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java @@ -0,0 +1,227 @@ +// 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.micro; + +import java.io.UnsupportedEncodingException; + +/** + * Immutable array of bytes. + * + * @author crazybob@google.com Bob Lee + * @author kenton@google.com Kenton Varda + */ +public final class ByteStringMicro { + private final byte[] bytes; + + private ByteStringMicro(final byte[] bytes) { + this.bytes = bytes; + } + + /** + * Gets the byte at the given index. + * + * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size + */ + public byte byteAt(final int index) { + return bytes[index]; + } + + /** + * Gets the number of bytes. + */ + public int size() { + return bytes.length; + } + + /** + * Returns {@code true} if the size is {@code 0}, {@code false} otherwise. + */ + public boolean isEmpty() { + return bytes.length == 0; + } + + // ================================================================= + // byte[] -> ByteStringMicro + + /** + * Empty ByteStringMicro. + */ + public static final ByteStringMicro EMPTY = new ByteStringMicro(new byte[0]); + + /** + * Copies the given bytes into a {@code ByteStringMicro}. + */ + public static ByteStringMicro copyFrom(final byte[] bytes, final int offset, + final int size) { + final byte[] copy = new byte[size]; + System.arraycopy(bytes, offset, copy, 0, size); + return new ByteStringMicro(copy); + } + + /** + * Copies the given bytes into a {@code ByteStringMicro}. + */ + public static ByteStringMicro copyFrom(final byte[] bytes) { + return copyFrom(bytes, 0, bytes.length); + } + + /** + * Encodes {@code text} into a sequence of bytes using the named charset + * and returns the result as a {@code ByteStringMicro}. + */ + public static ByteStringMicro copyFrom(final String text, final String charsetName) + throws UnsupportedEncodingException { + return new ByteStringMicro(text.getBytes(charsetName)); + } + + /** + * Encodes {@code text} into a sequence of UTF-8 bytes and returns the + * result as a {@code ByteStringMicro}. + */ + public static ByteStringMicro copyFromUtf8(final String text) { + try { + return new ByteStringMicro(text.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported?"); + } + } + + // ================================================================= + // ByteStringMicro -> byte[] + + /** + * Copies bytes into a buffer at the given offset. + * + * @param target buffer to copy into + * @param offset in the target buffer + */ + public void copyTo(final byte[] target, final int offset) { + System.arraycopy(bytes, 0, target, offset, bytes.length); + } + + /** + * 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 size number of bytes to copy + */ + public void copyTo(final byte[] target, final int sourceOffset, + final int targetOffset, + final int size) { + System.arraycopy(bytes, sourceOffset, target, targetOffset, size); + } + + /** + * Copies bytes to a {@code byte[]}. + */ + public byte[] toByteArray() { + final int size = bytes.length; + final byte[] copy = new byte[size]; + System.arraycopy(bytes, 0, copy, 0, size); + return copy; + } + + /** + * Constructs a new {@code String} by decoding the bytes using the + * specified charset. + */ + public String toString(final String charsetName) + throws UnsupportedEncodingException { + return new String(bytes, charsetName); + } + + /** + * Constructs a new {@code String} by decoding the bytes as UTF-8. + */ + public String toStringUtf8() { + try { + return new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported?"); + } + } + + // ================================================================= + // equals() and hashCode() + + //@Override for compatibility with Java 1.3 code we can't use annotations + public boolean equals(final Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof ByteStringMicro)) { + return false; + } + + final ByteStringMicro other = (ByteStringMicro) o; + final int size = bytes.length; + if (size != other.bytes.length) { + return false; + } + + final byte[] thisBytes = bytes; + final byte[] otherBytes = other.bytes; + for (int i = 0; i < size; i++) { + if (thisBytes[i] != otherBytes[i]) { + return false; + } + } + + return true; + } + + private volatile int hash = 0; + + //@Override for compatibility with Java 1.3 code we can't use annotations + public int hashCode() { + int h = hash; + + if (h == 0) { + final byte[] thisBytes = bytes; + final int size = bytes.length; + + h = size; + for (int i = 0; i < size; i++) { + h = h * 31 + thisBytes[i]; + } + if (h == 0) { + h = 1; + } + + hash = h; + } + + return h; + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java b/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java new file mode 100644 index 0000000..0791b8f --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java @@ -0,0 +1,804 @@ +// 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.micro; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 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 CodedInputStreamMicro { + /** + * Create a new CodedInputStream wrapping the given InputStream. + */ + public static CodedInputStreamMicro newInstance(final InputStream input) { + return new CodedInputStreamMicro(input); + } + + /** + * Create a new CodedInputStream wrapping the given byte array. + */ + public static CodedInputStreamMicro newInstance(final byte[] buf) { + return newInstance(buf, 0, buf.length); + } + + /** + * Create a new CodedInputStream wrapping the given byte array slice. + */ + public static CodedInputStreamMicro newInstance(final byte[] buf, final int off, + final int len) { + return new CodedInputStreamMicro(buf, off, len); + } + + // ----------------------------------------------------------------- + + /** + * 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 (lastTag == 0) { + // If we actually read zero, that's not a valid tag. + throw InvalidProtocolBufferMicroException.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 InvalidProtocolBufferMicroException {@code value} does not match the + * last tag. + */ + public void checkLastTagWas(final int value) + throws InvalidProtocolBufferMicroException { + if (lastTag != value) { + throw InvalidProtocolBufferMicroException.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 (WireFormatMicro.getTagWireType(tag)) { + case WireFormatMicro.WIRETYPE_VARINT: + readInt32(); + return true; + case WireFormatMicro.WIRETYPE_FIXED64: + readRawLittleEndian64(); + return true; + case WireFormatMicro.WIRETYPE_LENGTH_DELIMITED: + skipRawBytes(readRawVarint32()); + return true; + case WireFormatMicro.WIRETYPE_START_GROUP: + skipMessage(); + checkLastTagWas( + WireFormatMicro.makeTag(WireFormatMicro.getTagFieldNumber(tag), + WireFormatMicro.WIRETYPE_END_GROUP)); + return true; + case WireFormatMicro.WIRETYPE_END_GROUP: + return false; + case WireFormatMicro.WIRETYPE_FIXED32: + readRawLittleEndian32(); + return true; + default: + throw InvalidProtocolBufferMicroException.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 MessageMicro msg, final int fieldNumber) + throws IOException { + if (recursionDepth >= recursionLimit) { + throw InvalidProtocolBufferMicroException.recursionLimitExceeded(); + } + ++recursionDepth; + msg.mergeFrom(this); + checkLastTagWas( + WireFormatMicro.makeTag(fieldNumber, WireFormatMicro.WIRETYPE_END_GROUP)); + --recursionDepth; + } + + public void readMessage(final MessageMicro msg) + throws IOException { + final int length = readRawVarint32(); + if (recursionDepth >= recursionLimit) { + throw InvalidProtocolBufferMicroException.recursionLimitExceeded(); + } + final int oldLimit = pushLimit(length); + ++recursionDepth; + msg.mergeFrom(this); + checkLastTagWas(0); + --recursionDepth; + popLimit(oldLimit); + } + + /** Read a {@code bytes} field value from the stream. */ + public ByteStringMicro readBytes() 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 ByteStringMicro result = ByteStringMicro.copyFrom(buffer, bufferPos, size); + bufferPos += size; + return result; + } else { + // Slow path: Build a byte array first then copy it. + return ByteStringMicro.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 InvalidProtocolBufferMicroException.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 { + int result = 0; + int offset = 0; + for (; offset < 32; offset += 7) { + final int b = input.read(); + if (b == -1) { + throw InvalidProtocolBufferMicroException.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 InvalidProtocolBufferMicroException.truncatedMessage(); + } + if ((b & 0x80) == 0) { + return result; + } + } + throw InvalidProtocolBufferMicroException.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 InvalidProtocolBufferMicroException.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 ((b1 & 0xff) ) | + ((b2 & 0xff) << 8) | + ((b3 & 0xff) << 16) | + ((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}. + */ + 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 CodedInputStreamMicro(final byte[] buffer, final int off, final int len) { + this.buffer = buffer; + bufferSize = off + len; + bufferPos = off; + input = null; + } + + private CodedInputStreamMicro(final InputStream input) { + buffer = new byte[BUFFER_SIZE]; + bufferSize = 0; + bufferPos = 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 ByteStringMicro#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 = 0; + } + + /** + * Sets {@code currentLimit} to (current position) + {@code byteLimit}. This + * is called when descending into a length-delimited embedded message. + * + * @return the old limit. + */ + public int pushLimit(int byteLimit) throws InvalidProtocolBufferMicroException { + if (byteLimit < 0) { + throw InvalidProtocolBufferMicroException.negativeSize(); + } + byteLimit += totalBytesRetired + bufferPos; + final int oldLimit = currentLimit; + if (byteLimit > oldLimit) { + throw InvalidProtocolBufferMicroException.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); + } + + /** + * Called with {@code this.buffer} is empty to read more bytes from the + * input. If {@code mustSucceed} is true, refillBuffer() gurantees 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 InvalidProtocolBufferMicroException.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 InvalidProtocolBufferMicroException.truncatedMessage(); + } else { + return false; + } + } else { + recomputeBufferSizeAfterLimit(); + final int totalBytesRead = + totalBytesRetired + bufferSize + bufferSizeAfterLimit; + if (totalBytesRead > sizeLimit || totalBytesRead < 0) { + throw InvalidProtocolBufferMicroException.sizeLimitExceeded(); + } + return true; + } + } + + /** + * Read one byte from the input. + * + * @throws InvalidProtocolBufferMicroException 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 InvalidProtocolBufferMicroException The end of the stream or the current + * limit was reached. + */ + public byte[] readRawBytes(final int size) throws IOException { + if (size < 0) { + throw InvalidProtocolBufferMicroException.negativeSize(); + } + + if (totalBytesRetired + bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + skipRawBytes(currentLimit - totalBytesRetired - bufferPos); + // Then fail. + throw InvalidProtocolBufferMicroException.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); + + // For compatibility with Java 1.3 use Vector + final java.util.Vector chunks = new java.util.Vector(); + + 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 InvalidProtocolBufferMicroException.truncatedMessage(); + } + totalBytesRetired += n; + pos += n; + } + sizeLeft -= chunk.length; + chunks.addElement(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 (int i = 0; i < chunks.size(); i++) { + byte [] chunk = (byte [])chunks.elementAt(i); + System.arraycopy(chunk, 0, bytes, pos, chunk.length); + pos += chunk.length; + } + + // Done. + return bytes; + } + } + + /** + * Reads and discards {@code size} bytes. + * + * @throws InvalidProtocolBufferMicroException The end of the stream or the current + * limit was reached. + */ + public void skipRawBytes(final int size) throws IOException { + if (size < 0) { + throw InvalidProtocolBufferMicroException.negativeSize(); + } + + if (totalBytesRetired + bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + skipRawBytes(currentLimit - totalBytesRetired - bufferPos); + // Then fail. + throw InvalidProtocolBufferMicroException.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; + totalBytesRetired += pos; + bufferPos = 0; + bufferSize = 0; + + // Then skip directly from the InputStream for the rest. + while (pos < size) { + final int n = (input == null) ? -1 : (int) input.skip(size - pos); + if (n <= 0) { + throw InvalidProtocolBufferMicroException.truncatedMessage(); + } + pos += n; + totalBytesRetired += n; + } + } + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java b/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java new file mode 100644 index 0000000..68b6e97 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java @@ -0,0 +1,996 @@ +// 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.micro; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +/** + * Encodes and writes protocol message fields. + * + * <p>This class contains two kinds of methods: methods that write specific + * protocol message constructs and field types (e.g. {@link #writeTag} and + * {@link #writeInt32}) and methods that write low-level values (e.g. + * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are + * writing encoded protocol messages, you should use the former methods, but if + * you are writing some other format of your own design, use the latter. + * + * <p>This class is totally unsynchronized. + * + * @author kneton@google.com Kenton Varda + */ +public final class CodedOutputStreamMicro { + private final byte[] buffer; + private final int limit; + private int position; + + private final OutputStream output; + + /** + * The buffer size used in {@link #newInstance(OutputStream)}. + */ + public static final int DEFAULT_BUFFER_SIZE = 4096; + + private CodedOutputStreamMicro(final byte[] buffer, final int offset, + final int length) { + output = null; + this.buffer = buffer; + position = offset; + limit = offset + length; + } + + private CodedOutputStreamMicro(final OutputStream output, final byte[] buffer) { + this.output = output; + this.buffer = buffer; + position = 0; + limit = buffer.length; + } + + /** + * Create a new {@code CodedOutputStream} wrapping the given + * {@code OutputStream}. + */ + public static CodedOutputStreamMicro newInstance(final OutputStream output) { + return newInstance(output, DEFAULT_BUFFER_SIZE); + } + + /** + * Create a new {@code CodedOutputStream} wrapping the given + * {@code OutputStream} with a given buffer size. + */ + public static CodedOutputStreamMicro newInstance(final OutputStream output, + final int bufferSize) { + return new CodedOutputStreamMicro(output, new byte[bufferSize]); + } + + /** + * Create a new {@code CodedOutputStream} that writes directly to the given + * byte array. If more bytes are written than fit in the array, + * {@link OutOfSpaceException} will be thrown. Writing directly to a flat + * array is faster than writing to an {@code OutputStream}. + */ + public static CodedOutputStreamMicro newInstance(final byte[] flatArray) { + return newInstance(flatArray, 0, flatArray.length); + } + + /** + * Create a new {@code CodedOutputStream} that writes directly to the given + * byte array slice. If more bytes are written than fit in the slice, + * {@link OutOfSpaceException} will be thrown. Writing directly to a flat + * array is faster than writing to an {@code OutputStream}. + */ + public static CodedOutputStreamMicro newInstance(final byte[] flatArray, + final int offset, + final int length) { + return new CodedOutputStreamMicro(flatArray, offset, length); + } + + // ----------------------------------------------------------------- + + /** Write a {@code double} field, including tag, to the stream. */ + public void writeDouble(final int fieldNumber, final double value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64); + writeDoubleNoTag(value); + } + + /** Write a {@code float} field, including tag, to the stream. */ + public void writeFloat(final int fieldNumber, final float value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32); + writeFloatNoTag(value); + } + + /** Write a {@code uint64} field, including tag, to the stream. */ + public void writeUInt64(final int fieldNumber, final long value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeUInt64NoTag(value); + } + + /** Write an {@code int64} field, including tag, to the stream. */ + public void writeInt64(final int fieldNumber, final long value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeInt64NoTag(value); + } + + /** Write an {@code int32} field, including tag, to the stream. */ + public void writeInt32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeInt32NoTag(value); + } + + /** Write a {@code fixed64} field, including tag, to the stream. */ + public void writeFixed64(final int fieldNumber, final long value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64); + writeFixed64NoTag(value); + } + + /** Write a {@code fixed32} field, including tag, to the stream. */ + public void writeFixed32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32); + writeFixed32NoTag(value); + } + + /** Write a {@code bool} field, including tag, to the stream. */ + public void writeBool(final int fieldNumber, final boolean value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeBoolNoTag(value); + } + + /** Write a {@code string} field, including tag, to the stream. */ + public void writeString(final int fieldNumber, final String value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + /** Write a {@code StringUtf8Micro} field, including tag, to the stream. */ + public void writeStringUtf8(final int fieldNumber, final StringUtf8Micro value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED); + writeStringUtf8NoTag(value); + } + + /** Write a {@code group} field, including tag, to the stream. */ + public void writeGroup(final int fieldNumber, final MessageMicro value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_START_GROUP); + writeGroupNoTag(value); + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_END_GROUP); + } + + /** Write an embedded message field, including tag, to the stream. */ + public void writeMessage(final int fieldNumber, final MessageMicro value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + /** Write a {@code bytes} field, including tag, to the stream. */ + public void writeBytes(final int fieldNumber, final ByteStringMicro value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + /** Write a {@code uint32} field, including tag, to the stream. */ + public void writeUInt32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeUInt32NoTag(value); + } + + /** + * Write an enum field, including tag, to the stream. Caller is responsible + * for converting the enum value to its numeric value. + */ + public void writeEnum(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeEnumNoTag(value); + } + + /** Write an {@code sfixed32} field, including tag, to the stream. */ + public void writeSFixed32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32); + writeSFixed32NoTag(value); + } + + /** Write an {@code sfixed64} field, including tag, to the stream. */ + public void writeSFixed64(final int fieldNumber, final long value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64); + writeSFixed64NoTag(value); + } + + /** Write an {@code sint32} field, including tag, to the stream. */ + public void writeSInt32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeSInt32NoTag(value); + } + + /** Write an {@code sint64} field, including tag, to the stream. */ + public void writeSInt64(final int fieldNumber, final long value) + throws IOException { + writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT); + writeSInt64NoTag(value); + } + + /** + * Write a MessageSet extension field to the stream. For historical reasons, + * the wire format differs from normal fields. + */ +// public void writeMessageSetExtension(final int fieldNumber, +// final MessageMicro value) +// throws IOException { +// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP); +// writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber); +// writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value); +// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP); +// } + + /** + * Write an unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ +// public void writeRawMessageSetExtension(final int fieldNumber, +// final ByteStringMicro value) +// throws IOException { +// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP); +// writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber); +// writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value); +// writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP); +// } + + // ----------------------------------------------------------------- + + /** Write a {@code double} field to the stream. */ + public void writeDoubleNoTag(final double value) throws IOException { + writeRawLittleEndian64(Double.doubleToLongBits(value)); + } + + /** Write a {@code float} field to the stream. */ + public void writeFloatNoTag(final float value) throws IOException { + writeRawLittleEndian32(Float.floatToIntBits(value)); + } + + /** Write a {@code uint64} field to the stream. */ + public void writeUInt64NoTag(final long value) throws IOException { + writeRawVarint64(value); + } + + /** Write an {@code int64} field to the stream. */ + public void writeInt64NoTag(final long value) throws IOException { + writeRawVarint64(value); + } + + /** Write an {@code int32} field to the stream. */ + public void writeInt32NoTag(final int value) throws IOException { + if (value >= 0) { + writeRawVarint32(value); + } else { + // Must sign-extend. + writeRawVarint64(value); + } + } + + /** Write a {@code fixed64} field to the stream. */ + public void writeFixed64NoTag(final long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write a {@code fixed32} field to the stream. */ + public void writeFixed32NoTag(final int value) throws IOException { + writeRawLittleEndian32(value); + } + + /** Write a {@code bool} field to the stream. */ + public void writeBoolNoTag(final boolean value) throws IOException { + writeRawByte(value ? 1 : 0); + } + + /** Write a {@code string} field to the stream. */ + public void writeStringNoTag(final String value) throws IOException { + // Unfortunately there does not appear to be any way to tell Java to encode + // UTF-8 directly into our buffer, so we have to let it create its own byte + // array and then copy. + final byte[] bytes = value.getBytes("UTF-8"); + writeRawVarint32(bytes.length); + writeRawBytes(bytes); + } + + /** Write a {@code StringUtf8Micro} field to the stream. */ + public void writeStringUtf8NoTag(final StringUtf8Micro value) throws IOException { + final byte[] bytes = value.getBytes(); + writeRawVarint32(bytes.length); + writeRawBytes(bytes); + } + + /** Write a {@code group} field to the stream. */ + public void writeGroupNoTag(final MessageMicro value) throws IOException { + value.writeTo(this); + } + + /** Write an embedded message field to the stream. */ + public void writeMessageNoTag(final MessageMicro value) throws IOException { + writeRawVarint32(value.getCachedSize()); + value.writeTo(this); + } + + /** Write a {@code bytes} field to the stream. */ + public void writeBytesNoTag(final ByteStringMicro value) throws IOException { + final byte[] bytes = value.toByteArray(); + writeRawVarint32(bytes.length); + writeRawBytes(bytes); + } + + /** Write a {@code uint32} field to the stream. */ + public void writeUInt32NoTag(final int value) throws IOException { + writeRawVarint32(value); + } + + /** + * Write an enum field to the stream. Caller is responsible + * for converting the enum value to its numeric value. + */ + public void writeEnumNoTag(final int value) throws IOException { + writeRawVarint32(value); + } + + /** Write an {@code sfixed32} field to the stream. */ + public void writeSFixed32NoTag(final int value) throws IOException { + writeRawLittleEndian32(value); + } + + /** Write an {@code sfixed64} field to the stream. */ + public void writeSFixed64NoTag(final long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write an {@code sint32} field to the stream. */ + public void writeSInt32NoTag(final int value) throws IOException { + writeRawVarint32(encodeZigZag32(value)); + } + + /** Write an {@code sint64} field to the stream. */ + public void writeSInt64NoTag(final long value) throws IOException { + writeRawVarint64(encodeZigZag64(value)); + } + + // ================================================================= + + /** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ + public static int computeDoubleSize(final int fieldNumber, + final double value) { + return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ + public static int computeFloatSize(final int fieldNumber, final float value) { + return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ + public static int computeUInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ + public static int computeInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ + public static int computeInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field, including tag. + */ + public static int computeFixed64Size(final int fieldNumber, + final long value) { + return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field, including tag. + */ + public static int computeFixed32Size(final int fieldNumber, + final int value) { + return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field, including tag. + */ + public static int computeBoolSize(final int fieldNumber, + final boolean value) { + return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code string} field, including tag. + */ + public static int computeStringSize(final int fieldNumber, + final String value) { + return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code StringUtf8Micro} field, including tag. + */ + public static int computeStringUtf8Size(final int fieldNumber, + final StringUtf8Micro value) { + return computeTagSize(fieldNumber) + computeStringUtf8SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field, including tag. + */ + public static int computeGroupSize(final int fieldNumber, + final MessageMicro value) { + return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * embedded message field, including tag. + */ + public static int computeMessageSize(final int fieldNumber, + final MessageMicro value) { + return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ + public static int computeBytesSize(final int fieldNumber, + final ByteStringMicro value) { + return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field, including tag. + */ + public static int computeUInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * enum field, including tag. Caller is responsible for converting the + * enum value to its numeric value. + */ + public static int computeEnumSize(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field, including tag. + */ + public static int computeSFixed32Size(final int fieldNumber, + final int value) { + return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field, including tag. + */ + public static int computeSFixed64Size(final int fieldNumber, + final long value) { + return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field, including tag. + */ + public static int computeSInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field, including tag. + */ + public static int computeSInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * MessageSet extension to the stream. For historical reasons, + * the wire format differs from normal fields. + */ +// public static int computeMessageSetExtensionSize( +// final int fieldNumber, final MessageMicro value) { +// return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 + +// computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) + +// computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value); +// } + + /** + * Compute the number of bytes that would be needed to encode an + * unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ +// public static int computeRawMessageSetExtensionSize( +// final int fieldNumber, final ByteStringMicro value) { +// return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 + +// computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) + +// computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value); +// } + + // ----------------------------------------------------------------- + + /** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ + public static int computeDoubleSizeNoTag(final double value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ + public static int computeFloatSizeNoTag(final float value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ + public static int computeUInt64SizeNoTag(final long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ + public static int computeInt64SizeNoTag(final long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ + public static int computeInt32SizeNoTag(final int value) { + if (value >= 0) { + return computeRawVarint32Size(value); + } else { + // Must sign-extend. + return 10; + } + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field. + */ + public static int computeFixed64SizeNoTag(final long value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field. + */ + public static int computeFixed32SizeNoTag(final int value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field. + */ + public static int computeBoolSizeNoTag(final boolean value) { + return 1; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code string} field. + */ + public static int computeStringSizeNoTag(final String value) { + try { + final byte[] bytes = value.getBytes("UTF-8"); + return computeRawVarint32Size(bytes.length) + + bytes.length; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported."); + } + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code StringUtf8Micro} field. + */ + public static int computeStringUtf8SizeNoTag(final StringUtf8Micro value) { + final byte[] bytes = value.getBytes(); + return computeRawVarint32Size(bytes.length) + + bytes.length; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field. + */ + public static int computeGroupSizeNoTag(final MessageMicro value) { + return value.getCachedSize(); + } + + /** + * Compute the number of bytes that would be needed to encode an embedded + * message field. + */ + public static int computeMessageSizeNoTag(final MessageMicro value) { + final int size = value.getCachedSize(); + return computeRawVarint32Size(size) + size; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeBytesSizeNoTag(final ByteStringMicro value) { + return computeRawVarint32Size(value.size()) + + value.size(); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field. + */ + public static int computeUInt32SizeNoTag(final int value) { + return computeRawVarint32Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an enum field. + * Caller is responsible for converting the enum value to its numeric value. + */ + public static int computeEnumSizeNoTag(final int value) { + return computeRawVarint32Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field. + */ + public static int computeSFixed32SizeNoTag(final int value) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field. + */ + public static int computeSFixed64SizeNoTag(final long value) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field. + */ + public static int computeSInt32SizeNoTag(final int value) { + return computeRawVarint32Size(encodeZigZag32(value)); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field. + */ + public static int computeSInt64SizeNoTag(final long value) { + return computeRawVarint64Size(encodeZigZag64(value)); + } + + // ================================================================= + + /** + * Internal helper that writes the current buffer to the output. The + * buffer position is reset to its initial value when this returns. + */ + private void refreshBuffer() throws IOException { + if (output == null) { + // We're writing to a single buffer. + throw new OutOfSpaceException(); + } + + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + output.write(buffer, 0, position); + position = 0; + } + + /** + * Flushes the stream and forces any buffered bytes to be written. This + * does not flush the underlying OutputStream. + */ + public void flush() throws IOException { + if (output != null) { + refreshBuffer(); + } + } + + /** + * If writing to a flat array, return the space left in the array. + * Otherwise, throws {@code UnsupportedOperationException}. + */ + public int spaceLeft() { + if (output == null) { + return limit - position; + } else { + throw new UnsupportedOperationException( + "spaceLeft() can only be called on CodedOutputStreams that are " + + "writing to a flat array."); + } + } + + /** + * Verifies that {@link #spaceLeft()} returns zero. It's common to create + * a byte array that is exactly big enough to hold a message, then write to + * it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()} + * after writing verifies that the message was actually as big as expected, + * which can help catch bugs. + */ + public void checkNoSpaceLeft() { + if (spaceLeft() != 0) { + throw new IllegalStateException( + "Did not write as much data as expected."); + } + } + + /** + * If you create a CodedOutputStream around a simple flat array, you must + * not attempt to write more bytes than the array has space. Otherwise, + * this exception will be thrown. + */ + public static class OutOfSpaceException extends IOException { + private static final long serialVersionUID = -6947486886997889499L; + + OutOfSpaceException() { + super("CodedOutputStream was writing to a flat byte array and ran " + + "out of space."); + } + } + + /** Write a single byte. */ + public void writeRawByte(final byte value) throws IOException { + if (position == limit) { + refreshBuffer(); + } + + buffer[position++] = value; + } + + /** Write a single byte, represented by an integer value. */ + public void writeRawByte(final int value) throws IOException { + writeRawByte((byte) value); + } + + /** Write an array of bytes. */ + public void writeRawBytes(final byte[] value) throws IOException { + writeRawBytes(value, 0, value.length); + } + + /** Write part of an array of bytes. */ + public void writeRawBytes(final byte[] value, int offset, int length) + throws IOException { + if (limit - position >= length) { + // We have room in the current buffer. + System.arraycopy(value, offset, buffer, position, length); + position += length; + } else { + // Write extends past current buffer. Fill the rest of this buffer and + // flush. + final int bytesWritten = limit - position; + System.arraycopy(value, offset, buffer, position, bytesWritten); + offset += bytesWritten; + length -= bytesWritten; + position = limit; + refreshBuffer(); + + // Now deal with the rest. + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + if (length <= limit) { + // Fits in new buffer. + System.arraycopy(value, offset, buffer, 0, length); + position = length; + } else { + // Write is very big. Let's do it all at once. + output.write(value, offset, length); + } + } + } + + /** Encode and write a tag. */ + public void writeTag(final int fieldNumber, final int wireType) + throws IOException { + writeRawVarint32(WireFormatMicro.makeTag(fieldNumber, wireType)); + } + + /** Compute the number of bytes that would be needed to encode a tag. */ + public static int computeTagSize(final int fieldNumber) { + return computeRawVarint32Size(WireFormatMicro.makeTag(fieldNumber, 0)); + } + + /** + * Encode and write a varint. {@code value} is treated as + * unsigned, so it won't be sign-extended if negative. + */ + public void writeRawVarint32(int value) throws IOException { + while (true) { + if ((value & ~0x7F) == 0) { + writeRawByte(value); + return; + } else { + writeRawByte((value & 0x7F) | 0x80); + value >>>= 7; + } + } + } + + /** + * Compute the number of bytes that would be needed to encode a varint. + * {@code value} is treated as unsigned, so it won't be sign-extended if + * negative. + */ + public static int computeRawVarint32Size(final int value) { + if ((value & (0xffffffff << 7)) == 0) return 1; + if ((value & (0xffffffff << 14)) == 0) return 2; + if ((value & (0xffffffff << 21)) == 0) return 3; + if ((value & (0xffffffff << 28)) == 0) return 4; + return 5; + } + + /** Encode and write a varint. */ + public void writeRawVarint64(long value) throws IOException { + while (true) { + if ((value & ~0x7FL) == 0) { + writeRawByte((int)value); + return; + } else { + writeRawByte(((int)value & 0x7F) | 0x80); + value >>>= 7; + } + } + } + + /** Compute the number of bytes that would be needed to encode a varint. */ + public static int computeRawVarint64Size(final long value) { + if ((value & (0xffffffffffffffffL << 7)) == 0) return 1; + if ((value & (0xffffffffffffffffL << 14)) == 0) return 2; + if ((value & (0xffffffffffffffffL << 21)) == 0) return 3; + if ((value & (0xffffffffffffffffL << 28)) == 0) return 4; + if ((value & (0xffffffffffffffffL << 35)) == 0) return 5; + if ((value & (0xffffffffffffffffL << 42)) == 0) return 6; + if ((value & (0xffffffffffffffffL << 49)) == 0) return 7; + if ((value & (0xffffffffffffffffL << 56)) == 0) return 8; + if ((value & (0xffffffffffffffffL << 63)) == 0) return 9; + return 10; + } + + /** Write a little-endian 32-bit integer. */ + public void writeRawLittleEndian32(final int value) throws IOException { + writeRawByte((value ) & 0xFF); + writeRawByte((value >> 8) & 0xFF); + writeRawByte((value >> 16) & 0xFF); + writeRawByte((value >> 24) & 0xFF); + } + + public static final int LITTLE_ENDIAN_32_SIZE = 4; + + /** Write a little-endian 64-bit integer. */ + public void writeRawLittleEndian64(final long value) throws IOException { + writeRawByte((int)(value ) & 0xFF); + writeRawByte((int)(value >> 8) & 0xFF); + writeRawByte((int)(value >> 16) & 0xFF); + writeRawByte((int)(value >> 24) & 0xFF); + writeRawByte((int)(value >> 32) & 0xFF); + writeRawByte((int)(value >> 40) & 0xFF); + writeRawByte((int)(value >> 48) & 0xFF); + writeRawByte((int)(value >> 56) & 0xFF); + } + + public static final int LITTLE_ENDIAN_64_SIZE = 8; + + /** + * Encode 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 A signed 32-bit integer. + * @return An unsigned 32-bit integer, stored in a signed int because + * Java has no explicit unsigned support. + */ + public static int encodeZigZag32(final int n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); + } + + /** + * Encode 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 A signed 64-bit integer. + * @return An unsigned 64-bit integer, stored in a signed int because + * Java has no explicit unsigned support. + */ + public static long encodeZigZag64(final long n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java b/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java new file mode 100644 index 0000000..050f99b --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java @@ -0,0 +1,93 @@ +// 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.micro; + +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 InvalidProtocolBufferMicroException extends IOException { + private static final long serialVersionUID = -1616151763072450476L; + + public InvalidProtocolBufferMicroException(final String description) { + super(description); + } + + static InvalidProtocolBufferMicroException truncatedMessage() { + return new InvalidProtocolBufferMicroException( + "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 InvalidProtocolBufferMicroException negativeSize() { + return new InvalidProtocolBufferMicroException( + "CodedInputStream encountered an embedded string or message " + + "which claimed to have negative size."); + } + + static InvalidProtocolBufferMicroException malformedVarint() { + return new InvalidProtocolBufferMicroException( + "CodedInputStream encountered a malformed varint."); + } + + static InvalidProtocolBufferMicroException invalidTag() { + return new InvalidProtocolBufferMicroException( + "Protocol message contained an invalid tag (zero)."); + } + + static InvalidProtocolBufferMicroException invalidEndTag() { + return new InvalidProtocolBufferMicroException( + "Protocol message end-group tag did not match expected tag."); + } + + static InvalidProtocolBufferMicroException invalidWireType() { + return new InvalidProtocolBufferMicroException( + "Protocol message tag had invalid wire type."); + } + + static InvalidProtocolBufferMicroException recursionLimitExceeded() { + return new InvalidProtocolBufferMicroException( + "Protocol message had too many levels of nesting. May be malicious. " + + "Use CodedInputStream.setRecursionLimit() to increase the depth limit."); + } + + static InvalidProtocolBufferMicroException sizeLimitExceeded() { + return new InvalidProtocolBufferMicroException( + "Protocol message was too large. May be malicious. " + + "Use CodedInputStream.setSizeLimit() to increase the size limit."); + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/MessageMicro.java b/java/src/main/java/com/google/protobuf/micro/MessageMicro.java new file mode 100644 index 0000000..0c02793 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/MessageMicro.java @@ -0,0 +1,136 @@ +// 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.micro; + +import com.google.protobuf.micro.CodedOutputStreamMicro; +import java.io.IOException; + +/** + * Abstract interface implemented by Protocol Message objects. + * + * @author wink@google.com Wink Saville + */ +public abstract class MessageMicro { + /** + * Get the number of bytes required to encode this message. + * Returns the cached size or calls getSerializedSize which + * sets the cached size. This is used internally when serializing + * so the size is only computed once. If a member is modified + * then this could be stale call getSerializedSize if in doubt. + */ + abstract public int getCachedSize(); + + /** + * Computes the number of bytes required to encode this message. + * The size is cached and the cached result can be retrieved + * using getCachedSize(). + */ + abstract public int getSerializedSize(); + + /** + * Serializes the message and writes it to {@code output}. This does not + * flush or close the stream. + */ + abstract public void writeTo(CodedOutputStreamMicro output) throws java.io.IOException; + + /** + * Parse {@code input} as a message of this type and merge it with the + * message being built. + */ + abstract public MessageMicro mergeFrom(final CodedInputStreamMicro input) throws IOException; + + /** + * Serialize to a byte array. + * @return byte array with the serialized data. + */ + public byte[] toByteArray() { + final byte[] result = new byte[getSerializedSize()]; + toByteArray(result, 0, result.length); + return result; + } + + /** + * Serialize to a byte array starting at offset through length. The + * method getSerializedSize must have been called prior to calling + * this method so the proper length is know. If an attempt to + * write more than length bytes OutOfSpaceException will be thrown + * and if length bytes are not written then IllegalStateException + * is thrown. + * @return byte array with the serialized data. + */ + public void toByteArray(byte [] data, int offset, int length) { + try { + final CodedOutputStreamMicro output = CodedOutputStreamMicro.newInstance(data, offset, length); + writeTo(output); + output.checkNoSpaceLeft(); + } catch (IOException e) { + throw new RuntimeException("Serializing to a byte array threw an IOException " + + "(should never happen)."); + } + } + + /** + * Parse {@code data} as a message of this type and merge it with the + * message being built. + */ + public MessageMicro mergeFrom(final byte[] data) throws InvalidProtocolBufferMicroException { + return mergeFrom(data, 0, data.length); + } + + /** + * Parse {@code data} as a message of this type and merge it with the + * message being built. + */ + public MessageMicro mergeFrom(final byte[] data, final int off, final int len) + throws InvalidProtocolBufferMicroException { + try { + final CodedInputStreamMicro input = CodedInputStreamMicro.newInstance(data, off, len); + mergeFrom(input); + input.checkLastTagWas(0); + return this; + } catch (InvalidProtocolBufferMicroException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException("Reading from a byte array threw an IOException (should " + + "never happen)."); + } + } + + /** + * Called by subclasses to parse an unknown field. + * @return {@code true} unless the tag is an end-group tag. + */ + protected boolean parseUnknownField( + final CodedInputStreamMicro input, + final int tag) throws IOException { + return input.skipField(tag); + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java b/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java new file mode 100644 index 0000000..0c43e54 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java @@ -0,0 +1,67 @@ +// 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.micro; + +/** + * A surogate for a String with a UTF8 representation. + * + * @author wink@google.com Wink Saville + */ +public final class StringUtf8Micro { + private String string; + private byte[] bytes; + + public StringUtf8Micro(String string) { + setString(string); + } + + public static final StringUtf8Micro EMPTY = new StringUtf8Micro(""); + + public String getString() { + return string; + } + + public void setString(String string) { + this.string = string; + bytes = null; + } + + public byte [] getBytes() { + if (bytes == null) { + try { + bytes = string.getBytes("UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported."); + } + } + return bytes; + } +} diff --git a/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java b/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java new file mode 100644 index 0000000..d8a88bd --- /dev/null +++ b/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java @@ -0,0 +1,87 @@ +// 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.micro; + +/** + * 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 WireFormatMicro { + // Do not allow instantiation. + private WireFormatMicro() {} + + static final int WIRETYPE_VARINT = 0; + static final int WIRETYPE_FIXED64 = 1; + static final int WIRETYPE_LENGTH_DELIMITED = 2; + static final int WIRETYPE_START_GROUP = 3; + static final int WIRETYPE_END_GROUP = 4; + 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; + } + + // Field numbers for feilds 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); +} diff --git a/java/src/test/java/com/google/protobuf/MicroTest.java b/java/src/test/java/com/google/protobuf/MicroTest.java new file mode 100644 index 0000000..ebfccc2 --- /dev/null +++ b/java/src/test/java/com/google/protobuf/MicroTest.java @@ -0,0 +1,2138 @@ +// 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.micro.MicroOuterClass; +import com.google.protobuf.micro.MicroOuterClass.TestAllTypesMicro; +import com.google.protobuf.micro.RecursiveMessageMicro; +import com.google.protobuf.micro.SimpleMessageMicro; +import com.google.protobuf.micro.StringUtf8; +import com.google.protobuf.micro.StringUtf8Micro; +import com.google.protobuf.micro.UnittestImportMicro; +import com.google.protobuf.micro.ByteStringMicro; + +import junit.framework.TestCase; + +/** + * Test micro runtime. + * + * @author wink@google.com Wink Saville + */ +public class MicroTest extends TestCase { + public void setUp() throws Exception { + } + + public void testSimpleMessageMicro() throws Exception { + SimpleMessageMicro msg = new SimpleMessageMicro(); + assertFalse(msg.hasD()); + assertEquals(123, msg.getD()); + assertFalse(msg.hasNestedMsg()); + assertEquals(null, msg.getNestedMsg()); + assertFalse(msg.hasDefaultNestedEnum()); + assertEquals(SimpleMessageMicro.BAZ, msg.getDefaultNestedEnum()); + + msg.setD(456); + assertTrue(msg.hasD()); + assertEquals(456, msg.getD()); + msg.clearD() + .setD(456); + assertTrue(msg.hasD()); + + SimpleMessageMicro.NestedMessage nestedMsg = new SimpleMessageMicro.NestedMessage() + .setBb(2); + assertTrue(nestedMsg.hasBb()); + assertEquals(2, nestedMsg.getBb()); + msg.setNestedMsg(nestedMsg); + assertTrue(msg.hasNestedMsg()); + assertEquals(2, msg.getNestedMsg().getBb()); + + msg.setDefaultNestedEnum(SimpleMessageMicro.BAR); + assertTrue(msg.hasDefaultNestedEnum()); + assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum()); + + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + SimpleMessageMicro newMsg = SimpleMessageMicro.parseFrom(result); + assertTrue(newMsg.hasD()); + assertTrue(newMsg.hasNestedMsg()); + assertTrue(newMsg.hasDefaultNestedEnum()); + assertEquals(456, newMsg.getD()); + assertEquals(2, msg.getNestedMsg().getBb()); + assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum()); + } + + public void testRecursiveMessageMicro() throws Exception { + RecursiveMessageMicro msg = new RecursiveMessageMicro(); + assertFalse(msg.hasId()); + assertFalse(msg.hasNestedMessage()); + assertFalse(msg.hasOptionalRecursiveMessageMicro()); + assertEquals(0, msg.getRepeatedRecursiveMessageMicroCount()); + + RecursiveMessageMicro msg1 = new RecursiveMessageMicro(); + msg1.setId(1); + assertEquals(1, msg1.getId()); + RecursiveMessageMicro msg2 = new RecursiveMessageMicro(); + msg2.setId(2); + RecursiveMessageMicro msg3 = new RecursiveMessageMicro(); + msg3.setId(3); + + RecursiveMessageMicro.NestedMessage nestedMsg = new RecursiveMessageMicro.NestedMessage(); + nestedMsg.setA(msg1); + assertEquals(1, nestedMsg.getA().getId()); + + msg.setId(0); + msg.setNestedMessage(nestedMsg); + msg.setOptionalRecursiveMessageMicro(msg2); + msg.addRepeatedRecursiveMessageMicro(msg3); + + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + RecursiveMessageMicro newMsg = RecursiveMessageMicro.parseFrom(result); + assertTrue(newMsg.hasId()); + assertTrue(newMsg.hasNestedMessage()); + assertTrue(newMsg.hasOptionalRecursiveMessageMicro()); + assertEquals(1, newMsg.getRepeatedRecursiveMessageMicroCount()); + + assertEquals(0, newMsg.getId()); + assertEquals(1, newMsg.getNestedMessage().getA().getId()); + assertEquals(2, newMsg.getOptionalRecursiveMessageMicro().getId()); + assertEquals(3, newMsg.getRepeatedRecursiveMessageMicro(0).getId()); + } + + public void testMicroRequiredInt32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasId()); + assertFalse(msg.isInitialized()); + msg.setId(123); + assertTrue(msg.hasId()); + assertTrue(msg.isInitialized()); + assertEquals(123, msg.getId()); + msg.clearId(); + assertFalse(msg.hasId()); + assertFalse(msg.isInitialized()); + msg.clearId() + .setId(456); + assertTrue(msg.hasId()); + msg.clear(); + assertFalse(msg.hasId()); + assertFalse(msg.isInitialized()); + + msg.setId(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasId()); + assertTrue(newMsg.isInitialized()); + assertEquals(123, newMsg.getId()); + } + + public void testMicroOptionalInt32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalInt32()); + msg.setOptionalInt32(123); + assertTrue(msg.hasOptionalInt32()); + assertEquals(123, msg.getOptionalInt32()); + msg.clearOptionalInt32(); + assertFalse(msg.hasOptionalInt32()); + msg.clearOptionalInt32() + .setOptionalInt32(456); + assertTrue(msg.hasOptionalInt32()); + msg.clear(); + assertFalse(msg.hasOptionalInt32()); + + msg.setOptionalInt32(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 2); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalInt32()); + assertEquals(123, newMsg.getOptionalInt32()); + } + + public void testMicroOptionalInt64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalInt64()); + msg.setOptionalInt64(123); + assertTrue(msg.hasOptionalInt64()); + assertEquals(123, msg.getOptionalInt64()); + msg.clearOptionalInt64(); + assertFalse(msg.hasOptionalInt64()); + msg.clearOptionalInt64() + .setOptionalInt64(456); + assertTrue(msg.hasOptionalInt64()); + msg.clear(); + assertFalse(msg.hasOptionalInt64()); + + msg.setOptionalInt64(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 2); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalInt64()); + assertEquals(123, newMsg.getOptionalInt64()); + } + + public void testMicroOptionalUint32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalUint32()); + msg.setOptionalUint32(123); + assertTrue(msg.hasOptionalUint32()); + assertEquals(123, msg.getOptionalUint32()); + msg.clearOptionalUint32(); + assertFalse(msg.hasOptionalUint32()); + msg.clearOptionalUint32() + .setOptionalUint32(456); + assertTrue(msg.hasOptionalUint32()); + msg.clear(); + assertFalse(msg.hasOptionalUint32()); + + msg.setOptionalUint32(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 2); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalUint32()); + assertEquals(123, newMsg.getOptionalUint32()); + } + + public void testMicroOptionalUint64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalUint64()); + msg.setOptionalUint64(123); + assertTrue(msg.hasOptionalUint64()); + assertEquals(123, msg.getOptionalUint64()); + msg.clearOptionalUint64(); + assertFalse(msg.hasOptionalUint64()); + msg.clearOptionalUint64() + .setOptionalUint64(456); + assertTrue(msg.hasOptionalUint64()); + msg.clear(); + assertFalse(msg.hasOptionalUint64()); + + msg.setOptionalUint64(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 2); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalUint64()); + assertEquals(123, newMsg.getOptionalUint64()); + } + + public void testMicroOptionalSint32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalSint32()); + msg.setOptionalSint32(123); + assertTrue(msg.hasOptionalSint32()); + assertEquals(123, msg.getOptionalSint32()); + msg.clearOptionalSint32(); + assertFalse(msg.hasOptionalSint32()); + msg.clearOptionalSint32() + .setOptionalSint32(456); + assertTrue(msg.hasOptionalSint32()); + msg.clear(); + assertFalse(msg.hasOptionalSint32()); + + msg.setOptionalSint32(-123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalSint32()); + assertEquals(-123, newMsg.getOptionalSint32()); + } + + public void testMicroOptionalSint64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalSint64()); + msg.setOptionalSint64(123); + assertTrue(msg.hasOptionalSint64()); + assertEquals(123, msg.getOptionalSint64()); + msg.clearOptionalSint64(); + assertFalse(msg.hasOptionalSint64()); + msg.clearOptionalSint64() + .setOptionalSint64(456); + assertTrue(msg.hasOptionalSint64()); + msg.clear(); + assertFalse(msg.hasOptionalSint64()); + + msg.setOptionalSint64(-123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalSint64()); + assertEquals(-123, newMsg.getOptionalSint64()); + } + + public void testMicroOptionalFixed32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalFixed32()); + msg.setOptionalFixed32(123); + assertTrue(msg.hasOptionalFixed32()); + assertEquals(123, msg.getOptionalFixed32()); + msg.clearOptionalFixed32(); + assertFalse(msg.hasOptionalFixed32()); + msg.clearOptionalFixed32() + .setOptionalFixed32(456); + assertTrue(msg.hasOptionalFixed32()); + msg.clear(); + assertFalse(msg.hasOptionalFixed32()); + + msg.setOptionalFixed32(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalFixed32()); + assertEquals(123, newMsg.getOptionalFixed32()); + } + + public void testMicroOptionalFixed64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalFixed64()); + msg.setOptionalFixed64(123); + assertTrue(msg.hasOptionalFixed64()); + assertEquals(123, msg.getOptionalFixed64()); + msg.clearOptionalFixed64(); + assertFalse(msg.hasOptionalFixed64()); + msg.clearOptionalFixed64() + .setOptionalFixed64(456); + assertTrue(msg.hasOptionalFixed64()); + msg.clear(); + assertFalse(msg.hasOptionalFixed64()); + + msg.setOptionalFixed64(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalFixed64()); + assertEquals(123, newMsg.getOptionalFixed64()); + } + public void testMicroOptionalSfixed32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalSfixed32()); + msg.setOptionalSfixed32(123); + assertTrue(msg.hasOptionalSfixed32()); + assertEquals(123, msg.getOptionalSfixed32()); + msg.clearOptionalSfixed32(); + assertFalse(msg.hasOptionalSfixed32()); + msg.clearOptionalSfixed32() + .setOptionalSfixed32(456); + assertTrue(msg.hasOptionalSfixed32()); + msg.clear(); + assertFalse(msg.hasOptionalSfixed32()); + + msg.setOptionalSfixed32(123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalSfixed32()); + assertEquals(123, newMsg.getOptionalSfixed32()); + } + + public void testMicroOptionalSfixed64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalSfixed64()); + msg.setOptionalSfixed64(123); + assertTrue(msg.hasOptionalSfixed64()); + assertEquals(123, msg.getOptionalSfixed64()); + msg.clearOptionalSfixed64(); + assertFalse(msg.hasOptionalSfixed64()); + msg.clearOptionalSfixed64() + .setOptionalSfixed64(456); + assertTrue(msg.hasOptionalSfixed64()); + msg.clear(); + assertFalse(msg.hasOptionalSfixed64()); + + msg.setOptionalSfixed64(-123); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalSfixed64()); + assertEquals(-123, newMsg.getOptionalSfixed64()); + } + + public void testMicroOptionalFloat() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalFloat()); + msg.setOptionalFloat(123f); + assertTrue(msg.hasOptionalFloat()); + assertTrue(123.0f == msg.getOptionalFloat()); + msg.clearOptionalFloat(); + assertFalse(msg.hasOptionalFloat()); + msg.clearOptionalFloat() + .setOptionalFloat(456.0f); + assertTrue(msg.hasOptionalFloat()); + msg.clear(); + assertFalse(msg.hasOptionalFloat()); + + msg.setOptionalFloat(-123.456f); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalFloat()); + assertTrue(-123.456f == newMsg.getOptionalFloat()); + } + + public void testMicroOptionalDouble() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalDouble()); + msg.setOptionalDouble(123); + assertTrue(msg.hasOptionalDouble()); + assertTrue(123.0 == msg.getOptionalDouble()); + msg.clearOptionalDouble(); + assertFalse(msg.hasOptionalDouble()); + msg.clearOptionalDouble() + .setOptionalDouble(456.0); + assertTrue(msg.hasOptionalDouble()); + msg.clear(); + assertFalse(msg.hasOptionalDouble()); + + msg.setOptionalDouble(-123.456); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalDouble()); + assertTrue(-123.456 == newMsg.getOptionalDouble()); + } + + public void testMicroOptionalBool() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalBool()); + msg.setOptionalBool(true); + assertTrue(msg.hasOptionalBool()); + assertEquals(true, msg.getOptionalBool()); + msg.clearOptionalBool(); + assertFalse(msg.hasOptionalBool()); + msg.clearOptionalBool() + .setOptionalBool(true); + assertTrue(msg.hasOptionalBool()); + msg.clear(); + assertFalse(msg.hasOptionalBool()); + + msg.setOptionalBool(false); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 2); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalBool()); + assertEquals(false, newMsg.getOptionalBool()); + } + + public void testMicroOptionalString() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalString()); + msg.setOptionalString("hello"); + assertTrue(msg.hasOptionalString()); + assertEquals("hello", msg.getOptionalString()); + msg.clearOptionalString(); + assertFalse(msg.hasOptionalString()); + msg.clearOptionalString() + .setOptionalString("hello"); + assertTrue(msg.hasOptionalString()); + msg.clear(); + assertFalse(msg.hasOptionalString()); + + msg.setOptionalString("bye"); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalString()); + assertEquals("bye", newMsg.getOptionalString()); + } + + public void testMicroOptionalBytes() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalBytes()); + msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("hello")); + assertTrue(msg.hasOptionalBytes()); + assertEquals("hello", msg.getOptionalBytes().toStringUtf8()); + msg.clearOptionalBytes(); + assertFalse(msg.hasOptionalBytes()); + msg.clearOptionalBytes() + .setOptionalBytes(ByteStringMicro.copyFromUtf8("hello")); + assertTrue(msg.hasOptionalBytes()); + msg.clear(); + assertFalse(msg.hasOptionalBytes()); + + msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("bye")); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalBytes()); + assertEquals("bye", newMsg.getOptionalBytes().toStringUtf8()); + } + + public void testMicroOptionalGroup() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + TestAllTypesMicro.OptionalGroup grp = new TestAllTypesMicro.OptionalGroup(); + grp.setA(1); + assertFalse(msg.hasOptionalGroup()); + msg.setOptionalGroup(grp); + assertTrue(msg.hasOptionalGroup()); + assertEquals(1, msg.getOptionalGroup().getA()); + msg.clearOptionalGroup(); + assertFalse(msg.hasOptionalGroup()); + msg.clearOptionalGroup() + .setOptionalGroup(new TestAllTypesMicro.OptionalGroup().setA(2)); + assertTrue(msg.hasOptionalGroup()); + msg.clear(); + assertFalse(msg.hasOptionalGroup()); + + msg.setOptionalGroup(grp); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalGroup()); + assertEquals(1, newMsg.getOptionalGroup().getA()); + } + + public void testMicroOptionalNestedMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + TestAllTypesMicro.NestedMessage nestedMsg = new TestAllTypesMicro.NestedMessage(); + nestedMsg.setBb(1); + assertFalse(msg.hasOptionalNestedMessage()); + msg.setOptionalNestedMessage(nestedMsg); + assertTrue(msg.hasOptionalNestedMessage()); + assertEquals(1, msg.getOptionalNestedMessage().getBb()); + msg.clearOptionalNestedMessage(); + assertFalse(msg.hasOptionalNestedMessage()); + msg.clearOptionalNestedMessage() + .setOptionalNestedMessage(new TestAllTypesMicro.NestedMessage().setBb(2)); + assertTrue(msg.hasOptionalNestedMessage()); + msg.clear(); + assertFalse(msg.hasOptionalNestedMessage()); + + msg.setOptionalNestedMessage(nestedMsg); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalNestedMessage()); + assertEquals(1, newMsg.getOptionalNestedMessage().getBb()); + } + + public void testMicroOptionalForeignMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + MicroOuterClass.ForeignMessageMicro foreignMsg = + new MicroOuterClass.ForeignMessageMicro(); + assertFalse(foreignMsg.hasC()); + foreignMsg.setC(1); + assertTrue(foreignMsg.hasC()); + assertFalse(msg.hasOptionalForeignMessage()); + msg.setOptionalForeignMessage(foreignMsg); + assertTrue(msg.hasOptionalForeignMessage()); + assertEquals(1, msg.getOptionalForeignMessage().getC()); + msg.clearOptionalForeignMessage(); + assertFalse(msg.hasOptionalForeignMessage()); + msg.clearOptionalForeignMessage() + .setOptionalForeignMessage(new MicroOuterClass.ForeignMessageMicro().setC(2)); + assertTrue(msg.hasOptionalForeignMessage()); + msg.clear(); + assertFalse(msg.hasOptionalForeignMessage()); + + msg.setOptionalForeignMessage(foreignMsg); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalForeignMessage()); + assertEquals(1, newMsg.getOptionalForeignMessage().getC()); + } + + public void testMicroOptionalImportMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + UnittestImportMicro.ImportMessageMicro importMsg = + new UnittestImportMicro.ImportMessageMicro(); + assertFalse(importMsg.hasD()); + importMsg.setD(1); + assertTrue(importMsg.hasD()); + assertFalse(msg.hasOptionalImportMessage()); + msg.setOptionalImportMessage(importMsg); + assertTrue(msg.hasOptionalImportMessage()); + assertEquals(1, msg.getOptionalImportMessage().getD()); + msg.clearOptionalImportMessage(); + assertFalse(msg.hasOptionalImportMessage()); + msg.clearOptionalImportMessage() + .setOptionalImportMessage(new UnittestImportMicro.ImportMessageMicro().setD(2)); + assertTrue(msg.hasOptionalImportMessage()); + msg.clear(); + assertFalse(msg.hasOptionalImportMessage()); + + msg.setOptionalImportMessage(importMsg); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalImportMessage()); + assertEquals(1, newMsg.getOptionalImportMessage().getD()); + } + + public void testMicroOptionalNestedEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.setOptionalNestedEnum(TestAllTypesMicro.BAR); + assertTrue(msg.hasOptionalNestedEnum()); + assertEquals(TestAllTypesMicro.BAR, msg.getOptionalNestedEnum()); + msg.clearOptionalNestedEnum(); + assertFalse(msg.hasOptionalNestedEnum()); + msg.clearOptionalNestedEnum() + .setOptionalNestedEnum(TestAllTypesMicro.BAZ); + assertTrue(msg.hasOptionalNestedEnum()); + msg.clear(); + assertFalse(msg.hasOptionalNestedEnum()); + + msg.setOptionalNestedEnum(TestAllTypesMicro.BAR); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalNestedEnum()); + assertEquals(TestAllTypesMicro.BAR, newMsg.getOptionalNestedEnum()); + } + + public void testMicroOptionalForeignEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR); + assertTrue(msg.hasOptionalForeignEnum()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, + msg.getOptionalForeignEnum()); + msg.clearOptionalForeignEnum(); + assertFalse(msg.hasOptionalForeignEnum()); + msg.clearOptionalForeignEnum() + .setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAZ); + assertTrue(msg.hasOptionalForeignEnum()); + msg.clear(); + assertFalse(msg.hasOptionalForeignEnum()); + + msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalForeignEnum()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, + newMsg.getOptionalForeignEnum()); + } + + public void testMicroOptionalImportEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR); + assertTrue(msg.hasOptionalImportEnum()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, + msg.getOptionalImportEnum()); + msg.clearOptionalImportEnum(); + assertFalse(msg.hasOptionalImportEnum()); + msg.clearOptionalImportEnum() + .setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAZ); + assertTrue(msg.hasOptionalImportEnum()); + msg.clear(); + assertFalse(msg.hasOptionalImportEnum()); + + msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalImportEnum()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, + newMsg.getOptionalImportEnum()); + } + + public void testMicroOptionalStringPiece() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalStringPiece()); + msg.setOptionalStringPiece("hello"); + assertTrue(msg.hasOptionalStringPiece()); + assertEquals("hello", msg.getOptionalStringPiece()); + msg.clearOptionalStringPiece(); + assertFalse(msg.hasOptionalStringPiece()); + msg.clearOptionalStringPiece() + .setOptionalStringPiece("hello"); + assertTrue(msg.hasOptionalStringPiece()); + msg.clear(); + assertFalse(msg.hasOptionalStringPiece()); + + msg.setOptionalStringPiece("bye"); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalStringPiece()); + assertEquals("bye", newMsg.getOptionalStringPiece()); + } + + public void testMicroOptionalCord() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasOptionalCord()); + msg.setOptionalCord("hello"); + assertTrue(msg.hasOptionalCord()); + assertEquals("hello", msg.getOptionalCord()); + msg.clearOptionalCord(); + assertFalse(msg.hasOptionalCord()); + msg.clearOptionalCord() + .setOptionalCord("hello"); + assertTrue(msg.hasOptionalCord()); + msg.clear(); + assertFalse(msg.hasOptionalCord()); + + msg.setOptionalCord("bye"); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertTrue(newMsg.hasOptionalCord()); + assertEquals("bye", newMsg.getOptionalCord()); + } + + public void testMicroRepeatedInt32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedInt32Count()); + msg.addRepeatedInt32(123); + assertEquals(1, msg.getRepeatedInt32Count()); + assertEquals(123, msg.getRepeatedInt32(0)); + msg.addRepeatedInt32(456); + assertEquals(2, msg.getRepeatedInt32Count()); + assertEquals(123, msg.getRepeatedInt32(0)); + assertEquals(456, msg.getRepeatedInt32(1)); + msg.setRepeatedInt32(0, 789); + assertEquals(2, msg.getRepeatedInt32Count()); + assertEquals(789, msg.getRepeatedInt32(0)); + assertEquals(456, msg.getRepeatedInt32(1)); + msg.clearRepeatedInt32(); + assertEquals(0, msg.getRepeatedInt32Count()); + msg.clearRepeatedInt32() + .addRepeatedInt32(456); + assertEquals(1, msg.getRepeatedInt32Count()); + assertEquals(456, msg.getRepeatedInt32(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedInt32Count()); + + // Test 1 entry + msg.clear() + .addRepeatedInt32(123); + assertEquals(1, msg.getRepeatedInt32Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedInt32Count()); + assertEquals(123, newMsg.getRepeatedInt32(0)); + + // Test 2 entries + msg.clear() + .addRepeatedInt32(123) + .addRepeatedInt32(456); + assertEquals(2, msg.getRepeatedInt32Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedInt32Count()); + assertEquals(123, newMsg.getRepeatedInt32(0)); + assertEquals(456, newMsg.getRepeatedInt32(1)); + } + + public void testMicroRepeatedInt64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedInt64Count()); + msg.addRepeatedInt64(123); + assertEquals(1, msg.getRepeatedInt64Count()); + assertEquals(123, msg.getRepeatedInt64(0)); + msg.addRepeatedInt64(456); + assertEquals(2, msg.getRepeatedInt64Count()); + assertEquals(123, msg.getRepeatedInt64(0)); + assertEquals(456, msg.getRepeatedInt64(1)); + msg.setRepeatedInt64(0, 789); + assertEquals(2, msg.getRepeatedInt64Count()); + assertEquals(789, msg.getRepeatedInt64(0)); + assertEquals(456, msg.getRepeatedInt64(1)); + msg.clearRepeatedInt64(); + assertEquals(0, msg.getRepeatedInt64Count()); + msg.clearRepeatedInt64() + .addRepeatedInt64(456); + assertEquals(1, msg.getRepeatedInt64Count()); + assertEquals(456, msg.getRepeatedInt64(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedInt64Count()); + + // Test 1 entry + msg.clear() + .addRepeatedInt64(123); + assertEquals(1, msg.getRepeatedInt64Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedInt64Count()); + assertEquals(123, newMsg.getRepeatedInt64(0)); + + // Test 2 entries + msg.clear() + .addRepeatedInt64(123) + .addRepeatedInt64(456); + assertEquals(2, msg.getRepeatedInt64Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedInt64Count()); + assertEquals(123, newMsg.getRepeatedInt64(0)); + assertEquals(456, newMsg.getRepeatedInt64(1)); + } + + public void testMicroRepeatedUint32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedUint32Count()); + msg.addRepeatedUint32(123); + assertEquals(1, msg.getRepeatedUint32Count()); + assertEquals(123, msg.getRepeatedUint32(0)); + msg.addRepeatedUint32(456); + assertEquals(2, msg.getRepeatedUint32Count()); + assertEquals(123, msg.getRepeatedUint32(0)); + assertEquals(456, msg.getRepeatedUint32(1)); + msg.setRepeatedUint32(0, 789); + assertEquals(2, msg.getRepeatedUint32Count()); + assertEquals(789, msg.getRepeatedUint32(0)); + assertEquals(456, msg.getRepeatedUint32(1)); + msg.clearRepeatedUint32(); + assertEquals(0, msg.getRepeatedUint32Count()); + msg.clearRepeatedUint32() + .addRepeatedUint32(456); + assertEquals(1, msg.getRepeatedUint32Count()); + assertEquals(456, msg.getRepeatedUint32(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedUint32Count()); + + // Test 1 entry + msg.clear() + .addRepeatedUint32(123); + assertEquals(1, msg.getRepeatedUint32Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedUint32Count()); + assertEquals(123, newMsg.getRepeatedUint32(0)); + + // Test 2 entries + msg.clear() + .addRepeatedUint32(123) + .addRepeatedUint32(456); + assertEquals(2, msg.getRepeatedUint32Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedUint32Count()); + assertEquals(123, newMsg.getRepeatedUint32(0)); + assertEquals(456, newMsg.getRepeatedUint32(1)); + } + + public void testMicroRepeatedUint64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedUint64Count()); + msg.addRepeatedUint64(123); + assertEquals(1, msg.getRepeatedUint64Count()); + assertEquals(123, msg.getRepeatedUint64(0)); + msg.addRepeatedUint64(456); + assertEquals(2, msg.getRepeatedUint64Count()); + assertEquals(123, msg.getRepeatedUint64(0)); + assertEquals(456, msg.getRepeatedUint64(1)); + msg.setRepeatedUint64(0, 789); + assertEquals(2, msg.getRepeatedUint64Count()); + assertEquals(789, msg.getRepeatedUint64(0)); + assertEquals(456, msg.getRepeatedUint64(1)); + msg.clearRepeatedUint64(); + assertEquals(0, msg.getRepeatedUint64Count()); + msg.clearRepeatedUint64() + .addRepeatedUint64(456); + assertEquals(1, msg.getRepeatedUint64Count()); + assertEquals(456, msg.getRepeatedUint64(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedUint64Count()); + + // Test 1 entry + msg.clear() + .addRepeatedUint64(123); + assertEquals(1, msg.getRepeatedUint64Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedUint64Count()); + assertEquals(123, newMsg.getRepeatedUint64(0)); + + // Test 2 entries + msg.clear() + .addRepeatedUint64(123) + .addRepeatedUint64(456); + assertEquals(2, msg.getRepeatedUint64Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedUint64Count()); + assertEquals(123, newMsg.getRepeatedUint64(0)); + assertEquals(456, newMsg.getRepeatedUint64(1)); + } + + public void testMicroRepeatedSint32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedSint32Count()); + msg.addRepeatedSint32(123); + assertEquals(1, msg.getRepeatedSint32Count()); + assertEquals(123, msg.getRepeatedSint32(0)); + msg.addRepeatedSint32(456); + assertEquals(2, msg.getRepeatedSint32Count()); + assertEquals(123, msg.getRepeatedSint32(0)); + assertEquals(456, msg.getRepeatedSint32(1)); + msg.setRepeatedSint32(0, 789); + assertEquals(2, msg.getRepeatedSint32Count()); + assertEquals(789, msg.getRepeatedSint32(0)); + assertEquals(456, msg.getRepeatedSint32(1)); + msg.clearRepeatedSint32(); + assertEquals(0, msg.getRepeatedSint32Count()); + msg.clearRepeatedSint32() + .addRepeatedSint32(456); + assertEquals(1, msg.getRepeatedSint32Count()); + assertEquals(456, msg.getRepeatedSint32(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedSint32Count()); + + // Test 1 entry + msg.clear() + .addRepeatedSint32(123); + assertEquals(1, msg.getRepeatedSint32Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 4); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedSint32Count()); + assertEquals(123, newMsg.getRepeatedSint32(0)); + + // Test 2 entries + msg.clear() + .addRepeatedSint32(123) + .addRepeatedSint32(456); + assertEquals(2, msg.getRepeatedSint32Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedSint32Count()); + assertEquals(123, newMsg.getRepeatedSint32(0)); + assertEquals(456, newMsg.getRepeatedSint32(1)); + } + + public void testMicroRepeatedSint64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedSint64Count()); + msg.addRepeatedSint64(123); + assertEquals(1, msg.getRepeatedSint64Count()); + assertEquals(123, msg.getRepeatedSint64(0)); + msg.addRepeatedSint64(456); + assertEquals(2, msg.getRepeatedSint64Count()); + assertEquals(123, msg.getRepeatedSint64(0)); + assertEquals(456, msg.getRepeatedSint64(1)); + msg.setRepeatedSint64(0, 789); + assertEquals(2, msg.getRepeatedSint64Count()); + assertEquals(789, msg.getRepeatedSint64(0)); + assertEquals(456, msg.getRepeatedSint64(1)); + msg.clearRepeatedSint64(); + assertEquals(0, msg.getRepeatedSint64Count()); + msg.clearRepeatedSint64() + .addRepeatedSint64(456); + assertEquals(1, msg.getRepeatedSint64Count()); + assertEquals(456, msg.getRepeatedSint64(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedSint64Count()); + + // Test 1 entry + msg.clear() + .addRepeatedSint64(123); + assertEquals(1, msg.getRepeatedSint64Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 4); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedSint64Count()); + assertEquals(123, newMsg.getRepeatedSint64(0)); + + // Test 2 entries + msg.clear() + .addRepeatedSint64(123) + .addRepeatedSint64(456); + assertEquals(2, msg.getRepeatedSint64Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedSint64Count()); + assertEquals(123, newMsg.getRepeatedSint64(0)); + assertEquals(456, newMsg.getRepeatedSint64(1)); + } + + public void testMicroRepeatedFixed32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedFixed32Count()); + msg.addRepeatedFixed32(123); + assertEquals(1, msg.getRepeatedFixed32Count()); + assertEquals(123, msg.getRepeatedFixed32(0)); + msg.addRepeatedFixed32(456); + assertEquals(2, msg.getRepeatedFixed32Count()); + assertEquals(123, msg.getRepeatedFixed32(0)); + assertEquals(456, msg.getRepeatedFixed32(1)); + msg.setRepeatedFixed32(0, 789); + assertEquals(2, msg.getRepeatedFixed32Count()); + assertEquals(789, msg.getRepeatedFixed32(0)); + assertEquals(456, msg.getRepeatedFixed32(1)); + msg.clearRepeatedFixed32(); + assertEquals(0, msg.getRepeatedFixed32Count()); + msg.clearRepeatedFixed32() + .addRepeatedFixed32(456); + assertEquals(1, msg.getRepeatedFixed32Count()); + assertEquals(456, msg.getRepeatedFixed32(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedFixed32Count()); + + // Test 1 entry + msg.clear() + .addRepeatedFixed32(123); + assertEquals(1, msg.getRepeatedFixed32Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedFixed32Count()); + assertEquals(123, newMsg.getRepeatedFixed32(0)); + + // Test 2 entries + msg.clear() + .addRepeatedFixed32(123) + .addRepeatedFixed32(456); + assertEquals(2, msg.getRepeatedFixed32Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedFixed32Count()); + assertEquals(123, newMsg.getRepeatedFixed32(0)); + assertEquals(456, newMsg.getRepeatedFixed32(1)); + } + + public void testMicroRepeatedFixed64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedFixed64Count()); + msg.addRepeatedFixed64(123); + assertEquals(1, msg.getRepeatedFixed64Count()); + assertEquals(123, msg.getRepeatedFixed64(0)); + msg.addRepeatedFixed64(456); + assertEquals(2, msg.getRepeatedFixed64Count()); + assertEquals(123, msg.getRepeatedFixed64(0)); + assertEquals(456, msg.getRepeatedFixed64(1)); + msg.setRepeatedFixed64(0, 789); + assertEquals(2, msg.getRepeatedFixed64Count()); + assertEquals(789, msg.getRepeatedFixed64(0)); + assertEquals(456, msg.getRepeatedFixed64(1)); + msg.clearRepeatedFixed64(); + assertEquals(0, msg.getRepeatedFixed64Count()); + msg.clearRepeatedFixed64() + .addRepeatedFixed64(456); + assertEquals(1, msg.getRepeatedFixed64Count()); + assertEquals(456, msg.getRepeatedFixed64(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedFixed64Count()); + + // Test 1 entry + msg.clear() + .addRepeatedFixed64(123); + assertEquals(1, msg.getRepeatedFixed64Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedFixed64Count()); + assertEquals(123, newMsg.getRepeatedFixed64(0)); + + // Test 2 entries + msg.clear() + .addRepeatedFixed64(123) + .addRepeatedFixed64(456); + assertEquals(2, msg.getRepeatedFixed64Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 20); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedFixed64Count()); + assertEquals(123, newMsg.getRepeatedFixed64(0)); + assertEquals(456, newMsg.getRepeatedFixed64(1)); + } + + public void testMicroRepeatedSfixed32() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedSfixed32Count()); + msg.addRepeatedSfixed32(123); + assertEquals(1, msg.getRepeatedSfixed32Count()); + assertEquals(123, msg.getRepeatedSfixed32(0)); + msg.addRepeatedSfixed32(456); + assertEquals(2, msg.getRepeatedSfixed32Count()); + assertEquals(123, msg.getRepeatedSfixed32(0)); + assertEquals(456, msg.getRepeatedSfixed32(1)); + msg.setRepeatedSfixed32(0, 789); + assertEquals(2, msg.getRepeatedSfixed32Count()); + assertEquals(789, msg.getRepeatedSfixed32(0)); + assertEquals(456, msg.getRepeatedSfixed32(1)); + msg.clearRepeatedSfixed32(); + assertEquals(0, msg.getRepeatedSfixed32Count()); + msg.clearRepeatedSfixed32() + .addRepeatedSfixed32(456); + assertEquals(1, msg.getRepeatedSfixed32Count()); + assertEquals(456, msg.getRepeatedSfixed32(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedSfixed32Count()); + + // Test 1 entry + msg.clear() + .addRepeatedSfixed32(123); + assertEquals(1, msg.getRepeatedSfixed32Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedSfixed32Count()); + assertEquals(123, newMsg.getRepeatedSfixed32(0)); + + // Test 2 entries + msg.clear() + .addRepeatedSfixed32(123) + .addRepeatedSfixed32(456); + assertEquals(2, msg.getRepeatedSfixed32Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedSfixed32Count()); + assertEquals(123, newMsg.getRepeatedSfixed32(0)); + assertEquals(456, newMsg.getRepeatedSfixed32(1)); + } + + public void testMicroRepeatedSfixed64() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedSfixed64Count()); + msg.addRepeatedSfixed64(123); + assertEquals(1, msg.getRepeatedSfixed64Count()); + assertEquals(123, msg.getRepeatedSfixed64(0)); + msg.addRepeatedSfixed64(456); + assertEquals(2, msg.getRepeatedSfixed64Count()); + assertEquals(123, msg.getRepeatedSfixed64(0)); + assertEquals(456, msg.getRepeatedSfixed64(1)); + msg.setRepeatedSfixed64(0, 789); + assertEquals(2, msg.getRepeatedSfixed64Count()); + assertEquals(789, msg.getRepeatedSfixed64(0)); + assertEquals(456, msg.getRepeatedSfixed64(1)); + msg.clearRepeatedSfixed64(); + assertEquals(0, msg.getRepeatedSfixed64Count()); + msg.clearRepeatedSfixed64() + .addRepeatedSfixed64(456); + assertEquals(1, msg.getRepeatedSfixed64Count()); + assertEquals(456, msg.getRepeatedSfixed64(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedSfixed64Count()); + + // Test 1 entry + msg.clear() + .addRepeatedSfixed64(123); + assertEquals(1, msg.getRepeatedSfixed64Count()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedSfixed64Count()); + assertEquals(123, newMsg.getRepeatedSfixed64(0)); + + // Test 2 entries + msg.clear() + .addRepeatedSfixed64(123) + .addRepeatedSfixed64(456); + assertEquals(2, msg.getRepeatedSfixed64Count()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 20); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedSfixed64Count()); + assertEquals(123, newMsg.getRepeatedSfixed64(0)); + assertEquals(456, newMsg.getRepeatedSfixed64(1)); + } + + public void testMicroRepeatedFloat() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedFloatCount()); + msg.addRepeatedFloat(123f); + assertEquals(1, msg.getRepeatedFloatCount()); + assertTrue(123f == msg.getRepeatedFloat(0)); + msg.addRepeatedFloat(456f); + assertEquals(2, msg.getRepeatedFloatCount()); + assertTrue(123f == msg.getRepeatedFloat(0)); + assertTrue(456f == msg.getRepeatedFloat(1)); + msg.setRepeatedFloat(0, 789f); + assertEquals(2, msg.getRepeatedFloatCount()); + assertTrue(789f == msg.getRepeatedFloat(0)); + assertTrue(456f == msg.getRepeatedFloat(1)); + msg.clearRepeatedFloat(); + assertEquals(0, msg.getRepeatedFloatCount()); + msg.clearRepeatedFloat() + .addRepeatedFloat(456f); + assertEquals(1, msg.getRepeatedFloatCount()); + assertTrue(456f == msg.getRepeatedFloat(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedFloatCount()); + + // Test 1 entry + msg.clear() + .addRepeatedFloat(123f); + assertEquals(1, msg.getRepeatedFloatCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedFloatCount()); + assertTrue(123f == newMsg.getRepeatedFloat(0)); + + // Test 2 entries + msg.clear() + .addRepeatedFloat(123f) + .addRepeatedFloat(456f); + assertEquals(2, msg.getRepeatedFloatCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedFloatCount()); + assertTrue(123f == newMsg.getRepeatedFloat(0)); + assertTrue(456f == newMsg.getRepeatedFloat(1)); + } + + public void testMicroRepeatedDouble() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedDoubleCount()); + msg.addRepeatedDouble(123.0); + assertEquals(1, msg.getRepeatedDoubleCount()); + assertTrue(123.0 == msg.getRepeatedDouble(0)); + msg.addRepeatedDouble(456.0); + assertEquals(2, msg.getRepeatedDoubleCount()); + assertTrue(123.0 == msg.getRepeatedDouble(0)); + assertTrue(456.0 == msg.getRepeatedDouble(1)); + msg.setRepeatedDouble(0, 789.0); + assertEquals(2, msg.getRepeatedDoubleCount()); + assertTrue(789.0 == msg.getRepeatedDouble(0)); + assertTrue(456.0 == msg.getRepeatedDouble(1)); + msg.clearRepeatedDouble(); + assertEquals(0, msg.getRepeatedDoubleCount()); + msg.clearRepeatedDouble() + .addRepeatedDouble(456.0); + assertEquals(1, msg.getRepeatedDoubleCount()); + assertTrue(456.0 == msg.getRepeatedDouble(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedDoubleCount()); + + // Test 1 entry + msg.clear() + .addRepeatedDouble(123.0); + assertEquals(1, msg.getRepeatedDoubleCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedDoubleCount()); + assertTrue(123.0 == newMsg.getRepeatedDouble(0)); + + // Test 2 entries + msg.clear() + .addRepeatedDouble(123.0) + .addRepeatedDouble(456.0); + assertEquals(2, msg.getRepeatedDoubleCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 20); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedDoubleCount()); + assertTrue(123.0 == newMsg.getRepeatedDouble(0)); + assertTrue(456.0 == newMsg.getRepeatedDouble(1)); + } + + public void testMicroRepeatedBool() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedBoolCount()); + msg.addRepeatedBool(true); + assertEquals(1, msg.getRepeatedBoolCount()); + assertEquals(true, msg.getRepeatedBool(0)); + msg.addRepeatedBool(false); + assertEquals(2, msg.getRepeatedBoolCount()); + assertEquals(true, msg.getRepeatedBool(0)); + assertEquals(false, msg.getRepeatedBool(1)); + msg.setRepeatedBool(0, false); + assertEquals(2, msg.getRepeatedBoolCount()); + assertEquals(false, msg.getRepeatedBool(0)); + assertEquals(false, msg.getRepeatedBool(1)); + msg.clearRepeatedBool(); + assertEquals(0, msg.getRepeatedBoolCount()); + msg.clearRepeatedBool() + .addRepeatedBool(true); + assertEquals(1, msg.getRepeatedBoolCount()); + assertEquals(true, msg.getRepeatedBool(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedBoolCount()); + + // Test 1 entry + msg.clear() + .addRepeatedBool(false); + assertEquals(1, msg.getRepeatedBoolCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedBoolCount()); + assertEquals(false, newMsg.getRepeatedBool(0)); + + // Test 2 entries + msg.clear() + .addRepeatedBool(true) + .addRepeatedBool(false); + assertEquals(2, msg.getRepeatedBoolCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedBoolCount()); + assertEquals(true, newMsg.getRepeatedBool(0)); + assertEquals(false, newMsg.getRepeatedBool(1)); + } + + public void testMicroRepeatedString() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedStringCount()); + msg.addRepeatedString("hello"); + assertEquals(1, msg.getRepeatedStringCount()); + assertEquals("hello", msg.getRepeatedString(0)); + msg.addRepeatedString("bye"); + assertEquals(2, msg.getRepeatedStringCount()); + assertEquals("hello", msg.getRepeatedString(0)); + assertEquals("bye", msg.getRepeatedString(1)); + msg.setRepeatedString(0, "boo"); + assertEquals(2, msg.getRepeatedStringCount()); + assertEquals("boo", msg.getRepeatedString(0)); + assertEquals("bye", msg.getRepeatedString(1)); + msg.clearRepeatedString(); + assertEquals(0, msg.getRepeatedStringCount()); + msg.clearRepeatedString() + .addRepeatedString("hello"); + assertEquals(1, msg.getRepeatedStringCount()); + assertEquals("hello", msg.getRepeatedString(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedStringCount()); + + // Test 1 entry and an empty string + msg.clear() + .addRepeatedString(""); + assertEquals(1, msg.getRepeatedStringCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedStringCount()); + assertEquals("", newMsg.getRepeatedString(0)); + + // Test 2 entries + msg.clear() + .addRepeatedString("hello") + .addRepeatedString("world"); + assertEquals(2, msg.getRepeatedStringCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedStringCount()); + assertEquals("hello", newMsg.getRepeatedString(0)); + assertEquals("world", newMsg.getRepeatedString(1)); + } + + public void testMicroRepeatedBytes() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedBytesCount()); + msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello")); + assertEquals(1, msg.getRepeatedBytesCount()); + assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8()); + msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("bye")); + assertEquals(2, msg.getRepeatedBytesCount()); + assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8()); + assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8()); + msg.setRepeatedBytes(0, ByteStringMicro.copyFromUtf8("boo")); + assertEquals(2, msg.getRepeatedBytesCount()); + assertEquals("boo", msg.getRepeatedBytes(0).toStringUtf8()); + assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8()); + msg.clearRepeatedBytes(); + assertEquals(0, msg.getRepeatedBytesCount()); + msg.clearRepeatedBytes() + .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello")); + assertEquals(1, msg.getRepeatedBytesCount()); + assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8()); + msg.clear(); + assertEquals(0, msg.getRepeatedBytesCount()); + + // Test 1 entry and an empty byte array can be serialized + msg.clear() + .addRepeatedBytes(ByteStringMicro.copyFromUtf8("")); + assertEquals(1, msg.getRepeatedBytesCount()); + assertEquals("", msg.getRepeatedBytes(0).toStringUtf8()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedBytesCount()); + assertEquals("", newMsg.getRepeatedBytes(0).toStringUtf8()); + + // Test 2 entries + msg.clear() + .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello")) + .addRepeatedBytes(ByteStringMicro.copyFromUtf8("world")); + assertEquals(2, msg.getRepeatedBytesCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedBytesCount()); + assertEquals("hello", newMsg.getRepeatedBytes(0).toStringUtf8()); + assertEquals("world", newMsg.getRepeatedBytes(1).toStringUtf8()); + } + + public void testMicroRepeatedGroup() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + TestAllTypesMicro.RepeatedGroup group0 = + new TestAllTypesMicro.RepeatedGroup().setA(0); + TestAllTypesMicro.RepeatedGroup group1 = + new TestAllTypesMicro.RepeatedGroup().setA(1); + TestAllTypesMicro.RepeatedGroup group2 = + new TestAllTypesMicro.RepeatedGroup().setA(2); + + msg.addRepeatedGroup(group0); + assertEquals(1, msg.getRepeatedGroupCount()); + assertEquals(0, msg.getRepeatedGroup(0).getA()); + msg.addRepeatedGroup(group1); + assertEquals(2, msg.getRepeatedGroupCount()); + assertEquals(0, msg.getRepeatedGroup(0).getA()); + assertEquals(1, msg.getRepeatedGroup(1).getA()); + msg.setRepeatedGroup(0, group2); + assertEquals(2, msg.getRepeatedGroupCount()); + assertEquals(2, msg.getRepeatedGroup(0).getA()); + assertEquals(1, msg.getRepeatedGroup(1).getA()); + msg.clearRepeatedGroup(); + assertEquals(0, msg.getRepeatedGroupCount()); + msg.clearRepeatedGroup() + .addRepeatedGroup(group1); + assertEquals(1, msg.getRepeatedGroupCount()); + assertEquals(1, msg.getRepeatedGroup(0).getA()); + msg.clear(); + assertEquals(0, msg.getRepeatedGroupCount()); + + // Test 1 entry + msg.clear() + .addRepeatedGroup(group0); + assertEquals(1, msg.getRepeatedGroupCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedGroupCount()); + assertEquals(0, newMsg.getRepeatedGroup(0).getA()); + + // Test 2 entries + msg.clear() + .addRepeatedGroup(group0) + .addRepeatedGroup(group1); + assertEquals(2, msg.getRepeatedGroupCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 14); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedGroupCount()); + assertEquals(0, newMsg.getRepeatedGroup(0).getA()); + assertEquals(1, newMsg.getRepeatedGroup(1).getA()); + } + + + public void testMicroRepeatedNestedMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + TestAllTypesMicro.NestedMessage nestedMsg0 = + new TestAllTypesMicro.NestedMessage().setBb(0); + TestAllTypesMicro.NestedMessage nestedMsg1 = + new TestAllTypesMicro.NestedMessage().setBb(1); + TestAllTypesMicro.NestedMessage nestedMsg2 = + new TestAllTypesMicro.NestedMessage().setBb(2); + + msg.addRepeatedNestedMessage(nestedMsg0); + assertEquals(1, msg.getRepeatedNestedMessageCount()); + assertEquals(0, msg.getRepeatedNestedMessage(0).getBb()); + msg.addRepeatedNestedMessage(nestedMsg1); + assertEquals(2, msg.getRepeatedNestedMessageCount()); + assertEquals(0, msg.getRepeatedNestedMessage(0).getBb()); + assertEquals(1, msg.getRepeatedNestedMessage(1).getBb()); + msg.setRepeatedNestedMessage(0, nestedMsg2); + assertEquals(2, msg.getRepeatedNestedMessageCount()); + assertEquals(2, msg.getRepeatedNestedMessage(0).getBb()); + assertEquals(1, msg.getRepeatedNestedMessage(1).getBb()); + msg.clearRepeatedNestedMessage(); + assertEquals(0, msg.getRepeatedNestedMessageCount()); + msg.clearRepeatedNestedMessage() + .addRepeatedNestedMessage(nestedMsg1); + assertEquals(1, msg.getRepeatedNestedMessageCount()); + assertEquals(1, msg.getRepeatedNestedMessage(0).getBb()); + msg.clear(); + assertEquals(0, msg.getRepeatedNestedMessageCount()); + + // Test 1 entry + msg.clear() + .addRepeatedNestedMessage(nestedMsg0); + assertEquals(1, msg.getRepeatedNestedMessageCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedNestedMessageCount()); + assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb()); + + // Test 2 entries + msg.clear() + .addRepeatedNestedMessage(nestedMsg0) + .addRepeatedNestedMessage(nestedMsg1); + assertEquals(2, msg.getRepeatedNestedMessageCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedNestedMessageCount()); + assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb()); + assertEquals(1, newMsg.getRepeatedNestedMessage(1).getBb()); + } + + public void testMicroRepeatedForeignMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + MicroOuterClass.ForeignMessageMicro foreignMsg0 = + new MicroOuterClass.ForeignMessageMicro().setC(0); + MicroOuterClass.ForeignMessageMicro foreignMsg1 = + new MicroOuterClass.ForeignMessageMicro().setC(1); + MicroOuterClass.ForeignMessageMicro foreignMsg2 = + new MicroOuterClass.ForeignMessageMicro().setC(2); + + msg.addRepeatedForeignMessage(foreignMsg0); + assertEquals(1, msg.getRepeatedForeignMessageCount()); + assertEquals(0, msg.getRepeatedForeignMessage(0).getC()); + msg.addRepeatedForeignMessage(foreignMsg1); + assertEquals(2, msg.getRepeatedForeignMessageCount()); + assertEquals(0, msg.getRepeatedForeignMessage(0).getC()); + assertEquals(1, msg.getRepeatedForeignMessage(1).getC()); + msg.setRepeatedForeignMessage(0, foreignMsg2); + assertEquals(2, msg.getRepeatedForeignMessageCount()); + assertEquals(2, msg.getRepeatedForeignMessage(0).getC()); + assertEquals(1, msg.getRepeatedForeignMessage(1).getC()); + msg.clearRepeatedForeignMessage(); + assertEquals(0, msg.getRepeatedForeignMessageCount()); + msg.clearRepeatedForeignMessage() + .addRepeatedForeignMessage(foreignMsg1); + assertEquals(1, msg.getRepeatedForeignMessageCount()); + assertEquals(1, msg.getRepeatedForeignMessage(0).getC()); + msg.clear(); + assertEquals(0, msg.getRepeatedForeignMessageCount()); + + // Test 1 entry + msg.clear() + .addRepeatedForeignMessage(foreignMsg0); + assertEquals(1, msg.getRepeatedForeignMessageCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedForeignMessageCount()); + assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC()); + + // Test 2 entries + msg.clear() + .addRepeatedForeignMessage(foreignMsg0) + .addRepeatedForeignMessage(foreignMsg1); + assertEquals(2, msg.getRepeatedForeignMessageCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedForeignMessageCount()); + assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC()); + assertEquals(1, newMsg.getRepeatedForeignMessage(1).getC()); + } + + public void testMicroRepeatedImportMessage() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + UnittestImportMicro.ImportMessageMicro importMsg0 = + new UnittestImportMicro.ImportMessageMicro().setD(0); + UnittestImportMicro.ImportMessageMicro importMsg1 = + new UnittestImportMicro.ImportMessageMicro().setD(1); + UnittestImportMicro.ImportMessageMicro importMsg2 = + new UnittestImportMicro.ImportMessageMicro().setD(2); + + msg.addRepeatedImportMessage(importMsg0); + assertEquals(1, msg.getRepeatedImportMessageCount()); + assertEquals(0, msg.getRepeatedImportMessage(0).getD()); + msg.addRepeatedImportMessage(importMsg1); + assertEquals(2, msg.getRepeatedImportMessageCount()); + assertEquals(0, msg.getRepeatedImportMessage(0).getD()); + assertEquals(1, msg.getRepeatedImportMessage(1).getD()); + msg.setRepeatedImportMessage(0, importMsg2); + assertEquals(2, msg.getRepeatedImportMessageCount()); + assertEquals(2, msg.getRepeatedImportMessage(0).getD()); + assertEquals(1, msg.getRepeatedImportMessage(1).getD()); + msg.clearRepeatedImportMessage(); + assertEquals(0, msg.getRepeatedImportMessageCount()); + msg.clearRepeatedImportMessage() + .addRepeatedImportMessage(importMsg1); + assertEquals(1, msg.getRepeatedImportMessageCount()); + assertEquals(1, msg.getRepeatedImportMessage(0).getD()); + msg.clear(); + assertEquals(0, msg.getRepeatedImportMessageCount()); + + // Test 1 entry + msg.clear() + .addRepeatedImportMessage(importMsg0); + assertEquals(1, msg.getRepeatedImportMessageCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedImportMessageCount()); + assertEquals(0, newMsg.getRepeatedImportMessage(0).getD()); + + // Test 2 entries + msg.clear() + .addRepeatedImportMessage(importMsg0) + .addRepeatedImportMessage(importMsg1); + assertEquals(2, msg.getRepeatedImportMessageCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedImportMessageCount()); + assertEquals(0, newMsg.getRepeatedImportMessage(0).getD()); + assertEquals(1, newMsg.getRepeatedImportMessage(1).getD()); + } + + public void testMicroRepeatedNestedEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.addRepeatedNestedEnum(TestAllTypesMicro.FOO); + assertEquals(1, msg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0)); + msg.addRepeatedNestedEnum(TestAllTypesMicro.BAR); + assertEquals(2, msg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1)); + msg.setRepeatedNestedEnum(0, TestAllTypesMicro.BAZ); + assertEquals(2, msg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.BAZ, msg.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1)); + msg.clearRepeatedNestedEnum(); + assertEquals(0, msg.getRepeatedNestedEnumCount()); + msg.clearRepeatedNestedEnum() + .addRepeatedNestedEnum(TestAllTypesMicro.BAR); + assertEquals(1, msg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedNestedEnumCount()); + + // Test 1 entry + msg.clear() + .addRepeatedNestedEnum(TestAllTypesMicro.FOO); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0)); + + // Test 2 entries + msg.clear() + .addRepeatedNestedEnum(TestAllTypesMicro.FOO) + .addRepeatedNestedEnum(TestAllTypesMicro.BAR); + assertEquals(2, msg.getRepeatedNestedEnumCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedNestedEnumCount()); + assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0)); + assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1)); + } + + public void testMicroRepeatedForeignEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO); + assertEquals(1, msg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0)); + msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR); + assertEquals(2, msg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0)); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1)); + msg.setRepeatedForeignEnum(0, MicroOuterClass.FOREIGN_MICRO_BAZ); + assertEquals(2, msg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAZ, msg.getRepeatedForeignEnum(0)); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1)); + msg.clearRepeatedForeignEnum(); + assertEquals(0, msg.getRepeatedForeignEnumCount()); + msg.clearRepeatedForeignEnum() + .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR); + assertEquals(1, msg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedForeignEnumCount()); + + // Test 1 entry + msg.clear() + .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0)); + + // Test 2 entries + msg.clear() + .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO) + .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR); + assertEquals(2, msg.getRepeatedForeignEnumCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedForeignEnumCount()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0)); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1)); + } + + public void testMicroRepeatedImportEnum() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO); + assertEquals(1, msg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0)); + msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR); + assertEquals(2, msg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0)); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1)); + msg.setRepeatedImportEnum(0, UnittestImportMicro.IMPORT_MICRO_BAZ); + assertEquals(2, msg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAZ, msg.getRepeatedImportEnum(0)); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1)); + msg.clearRepeatedImportEnum(); + assertEquals(0, msg.getRepeatedImportEnumCount()); + msg.clearRepeatedImportEnum() + .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR); + assertEquals(1, msg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedImportEnumCount()); + + // Test 1 entry + msg.clear() + .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0)); + + // Test 2 entries + msg.clear() + .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO) + .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR); + assertEquals(2, msg.getRepeatedImportEnumCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedImportEnumCount()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0)); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1)); + } + + public void testMicroRepeatedStringPiece() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedStringPieceCount()); + msg.addRepeatedStringPiece("hello"); + assertEquals(1, msg.getRepeatedStringPieceCount()); + assertEquals("hello", msg.getRepeatedStringPiece(0)); + msg.addRepeatedStringPiece("bye"); + assertEquals(2, msg.getRepeatedStringPieceCount()); + assertEquals("hello", msg.getRepeatedStringPiece(0)); + assertEquals("bye", msg.getRepeatedStringPiece(1)); + msg.setRepeatedStringPiece(0, "boo"); + assertEquals(2, msg.getRepeatedStringPieceCount()); + assertEquals("boo", msg.getRepeatedStringPiece(0)); + assertEquals("bye", msg.getRepeatedStringPiece(1)); + msg.clearRepeatedStringPiece(); + assertEquals(0, msg.getRepeatedStringPieceCount()); + msg.clearRepeatedStringPiece() + .addRepeatedStringPiece("hello"); + assertEquals(1, msg.getRepeatedStringPieceCount()); + assertEquals("hello", msg.getRepeatedStringPiece(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedStringPieceCount()); + + // Test 1 entry and an empty string + msg.clear() + .addRepeatedStringPiece(""); + assertEquals(1, msg.getRepeatedStringPieceCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedStringPieceCount()); + assertEquals("", newMsg.getRepeatedStringPiece(0)); + + // Test 2 entries + msg.clear() + .addRepeatedStringPiece("hello") + .addRepeatedStringPiece("world"); + assertEquals(2, msg.getRepeatedStringPieceCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedStringPieceCount()); + assertEquals("hello", newMsg.getRepeatedStringPiece(0)); + assertEquals("world", newMsg.getRepeatedStringPiece(1)); + } + + public void testMicroRepeatedCord() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertEquals(0, msg.getRepeatedCordCount()); + msg.addRepeatedCord("hello"); + assertEquals(1, msg.getRepeatedCordCount()); + assertEquals("hello", msg.getRepeatedCord(0)); + msg.addRepeatedCord("bye"); + assertEquals(2, msg.getRepeatedCordCount()); + assertEquals("hello", msg.getRepeatedCord(0)); + assertEquals("bye", msg.getRepeatedCord(1)); + msg.setRepeatedCord(0, "boo"); + assertEquals(2, msg.getRepeatedCordCount()); + assertEquals("boo", msg.getRepeatedCord(0)); + assertEquals("bye", msg.getRepeatedCord(1)); + msg.clearRepeatedCord(); + assertEquals(0, msg.getRepeatedCordCount()); + msg.clearRepeatedCord() + .addRepeatedCord("hello"); + assertEquals(1, msg.getRepeatedCordCount()); + assertEquals("hello", msg.getRepeatedCord(0)); + msg.clear(); + assertEquals(0, msg.getRepeatedCordCount()); + + // Test 1 entry and an empty string + msg.clear() + .addRepeatedCord(""); + assertEquals(1, msg.getRepeatedCordCount()); + byte [] result = msg.toByteArray(); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(1, newMsg.getRepeatedCordCount()); + assertEquals("", newMsg.getRepeatedCord(0)); + + // Test 2 entries + msg.clear() + .addRepeatedCord("hello") + .addRepeatedCord("world"); + assertEquals(2, msg.getRepeatedCordCount()); + result = msg.toByteArray(); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesMicro.parseFrom(result); + assertEquals(2, newMsg.getRepeatedCordCount()); + assertEquals("hello", newMsg.getRepeatedCord(0)); + assertEquals("world", newMsg.getRepeatedCord(1)); + } + + public void testMicroDefaults() throws Exception { + TestAllTypesMicro msg = new TestAllTypesMicro(); + assertFalse(msg.hasDefaultInt32()); + assertEquals(41, msg.getDefaultInt32()); + assertFalse(msg.hasDefaultInt64()); + assertEquals(42, msg.getDefaultInt64()); + assertFalse(msg.hasDefaultUint32()); + assertEquals(43, msg.getDefaultUint32()); + assertFalse(msg.hasDefaultUint64()); + assertEquals(44, msg.getDefaultUint64()); + assertFalse(msg.hasDefaultSint32()); + assertEquals(-45, msg.getDefaultSint32()); + assertFalse(msg.hasDefaultSint64()); + assertEquals(46, msg.getDefaultSint64()); + assertFalse(msg.hasDefaultFixed32()); + assertEquals(47, msg.getDefaultFixed32()); + assertFalse(msg.hasDefaultFixed64()); + assertEquals(48, msg.getDefaultFixed64()); + assertFalse(msg.hasDefaultSfixed32()); + assertEquals(49, msg.getDefaultSfixed32()); + assertFalse(msg.hasDefaultSfixed64()); + assertEquals(-50, msg.getDefaultSfixed64()); + assertFalse(msg.hasDefaultFloat()); + assertTrue(51.5f == msg.getDefaultFloat()); + assertFalse(msg.hasDefaultDouble()); + assertTrue(52.0e3 == msg.getDefaultDouble()); + assertFalse(msg.hasDefaultBool()); + assertEquals(true, msg.getDefaultBool()); + assertFalse(msg.hasDefaultString()); + assertEquals("hello", msg.getDefaultString()); + assertFalse(msg.hasDefaultBytes()); + assertEquals("world", msg.getDefaultBytes().toStringUtf8()); + assertFalse(msg.hasDefaultNestedEnum()); + assertEquals(TestAllTypesMicro.BAR, msg.getDefaultNestedEnum()); + assertFalse(msg.hasDefaultForeignEnum()); + assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getDefaultForeignEnum()); + assertFalse(msg.hasDefaultImportEnum()); + assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getDefaultImportEnum()); + } +} diff --git a/java/src/test/java/com/google/protobuf/PerfTimer.java b/java/src/test/java/com/google/protobuf/PerfTimer.java new file mode 100644 index 0000000..d6df4ff --- /dev/null +++ b/java/src/test/java/com/google/protobuf/PerfTimer.java @@ -0,0 +1,832 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.protobuf; + +import java.util.Arrays; + +/** + * A Performance Timing class that can be used to estimate the amount of time a + * sequence of code takes. The typical code sequence would be as follows:</p> + * <code> + PerfTimer pt = new PerfTimer(); + pt.calibrate(); + pt.timeEachAutomatically(new Runnable() = { + public void run() { + // Add code to time + } + }); + System.out.printf("time per loop=" + pt); + + * The calibrate method determines the overhead of timing the run() method and + * the number of times to call the run() method to have approximately 1% precision + * for timing. The method pt.stats() method will return a string containing some + * statistics tpl, il, ol, min, max, mean, median, stddev and total. + * + * tpl ::= Timer per loop + * min ::= minimum time one call to run() took + * stddev ::= Standard deviation of the collected times + * mean ::= the average time to call run() + * median ::= 1/2 the times were > than this time and 1/2 were less. + * total ::= Sum of the times collected. + * il ::= innerLoops; the number of times run() between each call to start/stop + * ol ::= outerLoops, the number of times start/stop was called + * + * You can also use start/stop/restart to do simple timing: + * + * pt.start(); + * a += 1; + * pt.stop(); + * pt.log("time=" + pt); + * pt.restart(); + * doSomething(); + * pt.stop(); + * System.out.printf("time=" + pt); + * </code> + * + * @author wink@google.com (Wink Saville) + */ +public class PerfTimer { + /** No debug */ + public static final int DEBUG_LEVEL_NONE = 0; + + /** Some debug */ + public static final int DEBUG_LEVEL_SOME = 1; + + /** All debug */ + public static final int DEBUG_LEVEL_ALL = 2; + + /** Timer ticks per microsecond */ + private static final double TICKS_PER_MICROSECOND = 1000.0; + + /** Random number generator */ + java.util.Random rng = new java.util.Random(); + + /** get ticks */ + private static long getTicks() { + return System.nanoTime(); + } + + /** Debug logging */ + private static void log(String s) { + System.out.printf(String.format("[PerfTimer] %s\n", s)); + } + + /** Outer loops for timeEachAutomatically */ + private static final int OUTER_LOOPS = 100; + + /** Thrown if an error occurs while timing */ + public static class PerfTimerException extends RuntimeException { + } + + /** + * Calibration record + */ + public static class CalibrationRec { + /** Runnable overhead */ + public double mRunnableOverheadInMicros = 0.0; + + /** Minimum Threshold value for timeEachAutomaticaly */ + public double mMinThresholdInMicros = 3000.0; + + /** Maximum Threshold value for timeEachAutomaticaly */ + public double mMaxThresholdInMicros = 6000.0; + + /** Desired precision in decimal digits */ + public double mPrecisionInDecimalDigits = 2.0; + + /** + * Default number of retries if the standard deviation ratio is too + * large + */ + public final int mStdDevRetrys = 5; + + /** Default maximum standard deviation radio */ + public final double mMaxStdDevRatio = 0.15; + + /** Number of votes looking for smallest time per loop */ + public final int mVotes = 3; + + /** Convert to string */ + @Override + public String toString() { + return String + .format( + "oh=%.6fus minT=%.6fus maxT=%.6fus prc=%,.3f stdDevRetrys=%d maxStdDevRatio=%.2f votes=%d", + mRunnableOverheadInMicros, mMinThresholdInMicros, + mMaxThresholdInMicros, mPrecisionInDecimalDigits, mStdDevRetrys, + mMaxStdDevRatio, mVotes); + } + } + + /** + * Calibration record + */ + private CalibrationRec mCr; + + /** + * Statistics calculated on the timing data. + */ + public static class Stats { + /** Number of outer loops */ + private int mOuterLoops; + + /** Number of inner loops */ + private int mInnerLoops; + + /** Minimum time in times array */ + private long mMin; + + /** Maximum time in times array */ + private long mMax; + + /** Median value in times array */ + private double mMedian; + + /** The mean (average) of the values in times array */ + private double mMean; + + /** The standard deviation of the values in times array */ + private double mStdDev; + + private int mStdDevTooLargeCount; + + /** Sum of the times in the times array */ + private double mTotal; + + /** Initialize */ + public void init() { + mInnerLoops = 1; + mOuterLoops = 1; + mMin = 0; + mMax = 0; + mMedian = 0; + mMean = 0; + mStdDev = 0; + mStdDevTooLargeCount = 0; + mTotal = 0; + } + + /** Constructor */ + public Stats() { + init(); + } + + /** Set number of inner loops */ + public void setInnerLoops(int loops) { + mInnerLoops = loops; + } + + /** Get number of inner loops */ + public int getInnerLoops() { + return mInnerLoops; + } + + /** Set number of inner loops */ + public void setOuterLoops(int loops) { + mOuterLoops = loops; + } + + /** Get number of inner loops */ + public int getOuterLoops() { + return mOuterLoops; + } + + /** + * Minimum value of collected data in microseconds, valid after analyze. + */ + public double getMinInMicros() { + return mMin / TICKS_PER_MICROSECOND; + } + + /** + * Maximum value of collected data in microseconds, valid after analyze. + */ + public double getMaxInMicros() { + return mMax / TICKS_PER_MICROSECOND; + } + + /** + * Sum of the values of collected data in microseconds, valid after + * analyze. + */ + public double getTotalInMicros() { + return mTotal / TICKS_PER_MICROSECOND; + } + + /** Sum of the values of collected data in seconds, valid after analyze. */ + public double getTotalInSecs() { + return mTotal / (TICKS_PER_MICROSECOND * 1000000.0); + } + + /** Sum of the values of collected data in seconds, valid after analyze. */ + public double getMeanInMicros() { + return mMean / TICKS_PER_MICROSECOND; + } + + /** Median value of collected data in microseconds, valid after analyze. */ + public double getMedianInMicros() { + return mMedian / TICKS_PER_MICROSECOND; + } + + /** + * Standard deviation of collected data in microseconds, valid after + * analyze. + */ + public double getStdDevInMicros() { + return mStdDev / TICKS_PER_MICROSECOND; + } + + public double getStdDevRatio() { + return mStdDev / mMin; + } + + /** Return true if (mStdDev / mMin) <= maxStdDevRation */ + public boolean stdDevOk(double maxStdDevRatio) { + return getStdDevRatio() <= maxStdDevRatio; + } + + /** Increment StdDevTooLargeCount */ + public void incStdDevTooLargeCount() { + mStdDevTooLargeCount += 1; + } + + /** Return number of times stdDev was not ok */ + public int getStdDevTooLargeCount() { + return mStdDevTooLargeCount; + } + + /** Return time per loop */ + public double getTimePerLoop() { + return mMin / TICKS_PER_MICROSECOND / mInnerLoops; + } + + /** + * Calculate the stats for the data. Note the data in the range will be + * sorted. + * + * @param data + * @param count + */ + public Stats calculate(long data[], int count) { + if (count == 1) { + mMin = mMax = data[0]; + mTotal = mMedian = mMean = data[0]; + mStdDev = 0; + } else if (count > 1) { + Arrays.sort(data, 0, count); + mMin = data[0]; + mMax = data[count - 1]; + if ((count & 1) == 1) { + mMedian = data[((count + 1) / 2) - 1]; + } else { + mMedian = (data[count / 2] + data[(count / 2) - 1]) / 2; + } + mTotal = 0; + double sumSquares = 0; + for (int i = 0; i < count; i++) { + long t = data[i]; + mTotal += t; + sumSquares += t * t; + } + mMean = mTotal / count; + double variance = (sumSquares / count) - (mMean * mMean); + mStdDev = Math.pow(variance, 0.5); + } else { + init(); + } + return this; + } + + /** Convert to string */ + @Override + public String toString() { + double timePerLoop = getTimePerLoop(); + double stdDevPerLoop = mStdDev / TICKS_PER_MICROSECOND / mInnerLoops; + return String.format( + "tpl=%,.6fus stdDev=%,.6fus tpl/stdDev=%.2fpercent min=%,.6fus median=%,.6fus mean=%,.6fus max=%,.6fus total=%,.6fs il=%d, ol=%d tlc=%d", + timePerLoop, stdDevPerLoop, (stdDevPerLoop / timePerLoop) * 100, mMin + / TICKS_PER_MICROSECOND, mMedian / TICKS_PER_MICROSECOND, mMean + / TICKS_PER_MICROSECOND, mMax / TICKS_PER_MICROSECOND, mTotal + / (TICKS_PER_MICROSECOND * 1000000.0), mInnerLoops, mOuterLoops, mStdDevTooLargeCount); + } + } + + /** Statistics */ + private Stats mStats = new Stats(); + + /** Statistics of the clock precision */ + private Stats mClockStats; + + /** Number of items in times array */ + private int mCount; + + /** Array of stop - start times */ + private long mTimes[]; + + /** Time of last started */ + private long mStart; + + /** Sleep a little so we don't look like a hog */ + private void sleep() { + try { + Thread.sleep(0); + } catch (InterruptedException e) { + // Ignore exception + } + } + + /** Empty Runnable used for determining overhead */ + private Runnable mEmptyRunnable = new Runnable() { + public void run() { + } + }; + + /** Initialize */ + private void init(int maxCount, CalibrationRec cr) { + mTimes = new long[maxCount]; + mCr = cr; + reset(); + } + + /** Construct the stop watch */ + public PerfTimer() { + init(10, new CalibrationRec()); + } + + /** Construct setting size of times array */ + public PerfTimer(int maxCount) { + init(maxCount, new CalibrationRec()); + } + + /** Construct the stop watch */ + public PerfTimer(CalibrationRec cr) { + init(10, cr); + } + + /** Construct the stop watch */ + public PerfTimer(int maxCount, CalibrationRec cr) { + init(maxCount, cr); + } + + /** Reset the contents of the times array */ + public PerfTimer reset() { + mCount = 0; + mStats.init(); + return this; + } + + /** Reset and then start the timer */ + public PerfTimer restart() { + reset(); + mStart = getTicks(); + return this; + } + + /** Start timing */ + public PerfTimer start() { + mStart = getTicks(); + return this; + } + + /** + * Record the difference between start and now in the times array + * incrementing count. The time will be stored in the times array if the + * array is not full. + */ + public PerfTimer stop() { + long stop = getTicks(); + if (mCount < mTimes.length) { + mTimes[mCount++] = stop - mStart; + } + return this; + } + + /** + * Time how long it takes to execute runnable.run() innerLoop number of + * times outerLoops number of times. + * + * @param outerLoops + * @param innerLoops + * @param runnable + * @return PerfTimer + */ + public PerfTimer timeEach(Stats stats, int outerLoops, int innerLoops, Runnable runnable) { + reset(); + resize(outerLoops); + stats.setOuterLoops(outerLoops); + stats.setInnerLoops(innerLoops); + for (int i = 0; i < outerLoops; i++) { + start(); + for (int j = 0; j < innerLoops; j++) { + runnable.run(); + } + stop(); + sleep(); + } + return this; + } + + /** + * Time how long it takes to execute runnable.run(). Runs runnable votes + * times and returns the Stats of the fastest run. The actual number times + * that runnable.run() is executes is enough times so that it runs at least + * minThreadholeInMicros but not greater than maxThreadholdInMicro. This + * minimizes the chance that long context switches influence the result. + * + * @param votes is the number of runnable will be executed to determine + * fastest run + * @param outerLoops is the number of of times the inner loop is run + * @param initialInnerLoops is the initial inner loop + * @param maxStdDevRetrys if the maxStdDevRatio is exceeded this number of + * time the PerfTimerException is thrown. + * @param maxStdDevRatio the ratio of the standard deviation of the run and + * the time to run. + * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL + * @param runnable is the code to test. + * @return Stats of the fastest run. + */ + public Stats timeEachAutomatically(int votes, int outerLoops, int initialInnerLoops, + double minThresholdInMicros, double maxThresholdInMicros, int maxStdDevRetrys, + double maxStdDevRatio, int debugLevel, Runnable runnable) throws PerfTimerException { + Stats minStats = null; + + for (int v = 0; v < votes; v++) { + boolean successful = false; + Stats stats = new Stats(); + int innerLoops = initialInnerLoops; + + /* Warm up cache */ + timeEach(stats, outerLoops, initialInnerLoops, runnable); + + for (int stdDevRetrys = 0; stdDevRetrys < maxStdDevRetrys; stdDevRetrys++) { + /** + * First time may be long enough + */ + timeEach(stats, outerLoops, innerLoops, runnable); + analyze(stats, mTimes, outerLoops, debugLevel); + double innerLoopTime = stats.getMinInMicros(); + if ((innerLoopTime >= minThresholdInMicros + - ((maxThresholdInMicros - minThresholdInMicros) / 2))) { + if (stats.stdDevOk(maxStdDevRatio)) { + successful = true; + break; + } else { + stats.incStdDevTooLargeCount(); + if (debugLevel >= DEBUG_LEVEL_SOME) { + log(String.format( + "tea: tlc=%d StdDevRatio=%.2f > maxStdDevRatio=%.2f", + stats.getStdDevTooLargeCount(), stats.getStdDevRatio(), + maxStdDevRatio)); + } + } + } else { + /** + * The initial number of loops is too short find the number + * of loops that exceeds maxThresholdInMicros. Then use a + * binary search to find the approriate innerLoop value that + * is between min/maxThreshold. + */ + innerLoops *= 10; + int maxInnerLoops = innerLoops; + int minInnerLoops = 1; + boolean binarySearch = false; + for (int i = 0; i < 10; i++) { + timeEach(stats, outerLoops, innerLoops, runnable); + analyze(stats, mTimes, outerLoops, debugLevel); + innerLoopTime = stats.getMedianInMicros(); + if ((innerLoopTime >= minThresholdInMicros) + && (innerLoopTime <= maxThresholdInMicros)) { + if (stats.stdDevOk(maxStdDevRatio)) { + successful = true; + break; + } else { + stats.incStdDevTooLargeCount(); + if (debugLevel >= DEBUG_LEVEL_SOME) { + log(String.format( + "tea: tlc=%d StdDevRatio=%.2f > maxStdDevRatio=%.2f", + stats.getStdDevTooLargeCount(), stats.getStdDevRatio(), + maxStdDevRatio)); + } + } + } else if (binarySearch) { + if ((innerLoopTime < minThresholdInMicros)) { + minInnerLoops = innerLoops; + } else { + maxInnerLoops = innerLoops; + } + innerLoops = (maxInnerLoops + minInnerLoops) / 2; + } else if (innerLoopTime >= maxThresholdInMicros) { + /* Found a too large value, change to binary search */ + binarySearch = true; + maxInnerLoops = innerLoops; + innerLoops = (maxInnerLoops + minInnerLoops) / 2; + } else { + innerLoops *= 10; + } + } + if (successful) { + break; + } + } + } + if (!successful) { + /* Couldn't find the number of loops to execute */ + throw new PerfTimerException(); + } + + /** Looking for minimum */ + if ((minStats == null) || (minStats.getTimePerLoop() > stats.getTimePerLoop())) { + minStats = stats; + } + if (debugLevel >= DEBUG_LEVEL_SOME) { + log(String.format("minStats.getTimePerLoop=%f minStats: %s", minStats.getTimePerLoop(), minStats)); + } + } + + return minStats; + } + + /** + * Time how long it takes to execute runnable.run() with a threshold of 1 to + * 10ms. + * + * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL + * @param runnable + * @throws PerfTimerException + */ + public Stats timeEachAutomatically(int debugLevel, Runnable runnable) + throws PerfTimerException { + mStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, 1, mCr.mMinThresholdInMicros, + mCr.mMaxThresholdInMicros, mCr.mStdDevRetrys, mCr.mMaxStdDevRatio, debugLevel, + runnable); + return mStats; + } + + /** + * Time how long it takes to execute runnable.run() with a threshold of 1 to + * 10ms. + * + * @param runnable + * @throws PerfTimerException + */ + public Stats timeEachAutomatically(Runnable runnable) throws PerfTimerException { + mStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, 1, mCr.mMinThresholdInMicros, + mCr.mMaxThresholdInMicros, mCr.mStdDevRetrys, mCr.mMaxStdDevRatio, + DEBUG_LEVEL_NONE, runnable); + return mStats; + } + + /** Resize the times array */ + public void resize(int maxCount) { + if (maxCount > mTimes.length) { + mTimes = new long[maxCount]; + } + } + + /** + * Analyze the data calculating the min, max, total, median, mean and + * stdDev. The standard deviation is calculated as sqrt(((sum of the squares + * of each time) / count) - mean^2) + * {@link "http://www.sciencebuddies.org/mentoring/project_data_analysis_variance_std_deviation.shtml"} + * + * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL + * @return StopWatch + */ + public Stats analyze(Stats stats, long data[], int count, int debugLevel) { + if (count > 0) { + if (debugLevel >= DEBUG_LEVEL_ALL) { + for (int j = 0; j < count; j++) { + log(String.format("data[%d]=%,dns", j, data[j])); + } + } + stats.calculate(data, count); + } else { + stats.init(); + } + if (debugLevel >= DEBUG_LEVEL_SOME) { + log("stats: " + stats); + } + return stats; + } + + /** + * Calibrate the system and set it for this PerfTimer instance + * + * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL + * @param precisionInDecimalDigits the precision in number of decimal digits + */ + public CalibrationRec calibrate(int debugLevel, double precisionInDecimalDigits) + throws PerfTimerException { + int nonZeroCount = 0; + Stats stats = new Stats(); + CalibrationRec cr = new CalibrationRec(); + + /* initialize the precision */ + cr.mPrecisionInDecimalDigits = precisionInDecimalDigits; + + /* Warm up the cache */ + timeEach(stats, OUTER_LOOPS, 10, mEmptyRunnable); + + /* + * Determine the clock stats with at least 20% non-zero unique values. + */ + for (int clockStatsTries = 1; clockStatsTries < 100; clockStatsTries++) { + int j; + int i; + long cur; + long prev; + long min; + + int innerLoops = clockStatsTries * 10; + timeEach(stats, OUTER_LOOPS, innerLoops, mEmptyRunnable); + long nonZeroValues[] = new long[mCount]; + prev = 0; + for (nonZeroCount = 0, i = 0; i < mCount; i++) { + cur = mTimes[i]; + if (cur > 0) { + nonZeroValues[nonZeroCount++] = cur; + } + } + if (nonZeroCount > (mCount * 0.20)) { + // Calculate thresholds + analyze(stats, nonZeroValues, nonZeroCount, debugLevel); + stats.calculate(nonZeroValues, nonZeroCount); + cr.mMinThresholdInMicros = stats.getMeanInMicros() + * Math.pow(10, cr.mPrecisionInDecimalDigits); + cr.mMaxThresholdInMicros = cr.mMinThresholdInMicros * 2; + + // Set overhead to 0 and time the empty loop then set overhead. + cr.mRunnableOverheadInMicros = 0; + mClockStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, innerLoops, + cr.mMinThresholdInMicros, cr.mMaxThresholdInMicros, mCr.mStdDevRetrys, + mCr.mMaxStdDevRatio, debugLevel, mEmptyRunnable); + cr.mRunnableOverheadInMicros = mClockStats.getMinInMicros() + / mClockStats.getInnerLoops(); + break; + } + nonZeroCount = 0; + } + if (nonZeroCount == 0) { + throw new PerfTimerException(); + } + if (debugLevel >= DEBUG_LEVEL_SOME) { + log(String.format("calibrate X oh=%.6fus minT=%,.6fus maxT=%,.6fus stats: %s", + cr.mRunnableOverheadInMicros, cr.mMinThresholdInMicros, + cr.mMaxThresholdInMicros, stats)); + } + mCr = cr; + return mCr; + } + + /** Calibrate the system and set it for this PerfTimer instance */ + public CalibrationRec calibrate(double precisionInDecimalDigits) throws PerfTimerException { + return calibrate(DEBUG_LEVEL_NONE, precisionInDecimalDigits); + } + + /** Calibrate the system and set it for this PerfTimer instance */ + public CalibrationRec calibrate() throws PerfTimerException { + return calibrate(DEBUG_LEVEL_NONE, mCr.mPrecisionInDecimalDigits); + } + + /* + * Accessors for the private data + */ + + /** Set calibration record */ + public void setCalibrationRec(CalibrationRec cr) { + mCr = cr; + } + + /** Get calibration record */ + public CalibrationRec getCalibrationRec() { + return mCr; + } + + /** Number of samples in times array. */ + public int getCount() { + return mCount; + } + + /** Minimum value of collected data in microseconds, valid after analyze. */ + public double getMinInMicros() { + return mStats.getMinInMicros(); + } + + /** Maximum value of collected data in microseconds, valid after analyze. */ + public double getMaxInMicros() { + return mStats.getMaxInMicros(); + } + + /** + * Sum of the values of collected data in microseconds, valid after analyze. + */ + public double getTotalInMicros() { + return mStats.getTotalInMicros(); + } + + /** Sum of the values of collected data in seconds, valid after analyze. */ + public double getTotalInSecs() { + return mStats.getTotalInSecs(); + } + + /** Sum of the values of collected data in seconds, valid after analyze. */ + public double getMeanInMicros() { + return mStats.getMeanInMicros(); + } + + /** Median value of collected data in microseconds, valid after analyze. */ + public double getMedianInMicros() { + return mStats.getMedianInMicros(); + } + + /** + * Standard deviation of collected data in microseconds, valid after + * analyze. + */ + public double getStdDevInMicros() { + return mStats.getStdDevInMicros(); + } + + /** The mTimes[index] value */ + public long getTime(int index) { + return mTimes[index]; + } + + /** The mTimes */ + public long[] getTimes() { + return mTimes; + } + + /** @return the clock stats as measured in calibrate */ + public Stats getClockStats() { + return mClockStats; + } + + /** @return the stats */ + public Stats getStats() { + return mStats; + } + + /** + * Convert stats to string + * + * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL + */ + public String stats(int debugLevel) { + int innerLoops = mStats.getInnerLoops(); + if (mCount == 0) { + return String.format("%,.3fus", (getTicks() - mStart) / TICKS_PER_MICROSECOND); + } else { + if (mCount == 1) { + return String.format("%,.3fus", getTime()); + } else { + analyze(mStats, mTimes, mCount, debugLevel); + return mStats.toString(); + } + } + } + + /** + * Convert string + */ + public String stats() { + return stats(0); + } + + /** + * Get time + */ + public double getTime() { + int innerLoops = mStats.getInnerLoops(); + if (mCount == 0) { + return (getTicks() - mStart) / TICKS_PER_MICROSECOND; + } else { + if (mCount == 1) { + return mStats.getTotalInMicros(); + } else { + analyze(mStats, mTimes, mCount, DEBUG_LEVEL_NONE); + return (mStats.getMinInMicros() / innerLoops) - mCr.mRunnableOverheadInMicros; + } + } + } + + /** Convert to string */ + @Override + public String toString() { + return String.format("%,.3fus", getTime()); + } +} diff --git a/src/Makefile.am b/src/Makefile.am index 35f5c0c..de83a4e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -72,6 +72,7 @@ nobase_include_HEADERS = \ google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ google/protobuf/compiler/java/java_generator.h \ + google/protobuf/compiler/javamicro/javamicro_generator.h \ google/protobuf/compiler/python/python_generator.h lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la @@ -178,6 +179,23 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_primitive_field.h \ google/protobuf/compiler/java/java_service.cc \ google/protobuf/compiler/java/java_service.h \ + google/protobuf/compiler/javamicro/javamicro_enum.cc \ + google/protobuf/compiler/javamicro/javamicro_enum.h \ + google/protobuf/compiler/javamicro/javamicro_enum_field.cc \ + google/protobuf/compiler/javamicro/javamicro_enum_field.h \ + google/protobuf/compiler/javamicro/javamicro_field.cc \ + google/protobuf/compiler/javamicro/javamicro_field.h \ + google/protobuf/compiler/javamicro/javamicro_file.cc \ + google/protobuf/compiler/javamicro/javamicro_file.h \ + google/protobuf/compiler/javamicro/javamicro_generator.cc \ + google/protobuf/compiler/javamicro/javamicro_helpers.cc \ + google/protobuf/compiler/javamicro/javamicro_helpers.h \ + google/protobuf/compiler/javamicro/javamicro_message.cc \ + google/protobuf/compiler/javamicro/javamicro_message.h \ + google/protobuf/compiler/javamicro/javamicro_message_field.cc\ + google/protobuf/compiler/javamicro/javamicro_message_field.h \ + google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\ + google/protobuf/compiler/javamicro/javamicro_primitive_field.h\ google/protobuf/compiler/python/python_generator.cc bin_PROGRAMS = protoc diff --git a/src/Makefile.in b/src/Makefile.in index daf81af..b48721f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -106,7 +106,11 @@ am_libprotoc_la_OBJECTS = code_generator.lo command_line_interface.lo \ cpp_string_field.lo java_enum.lo java_enum_field.lo \ java_extension.lo java_field.lo java_file.lo java_generator.lo \ java_helpers.lo java_message.lo java_message_field.lo \ - java_primitive_field.lo java_service.lo python_generator.lo + java_primitive_field.lo java_service.lo javamicro_enum.lo \ + javamicro_enum_field.lo javamicro_field.lo javamicro_file.lo \ + javamicro_generator.lo javamicro_helpers.lo \ + javamicro_message.lo javamicro_message_field.lo \ + javamicro_primitive_field.lo python_generator.lo libprotoc_la_OBJECTS = $(am_libprotoc_la_OBJECTS) libprotoc_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ @@ -298,6 +302,7 @@ am__nobase_include_HEADERS_DIST = google/protobuf/stubs/common.h \ google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ google/protobuf/compiler/java/java_generator.h \ + google/protobuf/compiler/javamicro/javamicro_generator.h \ google/protobuf/compiler/python/python_generator.h nobase_includeHEADERS_INSTALL = $(install_sh_DATA) HEADERS = $(nobase_include_HEADERS) @@ -491,6 +496,7 @@ nobase_include_HEADERS = \ google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ google/protobuf/compiler/java/java_generator.h \ + google/protobuf/compiler/javamicro/javamicro_generator.h \ google/protobuf/compiler/python/python_generator.h lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la @@ -596,6 +602,23 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_primitive_field.h \ google/protobuf/compiler/java/java_service.cc \ google/protobuf/compiler/java/java_service.h \ + google/protobuf/compiler/javamicro/javamicro_enum.cc \ + google/protobuf/compiler/javamicro/javamicro_enum.h \ + google/protobuf/compiler/javamicro/javamicro_enum_field.cc \ + google/protobuf/compiler/javamicro/javamicro_enum_field.h \ + google/protobuf/compiler/javamicro/javamicro_field.cc \ + google/protobuf/compiler/javamicro/javamicro_field.h \ + google/protobuf/compiler/javamicro/javamicro_file.cc \ + google/protobuf/compiler/javamicro/javamicro_file.h \ + google/protobuf/compiler/javamicro/javamicro_generator.cc \ + google/protobuf/compiler/javamicro/javamicro_helpers.cc \ + google/protobuf/compiler/javamicro/javamicro_helpers.h \ + google/protobuf/compiler/javamicro/javamicro_message.cc \ + google/protobuf/compiler/javamicro/javamicro_message.h \ + google/protobuf/compiler/javamicro/javamicro_message_field.cc\ + google/protobuf/compiler/javamicro/javamicro_message_field.h \ + google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\ + google/protobuf/compiler/javamicro/javamicro_primitive_field.h\ google/protobuf/compiler/python/python_generator.cc protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la @@ -925,6 +948,15 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_message_field.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_primitive_field.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_service.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_enum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_enum_field.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_field.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_generator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_helpers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_message.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_message_field.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_primitive_field.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message_lite.Plo@am__quote@ @@ -1467,6 +1499,69 @@ java_service.lo: google/protobuf/compiler/java/java_service.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o java_service.lo `test -f 'google/protobuf/compiler/java/java_service.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_service.cc +javamicro_enum.lo: google/protobuf/compiler/javamicro/javamicro_enum.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_enum.lo -MD -MP -MF $(DEPDIR)/javamicro_enum.Tpo -c -o javamicro_enum.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_enum.Tpo $(DEPDIR)/javamicro_enum.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_enum.cc' object='javamicro_enum.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_enum.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum.cc + +javamicro_enum_field.lo: google/protobuf/compiler/javamicro/javamicro_enum_field.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_enum_field.lo -MD -MP -MF $(DEPDIR)/javamicro_enum_field.Tpo -c -o javamicro_enum_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum_field.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_enum_field.Tpo $(DEPDIR)/javamicro_enum_field.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_enum_field.cc' object='javamicro_enum_field.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_enum_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum_field.cc + +javamicro_field.lo: google/protobuf/compiler/javamicro/javamicro_field.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_field.lo -MD -MP -MF $(DEPDIR)/javamicro_field.Tpo -c -o javamicro_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_field.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_field.Tpo $(DEPDIR)/javamicro_field.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_field.cc' object='javamicro_field.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_field.cc + +javamicro_file.lo: google/protobuf/compiler/javamicro/javamicro_file.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_file.lo -MD -MP -MF $(DEPDIR)/javamicro_file.Tpo -c -o javamicro_file.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_file.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_file.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_file.Tpo $(DEPDIR)/javamicro_file.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_file.cc' object='javamicro_file.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_file.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_file.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_file.cc + +javamicro_generator.lo: google/protobuf/compiler/javamicro/javamicro_generator.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_generator.lo -MD -MP -MF $(DEPDIR)/javamicro_generator.Tpo -c -o javamicro_generator.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_generator.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_generator.Tpo $(DEPDIR)/javamicro_generator.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_generator.cc' object='javamicro_generator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_generator.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_generator.cc + +javamicro_helpers.lo: google/protobuf/compiler/javamicro/javamicro_helpers.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_helpers.lo -MD -MP -MF $(DEPDIR)/javamicro_helpers.Tpo -c -o javamicro_helpers.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_helpers.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_helpers.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_helpers.Tpo $(DEPDIR)/javamicro_helpers.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_helpers.cc' object='javamicro_helpers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_helpers.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_helpers.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_helpers.cc + +javamicro_message.lo: google/protobuf/compiler/javamicro/javamicro_message.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_message.lo -MD -MP -MF $(DEPDIR)/javamicro_message.Tpo -c -o javamicro_message.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_message.Tpo $(DEPDIR)/javamicro_message.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_message.cc' object='javamicro_message.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_message.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message.cc + +javamicro_message_field.lo: google/protobuf/compiler/javamicro/javamicro_message_field.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_message_field.lo -MD -MP -MF $(DEPDIR)/javamicro_message_field.Tpo -c -o javamicro_message_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message_field.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_message_field.Tpo $(DEPDIR)/javamicro_message_field.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_message_field.cc' object='javamicro_message_field.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_message_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message_field.cc + +javamicro_primitive_field.lo: google/protobuf/compiler/javamicro/javamicro_primitive_field.cc +@am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_primitive_field.lo -MD -MP -MF $(DEPDIR)/javamicro_primitive_field.Tpo -c -o javamicro_primitive_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_primitive_field.cc +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/javamicro_primitive_field.Tpo $(DEPDIR)/javamicro_primitive_field.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' object='javamicro_primitive_field.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_primitive_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_primitive_field.cc + python_generator.lo: google/protobuf/compiler/python/python_generator.cc @am__fastdepCXX_TRUE@ $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT python_generator.lo -MD -MP -MF $(DEPDIR)/python_generator.Tpo -c -o python_generator.lo `test -f 'google/protobuf/compiler/python/python_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/python_generator.cc @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/python_generator.Tpo $(DEPDIR)/python_generator.Plo diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum.cc new file mode 100644 index 0000000..d74a149 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_enum.cc @@ -0,0 +1,96 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/compiler/javamicro/javamicro_enum.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& params) + : params_(params), descriptor_(descriptor) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::Generate(io::Printer* printer) { + printer->Print("// enum $classname$\n", "classname", descriptor_->name()); + for (int i = 0; i < canonical_values_.size(); i++) { + map<string, string> vars; + vars["name"] = canonical_values_[i]->name(); + vars["canonical_value"] = SimpleItoa(canonical_values_[i]->number()); + printer->Print(vars, + "public static final int $name$ = $canonical_value$;\n"); + } + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + map<string, string> vars; + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + printer->Print(vars, + "public static final int $name$ = $canonical_name$;\n"); + } + + printer->Print("\n"); +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.h b/src/google/protobuf/compiler/javamicro/javamicro_enum.h new file mode 100644 index 0000000..9cf226f --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_enum.h @@ -0,0 +1,87 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ + +#include <string> +#include <vector> + +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javamicro { + +class EnumGenerator { + public: + explicit EnumGenerator(const EnumDescriptor* descriptor, const Params& params); + ~EnumGenerator(); + + void Generate(io::Printer* printer); + + private: + const Params& params_; + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same numeric + // value. Java, however, does not allow multiple enum constants to be + // considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector<Alias> aliases_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc new file mode 100644 index 0000000..0ff49a3 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc @@ -0,0 +1,333 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +namespace { + +// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of +// repeat code between this and the other field types. +void SetEnumVariables(const Params& params, + const FieldDescriptor* descriptor, map<string, string>* variables) { + (*variables)["name"] = + UnderscoresToCamelCase(descriptor); + (*variables)["capitalized_name"] = + UnderscoresToCapitalizedCamelCase(descriptor); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["type"] = "int"; + (*variables)["default"] = DefaultValue(params, descriptor); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["message_name"] = descriptor->containing_type()->name(); +} + +} // namespace + +// =================================================================== + +EnumFieldGenerator:: +EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetEnumVariables(params, descriptor, &variables_); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private boolean has$capitalized_name$;\n" + "private int $name$_ = $default$;\n" + "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" + "public int get$capitalized_name$() { return $name$_; }\n" + "public $message_name$ set$capitalized_name$(int value) {\n" + " has$capitalized_name$ = true;\n" + " $name$_ = value;\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " has$capitalized_name$ = false;\n" + " $name$_ = $default$;\n" + " return this;\n" + "}\n"); +} + +void EnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "what is other??" + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); +} + +void EnumFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + " set$capitalized_name$(input.readInt32());\n"); +} + +void EnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " output.writeInt32($number$, get$capitalized_name$());\n" + "}\n"); +} + +void EnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeInt32Size($number$, get$capitalized_name$());\n" + "}\n"); +} + +string EnumFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->enum_type()); +} + +// =================================================================== + +RepeatedEnumFieldGenerator:: +RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetEnumVariables(params, descriptor, &variables_); + if (descriptor_->options().packed()) { + GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed"; + } +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "private java.util.Vector $name$_ = new java.util.Vector();\n" + "public java.util.Vector get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public int get$capitalized_name$(int index) {\n" + " return ((Integer)$name$_.elementAt(index)).intValue();\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, int value) {\n" + " $name$_.setElementAt(new Integer(value), index);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$(int value) {\n" + " $name$_.addElement(new Integer(value));\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_.removeAllElements();\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "private java.util.List<Integer> $name$_ =\n" + " java.util.Collections.emptyList();\n" + "public java.util.List<Integer> get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public int get$capitalized_name$(int index) {\n" + " return $name$_.get(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, int value) {\n" + " $name$_.set(index, value);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$(int value) {\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " }\n" + " $name$_.add(value);\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = java.util.Collections.emptyList();\n" + " return this;\n" + "}\n"); + } + if (descriptor_->options().packed()) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "if (other.$name$_.size() != 0) {\n" + " for (int i = 0; i < other.$name$_.size(); i++)) {\n" + " result.$name$_.addElement(other.$name$_.elementAt(i));\n" + " }\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if (result.$name$_.isEmpty()) {\n" + " result.$name$_ = new java.util.ArrayList<java.lang.Integer>();\n" + " }\n" + " result.$name$_.addAll(other.$name$_);\n" + "}\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + // If packed, set up the while loop + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + } + + // Read and store the enum + printer->Print(variables_, + " add$capitalized_name$(input.readInt32());\n"); + + if (descriptor_->options().packed()) { + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n"); + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.writeRawVarint32(get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.writeRawVarint32(element.getNumber());\n" + "}\n"); + } + } else { + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.writeInt32($number$, (int)get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (java.lang.Integer element : get$capitalized_name$List()) {\n" + " output.writeInt32($number$, element);\n" + "}\n"); + } + } +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeInt32SizeNoTag(get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (java.lang.Integer element : get$capitalized_name$List()) {\n" + " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeInt32SizeNoTag(element);\n" + "}\n"); + } + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() != 0) {" + " size += $tag_size$;\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeRawVarint32Size(dataSize);\n" + "}"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +string RepeatedEnumFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->enum_type()); +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h new file mode 100644 index 0000000..ab671c1 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h @@ -0,0 +1,94 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/javamicro/javamicro_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +class EnumFieldGenerator : public FieldGenerator { + public: + explicit EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params); + ~EnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +class RepeatedEnumFieldGenerator : public FieldGenerator { + public: + explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params); + ~RepeatedEnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_field.cc new file mode 100644 index 0000000..a2ea4f9 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_field.cc @@ -0,0 +1,102 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/javamicro/javamicro_field.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h> +#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h> +#include <google/protobuf/compiler/javamicro/javamicro_message_field.h> +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +FieldGenerator::~FieldGenerator() {} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms) + : descriptor_(descriptor), + field_generators_( + new scoped_ptr<FieldGenerator>[descriptor->field_count()]), + extension_generators_( + new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { + + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + field_generators_[i].reset(MakeGenerator(descriptor->field(i), params)); + } + for (int i = 0; i < descriptor->extension_count(); i++) { + extension_generators_[i].reset(MakeGenerator(descriptor->extension(i), params)); + } +} + +FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, const Params ¶ms) { + if (field->is_repeated()) { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new RepeatedMessageFieldGenerator(field, params); + case JAVATYPE_ENUM: + return new RepeatedEnumFieldGenerator(field, params); + default: + return new RepeatedPrimitiveFieldGenerator(field, params); + } + } else { + switch (GetJavaType(field)) { + case JAVATYPE_MESSAGE: + return new MessageFieldGenerator(field, params); + case JAVATYPE_ENUM: + return new EnumFieldGenerator(field, params); + default: + return new PrimitiveFieldGenerator(field, params); + } + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { + return *extension_generators_[index]; +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.h b/src/google/protobuf/compiler/javamicro/javamicro_field.h new file mode 100644 index 0000000..1530778 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_field.h @@ -0,0 +1,98 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ + +#include <string> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/javamicro/javamicro_params.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javamicro { + +class FieldGenerator { + public: + //FieldGenerator() {} + FieldGenerator(const Params& params) : params_(params) {} + virtual ~FieldGenerator(); + + virtual void GenerateMembers(io::Printer* printer) const = 0; + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateSerializationCode(io::Printer* printer) const = 0; + virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; + + virtual string GetBoxedType() const = 0; + + protected: + const Params& params_; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + explicit FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms); + ~FieldGeneratorMap(); + + const FieldGenerator& get(const FieldDescriptor* field) const; + const FieldGenerator& get_extension(int index) const; + + private: + const Descriptor* descriptor_; + scoped_array<scoped_ptr<FieldGenerator> > field_generators_; + scoped_array<scoped_ptr<FieldGenerator> > extension_generators_; + + static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Params ¶ms); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.cc b/src/google/protobuf/compiler/javamicro/javamicro_file.cc new file mode 100644 index 0000000..0985538 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_file.cc @@ -0,0 +1,251 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/javamicro/javamicro_file.h> +#include <google/protobuf/compiler/javamicro/javamicro_enum.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/compiler/javamicro/javamicro_message.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +namespace { + +// Recursively searches the given message to see if it contains any extensions. +bool UsesExtensions(const Message& message) { + const Reflection* reflection = message.GetReflection(); + + // We conservatively assume that unknown fields are extensions. + if (reflection->GetUnknownFields(message).field_count() > 0) return true; + + vector<const FieldDescriptor*> fields; + reflection->ListFields(message, &fields); + + for (int i = 0; i < fields.size(); i++) { + if (fields[i]->is_extension()) return true; + + if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (fields[i]->is_repeated()) { + int size = reflection->FieldSize(message, fields[i]); + for (int j = 0; j < size; j++) { + const Message& sub_message = + reflection->GetRepeatedMessage(message, fields[i], j); + if (UsesExtensions(sub_message)) return true; + } + } else { + const Message& sub_message = reflection->GetMessage(message, fields[i]); + if (UsesExtensions(sub_message)) return true; + } + } + } + + return false; +} + +} // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params) + : file_(file), + params_(params), + java_package_(FileJavaPackage(params, file)), + classname_(FileClassName(params, file)) {} + +FileGenerator::~FileGenerator() {} + +bool FileGenerator::Validate(string* error) { + // Check for extensions + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + if (UsesExtensions(file_proto)) { + error->assign(file_->name()); + error->append( + ": Java MICRO_RUNTIME does not support extensions\""); + return false; + } + + // If there is no outer class name then there must be only + // message and no enums defined in the file scope. + if (!params_.has_java_outer_classname(file_->name())) { + if (file_->message_type_count() != 1) { + error->assign(file_->name()); + error->append( + ": Java MICRO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\""); + return false; + } + + if (file_->enum_type_count() != 0) { + error->assign(file_->name()); + error->append( + ": Java MICRO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\""); + return false; + } + } + + // Check that no class name matches the file's class name. This is a common + // problem that leads to Java compile errors that can be hard to understand. + // It's especially bad when using the java_multiple_files, since we would + // end up overwriting the outer class with one of the inner ones. + int found_fileName = 0; + for (int i = 0; i < file_->enum_type_count(); i++) { + if (file_->enum_type(i)->name() == classname_) { + found_fileName += 1; + } + } + for (int i = 0; i < file_->message_type_count(); i++) { + if (file_->message_type(i)->name() == classname_) { + found_fileName += 1; + } + } + if (file_->service_count() != 0) { + error->assign(file_->name()); + error->append( + ": Java MICRO_RUNTIME does not support services\""); + return false; + } + + if (found_fileName > 1) { + error->assign(file_->name()); + error->append( + ": Cannot generate Java output because there is more than one class name, \""); + error->append(classname_); + error->append( + "\", matches the name of one of the types declared inside it. " + "Please either rename the type or use the java_outer_classname " + "option to specify a different outer class name for the .proto file." + " -- FIX THIS MESSAGE"); + return false; + } + return true; +} + +void FileGenerator::Generate(io::Printer* printer) { + // We don't import anything because we refer to all classes by their + // fully-qualified names in the generated source. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "\n"); + if (!java_package_.empty()) { + printer->Print( + "package $package$;\n" + "\n", + "package", java_package_); + } + + if (params_.has_java_outer_classname(file_->name())) { + printer->Print( + "public final class $classname$ {\n" + " private $classname$() {}\n", + "classname", classname_); + printer->Indent(); + } + + // ----------------------------------------------------------------- + + if (!params_.java_multiple_files()) { + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator(file_->enum_type(i), params_).Generate(printer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator(file_->message_type(i), params_).Generate(printer); + } + } + + // Static variables. + for (int i = 0; i < file_->message_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); + } + + if (params_.has_java_outer_classname(file_->name())) { + printer->Outdent(); + printer->Print( + "}\n"); + } +} + +template<typename GeneratorClass, typename DescriptorClass> +static void GenerateSibling(const string& package_dir, + const string& java_package, + const DescriptorClass* descriptor, + OutputDirectory* output_directory, + vector<string>* file_list, + const Params& params) { + string filename = package_dir + descriptor->name() + ".java"; + file_list->push_back(filename); + + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(filename)); + io::Printer printer(output.get(), '$'); + + printer.Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "\n"); + if (!java_package.empty()) { + printer.Print( + "package $package$;\n" + "\n", + "package", java_package); + } + + GeneratorClass(descriptor, params).Generate(&printer); +} + +void FileGenerator::GenerateSiblings(const string& package_dir, + OutputDirectory* output_directory, + vector<string>* file_list) { + if (params_.java_multiple_files()) { + for (int i = 0; i < file_->enum_type_count(); i++) { + GenerateSibling<EnumGenerator>(package_dir, java_package_, + file_->enum_type(i), + output_directory, file_list, params_); + } + for (int i = 0; i < file_->message_type_count(); i++) { + GenerateSibling<MessageGenerator>(package_dir, java_package_, + file_->message_type(i), + output_directory, file_list, params_); + } + } +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.h b/src/google/protobuf/compiler/javamicro/javamicro_file.h new file mode 100644 index 0000000..430172a --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_file.h @@ -0,0 +1,94 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ + +#include <string> +#include <vector> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javamicro/javamicro_params.h> + +namespace google { +namespace protobuf { + class FileDescriptor; // descriptor.h + namespace io { + class Printer; // printer.h + } + namespace compiler { + class OutputDirectory; // code_generator.h + } +} + +namespace protobuf { +namespace compiler { +namespace javamicro { + +class FileGenerator { + public: + explicit FileGenerator(const FileDescriptor* file, const Params& params); + ~FileGenerator(); + + // Checks for problems that would otherwise lead to cryptic compile errors. + // Returns true if there are no problems, or writes an error description to + // the given string and returns false otherwise. + bool Validate(string* error); + + void Generate(io::Printer* printer); + + // If we aren't putting everything into one file, this will write all the + // files other than the outer file (i.e. one for each message, enum, and + // service type). + void GenerateSiblings(const string& package_dir, + OutputDirectory* output_directory, + vector<string>* file_list); + + const string& java_package() { return java_package_; } + const string& classname() { return classname_; } + + private: + const FileDescriptor* file_; + const Params& params_; + string java_package_; + string classname_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc new file mode 100644 index 0000000..bfba8c5 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc @@ -0,0 +1,209 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/compiler/javamicro/javamicro_generator.h> +#include <google/protobuf/compiler/javamicro/javamicro_file.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +void UpdateParamsRecursively(Params& params, + const FileDescriptor* file) { + // Add any parameters for this file + if (file->options().has_java_outer_classname()) { + params.set_java_outer_classname( + file->name(), file->options().java_outer_classname()); + } + if (file->options().has_java_package()) { + params.set_java_package( + file->name(), file->options().java_package()); + } + + // Loop through all dependent files recursively + // adding dep + for (int i = 0; i < file->dependency_count(); i++) { + UpdateParamsRecursively(params, file->dependency(i)); + } +} + +JavaMicroGenerator::JavaMicroGenerator() {} +JavaMicroGenerator::~JavaMicroGenerator() {} + +bool JavaMicroGenerator::Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + vector<pair<string, string> > options; + +// GOOGLE_LOG(INFO) << "wink: JavaMicroGenerator::Generate INFO"; +// GOOGLE_LOG(WARNING) << "wink: JavaMicroGenerator::Generate WARNING"; +// GOOGLE_LOG(ERROR) << "wink: JavaMicroGenerator::Generate ERROR"; +// GOOGLE_LOG(FATAL) << "wink: JavaMicroGenerator::Generate"; + + ParseGeneratorParameter(parameter, &options); + + // ----------------------------------------------------------------- + // parse generator options + + // Name a file where we will write a list of generated file names, one + // per line. + string output_list_file; + Params params(file->name()); + + // Get options from the proto file + if (file->options().has_java_multiple_files()) { + params.set_java_multiple_files(file->options().java_multiple_files()); + } + + // Update per file params + UpdateParamsRecursively(params, file); + + // Replace any existing options with ones from command line + for (int i = 0; i < options.size(); i++) { + // GOOGLE_LOG(WARNING) << "first=" << options[i].first + // << " second=" << options[i].second; + if (options[i].first == "output_list_file") { + output_list_file = options[i].second; + } else if (options[i].first == "opt") { + if (options[i].second == "speed") { + params.set_optimization(JAVAMICRO_OPT_SPEED); + } else if (options[i].second == "space") { + params.set_optimization(JAVAMICRO_OPT_SPACE); + } else { + *error = "Unknown javamicro generator option: opt=" + + options[i].second + " expecting opt=space or opt=speed"; + return false; + } + } else if (options[i].first == "java_package") { + vector<string> parts; + SplitStringUsing(options[i].second, "|", &parts); + if (parts.size() != 2) { + *error = "Bad java_package, expecting filename|PackageName found '" + + options[i].second + "'"; + return false; + } + params.set_java_package(parts[0], parts[1]); + } else if (options[i].first == "java_outer_classname") { + vector<string> parts; + SplitStringUsing(options[i].second, "|", &parts); + if (parts.size() != 2) { + *error = "Bad java_outer_classname, " + "expecting filename|ClassName found '" + + options[i].second + "'"; + return false; + } + params.set_java_outer_classname(parts[0], parts[1]); + } else if (options[i].first == "java_multiple_files") { + params.set_java_multiple_files(options[i].second == "true"); + } else if (options[i].first == "java_use_vector") { + params.set_java_use_vector(options[i].second == "true"); + } else { + *error = "Ignore unknown javamicro generator option: " + options[i].first; + } + } + +#if 0 + GOOGLE_LOG(WARNING) << "optimization()=" << params.optimization(); + GOOGLE_LOG(WARNING) << "java_multiple_files()=" << params.java_multiple_files(); + GOOGLE_LOG(WARNING) << "java_use_vector()=" << params.java_use_vector(); + + GOOGLE_LOG(WARNING) << "----------"; + for (Params::NameMap::const_iterator it = params.java_packages().begin(); + it != params.java_packages().end(); + ++it) { + GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " package=" << it->second; + } + for (Params::NameMap::const_iterator it = params.java_outer_classnames().begin(); + it != params.java_outer_classnames().end(); + ++it) { + GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " classname=" << it->second; + } + GOOGLE_LOG(WARNING) << "=========="; + +#endif + + // ----------------------------------------------------------------- + + FileGenerator file_generator(file, params); + if (!file_generator.Validate(error)) { + return false; + } + + string package_dir = + StringReplace(file_generator.java_package(), ".", "/", true); + if (!package_dir.empty()) package_dir += "/"; + + vector<string> all_files; + + string java_filename = package_dir; + java_filename += file_generator.classname(); + java_filename += ".java"; + all_files.push_back(java_filename); + + // Generate main java file. + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(java_filename)); + io::Printer printer(output.get(), '$'); + file_generator.Generate(&printer); + + // Generate sibling files. + file_generator.GenerateSiblings(package_dir, output_directory, &all_files); + + // Generate output list if requested. + if (!output_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .java files being generated. + scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output( + output_directory->Open(output_list_file)); + io::Printer srclist_printer(srclist_raw_output.get(), '$'); + for (int i = 0; i < all_files.size(); i++) { + srclist_printer.Print("$filename$\n", "filename", all_files[i]); + } + } + + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.h b/src/google/protobuf/compiler/javamicro/javamicro_generator.h new file mode 100644 index 0000000..a1c33b7 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_generator.h @@ -0,0 +1,72 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates Java micro code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__ + +#include <string> +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +// CodeGenerator implementation which generates Java micro code. If you create your +// own protocol compiler binary and you want it to support Java output for the +// micro runtime, you can do so by registering an instance of this CodeGenerator with +// the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT JavaMicroGenerator : public CodeGenerator { + public: + JavaMicroGenerator(); + ~JavaMicroGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaMicroGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc new file mode 100644 index 0000000..11ba71a --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc @@ -0,0 +1,381 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <vector> + +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +const char kThickSeparator[] = + "// ===================================================================\n"; +const char kThinSeparator[] = + "// -------------------------------------------------------------------\n"; + +namespace { + +const char* kDefaultPackage = ""; + +const string& FieldName(const FieldDescriptor* field) { + // Groups are hacky: The name of the field is just the lower-cased name + // of the group type. In Java, though, we would like to retain the original + // capitalization of the type name. + if (field->type() == FieldDescriptor::TYPE_GROUP) { + return field->message_type()->name(); + } else { + return field->name(); + } +} + +string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { + string result; + // Note: I distrust ctype.h due to locales. + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_next_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_next_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + if (i == 0 && !cap_next_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += input[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += input[i]; + } + cap_next_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_next_letter = true; + } else { + cap_next_letter = true; + } + } + return result; +} + +} // namespace + +string UnderscoresToCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCaseImpl(FieldName(field), false); +} + +string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCaseImpl(FieldName(field), true); +} + +string UnderscoresToCamelCase(const MethodDescriptor* method) { + return UnderscoresToCamelCaseImpl(method->name(), false); +} + +string StripProto(const string& filename) { + if (HasSuffixString(filename, ".protodevel")) { + return StripSuffixString(filename, ".protodevel"); + } else { + return StripSuffixString(filename, ".proto"); + } +} + +string FileClassName(const Params& params, const FileDescriptor* file) { + string name; + + if (params.has_java_outer_classname(file->name())) { + name = params.java_outer_classname(file->name()); + } else { + if ((file->message_type_count() == 1) + || (file->enum_type_count() == 0)) { + // If no outer calls and only one message then + // use the message name as the file name + name = file->message_type(0)->name(); + } else { + // Use the filename it self with underscores removed + // and a CamelCase style name. + string basename; + string::size_type last_slash = file->name().find_last_of('/'); + if (last_slash == string::npos) { + basename = file->name(); + } else { + basename = file->name().substr(last_slash + 1); + } + name = UnderscoresToCamelCaseImpl(StripProto(basename), true); + } + } + + return name; +} + +string FileJavaPackage(const Params& params, const FileDescriptor* file) { + if (params.has_java_package(file->name())) { + return params.java_package(file->name()); + } else { + string result = kDefaultPackage; + if (!file->package().empty()) { + if (!result.empty()) result += '.'; + result += file->package(); + } + return result; + } +} + +string ToJavaName(const Params& params, const string& full_name, + const FileDescriptor* file) { + string result; + if (params.java_multiple_files()) { + result = FileJavaPackage(params, file); + } else { + result = ClassName(params, file); + } + if (file->package().empty()) { + result += '.'; + result += full_name; + } else { + // Strip the proto package from full_name since we've replaced it with + // the Java package. If there isn't an outer classname then strip it too. + int sizeToSkipPackageName = file->package().size(); + int sizeToSkipOutClassName; + if (params.has_java_outer_classname(file->name())) { + sizeToSkipOutClassName = 0; + } else { + sizeToSkipOutClassName = + full_name.find_first_of('.', sizeToSkipPackageName + 1); + } + int sizeToSkip = sizeToSkipOutClassName > 0 ? + sizeToSkipOutClassName : sizeToSkipPackageName; + string class_name = full_name.substr(sizeToSkip + 1); + if (class_name == FileClassName(params, file)) { + // Done class_name is already present. + } else { + result += '.'; + result += class_name; + } + } + return result; +} + +string ClassName(const Params& params, const FileDescriptor* descriptor) { + string result = FileJavaPackage(params, descriptor); + if (!result.empty()) result += '.'; + result += FileClassName(params, descriptor); + return result; +} + +string ClassName(const Params& params, const EnumDescriptor* descriptor) { + string result; + const FileDescriptor* file = descriptor->file(); + const string file_name = file->name(); + const string full_name = descriptor->full_name(); + int last_period = full_name.find_last_of('.'); + int first_period = full_name.find_first_of('.'); + + // Remove class_name as we're using public static final int's not enums + string base_name = full_name.substr(0, full_name.find_last_of('.')); + + if (!file->package().empty()) { + // Remove package name. + int offset = first_period; + if (last_period > first_period) { + // There was two or more periods so we need to remove this one too. + offset += 1; + } + base_name = base_name.substr(offset); + } + + if (params.has_java_package(file_name)) { + result += params.java_package(file_name); + } + if (params.has_java_outer_classname(file_name)) { + result += "."; + result += params.java_outer_classname(file_name); + } + if (!base_name.empty()) { + result += "."; + result += base_name; + } + return result; +} + +string FieldConstantName(const FieldDescriptor *field) { + string name = field->name() + "_FIELD_NUMBER"; + UpperString(&name); + return name; +} + +JavaType GetJavaType(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + return JAVATYPE_INT; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + return JAVATYPE_LONG; + + case FieldDescriptor::TYPE_FLOAT: + return JAVATYPE_FLOAT; + + case FieldDescriptor::TYPE_DOUBLE: + return JAVATYPE_DOUBLE; + + case FieldDescriptor::TYPE_BOOL: + return JAVATYPE_BOOLEAN; + + case FieldDescriptor::TYPE_STRING: + return JAVATYPE_STRING; + + case FieldDescriptor::TYPE_BYTES: + return JAVATYPE_BYTES; + + case FieldDescriptor::TYPE_ENUM: + return JAVATYPE_ENUM; + + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return JAVATYPE_MESSAGE; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return JAVATYPE_INT; +} + +const char* BoxedPrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "java.lang.Integer"; + case JAVATYPE_LONG : return "java.lang.Long"; + case JAVATYPE_FLOAT : return "java.lang.Float"; + case JAVATYPE_DOUBLE : return "java.lang.Double"; + case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "com.google.protobuf.micro.ByteStringMicro"; + case JAVATYPE_ENUM : return "java.lang.Integer"; + case JAVATYPE_MESSAGE: return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +bool AllAscii(const string& text) { + for (int i = 0; i < text.size(); i++) { + if ((text[i] & 0x80) != 0) { + return false; + } + } + return true; +} + +string DefaultValue(const Params& params, const FieldDescriptor* field) { + // Switch on cpp_type since we need to know which default_value_* method + // of FieldDescriptor to call. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + // Need to print as a signed int since Java has no unsigned. + return SimpleItoa(static_cast<int32>(field->default_value_uint32())); + case FieldDescriptor::CPPTYPE_INT64: + return SimpleItoa(field->default_value_int64()) + "L"; + case FieldDescriptor::CPPTYPE_UINT64: + return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + + "L"; + case FieldDescriptor::CPPTYPE_DOUBLE: + return SimpleDtoa(field->default_value_double()) + "D"; + case FieldDescriptor::CPPTYPE_FLOAT: + return SimpleFtoa(field->default_value_float()) + "F"; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_STRING: + if (field->type() == FieldDescriptor::TYPE_BYTES) { + if (field->has_default_value()) { + // See comments in Internal.java for gory details. + return strings::Substitute( + "com.google.protobuf.micro.ByteStringMicro.copyFromUtf8(\"$0\")", + CEscape(field->default_value_string())); + } else { + return "com.google.protobuf.micro.ByteStringMicro.EMPTY"; + } + } else { + if (AllAscii(field->default_value_string())) { + // All chars are ASCII. In this case CEscape() works fine. + return "\"" + CEscape(field->default_value_string()) + "\""; + } else { + // See comments in Internal.java for gory details. + // BUG: Internal NOT SUPPORTED need to fix!! + return strings::Substitute( + "com.google.protobuf.micro.Internal.stringDefaultValue(\"$0\")", + CEscape(field->default_value_string())); + } + } + + case FieldDescriptor::CPPTYPE_ENUM: + return ClassName(params, field->enum_type()) + "." + + field->default_value_enum()->name(); + + case FieldDescriptor::CPPTYPE_MESSAGE: + return ClassName(params, field->message_type()) + ".getDefaultInstance()"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h new file mode 100644 index 0000000..eeddbf9 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h @@ -0,0 +1,128 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ + +#include <string> +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes +// "fooBarBaz" or "FooBarBaz", respectively. +string UnderscoresToCamelCase(const FieldDescriptor* field); +string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); + +// Similar, but for method names. (Typically, this merely has the effect +// of lower-casing the first letter of the name.) +string UnderscoresToCamelCase(const MethodDescriptor* method); + +// Strips ".proto" or ".protodevel" from the end of a filename. +string StripProto(const string& filename); + +// Gets the unqualified class name for the file. Each .proto file becomes a +// single Java class, with all its contents nested in that class. +string FileClassName(const Params& params, const FileDescriptor* file); + +// Returns the file's Java package name. +string FileJavaPackage(const Params& params, const FileDescriptor* file); + +// Converts the given fully-qualified name in the proto namespace to its +// fully-qualified name in the Java namespace, given that it is in the given +// file. +string ToJavaName(const Params& params, const string& full_name, + const FileDescriptor* file); + +// These return the fully-qualified class name corresponding to the given +// descriptor. +inline string ClassName(const Params& params, const Descriptor* descriptor) { + return ToJavaName(params, descriptor->full_name(), descriptor->file()); +} +string ClassName(const Params& params, const EnumDescriptor* descriptor); +inline string ClassName(const Params& params, + const ServiceDescriptor* descriptor) { + return ToJavaName(params, descriptor->full_name(), descriptor->file()); +} +inline string ExtensionIdentifierName(const Params& params, + const FieldDescriptor* descriptor) { + return ToJavaName(params, descriptor->full_name(), descriptor->file()); +} +string ClassName(const Params& params, const FileDescriptor* descriptor); + +// Get the unqualified name that should be used for a field's field +// number constant. +string FieldConstantName(const FieldDescriptor *field); + +enum JavaType { + JAVATYPE_INT, + JAVATYPE_LONG, + JAVATYPE_FLOAT, + JAVATYPE_DOUBLE, + JAVATYPE_BOOLEAN, + JAVATYPE_STRING, + JAVATYPE_BYTES, + JAVATYPE_ENUM, + JAVATYPE_MESSAGE +}; + +JavaType GetJavaType(FieldDescriptor::Type field_type); + +inline JavaType GetJavaType(const FieldDescriptor* field) { + return GetJavaType(field->type()); +} + +// Get the fully-qualified class name for a boxed primitive type, e.g. +// "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message +// types. +const char* BoxedPrimitiveTypeName(JavaType type); + +string DefaultValue(const Params& params, const FieldDescriptor* field); + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.cc b/src/google/protobuf/compiler/javamicro/javamicro_message.cc new file mode 100644 index 0000000..7fc6c3d --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_message.cc @@ -0,0 +1,474 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/compiler/javamicro/javamicro_message.h> +#include <google/protobuf/compiler/javamicro/javamicro_enum.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { + // Print the field's proto-syntax definition as a comment. We don't want to + // print group bodies so we cut off after the first line. + string def = field->DebugString(); + printer->Print("// $def$\n", + "def", def.substr(0, def.find_first_of('\n'))); +} + +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); + return fields; +} + +// Get an identifier that uniquely identifies this type within the file. +// This is used to declare static variables related to this type at the +// outermost file scope. +string UniqueFileScopeIdentifier(const Descriptor* descriptor) { + return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); +} + +// Returns true if the message type has any required fields. If it doesn't, +// we can optimize out calls to its isInitialized() method. +// +// already_seen is used to avoid checking the same type multiple times +// (and also to protect against recursion). +static bool HasRequiredFields( + const Descriptor* type, + hash_set<const Descriptor*>* already_seen) { + if (already_seen->count(type) > 0) { + // The type is already in cache. This means that either: + // a. The type has no required fields. + // b. We are in the midst of checking if the type has required fields, + // somewhere up the stack. In this case, we know that if the type + // has any required fields, they'll be found when we return to it, + // and the whole call to HasRequiredFields() will return true. + // Therefore, we don't have to check if this type has required fields + // here. + return false; + } + already_seen->insert(type); + + // If the type has extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (type->extension_range_count() > 0) return true; + + for (int i = 0; i < type->field_count(); i++) { + const FieldDescriptor* field = type->field(i); + if (field->is_required()) { + return true; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (HasRequiredFields(field->message_type(), already_seen)) { + return true; + } + } + } + + return false; +} + +static bool HasRequiredFields(const Descriptor* type) { + hash_set<const Descriptor*> already_seen; + return HasRequiredFields(type, &already_seen); +} + +} // namespace + +// =================================================================== + +MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params) + : params_(params), + descriptor_(descriptor), + field_generators_(descriptor, params) { +} + +MessageGenerator::~MessageGenerator() {} + +void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { + // Generate static members for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(descriptor_->nested_type(i), params_) + .GenerateStaticVariables(printer); + } +} + +void MessageGenerator::GenerateStaticVariableInitializers( + io::Printer* printer) { + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(descriptor_->nested_type(i), params_) + .GenerateStaticVariableInitializers(printer); + } + + if (descriptor_->extension_count() != 0) { + GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; + } +} + +void MessageGenerator::Generate(io::Printer* printer) { + bool is_own_file = + params_.java_multiple_files() || ((descriptor_->containing_type() == NULL) + && !params_.has_java_outer_classname(descriptor_->file()->name())); + +#if 0 + GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file; + GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null"); + GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files(); + GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name()); +#endif + + if ((descriptor_->extension_count() != 0) + || (descriptor_->extension_range_count() != 0)) { + GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; + } + + printer->Print( + "public $modifiers$ final class $classname$ extends\n" + " com.google.protobuf.micro.MessageMicro {\n", + "modifiers", is_own_file ? "" : "static", + "classname", descriptor_->name()); + printer->Indent(); + printer->Print( + "public $classname$() {}\n" + "\n", + "classname", descriptor_->name()); + + // Nested types and extensions + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer); + } + + // Fields + for (int i = 0; i < descriptor_->field_count(); i++) { + PrintFieldComment(printer, descriptor_->field(i)); + printer->Print("public static final int $constant_name$ = $number$;\n", + "constant_name", FieldConstantName(descriptor_->field(i)), + "number", SimpleItoa(descriptor_->field(i)->number())); + field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); + printer->Print("\n"); + } + + GenerateClear(printer); + GenerateIsInitialized(printer); + GenerateMessageSerializationMethods(printer); + GenerateMergeFromMethods(printer); + GenerateParseFromMethods(printer); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +// =================================================================== + +void MessageGenerator:: +GenerateMessageSerializationMethods(io::Printer* printer) { + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + if (descriptor_->extension_range_count() != 0) { + GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; + } + + printer->Print( + "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n" + " throws java.io.IOException {\n"); + printer->Indent(); + + // Output the fields in sorted order + for (int i = 0; i < descriptor_->field_count(); i++) { + GenerateSerializeOneField(printer, sorted_fields[i]); + } + + printer->Outdent(); + printer->Print( + "}\n" + "\n" + "private int cachedSize = -1;\n" + "public int getCachedSize() {\n" + " if (cachedSize < 0) {\n" + " // getSerializedSize sets cachedSize\n" + " getSerializedSize();\n" + " }\n" + " return cachedSize;\n" + "}\n" + "\n" + "public int getSerializedSize() {\n" + " int size = 0;\n"); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); + } + + printer->Outdent(); + printer->Print( + " cachedSize = size;\n" + " return size;\n" + "}\n" + "\n"); +} + +void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + if (params_.java_use_vector()) { + printer->Print( + "public com.google.protobuf.micro.MessageMicro mergeFrom(\n" + " com.google.protobuf.micro.CodedInputStreamMicro input)\n" + " throws java.io.IOException {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "public $classname$ mergeFrom(\n" + " com.google.protobuf.micro.CodedInputStreamMicro input)\n" + " throws java.io.IOException {\n", + "classname", descriptor_->name()); + } + printer->Indent(); + + printer->Print( + "while (true) {\n"); + printer->Indent(); + + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); + + printer->Print( + "case 0:\n" // zero signals EOF / limit reached + " return this;\n" + "default: {\n" + " if (!parseUnknownField(input, tag)) {\n" + " return this;\n" // it's an endgroup tag + " }\n" + " break;\n" + "}\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32 tag = WireFormatLite::MakeTag(field->number(), + WireFormat::WireTypeForField(field)); + + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } + + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + " }\n" // while (true) + "}\n" + "\n"); +} + +void MessageGenerator:: +GenerateParseFromMethods(io::Printer* printer) { + bool is_own_file = + descriptor_->containing_type() == NULL; + + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + printer->Print( + "public $static$ $classname$ parseFrom(byte[] data)\n" + " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n" + " return ($classname$) (new $classname$().mergeFrom(data));\n" + "}\n" + "\n" + "public $static$ $classname$ parseFrom(\n" + " com.google.protobuf.micro.CodedInputStreamMicro input)\n" + " throws java.io.IOException {\n" + " return ($classname$) (new $classname$().mergeFrom(input));\n" + "}\n" + "\n", + "static", (is_own_file ? "static" : ""), + "classname", descriptor_->name()); +} + +void MessageGenerator::GenerateSerializeOneField( + io::Printer* printer, const FieldDescriptor* field) { + field_generators_.get(field).GenerateSerializationCode(printer); +} + +void MessageGenerator::GenerateClear(io::Printer* printer) { + printer->Print( + "public final $classname$ clear() {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Call clear for all of the fields. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + printer->Print( + "clear$name$();\n", + "name", UnderscoresToCapitalizedCamelCase(field)); + } + + printer->Outdent(); + printer->Print( + " cachedSize = -1;\n" + " return this;\n" + "}\n" + "\n"); +} + + +void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { + printer->Print( + "public final boolean isInitialized() {\n"); + printer->Indent(); + + // Check that all required fields in this message are set. + // TODO(kenton): We can optimize this when we switch to putting all the + // "has" fields into a single bitfield. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + + if (field->is_required()) { + printer->Print( + "if (!has$name$) return false;\n", + "name", UnderscoresToCapitalizedCamelCase(field)); + } + } + + // Now check that all embedded messages are initialized. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + HasRequiredFields(field->message_type())) { + switch (field->label()) { + case FieldDescriptor::LABEL_REQUIRED: + printer->Print( + "if (!get$name$().isInitialized()) return false;\n", + "type", ClassName(params_, field->message_type()), + "name", UnderscoresToCapitalizedCamelCase(field)); + break; + case FieldDescriptor::LABEL_OPTIONAL: + printer->Print( + "if (has$name$()) {\n" + " if (!get$name$().isInitialized()) return false;\n" + "}\n", + "type", ClassName(params_, field->message_type()), + "name", UnderscoresToCapitalizedCamelCase(field)); + break; + case FieldDescriptor::LABEL_REPEATED: + if (params_.java_use_vector()) { + printer->Print( + "for (int i = 0; i < get$name$List().size(); i++) {\n" + " if (get$name$(i).isInitialized()) return false;\n" + "}\n", + "type", ClassName(params_, field->message_type()), + "name", UnderscoresToCapitalizedCamelCase(field)); + } else { + printer->Print( + "for ($type$ element : get$name$List()) {\n" + " if (!element.isInitialized()) return false;\n" + "}\n", + "type", ClassName(params_, field->message_type()), + "name", UnderscoresToCapitalizedCamelCase(field)); + } + break; + } + } + } + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (!extensionsAreInitialized()) return false;\n"); + } + + printer->Outdent(); + printer->Print( + " return true;\n" + "}\n" + "\n"); +} + +// =================================================================== + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.h b/src/google/protobuf/compiler/javamicro/javamicro_message.h new file mode 100644 index 0000000..f44c7a7 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_message.h @@ -0,0 +1,93 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ + +#include <string> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javamicro/javamicro_params.h> +#include <google/protobuf/compiler/javamicro/javamicro_field.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javamicro { + +class MessageGenerator { + public: + explicit MessageGenerator(const Descriptor* descriptor, const Params& params); + ~MessageGenerator(); + + // All static variables have to be declared at the top-level of the file + // so that we can control initialization order, which is important for + // DescriptorProto bootstrapping to work. + void GenerateStaticVariables(io::Printer* printer); + + // Output code which initializes the static variables generated by + // GenerateStaticVariables(). + void GenerateStaticVariableInitializers(io::Printer* printer); + + // Generate the class itself. + void Generate(io::Printer* printer); + + private: + void GenerateMessageSerializationMethods(io::Printer* printer); + void GenerateMergeFromMethods(io::Printer* printer); + void GenerateParseFromMethods(io::Printer* printer); + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field); + + void GenerateClear(io::Printer* printer); + void GenerateIsInitialized(io::Printer* printer); + + const Params& params_; + const Descriptor* descriptor_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc new file mode 100644 index 0000000..103c302 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc @@ -0,0 +1,302 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javamicro/javamicro_message_field.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +namespace { + +// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of +// repeat code between this and the other field types. +void SetMessageVariables(const Params& params, + const FieldDescriptor* descriptor, map<string, string>* variables) { + (*variables)["name"] = + UnderscoresToCamelCase(descriptor); + (*variables)["capitalized_name"] = + UnderscoresToCapitalizedCamelCase(descriptor); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["type"] = ClassName(params, descriptor->message_type()); + (*variables)["group_or_message"] = + (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? + "Group" : "Message"; + (*variables)["message_name"] = descriptor->containing_type()->name(); + //(*variables)["message_type"] = descriptor->message_type()->name(); +} + +} // namespace + +// =================================================================== + +MessageFieldGenerator:: +MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetMessageVariables(params, descriptor, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +void MessageFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private boolean has$capitalized_name$;\n" +// "private $type$ $name$_ = null;\n" +// "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" +// "public $type$ get$capitalized_name$() { return $name$_; }\n" + "private $type$ $name$_ = null;\n" + "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" + "public $type$ get$capitalized_name$() { return $name$_; }\n" + "public $message_name$ set$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " has$capitalized_name$ = true;\n" + " $name$_ = value;\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " has$capitalized_name$ = false;\n" + " $name$_ = null;\n" + " return this;\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " merge$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$type$ value = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup(value, $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage(value);\n"); + } + + printer->Print(variables_, + "set$capitalized_name$(value);\n"); +} + +void MessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " output.write$group_or_message$($number$, get$capitalized_name$());\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" + "}\n"); +} + +string MessageFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->message_type()); +} + +// =================================================================== + +RepeatedMessageFieldGenerator:: +RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetMessageVariables(params, descriptor, &variables_); +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +void RepeatedMessageFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "private java.util.Vector $name$_ = new java.util.Vector();\n" + "public java.util.Vector get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public $type$ get$capitalized_name$(int index) {\n" + " return ($type$) $name$_.elementAt(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $name$_.setElementAt(value, index);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $name$_.addElement(value);\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_.removeAllElements();\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "private java.util.List<$type$> $name$_ =\n" + " java.util.Collections.emptyList();\n" + "public java.util.List<$type$> get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public $type$ get$capitalized_name$(int index) {\n" + " return $name$_.get(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " $name$_.set(index, value);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$($type$ value) {\n" + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n" + " if ($name$_.isEmpty()) {\n" + " $name$_ = new java.util.ArrayList<$type$>();\n" + " }\n" + " $name$_.add(value);\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = java.util.Collections.emptyList();\n" + " return this;\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "if (other.$name$_.size() != 0) {\n" + " for (int i = 0; i < other.$name$_.size(); i++) {\n" + " result.$name$_.addElement(other.$name$_.elementAt(i));\n" + " }\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if (result.$name$_.isEmpty()) {\n" + " result.$name$_ = new java.util.ArrayList<$type$>();\n" + " }\n" + " result.$name$_.addAll(other.$name$_);\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$type$ value = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup(value, $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage(value);\n"); + } + + printer->Print(variables_, + "add$capitalized_name$(value);\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.write$group_or_message$($number$, get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.write$group_or_message$($number$, element);\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .compute$group_or_message$Size($number$, get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .compute$group_or_message$Size($number$, element);\n" + "}\n"); + } +} + +string RepeatedMessageFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->message_type()); +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.h b/src/google/protobuf/compiler/javamicro/javamicro_message_field.h new file mode 100644 index 0000000..a32aa4e --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_message_field.h @@ -0,0 +1,95 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/javamicro/javamicro_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +class MessageFieldGenerator : public FieldGenerator { + public: + explicit MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params); + ~MessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +class RepeatedMessageFieldGenerator : public FieldGenerator { + public: + explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Params& params); + ~RepeatedMessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_params.h b/src/google/protobuf/compiler/javamicro/javamicro_params.h new file mode 100644 index 0000000..a4a72b7 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_params.h @@ -0,0 +1,143 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2010 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: wink@google.com (Wink Saville) + +#ifndef PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ +#define PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ + +#include <map> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +enum eOptimization { JAVAMICRO_OPT_SPEED, JAVAMICRO_OPT_SPACE, JAVAMICRO_OPT_DEFAULT = JAVAMICRO_OPT_SPACE }; + +// Parameters for used by the generators +class Params { + public: + typedef map<string, string> NameMap; + private: + string empty_; + string base_name_; + eOptimization optimization_; + bool java_multiple_files_; + bool java_use_vector_; + NameMap java_packages_; + NameMap java_outer_classnames_; + + public: + Params(const string & base_name) : + empty_(""), + base_name_(base_name), + optimization_(JAVAMICRO_OPT_DEFAULT), + java_multiple_files_(false), + java_use_vector_(false) { + } + + const string& base_name() const { + return base_name_; + } + + bool has_java_package(const string& file_name) const { + return java_packages_.find(file_name) + != java_packages_.end(); + } + void set_java_package(const string& file_name, + const string& java_package) { + java_packages_[file_name] = java_package; + } + const string& java_package(const string& file_name) const { + NameMap::const_iterator itr; + + itr = java_packages_.find(file_name); + if (itr == java_packages_.end()) { + return empty_; + } else { + return itr->second; + } + } + const NameMap& java_packages() { + return java_packages_; + } + + bool has_java_outer_classname(const string& file_name) const { + return java_outer_classnames_.find(file_name) + != java_outer_classnames_.end(); + } + void set_java_outer_classname(const string& file_name, + const string& java_outer_classname) { + java_outer_classnames_[file_name] = java_outer_classname; + } + const string& java_outer_classname(const string& file_name) const { + NameMap::const_iterator itr; + + itr = java_outer_classnames_.find(file_name); + if (itr == java_outer_classnames_.end()) { + return empty_; + } else { + return itr->second; + } + } + const NameMap& java_outer_classnames() { + return java_outer_classnames_; + } + + void set_optimization(eOptimization optimization) { + optimization_ = optimization; + } + eOptimization optimization() const { + return optimization_; + } + + void set_java_multiple_files(bool value) { + java_multiple_files_ = value; + } + bool java_multiple_files() const { + return java_multiple_files_; + } + + void set_java_use_vector(bool value) { + java_use_vector_ = value; + } + bool java_use_vector() const { + return java_use_vector_; + } + +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc new file mode 100644 index 0000000..d6daa44 --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc @@ -0,0 +1,660 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +const char* PrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "int"; + case JAVATYPE_LONG : return "long"; + case JAVATYPE_FLOAT : return "float"; + case JAVATYPE_DOUBLE : return "double"; + case JAVATYPE_BOOLEAN: return "boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "com.google.protobuf.micro.ByteStringMicro"; + case JAVATYPE_ENUM : return NULL; + case JAVATYPE_MESSAGE: return NULL; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +bool IsReferenceType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +const char* GetCapitalizedType(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32 : return "Int32" ; + case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; + case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; + case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; + case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; + case FieldDescriptor::TYPE_INT64 : return "Int64" ; + case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; + case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; + case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; + case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT : return "Float" ; + case FieldDescriptor::TYPE_DOUBLE : return "Double" ; + case FieldDescriptor::TYPE_BOOL : return "Bool" ; + case FieldDescriptor::TYPE_STRING : return "String" ; + case FieldDescriptor::TYPE_BYTES : return "Bytes" ; + case FieldDescriptor::TYPE_ENUM : return "Enum" ; + case FieldDescriptor::TYPE_GROUP : return "Group" ; + case FieldDescriptor::TYPE_MESSAGE : return "Message" ; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +// Return true if the type is a that has variable length +// for instance String's. +bool IsVariableLenType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +bool IsStringUtf8Handling(const FieldDescriptor* descriptor, + const Params params) { + return ((params.optimization() == JAVAMICRO_OPT_SPEED) + && (GetJavaType(descriptor) == JAVATYPE_STRING)); +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, + map<string, string>* variables) { + (*variables)["name"] = + UnderscoresToCamelCase(descriptor); + (*variables)["capitalized_name"] = + UnderscoresToCapitalizedCamelCase(descriptor); + (*variables)["number"] = SimpleItoa(descriptor->number()); + if (IsStringUtf8Handling(descriptor, params)) { + (*variables)["type"] = "com.google.protobuf.micro.StringUtf8Micro"; + string defaultValue = DefaultValue(params, descriptor); + if (defaultValue == "\"\"") { + (*variables)["default"] = + "com.google.protobuf.micro.StringUtf8Micro.EMPTY"; + } else { + (*variables)["default"] = "new com.google.protobuf.micro.StringUtf8Micro(" + + defaultValue + ")"; + } + } else { + (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["default"] = DefaultValue(params, descriptor); + } + (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), descriptor->type())); + if (IsReferenceType(GetJavaType(descriptor))) { + (*variables)["null_check"] = + " if (value == null) {\n" + " throw new NullPointerException();\n" + " }\n"; + } else { + (*variables)["null_check"] = ""; + } + int fixed_size = FixedSize(descriptor->type()); + if (fixed_size != -1) { + (*variables)["fixed_size"] = SimpleItoa(fixed_size); + } + (*variables)["message_name"] = descriptor->containing_type()->name(); +} +} // namespace + +// =================================================================== + +PrimitiveFieldGenerator:: +PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, params, &variables_); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +void PrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "private boolean has$capitalized_name$;\n" + "private $type$ $name$_ = $default$;\n" + "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"); + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + "public String get$capitalized_name$() { return $name$_.getString(); }\n" + "public $type$ get$capitalized_name$StringUtf8() { return $name$_; }\n" + "public $message_name$ set$capitalized_name$(String value) {\n" + " has$capitalized_name$ = true;\n" + " if ($name$_ == $default$) {\n" + " $name$_ = new $type$(value);\n" + " } else {\n" + " $name$_.setString(value);\n" + " }\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " has$capitalized_name$ = false;\n" + " $name$_ = $default$;\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "public $type$ get$capitalized_name$() { return $name$_; }\n"); + if (IsVariableLenType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "public $message_name$ set$capitalized_name$($type$ value) {\n" + " has$capitalized_name$ = true;\n" + " $name$_ = value;\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " has$capitalized_name$ = false;\n" + " $name$_ = $default$;\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "public $message_name$ set$capitalized_name$($type$ value) {\n" + " has$capitalized_name$ = true;\n" + " $name$_ = value;\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " has$capitalized_name$ = false;\n" + " $name$_ = $default$;\n" + " return this;\n" + "}\n"); + } + } +} + +void PrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.has$capitalized_name$()) {\n" + " set$capitalized_name$(other.get$capitalized_name$());\n" + "}\n"); +} + +void PrimitiveFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "set$capitalized_name$(input.read$capitalized_type$());\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " output.writeStringUtf8($number$, get$capitalized_name$StringUtf8());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " output.write$capitalized_type$($number$, get$capitalized_name$());\n" + "}\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeStringUtf8Size($number$, get$capitalized_name$StringUtf8());\n" + "}\n"); + } else { + printer->Print(variables_, + "if (has$capitalized_name$()) {\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .compute$capitalized_type$Size($number$, get$capitalized_name$());\n" + "}\n"); + } +} + +string PrimitiveFieldGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +// =================================================================== + +RepeatedPrimitiveFieldGenerator:: +RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, params, &variables_); + if (descriptor_->options().packed()) { + GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed"; + } +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + if (IsStringUtf8Handling(descriptor_, params_)) { + if (params_.java_use_vector()) { + printer->Print(variables_, + "private java.util.Vector $name$_ = new java.util.Vector();\n" + "public java.util.Vector get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public String get$capitalized_name$(int index) {\n" + " return (($type$)$name$_.elementAt(index)).getString();\n" + "}\n" + "public $type$ get$capitalized_name$StringUtf8(int index) {\n" + " return ($type$)$name$_.elementAt(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, String value) {\n" + "$null_check$" + " $name$_.setElementAt(new $type$(value), index);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$(String value) {\n" + "$null_check$" + " $name$_.addElement(new $type$(value));\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_.removeAllElements();\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "private java.util.List<$type$> $name$_ =\n" + " java.util.Collections.emptyList();\n" + "public java.util.List<$type$> get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public String get$capitalized_name$(int index) {\n" + " return $name$_.get(index).getString();\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, String value) {\n" + "$null_check$" + " $name$_.set(index, new $type$(value));\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$(String value) {\n" + "$null_check$" + " if ($name$_.isEmpty()) {\n" + " $name$_ = new java.util.ArrayList<$type$>();\n" + " }\n" + " $name$_.add(new $type$(value));\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = java.util.Collections.emptyList();\n" + " return this;\n" + "}\n"); + } + } else if (params_.java_use_vector()) { + if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "private java.util.Vector $name$_ = new java.util.Vector();\n" + "public java.util.Vector get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public $type$ get$capitalized_name$(int index) {\n" + " return ($type$) $name$_.elementAt(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" + "$null_check$" + " $name$_.setElementAt(value, index);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$($type$ value) {\n" + "$null_check$" + " $name$_.addElement(value);\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_.removeAllElements();\n" + " return this;\n" + "}\n"); + } else { + printer->Print(variables_, + "private java.util.Vector $name$_ = new java.util.Vector();\n" + "public java.util.Vector get$capitalized_name$List() {\n" + " return $name$_;\n" + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public $type$ get$capitalized_name$(int index) {\n" + " return (($boxed_type$)$name$_.elementAt(index)).$type$Value();\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" + "$null_check$" + " $name$_.setElementAt(new $boxed_type$(value), index);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$($type$ value) {\n" + "$null_check$" + " $name$_.addElement(new $boxed_type$(value));\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_.removeAllElements();\n" + " return this;\n" + "}\n"); + } + } else { + printer->Print(variables_, + "private java.util.List<$boxed_type$> $name$_ =\n" + " java.util.Collections.emptyList();\n" + "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n" + " return $name$_;\n" // note: unmodifiable list + "}\n" + "public int get$capitalized_name$Count() { return $name$_.size(); }\n" + "public $type$ get$capitalized_name$(int index) {\n" + " return $name$_.get(index);\n" + "}\n" + "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" + "$null_check$" + " $name$_.set(index, value);\n" + " return this;\n" + "}\n" + "public $message_name$ add$capitalized_name$($type$ value) {\n" + "$null_check$" + " if ($name$_.isEmpty()) {\n" + " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" + " }\n" + " $name$_.add(value);\n" + " return this;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = java.util.Collections.emptyList();\n" + " return this;\n" + "}\n"); + } + if (descriptor_->options().packed()) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + if (params_.java_use_vector()) { + printer->Print(variables_, + "if (other.$name$_.size() != 0) {\n" + " for (int i = 0; i < other.$name$_.size(); i++)) {\n" + " result.$name$_.addElement(other.$name$_.elementAt(i));\n" + " }\n" + "}\n"); + } else { + printer->Print(variables_, + "if (!other.$name$_.isEmpty()) {\n" + " if (result.$name$_.isEmpty()) {\n" + " result.$name$_ = new java.util.ArrayList<$type$>();\n" + " }\n" + " result.$name$_.addAll(other.$name$_);\n" + "}\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " add$capitalized_name$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); + } else { + printer->Print(variables_, + "add$capitalized_name$(input.read$capitalized_type$());\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n"); + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.write$capitalized_type$NoTag(get$capitalized_name$(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.write$capitalized_type$NoTag(element);\n" + "}\n"); + } + } else { + if (params_.java_use_vector()) { + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.writeStringUtf8($number$, get$capitalized_name$StringUtf8(i));\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " output.write$capitalized_type$($number$, get$capitalized_name$(i));\n" + "}\n"); + } + } else { + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.writeStringUtf8($number$, element);\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " output.write$capitalized_type$($number$, element);\n" + "}\n"); + } + } + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "{\n" + " int dataSize = 0;\n"); + printer->Indent(); + + if (FixedSize(descriptor_->type()) == -1) { + if (params_.java_use_vector()) { + printer->Print(variables_, + "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" + " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"); + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + " .computeStringUtf8SizeNoTag(get$capitalized_name$StringUtf8(i));\n" + "}\n"); + } else { + printer->Print(variables_, + " .compute$capitalized_type$SizeNoTag(($type$)get$capitalized_name$(i));\n" + "}\n"); + } + } else { + printer->Print(variables_, + "for ($type$ element : get$capitalized_name$List()) {\n" + " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"); + if (IsStringUtf8Handling(descriptor_, params_)) { + printer->Print(variables_, + " .computeStringUtf8SizeNoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + " .compute$capitalized_type$SizeNoTag(element);\n" + "}\n"); + } + } + } else { + printer->Print(variables_, + "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); + } + + printer->Print( + "size += dataSize;\n"); + + if (descriptor_->options().packed()) { + if (params_.java_use_vector()) { + printer->Print(variables_, + "if (get$capitalized_name$List().size() != 0) {\n"); + } else { + printer->Print(variables_, + "if (!get$capitalized_name$List().isEmpty()) {\n"); + } + printer->Print(variables_, + " size += $tag_size$;\n" + " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" + " .computeInt32SizeNoTag(dataSize);\n" + "}\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * get$capitalized_name$List().size();\n"); + } + + // cache the data size for packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "$name$MemoizedSerializedSize = dataSize;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h new file mode 100644 index 0000000..88d8eec --- /dev/null +++ b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h @@ -0,0 +1,94 @@ +// 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) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/javamicro/javamicro_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javamicro { + +class PrimitiveFieldGenerator : public FieldGenerator { + public: + explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params ¶ms); + ~PrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +class RepeatedPrimitiveFieldGenerator : public FieldGenerator { + public: + explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params); + ~RepeatedPrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateParsingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + + string GetBoxedType() const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace javamicro +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index d9b0c3f..813a011 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> +#include <google/protobuf/compiler/javamicro/javamicro_generator.h> int main(int argc, char* argv[]) { @@ -57,5 +58,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--python_out", &py_generator, "Generate Python source file."); + // Proto2 JavaMicro + google::protobuf::compiler::javamicro::JavaMicroGenerator javamicro_generator; + cli.RegisterGenerator("--javamicro_out", &javamicro_generator, + "Generate Java source file micro runtime."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/unittest_import_micro.proto b/src/google/protobuf/unittest_import_micro.proto new file mode 100644 index 0000000..adac807 --- /dev/null +++ b/src/google/protobuf/unittest_import_micro.proto @@ -0,0 +1,49 @@ +// 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) +// +// This is like unittest_import.proto but with optimize_for = MICRO_RUNTIME. + +package protobuf_unittest_import; + +// java_package and java_outer_classname are specified on the command line. +//option java_package = "com.google.protobuf.micro"; +//option java_outer_classname = "UnittestImportMicro"; + +message ImportMessageMicro { + optional int32 d = 1; +} + +enum ImportEnumMicro { + IMPORT_MICRO_FOO = 7; + IMPORT_MICRO_BAR = 8; + IMPORT_MICRO_BAZ = 9; +} diff --git a/src/google/protobuf/unittest_micro.proto b/src/google/protobuf/unittest_micro.proto new file mode 100644 index 0000000..3d7fcd2 --- /dev/null +++ b/src/google/protobuf/unittest_micro.proto @@ -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. + +// Author: wink@google.com (Wink Saville) + +package protobuf_unittest; + +import "google/protobuf/unittest_import_micro.proto"; + +option java_package = "com.google.protobuf.micro"; +option java_outer_classname = "MicroOuterClass"; + +// Same as TestAllTypes but with the micro runtime. +message TestAllTypesMicro { + + message NestedMessage { + optional int32 bb = 1; + } + + enum NestedEnum { + FOO = 1; + BAR = 2; + BAZ = 3; + } + + // Singular + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + + optional group OptionalGroup = 16 { + optional int32 a = 17; + } + + optional NestedMessage optional_nested_message = 18; + optional ForeignMessageMicro optional_foreign_message = 19; + optional protobuf_unittest_import.ImportMessageMicro + optional_import_message = 20; + + optional NestedEnum optional_nested_enum = 21; + optional ForeignEnumMicro optional_foreign_enum = 22; + optional protobuf_unittest_import.ImportEnumMicro optional_import_enum = 23; + + optional string optional_string_piece = 24 [ctype=STRING_PIECE]; + optional string optional_cord = 25 [ctype=CORD]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + repeated group RepeatedGroup = 46 { + optional int32 a = 47; + } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessageMicro repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessageMicro + repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnumMicro repeated_foreign_enum = 52; + repeated protobuf_unittest_import.ImportEnumMicro repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + // Singular with defaults + optional int32 default_int32 = 61 [default = 41 ]; + optional int64 default_int64 = 62 [default = 42 ]; + optional uint32 default_uint32 = 63 [default = 43 ]; + optional uint64 default_uint64 = 64 [default = 44 ]; + optional sint32 default_sint32 = 65 [default = -45 ]; + optional sint64 default_sint64 = 66 [default = 46 ]; + optional fixed32 default_fixed32 = 67 [default = 47 ]; + optional fixed64 default_fixed64 = 68 [default = 48 ]; + optional sfixed32 default_sfixed32 = 69 [default = 49 ]; + optional sfixed64 default_sfixed64 = 70 [default = -50 ]; + optional float default_float = 71 [default = 51.5 ]; + optional double default_double = 72 [default = 52e3 ]; + optional bool default_bool = 73 [default = true ]; + optional string default_string = 74 [default = "hello"]; + optional bytes default_bytes = 75 [default = "world"]; + + optional NestedEnum default_nested_enum = 81 [default = BAR]; + optional ForeignEnumMicro default_foreign_enum = 82 + [default = FOREIGN_MICRO_BAR]; + optional protobuf_unittest_import.ImportEnumMicro + default_import_enum = 83 [default = IMPORT_MICRO_BAR]; + + optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"]; + optional string default_cord = 85 [ctype=CORD,default="123"]; + + required int32 id = 86; +} + +message ForeignMessageMicro { + optional int32 c = 1; +} + +enum ForeignEnumMicro { + FOREIGN_MICRO_FOO = 4; + FOREIGN_MICRO_BAR = 5; + FOREIGN_MICRO_BAZ = 6; +} + +// Test that deprecated fields work. We only verify that they compile (at one +// point this failed). +message TestDeprecatedMicro { + optional int32 deprecated_field = 1 [deprecated = true]; +} diff --git a/src/google/protobuf/unittest_recursive_micro.proto b/src/google/protobuf/unittest_recursive_micro.proto new file mode 100644 index 0000000..a256852 --- /dev/null +++ b/src/google/protobuf/unittest_recursive_micro.proto @@ -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. + +// Author: wink@google.com (Wink Saville) +// + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.micro"; + +message RecursiveMessageMicro { + message NestedMessage { + optional RecursiveMessageMicro a = 1; + } + + required int32 id = 1; + optional NestedMessage nested_message = 2; + optional RecursiveMessageMicro optional_recursive_message_micro = 3; + repeated RecursiveMessageMicro repeated_recursive_message_micro = 4; +} diff --git a/src/google/protobuf/unittest_simple_micro.proto b/src/google/protobuf/unittest_simple_micro.proto new file mode 100644 index 0000000..057bf3d --- /dev/null +++ b/src/google/protobuf/unittest_simple_micro.proto @@ -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. + +// Author: wink@google.com (Wink Saville) +// + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.micro"; + +message SimpleMessageMicro { + message NestedMessage { + optional int32 bb = 1; + } + + enum NestedEnum { + FOO = 1; + BAR = 2; + BAZ = 3; + } + + optional int32 d = 1 [default = 123]; + optional NestedMessage nested_msg = 2; + optional NestedEnum default_nested_enum = 3 [default = BAZ]; +} diff --git a/src/google/protobuf/unittest_stringutf8_micro.proto b/src/google/protobuf/unittest_stringutf8_micro.proto new file mode 100644 index 0000000..e4bbe3d --- /dev/null +++ b/src/google/protobuf/unittest_stringutf8_micro.proto @@ -0,0 +1,41 @@ +// 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: wink@google.com (Wink Saville) +// + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.micro"; + +message StringUtf8 { + optional string id = 1; + repeated string rs = 2; +} |