From 2337023fd9686b61f73f91588583685abf7d5773 Mon Sep 17 00:00:00 2001 From: Ulas Kirazci Date: Thu, 14 Mar 2013 16:44:33 -0700 Subject: Nano protobufs. Like micro protobufs except: - No setter/getter/hazzer functions. - Has state is not available. Outputs all fields != their default. - CodedInputStream can only take byte[] (not InputStream). - Repeated fields are in arrays, not ArrayList or Vector. - Unset messages/groups are null, not "defaultInstance()". - Required fields are always serialized. To use: - Link libprotobuf-java-2.3.0-nano runtime. - Use LOCAL_PROTOC_OPTIMIZE_TYPE := nano Change-Id: I7429015b3c5f7f38b7be01eb2d4927f7a9999c80 --- Android.mk | 32 + java/README.txt | 51 + .../protobuf/nano/CodedInputByteBufferNano.java | 624 ++++++ .../protobuf/nano/CodedOutputByteBufferNano.java | 910 +++++++++ .../com/google/protobuf/nano/InternalNano.java | 113 ++ .../nano/InvalidProtocolBufferNanoException.java | 93 + .../java/com/google/protobuf/nano/MessageNano.java | 128 ++ .../com/google/protobuf/nano/WireFormatNano.java | 138 ++ .../test/java/com/google/protobuf/NanoTest.java | 2104 ++++++++++++++++++++ .../protobuf/compiler/javanano/javanano_enum.cc | 96 + .../protobuf/compiler/javanano/javanano_enum.h | 87 + .../compiler/javanano/javanano_enum_field.cc | 266 +++ .../compiler/javanano/javanano_enum_field.h | 94 + .../protobuf/compiler/javanano/javanano_field.cc | 102 + .../protobuf/compiler/javanano/javanano_field.h | 98 + .../protobuf/compiler/javanano/javanano_file.cc | 251 +++ .../protobuf/compiler/javanano/javanano_file.h | 94 + .../compiler/javanano/javanano_generator.cc | 170 ++ .../compiler/javanano/javanano_generator.h | 72 + .../protobuf/compiler/javanano/javanano_helpers.cc | 404 ++++ .../protobuf/compiler/javanano/javanano_helpers.h | 132 ++ .../protobuf/compiler/javanano/javanano_message.cc | 372 ++++ .../protobuf/compiler/javanano/javanano_message.h | 92 + .../compiler/javanano/javanano_message_field.cc | 216 ++ .../compiler/javanano/javanano_message_field.h | 95 + .../protobuf/compiler/javanano/javanano_params.h | 123 ++ .../compiler/javanano/javanano_primitive_field.cc | 493 +++++ .../compiler/javanano/javanano_primitive_field.h | 94 + src/google/protobuf/unittest_import_nano.proto | 49 + src/google/protobuf/unittest_nano.proto | 171 ++ src/google/protobuf/unittest_recursive_nano.proto | 47 + src/google/protobuf/unittest_simple_nano.proto | 52 + src/google/protobuf/unittest_stringutf8_nano.proto | 41 + 33 files changed, 7904 insertions(+) create mode 100644 java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java create mode 100644 java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java create mode 100644 java/src/main/java/com/google/protobuf/nano/InternalNano.java create mode 100644 java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java create mode 100644 java/src/main/java/com/google/protobuf/nano/MessageNano.java create mode 100644 java/src/main/java/com/google/protobuf/nano/WireFormatNano.java create mode 100644 java/src/test/java/com/google/protobuf/NanoTest.java create mode 100644 src/google/protobuf/compiler/javanano/javanano_enum.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_enum.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_enum_field.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_enum_field.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_field.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_field.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_file.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_file.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_generator.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_generator.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_helpers.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_helpers.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_message.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_message.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_message_field.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_message_field.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_params.h create mode 100644 src/google/protobuf/compiler/javanano/javanano_primitive_field.cc create mode 100644 src/google/protobuf/compiler/javanano/javanano_primitive_field.h create mode 100644 src/google/protobuf/unittest_import_nano.proto create mode 100644 src/google/protobuf/unittest_nano.proto create mode 100644 src/google/protobuf/unittest_recursive_nano.proto create mode 100644 src/google/protobuf/unittest_simple_nano.proto create mode 100644 src/google/protobuf/unittest_stringutf8_nano.proto diff --git a/Android.mk b/Android.mk index 889764dd..dd489223 100644 --- a/Android.mk +++ b/Android.mk @@ -106,6 +106,15 @@ COMPILER_SRC_FILES := \ src/google/protobuf/compiler/javamicro/javamicro_message.cc \ src/google/protobuf/compiler/javamicro/javamicro_message_field.cc \ src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc \ + src/google/protobuf/compiler/javanano/javanano_enum.cc \ + src/google/protobuf/compiler/javanano/javanano_enum_field.cc \ + src/google/protobuf/compiler/javanano/javanano_field.cc \ + src/google/protobuf/compiler/javanano/javanano_file.cc \ + src/google/protobuf/compiler/javanano/javanano_generator.cc \ + src/google/protobuf/compiler/javanano/javanano_helpers.cc \ + src/google/protobuf/compiler/javanano/javanano_message.cc \ + src/google/protobuf/compiler/javanano/javanano_message_field.cc \ + src/google/protobuf/compiler/javanano/javanano_primitive_field.cc \ src/google/protobuf/compiler/python/python_generator.cc \ src/google/protobuf/io/coded_stream.cc \ src/google/protobuf/io/gzip_stream.cc \ @@ -121,6 +130,29 @@ COMPILER_SRC_FILES := \ src/google/protobuf/stubs/strutil.cc \ src/google/protobuf/stubs/substitute.cc +# Java nano library (for device-side users) +# ======================================================= +include $(CLEAR_VARS) + +LOCAL_MODULE := libprotobuf-java-2.3.0-nano +LOCAL_MODULE_TAGS := optional +LOCAL_SDK_VERSION := 8 + +LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano) + +include $(BUILD_STATIC_JAVA_LIBRARY) + +# Java nano library (for host-side users) +# ======================================================= +include $(CLEAR_VARS) + +LOCAL_MODULE := host-libprotobuf-java-2.3.0-nano +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/nano) + +include $(BUILD_HOST_JAVA_LIBRARY) + # Java micro library (for device-side users) # ======================================================= include $(CLEAR_VARS) diff --git a/java/README.txt b/java/README.txt index 8972792d..82c1ed53 100644 --- a/java/README.txt +++ b/java/README.txt @@ -260,6 +260,57 @@ This could be compiled using: With the result will be com/example/TestMessages.java +Nano version +============================ + +Nano is even smaller than micro, especially in the number of generated +functions. It is like micro except: + +- No setter/getter/hazzer functions. +- Has state is not available. Outputs all fields not equal to their + default. (See important implications below.) +- CodedInputStreamMicro is renamed to CodedInputByteBufferNano and can + only take byte[] (not InputStream). +- Similar rename from CodedOutputStreamMicro to + CodedOutputByteBufferNano. +- Repeated fields are in arrays, not ArrayList or Vector. +- Unset messages/groups are null, not an immutable empty default + instance. +- Required fields are always serialized. +- toByteArray(...) and mergeFrom(...) are now static functions of + MessageNano. +- "bytes" are of java type byte[]. + +IMPORTANT: If you have fields with defaults + +How fields with defaults are serialized has changed. Because we don't +keep "has" state, any field equal to its default is assumed to be not +set and therefore is not serialized. Consider the situation where we +change the default value of a field. Senders compiled against an older +version of the proto continue to match against the old default, and +don't send values to the receiver even though the receiver assumes the +new default value. Therefore, think carefully about the implications +of changing the default value. + +IMPORTANT: If you have "bytes" fields with non-empty defaults + +Because the byte buffer is now of mutable type byte[], the default +static final cannot be exposed through a public field. Each time a +message's constructor or clear() function is called, the default value +(kept in a private byte[]) is cloned. This causes a small memory +penalty. This is not a problem if the field has no default or is an +empty default. + + +To use nano protobufs: + +- Link with the generated jar file + java/target/protobuf-java-2.3.0-nano.jar. +- Invoke with --javanano_out, e.g.: + +../src/protoc '--javanano_out=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 + + Usage ===== diff --git a/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java new file mode 100644 index 00000000..ed387882 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java @@ -0,0 +1,624 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano; + +import java.io.IOException; + +/** + * 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 CodedInputByteBufferNano { + /** + * Create a new CodedInputStream wrapping the given byte array. + */ + public static CodedInputByteBufferNano newInstance(final byte[] buf) { + return newInstance(buf, 0, buf.length); + } + + /** + * Create a new CodedInputStream wrapping the given byte array slice. + */ + public static CodedInputByteBufferNano newInstance(final byte[] buf, final int off, + final int len) { + return new CodedInputByteBufferNano(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 InvalidProtocolBufferNanoException.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 InvalidProtocolBufferNanoException {@code value} does not match the + * last tag. + */ + public void checkLastTagWas(final int value) + throws InvalidProtocolBufferNanoException { + if (lastTag != value) { + throw InvalidProtocolBufferNanoException.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 (WireFormatNano.getTagWireType(tag)) { + case WireFormatNano.WIRETYPE_VARINT: + readInt32(); + return true; + case WireFormatNano.WIRETYPE_FIXED64: + readRawLittleEndian64(); + return true; + case WireFormatNano.WIRETYPE_LENGTH_DELIMITED: + skipRawBytes(readRawVarint32()); + return true; + case WireFormatNano.WIRETYPE_START_GROUP: + skipMessage(); + checkLastTagWas( + WireFormatNano.makeTag(WireFormatNano.getTagFieldNumber(tag), + WireFormatNano.WIRETYPE_END_GROUP)); + return true; + case WireFormatNano.WIRETYPE_END_GROUP: + return false; + case WireFormatNano.WIRETYPE_FIXED32: + readRawLittleEndian32(); + return true; + default: + throw InvalidProtocolBufferNanoException.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 MessageNano msg, final int fieldNumber) + throws IOException { + if (recursionDepth >= recursionLimit) { + throw InvalidProtocolBufferNanoException.recursionLimitExceeded(); + } + ++recursionDepth; + msg.mergeFrom(this); + checkLastTagWas( + WireFormatNano.makeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP)); + --recursionDepth; + } + + public void readMessage(final MessageNano msg) + throws IOException { + final int length = readRawVarint32(); + if (recursionDepth >= recursionLimit) { + throw InvalidProtocolBufferNanoException.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 byte[] 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 byte[] result = new byte[size]; + System.arraycopy(buffer, bufferPos, result, 0, size); + bufferPos += size; + return result; + } else { + // Slow path: Build a byte array first then copy it. + return 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 InvalidProtocolBufferNanoException.malformedVarint(); + } + } + } + } + return result; + } + + /** 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 InvalidProtocolBufferNanoException.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 bufferStart; + private int bufferSize; + private int bufferSizeAfterLimit; + private int bufferPos; + private int lastTag; + + /** 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 CodedInputByteBufferNano(final byte[] buffer, final int off, final int len) { + this.buffer = buffer; + bufferStart = off; + bufferSize = off + len; + bufferPos = off; + } + + /** + * 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. + *

+ * 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() { + } + + /** + * 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 InvalidProtocolBufferNanoException { + if (byteLimit < 0) { + throw InvalidProtocolBufferNanoException.negativeSize(); + } + byteLimit += bufferPos; + final int oldLimit = currentLimit; + if (byteLimit > oldLimit) { + throw InvalidProtocolBufferNanoException.truncatedMessage(); + } + currentLimit = byteLimit; + + recomputeBufferSizeAfterLimit(); + + return oldLimit; + } + + private void recomputeBufferSizeAfterLimit() { + bufferSize += bufferSizeAfterLimit; + final int bufferEnd = 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 = 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() { + return bufferPos == bufferSize; + } + + /** + * Get current position in buffer relative to beginning offset. + */ + public int getPosition() { + return bufferPos - bufferStart; + } + + /** + * Rewind to previous position. Cannot go forward. + */ + public void rewindToPosition(int position) { + if (position > bufferPos - bufferStart) { + throw new IllegalArgumentException( + "Position " + position + " is beyond current " + (bufferPos - bufferStart)); + } + if (position < 0) { + throw new IllegalArgumentException("Bad position " + position); + } + bufferPos = bufferStart + position; + } + + /** + * Read one byte from the input. + * + * @throws InvalidProtocolBufferNanoException The end of the stream or the current + * limit was reached. + */ + public byte readRawByte() throws IOException { + if (bufferPos == bufferSize) { + throw InvalidProtocolBufferNanoException.truncatedMessage(); + } + return buffer[bufferPos++]; + } + + /** + * Read a fixed size of bytes from the input. + * + * @throws InvalidProtocolBufferNanoException The end of the stream or the current + * limit was reached. + */ + public byte[] readRawBytes(final int size) throws IOException { + if (size < 0) { + throw InvalidProtocolBufferNanoException.negativeSize(); + } + + if (bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + skipRawBytes(currentLimit - bufferPos); + // Then fail. + throw InvalidProtocolBufferNanoException.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 { + throw InvalidProtocolBufferNanoException.truncatedMessage(); + } + } + + /** + * Reads and discards {@code size} bytes. + * + * @throws InvalidProtocolBufferNanoException The end of the stream or the current + * limit was reached. + */ + public void skipRawBytes(final int size) throws IOException { + if (size < 0) { + throw InvalidProtocolBufferNanoException.negativeSize(); + } + + if (bufferPos + size > currentLimit) { + // Read to the end of the stream anyway. + skipRawBytes(currentLimit - bufferPos); + // Then fail. + throw InvalidProtocolBufferNanoException.truncatedMessage(); + } + + if (size <= bufferSize - bufferPos) { + // We have all the bytes we need already. + bufferPos += size; + } else { + throw InvalidProtocolBufferNanoException.truncatedMessage(); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java new file mode 100644 index 00000000..769bb19c --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java @@ -0,0 +1,910 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +/** + * Encodes and writes protocol message fields. + * + *

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. + * + *

This class is totally unsynchronized. + * + * @author kneton@google.com Kenton Varda + */ +public final class CodedOutputByteBufferNano { + private final byte[] buffer; + private final int limit; + private int position; + + private CodedOutputByteBufferNano(final byte[] buffer, final int offset, + final int length) { + this.buffer = buffer; + position = offset; + limit = offset + length; + } + + /** + * 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 CodedOutputByteBufferNano 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 CodedOutputByteBufferNano newInstance(final byte[] flatArray, + final int offset, + final int length) { + return new CodedOutputByteBufferNano(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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + /** Write a {@code group} field, including tag, to the stream. */ + public void writeGroup(final int fieldNumber, final MessageNano value) + throws IOException { + writeTag(fieldNumber, WireFormatNano.WIRETYPE_START_GROUP); + writeGroupNoTag(value); + writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP); + } + + /** Write an embedded message field, including tag, to the stream. */ + public void writeMessage(final int fieldNumber, final MessageNano value) + throws IOException { + writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + /** Write a {@code bytes} field, including tag, to the stream. */ + public void writeBytes(final int fieldNumber, final byte[] value) + throws IOException { + writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + /** Write a {@code byte} field, including tag, to the stream. */ + public void writeByteArray(final int fieldNumber, final byte[] value) + throws IOException { + writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED); + writeByteArrayNoTag(value); + } + + + /** Write a {@code uint32} field, including tag, to the stream. */ + public void writeUInt32(final int fieldNumber, final int value) + throws IOException { + writeTag(fieldNumber, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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, WireFormatNano.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 group} field to the stream. */ + public void writeGroupNoTag(final MessageNano value) throws IOException { + value.writeTo(this); + } + + /** Write an embedded message field to the stream. */ + public void writeMessageNoTag(final MessageNano value) throws IOException { + writeRawVarint32(value.getCachedSize()); + value.writeTo(this); + } + + /** Write a {@code bytes} field to the stream. */ + public void writeBytesNoTag(final byte[] value) throws IOException { + writeRawVarint32(value.length); + writeRawBytes(value); + } + + /** Write a {@code byte[]} field to the stream. */ + public void writeByteArrayNoTag(final byte [] value) throws IOException { + writeRawVarint32(value.length); + writeRawBytes(value); + } + + /** 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 group} field, including tag. + */ + public static int computeGroupSize(final int fieldNumber, + final MessageNano 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 MessageNano 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 byte[] value) { + return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code byte[]} field, including tag. + */ + public static int computeByteArraySize(final int fieldNumber, + final byte[] value) { + return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(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 group} field. + */ + public static int computeGroupSizeNoTag(final MessageNano value) { + return value.getSerializedSize(); + } + + /** + * Compute the number of bytes that would be needed to encode an embedded + * message field. + */ + public static int computeMessageSizeNoTag(final MessageNano value) { + final int size = value.getSerializedSize(); + return computeRawVarint32Size(size) + size; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeBytesSizeNoTag(final byte[] value) { + return computeRawVarint32Size(value.length) + value.length; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code byte[]} field. + */ + public static int computeByteArraySizeNoTag(final byte[] value) { + return computeRawVarint32Size(value.length) + value.length; + } + + /** + * 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)); + } + + // ================================================================= + + /** + * If writing to a flat array, return the space left in the array. + * Otherwise, throws {@code UnsupportedOperationException}. + */ + public int spaceLeft() { + return limit - position; + } + + /** + * 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(int position, int limit) { + super("CodedOutputStream was writing to a flat byte array and ran " + + "out of space (pos " + position + " limit " + limit + ")."); + } + } + + /** Write a single byte. */ + public void writeRawByte(final byte value) throws IOException { + if (position == limit) { + // We're writing to a single buffer. + throw new OutOfSpaceException(position, limit); + } + + 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 { + // We're writing to a single buffer. + throw new OutOfSpaceException(position, limit); + } + } + + /** Encode and write a tag. */ + public void writeTag(final int fieldNumber, final int wireType) + throws IOException { + writeRawVarint32(WireFormatNano.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(WireFormatNano.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/nano/InternalNano.java b/java/src/main/java/com/google/protobuf/nano/InternalNano.java new file mode 100644 index 00000000..49309516 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/InternalNano.java @@ -0,0 +1,113 @@ +// 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.nano; + +import java.io.UnsupportedEncodingException; + +/** + * The classes contained within are used internally by the Protocol Buffer + * library and generated message implementations. They are public only because + * those generated messages do not reside in the {@code protobuf} package. + * Others should not use this class directly. + * + * @author kenton@google.com (Kenton Varda) + */ +public class InternalNano { + /** + * Helper called by generated code to construct default values for string + * fields. + *

+ * The protocol compiler does not actually contain a UTF-8 decoder -- it + * just pushes UTF-8-encoded text around without touching it. The one place + * where this presents a problem is when generating Java string literals. + * Unicode characters in the string literal would normally need to be encoded + * using a Unicode escape sequence, which would require decoding them. + * To get around this, protoc instead embeds the UTF-8 bytes into the + * generated code and leaves it to the runtime library to decode them. + *

+ * It gets worse, though. If protoc just generated a byte array, like: + * new byte[] {0x12, 0x34, 0x56, 0x78} + * Java actually generates *code* which allocates an array and then fills + * in each value. This is much less efficient than just embedding the bytes + * directly into the bytecode. To get around this, we need another + * work-around. String literals are embedded directly, so protoc actually + * generates a string literal corresponding to the bytes. The easiest way + * to do this is to use the ISO-8859-1 character set, which corresponds to + * the first 256 characters of the Unicode range. Protoc can then use + * good old CEscape to generate the string. + *

+ * So we have a string literal which represents a set of bytes which + * represents another string. This function -- stringDefaultValue -- + * converts from the generated string to the string we actually want. The + * generated code calls this automatically. + */ + public static final String stringDefaultValue(String bytes) { + try { + return new String(bytes.getBytes("ISO-8859-1"), "UTF-8"); + } catch (UnsupportedEncodingException e) { + // This should never happen since all JVMs are required to implement + // both of the above character sets. + throw new IllegalStateException( + "Java VM does not support a standard character set.", e); + } + } + + /** + * Helper called by generated code to construct default values for bytes + * fields. + *

+ * This is a lot like {@link #stringDefaultValue}, but for bytes fields. + * In this case we only need the second of the two hacks -- allowing us to + * embed raw bytes as a string literal with ISO-8859-1 encoding. + */ + public static final byte[] bytesDefaultValue(String bytes) { + try { + return bytes.getBytes("ISO-8859-1"); + } catch (UnsupportedEncodingException e) { + // This should never happen since all JVMs are required to implement + // ISO-8859-1. + throw new IllegalStateException( + "Java VM does not support a standard character set.", e); + } + } + + /** + * Helper function to convert a string into UTF-8 while turning the + * UnsupportedEncodingException to a RuntimeException. + */ + public static final byte[] copyFromUtf8(final String text) { + try { + return text.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("UTF-8 not supported?"); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java b/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java new file mode 100644 index 00000000..ff0af9df --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java @@ -0,0 +1,93 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano; + +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 InvalidProtocolBufferNanoException extends IOException { + private static final long serialVersionUID = -1616151763072450476L; + + public InvalidProtocolBufferNanoException(final String description) { + super(description); + } + + static InvalidProtocolBufferNanoException truncatedMessage() { + return new InvalidProtocolBufferNanoException( + "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 InvalidProtocolBufferNanoException negativeSize() { + return new InvalidProtocolBufferNanoException( + "CodedInputStream encountered an embedded string or message " + + "which claimed to have negative size."); + } + + static InvalidProtocolBufferNanoException malformedVarint() { + return new InvalidProtocolBufferNanoException( + "CodedInputStream encountered a malformed varint."); + } + + static InvalidProtocolBufferNanoException invalidTag() { + return new InvalidProtocolBufferNanoException( + "Protocol message contained an invalid tag (zero)."); + } + + static InvalidProtocolBufferNanoException invalidEndTag() { + return new InvalidProtocolBufferNanoException( + "Protocol message end-group tag did not match expected tag."); + } + + static InvalidProtocolBufferNanoException invalidWireType() { + return new InvalidProtocolBufferNanoException( + "Protocol message tag had invalid wire type."); + } + + static InvalidProtocolBufferNanoException recursionLimitExceeded() { + return new InvalidProtocolBufferNanoException( + "Protocol message had too many levels of nesting. May be malicious. " + + "Use CodedInputStream.setRecursionLimit() to increase the depth limit."); + } + + static InvalidProtocolBufferNanoException sizeLimitExceeded() { + return new InvalidProtocolBufferNanoException( + "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/nano/MessageNano.java b/java/src/main/java/com/google/protobuf/nano/MessageNano.java new file mode 100644 index 00000000..66080cc8 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/MessageNano.java @@ -0,0 +1,128 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano; + +import java.io.IOException; + +/** + * Abstract interface implemented by Protocol Message objects. + * + * @author wink@google.com Wink Saville + */ +public abstract class MessageNano { + /** + * 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(CodedOutputByteBufferNano output) throws java.io.IOException; + + /** + * Parse {@code input} as a message of this type and merge it with the + * message being built. + */ + abstract public MessageNano mergeFrom(final CodedInputByteBufferNano input) throws IOException; + + /** + * Serialize to a byte array. + * @return byte array with the serialized data. + */ + public static final byte[] toByteArray(MessageNano msg) { + final byte[] result = new byte[msg.getSerializedSize()]; + toByteArray(msg, 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 static final void toByteArray(MessageNano msg, byte [] data, int offset, int length) { + try { + final CodedOutputByteBufferNano output = + CodedOutputByteBufferNano.newInstance(data, offset, length); + msg.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 static final MessageNano mergeFrom(MessageNano msg, final byte[] data) + throws InvalidProtocolBufferNanoException { + return mergeFrom(msg, data, 0, data.length); + } + + /** + * Parse {@code data} as a message of this type and merge it with the + * message being built. + */ + public static final MessageNano mergeFrom(MessageNano msg, final byte[] data, final int off, + final int len) throws InvalidProtocolBufferNanoException { + try { + final CodedInputByteBufferNano input = + CodedInputByteBufferNano.newInstance(data, off, len); + msg.mergeFrom(input); + input.checkLastTagWas(0); + return msg; + } catch (InvalidProtocolBufferNanoException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException("Reading from a byte array threw an IOException (should " + + "never happen)."); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java new file mode 100644 index 00000000..8fa36364 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java @@ -0,0 +1,138 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano; + +import java.io.IOException; + +/** + * 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 WireFormatNano { + // Do not allow instantiation. + private WireFormatNano() {} + + 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); + + public static final int EMPTY_INT_ARRAY[] = {}; + public static final long EMPTY_LONG_ARRAY[] = {}; + public static final float EMPTY_FLOAT_ARRAY[] = {}; + public static final double EMPTY_DOUBLE_ARRAY[] = {}; + public static final boolean EMPTY_BOOLEAN_ARRAY[] = {}; + public static final String EMPTY_STRING_ARRAY[] = {}; + public static final byte[] EMPTY_BYTES_ARRAY[] = {}; + public static final byte[] EMPTY_BYTES = {}; + + /** + * Called by subclasses to parse an unknown field. + * @return {@code true} unless the tag is an end-group tag. + */ + public static boolean parseUnknownField( + final CodedInputByteBufferNano input, + final int tag) throws IOException { + return input.skipField(tag); + } + + /** + * Computes the array length of a repeated field. We assume that in the common case repeated + * fields are contiguously serialized but we still correctly handle interspersed values of a + * repeated field (but with extra allocations). + * + * Rewinds to current input position before returning. + * + * @param input stream input, pointing to the byte after the first tag + * @param tag repeated field tag just read + * @return length of array + * @throws IOException + */ + public static final int getRepeatedFieldArrayLength( + final CodedInputByteBufferNano input, + final int tag) throws IOException { + int arrayLength = 1; + int startPos = input.getPosition(); + input.skipField(tag); + while (input.getBytesUntilLimit() > 0) { + int thisTag = input.readTag(); + if (thisTag != tag) { + break; + } + input.skipField(tag); + arrayLength++; + } + input.rewindToPosition(startPos); + return arrayLength; + } +} diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java new file mode 100644 index 00000000..85389d1f --- /dev/null +++ b/java/src/test/java/com/google/protobuf/NanoTest.java @@ -0,0 +1,2104 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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.nano.InternalNano; +import com.google.protobuf.nano.MessageNano; +import com.google.protobuf.nano.NanoOuterClass; +import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano; +import com.google.protobuf.nano.RecursiveMessageNano; +import com.google.protobuf.nano.SimpleMessageNano; +import com.google.protobuf.nano.UnittestImportNano; +import com.google.protobuf.nano.CodedInputByteBufferNano; + +import junit.framework.TestCase; + +/** + * Test nano runtime. + * + * @author ulas@google.com Ulas Kirazci + */ +public class NanoTest extends TestCase { + public void setUp() throws Exception { + } + + public void testSimpleMessageNano() throws Exception { + SimpleMessageNano msg = new SimpleMessageNano(); + assertEquals(123, msg.d); + assertEquals(null, msg.nestedMsg); + assertEquals(SimpleMessageNano.BAZ, msg.defaultNestedEnum); + + msg.d = 456; + assertEquals(456, msg.d); + + SimpleMessageNano.NestedMessage nestedMsg = new SimpleMessageNano.NestedMessage(); + nestedMsg.bb = 2; + assertEquals(2, nestedMsg.bb); + msg.nestedMsg = nestedMsg; + assertEquals(2, msg.nestedMsg.bb); + + msg.defaultNestedEnum = SimpleMessageNano.BAR; + assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum); + + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + SimpleMessageNano newMsg = SimpleMessageNano.parseFrom(result); + assertEquals(456, newMsg.d); + assertEquals(2, msg.nestedMsg.bb); + assertEquals(SimpleMessageNano.BAR, msg.defaultNestedEnum); + } + + public void testRecursiveMessageNano() throws Exception { + RecursiveMessageNano msg = new RecursiveMessageNano(); + assertTrue(msg.repeatedRecursiveMessageNano.length == 0); + + RecursiveMessageNano msg1 = new RecursiveMessageNano(); + msg1.id = 1; + assertEquals(1, msg1.id); + RecursiveMessageNano msg2 = new RecursiveMessageNano(); + msg2.id = 2; + RecursiveMessageNano msg3 = new RecursiveMessageNano(); + msg3.id = 3; + + RecursiveMessageNano.NestedMessage nestedMsg = new RecursiveMessageNano.NestedMessage(); + nestedMsg.a = msg1; + assertEquals(1, nestedMsg.a.id); + + msg.id = 0; + msg.nestedMessage = nestedMsg; + msg.optionalRecursiveMessageNano = msg2; + msg.repeatedRecursiveMessageNano = new RecursiveMessageNano[] { msg3 }; + + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 16); + assertEquals(result.length, msgSerializedSize); + + RecursiveMessageNano newMsg = RecursiveMessageNano.parseFrom(result); + assertEquals(1, newMsg.repeatedRecursiveMessageNano.length); + + assertEquals(0, newMsg.id); + assertEquals(1, newMsg.nestedMessage.a.id); + assertEquals(2, newMsg.optionalRecursiveMessageNano.id); + assertEquals(3, newMsg.repeatedRecursiveMessageNano[0].id); + } + + public void testNanoRequiredInt32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.id = 123; + assertEquals(123, msg.id); + msg.clear().id = 456; + assertEquals(456, msg.id); + msg.clear(); + + msg.id = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.id); + } + + public void testNanoOptionalInt32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalInt32 = 123; + assertEquals(123, msg.optionalInt32); + msg.clear() + .optionalInt32 = 456; + assertEquals(456, msg.optionalInt32); + msg.clear(); + + msg.optionalInt32 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalInt32); + } + + public void testNanoOptionalInt64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalInt64 = 123; + assertEquals(123, msg.optionalInt64); + msg.clear() + .optionalInt64 = 456; + assertEquals(456, msg.optionalInt64); + msg.clear(); + assertEquals(0, msg.optionalInt64); + + msg.optionalInt64 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalInt64); + } + + public void testNanoOptionalUint32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalUint32 = 123; + assertEquals(123, msg.optionalUint32); + msg.clear() + .optionalUint32 = 456; + assertEquals(456, msg.optionalUint32); + msg.clear(); + assertEquals(0, msg.optionalUint32); + + msg.optionalUint32 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalUint32); + } + + public void testNanoOptionalUint64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalUint64 = 123; + assertEquals(123, msg.optionalUint64); + msg.clear() + .optionalUint64 = 456; + assertEquals(456, msg.optionalUint64); + msg.clear(); + assertEquals(0, msg.optionalUint64); + + msg.optionalUint64 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalUint64); + } + + public void testNanoOptionalSint32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalSint32 = 123; + assertEquals(123, msg.optionalSint32); + msg.clear() + .optionalSint32 = 456; + assertEquals(456, msg.optionalSint32); + msg.clear(); + assertEquals(0, msg.optionalSint32); + + msg.optionalSint32 = -123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(-123, newMsg.optionalSint32); + } + + public void testNanoOptionalSint64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalSint64 = 123; + assertEquals(123, msg.optionalSint64); + msg.clear() + .optionalSint64 = 456; + assertEquals(456, msg.optionalSint64); + msg.clear(); + assertEquals(0, msg.optionalSint64); + + msg.optionalSint64 = -123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(-123, newMsg.optionalSint64); + } + + public void testNanoOptionalFixed32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalFixed32 = 123; + assertEquals(123, msg.optionalFixed32); + msg.clear() + .optionalFixed32 = 456; + assertEquals(456, msg.optionalFixed32); + msg.clear(); + assertEquals(0, msg.optionalFixed32); + + msg.optionalFixed32 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalFixed32); + } + + public void testNanoOptionalFixed64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalFixed64 = 123; + assertEquals(123, msg.optionalFixed64); + msg.clear() + .optionalFixed64 = 456; + assertEquals(456, msg.optionalFixed64); + msg.clear(); + assertEquals(0, msg.optionalFixed64); + + msg.optionalFixed64 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalFixed64); + } + + public void testNanoOptionalSfixed32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalSfixed32 = 123; + assertEquals(123, msg.optionalSfixed32); + msg.clear() + .optionalSfixed32 = 456; + assertEquals(456, msg.optionalSfixed32); + msg.clear(); + assertEquals(0, msg.optionalSfixed32); + + msg.optionalSfixed32 = 123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(123, newMsg.optionalSfixed32); + } + + public void testNanoOptionalSfixed64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalSfixed64 = 123; + assertEquals(123, msg.optionalSfixed64); + msg.clear() + .optionalSfixed64 = 456; + assertEquals(456, msg.optionalSfixed64); + msg.clear(); + assertEquals(0, msg.optionalSfixed64); + + msg.optionalSfixed64 = -123; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(-123, newMsg.optionalSfixed64); + } + + public void testNanoOptionalFloat() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalFloat = 123f; + assertTrue(123.0f == msg.optionalFloat); + msg.clear() + .optionalFloat = 456.0f; + assertTrue(456.0f == msg.optionalFloat); + msg.clear(); + assertTrue(0.0f == msg.optionalFloat); + + msg.optionalFloat = -123.456f; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(-123.456f == newMsg.optionalFloat); + } + + public void testNanoOptionalDouble() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalDouble = 123; + assertTrue(123.0 == msg.optionalDouble); + msg.clear() + .optionalDouble = 456.0; + assertTrue(456.0 == msg.optionalDouble); + msg.clear(); + assertTrue(0.0 == msg.optionalDouble); + + msg.optionalDouble = -123.456; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 12); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(-123.456 == newMsg.optionalDouble); + } + + public void testNanoOptionalBool() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalBool = true; + assertTrue(msg.optionalBool); + msg.clear() + .optionalBool = true; + assertTrue(msg.optionalBool); + msg.clear(); + assertFalse(msg.optionalBool); + + msg.optionalBool = true; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 5); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalBool); + } + + public void testNanoOptionalString() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalString = "hello"; + assertEquals("hello", msg.optionalString); + msg.clear(); + assertTrue(msg.optionalString.isEmpty()); + msg.clear() + .optionalString = "hello2"; + assertEquals("hello2", msg.optionalString); + msg.clear(); + assertTrue(msg.optionalString.isEmpty()); + + msg.optionalString = "bye"; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalString != null); + assertEquals("bye", newMsg.optionalString); + } + + public void testNanoOptionalBytes() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertFalse(msg.optionalBytes.length > 0); + msg.optionalBytes = InternalNano.copyFromUtf8("hello"); + assertTrue(msg.optionalBytes.length > 0); + assertEquals("hello", new String(msg.optionalBytes, "UTF-8")); + msg.clear(); + assertFalse(msg.optionalBytes.length > 0); + msg.clear() + .optionalBytes = InternalNano.copyFromUtf8("hello"); + assertTrue(msg.optionalBytes.length > 0); + msg.clear(); + assertFalse(msg.optionalBytes.length > 0); + + msg.optionalBytes = InternalNano.copyFromUtf8("bye"); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalBytes.length > 0); + assertEquals("bye", new String(newMsg.optionalBytes, "UTF-8")); + } + + public void testNanoOptionalGroup() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + TestAllTypesNano.OptionalGroup grp = new TestAllTypesNano.OptionalGroup(); + grp.a = 1; + assertFalse(msg.optionalGroup != null); + msg.optionalGroup = grp; + assertTrue(msg.optionalGroup != null); + assertEquals(1, msg.optionalGroup.a); + msg.clear(); + assertFalse(msg.optionalGroup != null); + msg.clear() + .optionalGroup = new TestAllTypesNano.OptionalGroup(); + msg.optionalGroup.a = 2; + assertTrue(msg.optionalGroup != null); + msg.clear(); + assertFalse(msg.optionalGroup != null); + + msg.optionalGroup = grp; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalGroup != null); + assertEquals(1, newMsg.optionalGroup.a); + } + + public void testNanoOptionalNestedMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + TestAllTypesNano.NestedMessage nestedMsg = new TestAllTypesNano.NestedMessage(); + nestedMsg.bb = 1; + assertFalse(msg.optionalNestedMessage != null); + msg.optionalNestedMessage = nestedMsg; + assertTrue(msg.optionalNestedMessage != null); + assertEquals(1, msg.optionalNestedMessage.bb); + msg.clear(); + assertFalse(msg.optionalNestedMessage != null); + msg.clear() + .optionalNestedMessage = new TestAllTypesNano.NestedMessage(); + msg.optionalNestedMessage.bb = 2; + assertTrue(msg.optionalNestedMessage != null); + msg.clear(); + assertFalse(msg.optionalNestedMessage != null); + + msg.optionalNestedMessage = nestedMsg; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalNestedMessage != null); + assertEquals(1, newMsg.optionalNestedMessage.bb); + } + + public void testNanoOptionalForeignMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + NanoOuterClass.ForeignMessageNano nestedMsg = new NanoOuterClass.ForeignMessageNano(); + nestedMsg.c = 1; + assertFalse(msg.optionalForeignMessage != null); + msg.optionalForeignMessage = nestedMsg; + assertTrue(msg.optionalForeignMessage != null); + assertEquals(1, msg.optionalForeignMessage.c); + msg.clear(); + assertFalse(msg.optionalForeignMessage != null); + msg.clear() + .optionalForeignMessage = new NanoOuterClass.ForeignMessageNano(); + msg.optionalForeignMessage.c = 2; + assertTrue(msg.optionalForeignMessage != null); + msg.clear(); + assertFalse(msg.optionalForeignMessage != null); + + msg.optionalForeignMessage = nestedMsg; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalForeignMessage != null); + assertEquals(1, newMsg.optionalForeignMessage.c); + } + + public void testNanoOptionalImportMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + UnittestImportNano.ImportMessageNano nestedMsg = new UnittestImportNano.ImportMessageNano(); + nestedMsg.d = 1; + assertFalse(msg.optionalImportMessage != null); + msg.optionalImportMessage = nestedMsg; + assertTrue(msg.optionalImportMessage != null); + assertEquals(1, msg.optionalImportMessage.d); + msg.clear(); + assertFalse(msg.optionalImportMessage != null); + msg.clear() + .optionalImportMessage = new UnittestImportNano.ImportMessageNano(); + msg.optionalImportMessage.d = 2; + assertTrue(msg.optionalImportMessage != null); + msg.clear(); + assertFalse(msg.optionalImportMessage != null); + + msg.optionalImportMessage = nestedMsg; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalImportMessage != null); + assertEquals(1, newMsg.optionalImportMessage.d); + } + + public void testNanoOptionalNestedEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalNestedEnum = TestAllTypesNano.BAR; + assertEquals(TestAllTypesNano.BAR, msg.optionalNestedEnum); + msg.clear() + .optionalNestedEnum = TestAllTypesNano.BAZ; + assertEquals(TestAllTypesNano.BAZ, msg.optionalNestedEnum); + msg.clear(); + assertEquals(TestAllTypesNano.FOO, msg.optionalNestedEnum); + + msg.optionalNestedEnum = TestAllTypesNano.BAR; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(TestAllTypesNano.BAR, newMsg.optionalNestedEnum); + } + + public void testNanoOptionalForeignEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR; + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.optionalForeignEnum); + msg.clear() + .optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAZ; + assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.optionalForeignEnum); + msg.clear(); + assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.optionalForeignEnum); + + msg.optionalForeignEnum = NanoOuterClass.FOREIGN_NANO_BAR; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, newMsg.optionalForeignEnum); + } + + public void testNanoOptionalImportEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR; + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.optionalImportEnum); + msg.clear() + .optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAZ; + assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.optionalImportEnum); + msg.clear(); + assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.optionalImportEnum); + + msg.optionalImportEnum = UnittestImportNano.IMPORT_NANO_BAR; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, newMsg.optionalImportEnum); + } + + public void testNanoOptionalStringPiece() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalStringPiece = "hello"; + assertEquals("hello", msg.optionalStringPiece); + msg.clear(); + assertTrue(msg.optionalStringPiece.isEmpty()); + msg.clear() + .optionalStringPiece = "hello2"; + assertEquals("hello2", msg.optionalStringPiece); + msg.clear(); + assertTrue(msg.optionalStringPiece.isEmpty()); + + msg.optionalStringPiece = "bye"; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalStringPiece != null); + assertEquals("bye", newMsg.optionalStringPiece); + } + + public void testNanoOptionalCord() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.optionalCord = "hello"; + assertEquals("hello", msg.optionalCord); + msg.clear(); + assertTrue(msg.optionalCord.isEmpty()); + msg.clear() + .optionalCord = "hello2"; + assertEquals("hello2", msg.optionalCord); + msg.clear(); + assertTrue(msg.optionalCord.isEmpty()); + + msg.optionalCord = "bye"; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertTrue(newMsg.optionalCord != null); + assertEquals("bye", newMsg.optionalCord); + } + + public void testNanoRepeatedInt32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedInt32.length); + msg.repeatedInt32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedInt32[1]); + assertEquals(456, msg.repeatedInt32[2]); + msg.clear(); + assertEquals(0, msg.repeatedInt32.length); + msg.clear() + .repeatedInt32 = new int[] { 456 }; + assertEquals(1, msg.repeatedInt32.length); + assertEquals(456, msg.repeatedInt32[0]); + msg.clear(); + assertEquals(0, msg.repeatedInt32.length); + + // Test 1 entry + msg.clear() + .repeatedInt32 = new int[] { 123 }; + assertEquals(1, msg.repeatedInt32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedInt32.length); + assertEquals(123, newMsg.repeatedInt32[0]); + + // Test 2 entries + msg.clear() + .repeatedInt32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedInt32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedInt32.length); + assertEquals(123, newMsg.repeatedInt32[0]); + assertEquals(456, newMsg.repeatedInt32[1]); + } + + public void testNanoRepeatedInt64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedInt64.length); + msg.repeatedInt64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedInt64[1]); + assertEquals(456, msg.repeatedInt64[2]); + msg.clear(); + assertEquals(0, msg.repeatedInt64.length); + msg.clear() + .repeatedInt64 = new long[] { 456 }; + assertEquals(1, msg.repeatedInt64.length); + assertEquals(456, msg.repeatedInt64[0]); + msg.clear(); + assertEquals(0, msg.repeatedInt64.length); + + // Test 1 entry + msg.clear() + .repeatedInt64 = new long[] { 123 }; + assertEquals(1, msg.repeatedInt64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedInt64.length); + assertEquals(123, newMsg.repeatedInt64[0]); + + // Test 2 entries + msg.clear() + .repeatedInt64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedInt64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedInt64.length); + assertEquals(123, newMsg.repeatedInt64[0]); + assertEquals(456, newMsg.repeatedInt64[1]); + } + + public void testNanoRepeatedUint32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedUint32.length); + msg.repeatedUint32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedUint32[1]); + assertEquals(456, msg.repeatedUint32[2]); + msg.clear(); + assertEquals(0, msg.repeatedUint32.length); + msg.clear() + .repeatedUint32 = new int[] { 456 }; + assertEquals(1, msg.repeatedUint32.length); + assertEquals(456, msg.repeatedUint32[0]); + msg.clear(); + assertEquals(0, msg.repeatedUint32.length); + + // Test 1 entry + msg.clear() + .repeatedUint32 = new int[] { 123 }; + assertEquals(1, msg.repeatedUint32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedUint32.length); + assertEquals(123, newMsg.repeatedUint32[0]); + + // Test 2 entries + msg.clear() + .repeatedUint32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedUint32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedUint32.length); + assertEquals(123, newMsg.repeatedUint32[0]); + assertEquals(456, newMsg.repeatedUint32[1]); + } + + public void testNanoRepeatedUint64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedUint64.length); + msg.repeatedUint64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedUint64[1]); + assertEquals(456, msg.repeatedUint64[2]); + msg.clear(); + assertEquals(0, msg.repeatedUint64.length); + msg.clear() + .repeatedUint64 = new long[] { 456 }; + assertEquals(1, msg.repeatedUint64.length); + assertEquals(456, msg.repeatedUint64[0]); + msg.clear(); + assertEquals(0, msg.repeatedUint64.length); + + // Test 1 entry + msg.clear() + .repeatedUint64 = new long[] { 123 }; + assertEquals(1, msg.repeatedUint64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedUint64.length); + assertEquals(123, newMsg.repeatedUint64[0]); + + // Test 2 entries + msg.clear() + .repeatedUint64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedUint64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 10); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedUint64.length); + assertEquals(123, newMsg.repeatedUint64[0]); + assertEquals(456, newMsg.repeatedUint64[1]); + } + + public void testNanoRepeatedSint32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedSint32.length); + msg.repeatedSint32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedSint32[1]); + assertEquals(456, msg.repeatedSint32[2]); + msg.clear(); + assertEquals(0, msg.repeatedSint32.length); + msg.clear() + .repeatedSint32 = new int[] { 456 }; + assertEquals(1, msg.repeatedSint32.length); + assertEquals(456, msg.repeatedSint32[0]); + msg.clear(); + assertEquals(0, msg.repeatedSint32.length); + + // Test 1 entry + msg.clear() + .repeatedSint32 = new int[] { 123 }; + assertEquals(1, msg.repeatedSint32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedSint32.length); + assertEquals(123, newMsg.repeatedSint32[0]); + + // Test 2 entries + msg.clear() + .repeatedSint32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedSint32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 11); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedSint32.length); + assertEquals(123, newMsg.repeatedSint32[0]); + assertEquals(456, newMsg.repeatedSint32[1]); + } + + public void testNanoRepeatedSint64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedSint64.length); + msg.repeatedSint64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedSint64[1]); + assertEquals(456, msg.repeatedSint64[2]); + msg.clear(); + assertEquals(0, msg.repeatedSint64.length); + msg.clear() + .repeatedSint64 = new long[] { 456 }; + assertEquals(1, msg.repeatedSint64.length); + assertEquals(456, msg.repeatedSint64[0]); + msg.clear(); + assertEquals(0, msg.repeatedSint64.length); + + // Test 1 entry + msg.clear() + .repeatedSint64 = new long[] { 123 }; + assertEquals(1, msg.repeatedSint64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedSint64.length); + assertEquals(123, newMsg.repeatedSint64[0]); + + // Test 2 entries + msg.clear() + .repeatedSint64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedSint64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 11); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedSint64.length); + assertEquals(123, newMsg.repeatedSint64[0]); + assertEquals(456, newMsg.repeatedSint64[1]); + } + + public void testNanoRepeatedFixed32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedFixed32.length); + msg.repeatedFixed32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedFixed32[1]); + assertEquals(456, msg.repeatedFixed32[2]); + msg.clear(); + assertEquals(0, msg.repeatedFixed32.length); + msg.clear() + .repeatedFixed32 = new int[] { 456 }; + assertEquals(1, msg.repeatedFixed32.length); + assertEquals(456, msg.repeatedFixed32[0]); + msg.clear(); + assertEquals(0, msg.repeatedFixed32.length); + + // Test 1 entry + msg.clear() + .repeatedFixed32 = new int[] { 123 }; + assertEquals(1, msg.repeatedFixed32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedFixed32.length); + assertEquals(123, newMsg.repeatedFixed32[0]); + + // Test 2 entries + msg.clear() + .repeatedFixed32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedFixed32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 15); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedFixed32.length); + assertEquals(123, newMsg.repeatedFixed32[0]); + assertEquals(456, newMsg.repeatedFixed32[1]); + } + + public void testNanoRepeatedFixed64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedFixed64.length); + msg.repeatedFixed64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedFixed64[1]); + assertEquals(456, msg.repeatedFixed64[2]); + msg.clear(); + assertEquals(0, msg.repeatedFixed64.length); + msg.clear() + .repeatedFixed64 = new long[] { 456 }; + assertEquals(1, msg.repeatedFixed64.length); + assertEquals(456, msg.repeatedFixed64[0]); + msg.clear(); + assertEquals(0, msg.repeatedFixed64.length); + + // Test 1 entry + msg.clear() + .repeatedFixed64 = new long[] { 123 }; + assertEquals(1, msg.repeatedFixed64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 13); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedFixed64.length); + assertEquals(123, newMsg.repeatedFixed64[0]); + + // Test 2 entries + msg.clear() + .repeatedFixed64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedFixed64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 23); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedFixed64.length); + assertEquals(123, newMsg.repeatedFixed64[0]); + assertEquals(456, newMsg.repeatedFixed64[1]); + } + + public void testNanoRepeatedSfixed32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedSfixed32.length); + msg.repeatedSfixed32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedSfixed32[1]); + assertEquals(456, msg.repeatedSfixed32[2]); + msg.clear(); + assertEquals(0, msg.repeatedSfixed32.length); + msg.clear() + .repeatedSfixed32 = new int[] { 456 }; + assertEquals(1, msg.repeatedSfixed32.length); + assertEquals(456, msg.repeatedSfixed32[0]); + msg.clear(); + assertEquals(0, msg.repeatedSfixed32.length); + + // Test 1 entry + msg.clear() + .repeatedSfixed32 = new int[] { 123 }; + assertEquals(1, msg.repeatedSfixed32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedSfixed32.length); + assertEquals(123, newMsg.repeatedSfixed32[0]); + + // Test 2 entries + msg.clear() + .repeatedSfixed32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedSfixed32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 15); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedSfixed32.length); + assertEquals(123, newMsg.repeatedSfixed32[0]); + assertEquals(456, newMsg.repeatedSfixed32[1]); + } + + public void testNanoRepeatedSfixed64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedSfixed64.length); + msg.repeatedSfixed64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedSfixed64[1]); + assertEquals(456, msg.repeatedSfixed64[2]); + msg.clear(); + assertEquals(0, msg.repeatedSfixed64.length); + msg.clear() + .repeatedSfixed64 = new long[] { 456 }; + assertEquals(1, msg.repeatedSfixed64.length); + assertEquals(456, msg.repeatedSfixed64[0]); + msg.clear(); + assertEquals(0, msg.repeatedSfixed64.length); + + // Test 1 entry + msg.clear() + .repeatedSfixed64 = new long[] { 123 }; + assertEquals(1, msg.repeatedSfixed64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 13); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedSfixed64.length); + assertEquals(123, newMsg.repeatedSfixed64[0]); + + // Test 2 entries + msg.clear() + .repeatedSfixed64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedSfixed64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 23); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedSfixed64.length); + assertEquals(123, newMsg.repeatedSfixed64[0]); + assertEquals(456, newMsg.repeatedSfixed64[1]); + } + + public void testNanoRepeatedFloat() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedFloat.length); + msg.repeatedFloat = new float[] { 123f, 789f, 456f }; + assertEquals(789f, msg.repeatedFloat[1]); + assertEquals(456f, msg.repeatedFloat[2]); + msg.clear(); + assertEquals(0, msg.repeatedFloat.length); + msg.clear() + .repeatedFloat = new float[] { 456f }; + assertEquals(1, msg.repeatedFloat.length); + assertEquals(456f, msg.repeatedFloat[0]); + msg.clear(); + assertEquals(0, msg.repeatedFloat.length); + + // Test 1 entry + msg.clear() + .repeatedFloat = new float[] { 123f }; + assertEquals(1, msg.repeatedFloat.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedFloat.length); + assertEquals(123f, newMsg.repeatedFloat[0]); + + // Test 2 entries + msg.clear() + .repeatedFloat = new float[] { 123f, 456f }; + assertEquals(2, msg.repeatedFloat.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 15); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedFloat.length); + assertEquals(123f, newMsg.repeatedFloat[0]); + assertEquals(456f, newMsg.repeatedFloat[1]); + } + + public void testNanoRepeatedDouble() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedDouble.length); + msg.repeatedDouble = new double[] { 123.0, 789.0, 456.0 }; + assertEquals(789.0, msg.repeatedDouble[1]); + assertEquals(456.0, msg.repeatedDouble[2]); + msg.clear(); + assertEquals(0, msg.repeatedDouble.length); + msg.clear() + .repeatedDouble = new double[] { 456.0 }; + assertEquals(1, msg.repeatedDouble.length); + assertEquals(456.0, msg.repeatedDouble[0]); + msg.clear(); + assertEquals(0, msg.repeatedDouble.length); + + // Test 1 entry + msg.clear() + .repeatedDouble = new double[] { 123.0 }; + assertEquals(1, msg.repeatedDouble.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 13); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedDouble.length); + assertEquals(123.0, newMsg.repeatedDouble[0]); + + // Test 2 entries + msg.clear() + .repeatedDouble = new double[] { 123.0, 456.0 }; + assertEquals(2, msg.repeatedDouble.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 23); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedDouble.length); + assertEquals(123.0, newMsg.repeatedDouble[0]); + assertEquals(456.0, newMsg.repeatedDouble[1]); + } + + public void testNanoRepeatedBool() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedBool.length); + msg.repeatedBool = new boolean[] { false, true, false }; + assertTrue(msg.repeatedBool[1]); + assertFalse(msg.repeatedBool[2]); + msg.clear(); + assertEquals(0, msg.repeatedBool.length); + msg.clear() + .repeatedBool = new boolean[] { true }; + assertEquals(1, msg.repeatedBool.length); + assertTrue(msg.repeatedBool[0]); + msg.clear(); + assertEquals(0, msg.repeatedBool.length); + + // Test 1 entry + msg.clear() + .repeatedBool = new boolean[] { false }; + assertEquals(1, msg.repeatedBool.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedBool.length); + assertFalse(newMsg.repeatedBool[0]); + + // Test 2 entries + msg.clear() + .repeatedBool = new boolean[] { true, false }; + assertEquals(2, msg.repeatedBool.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedBool.length); + assertTrue(newMsg.repeatedBool[0]); + assertFalse(newMsg.repeatedBool[1]); + } + + public void testNanoRepeatedString() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedString.length); + msg.repeatedString = new String[] { "hello", "bye", "boo" }; + assertEquals("bye", msg.repeatedString[1]); + assertEquals("boo", msg.repeatedString[2]); + msg.clear(); + assertEquals(0, msg.repeatedString.length); + msg.clear() + .repeatedString = new String[] { "boo" }; + assertEquals(1, msg.repeatedString.length); + assertEquals("boo", msg.repeatedString[0]); + msg.clear(); + assertEquals(0, msg.repeatedString.length); + + // Test 1 entry + msg.clear() + .repeatedString = new String[] { "" }; + assertEquals(1, msg.repeatedString.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedString.length); + assertTrue(newMsg.repeatedString[0].isEmpty()); + + // Test 2 entries + msg.clear() + .repeatedString = new String[] { "hello", "world" }; + assertEquals(2, msg.repeatedString.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 19); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedString.length); + assertEquals("hello", newMsg.repeatedString[0]); + assertEquals("world", newMsg.repeatedString[1]); + } + + public void testNanoRepeatedBytes() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedBytes.length); + msg.repeatedBytes = new byte[][] { + InternalNano.copyFromUtf8("hello"), + InternalNano.copyFromUtf8("bye"), + InternalNano.copyFromUtf8("boo") + }; + assertEquals("bye", new String(msg.repeatedBytes[1], "UTF-8")); + assertEquals("boo", new String(msg.repeatedBytes[2], "UTF-8")); + msg.clear(); + assertEquals(0, msg.repeatedBytes.length); + msg.clear() + .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("boo") }; + assertEquals(1, msg.repeatedBytes.length); + assertEquals("boo", new String(msg.repeatedBytes[0], "UTF-8")); + msg.clear(); + assertEquals(0, msg.repeatedBytes.length); + + // Test 1 entry + msg.clear() + .repeatedBytes = new byte[][] { InternalNano.copyFromUtf8("") }; + assertEquals(1, msg.repeatedBytes.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedBytes.length); + assertTrue(newMsg.repeatedBytes[0].length == 0); + + // Test 2 entries + msg.clear() + .repeatedBytes = new byte[][] { + InternalNano.copyFromUtf8("hello"), + InternalNano.copyFromUtf8("world") + }; + assertEquals(2, msg.repeatedBytes.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 19); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedBytes.length); + assertEquals("hello", new String(newMsg.repeatedBytes[0], "UTF-8")); + assertEquals("world", new String(newMsg.repeatedBytes[1], "UTF-8")); + } + + public void testNanoRepeatedGroup() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + TestAllTypesNano.RepeatedGroup group0 = + new TestAllTypesNano.RepeatedGroup(); + group0.a = 0; + TestAllTypesNano.RepeatedGroup group1 = + new TestAllTypesNano.RepeatedGroup(); + group1.a = 1; + TestAllTypesNano.RepeatedGroup group2 = + new TestAllTypesNano.RepeatedGroup(); + group2.a = 2; + + msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1, group2 }; + assertEquals(3, msg.repeatedGroup.length); + assertEquals(0, msg.repeatedGroup[0].a); + assertEquals(1, msg.repeatedGroup[1].a); + assertEquals(2, msg.repeatedGroup[2].a); + msg.clear(); + assertEquals(0, msg.repeatedGroup.length); + msg.clear() + .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group1 }; + assertEquals(1, msg.repeatedGroup.length); + assertEquals(1, msg.repeatedGroup[0].a); + msg.clear(); + assertEquals(0, msg.repeatedGroup.length); + + // Test 1 entry + msg.clear() + .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0 }; + assertEquals(1, msg.repeatedGroup.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedGroup.length); + assertEquals(0, newMsg.repeatedGroup[0].a); + + // Test 2 entries + msg.clear() + .repeatedGroup = new TestAllTypesNano.RepeatedGroup[] { group0, group1 }; + assertEquals(2, msg.repeatedGroup.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 14); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedGroup.length); + assertEquals(0, newMsg.repeatedGroup[0].a); + assertEquals(1, newMsg.repeatedGroup[1].a); + } + + public void testNanoRepeatedNestedMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + TestAllTypesNano.NestedMessage nestedMsg0 = + new TestAllTypesNano.NestedMessage(); + nestedMsg0.bb = 0; + TestAllTypesNano.NestedMessage nestedMsg1 = + new TestAllTypesNano.NestedMessage(); + nestedMsg1.bb = 1; + TestAllTypesNano.NestedMessage nestedMsg2 = + new TestAllTypesNano.NestedMessage(); + nestedMsg2.bb = 2; + + msg.repeatedNestedMessage = + new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1, nestedMsg2 }; + assertEquals(3, msg.repeatedNestedMessage.length); + assertEquals(0, msg.repeatedNestedMessage[0].bb); + assertEquals(1, msg.repeatedNestedMessage[1].bb); + assertEquals(2, msg.repeatedNestedMessage[2].bb); + msg.clear(); + assertEquals(0, msg.repeatedNestedMessage.length); + msg.clear() + .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg1 }; + assertEquals(1, msg.repeatedNestedMessage.length); + assertEquals(1, msg.repeatedNestedMessage[0].bb); + msg.clear(); + assertEquals(0, msg.repeatedNestedMessage.length); + + // Test 1 entry + msg.clear() + .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 }; + assertEquals(1, msg.repeatedNestedMessage.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedNestedMessage.length); + assertEquals(0, newMsg.repeatedNestedMessage[0].bb); + + // Test 2 entries + msg.clear() + .repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0, nestedMsg1 }; + assertEquals(2, msg.repeatedNestedMessage.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 11); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedNestedMessage.length); + assertEquals(0, newMsg.repeatedNestedMessage[0].bb); + assertEquals(1, newMsg.repeatedNestedMessage[1].bb); + } + + public void testNanoRepeatedForeignMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + NanoOuterClass.ForeignMessageNano foreignMsg0 = + new NanoOuterClass.ForeignMessageNano(); + foreignMsg0.c = 0; + NanoOuterClass.ForeignMessageNano foreignMsg1 = + new NanoOuterClass.ForeignMessageNano(); + foreignMsg1.c = 1; + NanoOuterClass.ForeignMessageNano foreignMsg2 = + new NanoOuterClass.ForeignMessageNano(); + foreignMsg2.c = 2; + + msg.repeatedForeignMessage = + new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 }; + assertEquals(3, msg.repeatedForeignMessage.length); + assertEquals(0, msg.repeatedForeignMessage[0].c); + assertEquals(1, msg.repeatedForeignMessage[1].c); + assertEquals(2, msg.repeatedForeignMessage[2].c); + msg.clear(); + assertEquals(0, msg.repeatedForeignMessage.length); + msg.clear() + .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg1 }; + assertEquals(1, msg.repeatedForeignMessage.length); + assertEquals(1, msg.repeatedForeignMessage[0].c); + msg.clear(); + assertEquals(0, msg.repeatedForeignMessage.length); + + // Test 1 entry + msg.clear() + .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0 }; + assertEquals(1, msg.repeatedForeignMessage.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedForeignMessage.length); + assertEquals(0, newMsg.repeatedForeignMessage[0].c); + + // Test 2 entries + msg.clear() + .repeatedForeignMessage = new NanoOuterClass.ForeignMessageNano[] { foreignMsg0, foreignMsg1 }; + assertEquals(2, msg.repeatedForeignMessage.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 11); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedForeignMessage.length); + assertEquals(0, newMsg.repeatedForeignMessage[0].c); + assertEquals(1, newMsg.repeatedForeignMessage[1].c); + } + + public void testNanoRepeatedImportMessage() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + UnittestImportNano.ImportMessageNano foreignMsg0 = + new UnittestImportNano.ImportMessageNano(); + foreignMsg0.d = 0; + UnittestImportNano.ImportMessageNano foreignMsg1 = + new UnittestImportNano.ImportMessageNano(); + foreignMsg1.d = 1; + UnittestImportNano.ImportMessageNano foreignMsg2 = + new UnittestImportNano.ImportMessageNano(); + foreignMsg2.d = 2; + + msg.repeatedImportMessage = + new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1, foreignMsg2 }; + assertEquals(3, msg.repeatedImportMessage.length); + assertEquals(0, msg.repeatedImportMessage[0].d); + assertEquals(1, msg.repeatedImportMessage[1].d); + assertEquals(2, msg.repeatedImportMessage[2].d); + msg.clear(); + assertEquals(0, msg.repeatedImportMessage.length); + msg.clear() + .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg1 }; + assertEquals(1, msg.repeatedImportMessage.length); + assertEquals(1, msg.repeatedImportMessage[0].d); + msg.clear(); + assertEquals(0, msg.repeatedImportMessage.length); + + // Test 1 entry + msg.clear() + .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0 }; + assertEquals(1, msg.repeatedImportMessage.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedImportMessage.length); + assertEquals(0, newMsg.repeatedImportMessage[0].d); + + // Test 2 entries + msg.clear() + .repeatedImportMessage = new UnittestImportNano.ImportMessageNano[] { foreignMsg0, foreignMsg1 }; + assertEquals(2, msg.repeatedImportMessage.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 11); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedImportMessage.length); + assertEquals(0, newMsg.repeatedImportMessage[0].d); + assertEquals(1, newMsg.repeatedImportMessage[1].d); + } + + public void testNanoRepeatedNestedEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedNestedEnum = new int[] { + TestAllTypesNano.FOO, + TestAllTypesNano.BAR, + TestAllTypesNano.BAZ + }; + assertEquals(3, msg.repeatedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]); + assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]); + assertEquals(TestAllTypesNano.BAZ, msg.repeatedNestedEnum[2]); + msg.clear(); + assertEquals(0, msg.repeatedNestedEnum.length); + msg.clear() + .repeatedNestedEnum = new int[] { TestAllTypesNano.BAR }; + assertEquals(1, msg.repeatedNestedEnum.length); + assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[0]); + msg.clear(); + assertEquals(0, msg.repeatedNestedEnum.length); + + // Test 1 entry + msg.clear() + .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO }; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]); + + // Test 2 entries + msg.clear() + .repeatedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR }; + assertEquals(2, msg.repeatedNestedEnum.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedNestedEnum[0]); + assertEquals(TestAllTypesNano.BAR, msg.repeatedNestedEnum[1]); + } + + public void testNanoRepeatedForeignEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedForeignEnum = new int[] { + NanoOuterClass.FOREIGN_NANO_FOO, + NanoOuterClass.FOREIGN_NANO_BAR, + NanoOuterClass.FOREIGN_NANO_BAZ + }; + assertEquals(3, msg.repeatedForeignEnum.length); + assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAZ, msg.repeatedForeignEnum[2]); + msg.clear(); + assertEquals(0, msg.repeatedForeignEnum.length); + msg.clear() + .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_BAR }; + assertEquals(1, msg.repeatedForeignEnum.length); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[0]); + msg.clear(); + assertEquals(0, msg.repeatedForeignEnum.length); + + // Test 1 entry + msg.clear() + .repeatedForeignEnum = new int[] { NanoOuterClass.FOREIGN_NANO_FOO }; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedForeignEnum.length); + assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]); + + // Test 2 entries + msg.clear() + .repeatedForeignEnum = new int[] { + NanoOuterClass.FOREIGN_NANO_FOO, + NanoOuterClass.FOREIGN_NANO_BAR + }; + assertEquals(2, msg.repeatedForeignEnum.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedForeignEnum.length); + assertEquals(NanoOuterClass.FOREIGN_NANO_FOO, msg.repeatedForeignEnum[0]); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.repeatedForeignEnum[1]); + } + + public void testNanoRepeatedImportEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedImportEnum = new int[] { + UnittestImportNano.IMPORT_NANO_FOO, + UnittestImportNano.IMPORT_NANO_BAR, + UnittestImportNano.IMPORT_NANO_BAZ + }; + assertEquals(3, msg.repeatedImportEnum.length); + assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]); + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]); + assertEquals(UnittestImportNano.IMPORT_NANO_BAZ, msg.repeatedImportEnum[2]); + msg.clear(); + assertEquals(0, msg.repeatedImportEnum.length); + msg.clear() + .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_BAR }; + assertEquals(1, msg.repeatedImportEnum.length); + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[0]); + msg.clear(); + assertEquals(0, msg.repeatedImportEnum.length); + + // Test 1 entry + msg.clear() + .repeatedImportEnum = new int[] { UnittestImportNano.IMPORT_NANO_FOO }; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedImportEnum.length); + assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]); + + // Test 2 entries + msg.clear() + .repeatedImportEnum = new int[] { + UnittestImportNano.IMPORT_NANO_FOO, + UnittestImportNano.IMPORT_NANO_BAR + }; + assertEquals(2, msg.repeatedImportEnum.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedImportEnum.length); + assertEquals(UnittestImportNano.IMPORT_NANO_FOO, msg.repeatedImportEnum[0]); + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.repeatedImportEnum[1]); + } + + public void testNanoRepeatedStringPiece() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedStringPiece.length); + msg.repeatedStringPiece = new String[] { "hello", "bye", "boo" }; + assertEquals("bye", msg.repeatedStringPiece[1]); + assertEquals("boo", msg.repeatedStringPiece[2]); + msg.clear(); + assertEquals(0, msg.repeatedStringPiece.length); + msg.clear() + .repeatedStringPiece = new String[] { "boo" }; + assertEquals(1, msg.repeatedStringPiece.length); + assertEquals("boo", msg.repeatedStringPiece[0]); + msg.clear(); + assertEquals(0, msg.repeatedStringPiece.length); + + // Test 1 entry + msg.clear() + .repeatedStringPiece = new String[] { "" }; + assertEquals(1, msg.repeatedStringPiece.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedStringPiece.length); + assertTrue(newMsg.repeatedStringPiece[0].isEmpty()); + + // Test 2 entries + msg.clear() + .repeatedStringPiece = new String[] { "hello", "world" }; + assertEquals(2, msg.repeatedStringPiece.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 19); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedStringPiece.length); + assertEquals("hello", newMsg.repeatedStringPiece[0]); + assertEquals("world", newMsg.repeatedStringPiece[1]); + } + + public void testNanoRepeatedCord() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedCord.length); + msg.repeatedCord = new String[] { "hello", "bye", "boo" }; + assertEquals("bye", msg.repeatedCord[1]); + assertEquals("boo", msg.repeatedCord[2]); + msg.clear(); + assertEquals(0, msg.repeatedCord.length); + msg.clear() + .repeatedCord = new String[] { "boo" }; + assertEquals(1, msg.repeatedCord.length); + assertEquals("boo", msg.repeatedCord[0]); + msg.clear(); + assertEquals(0, msg.repeatedCord.length); + + // Test 1 entry + msg.clear() + .repeatedCord = new String[] { "" }; + assertEquals(1, msg.repeatedCord.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 6); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedCord.length); + assertTrue(newMsg.repeatedCord[0].isEmpty()); + + // Test 2 entries + msg.clear() + .repeatedCord = new String[] { "hello", "world" }; + assertEquals(2, msg.repeatedCord.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 19); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedCord.length); + assertEquals("hello", newMsg.repeatedCord[0]); + assertEquals("world", newMsg.repeatedCord[1]); + } + + public void testNanoRepeatedPackedInt32() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedPackedInt32.length); + msg.repeatedPackedInt32 = new int[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedPackedInt32[1]); + assertEquals(456, msg.repeatedPackedInt32[2]); + msg.clear(); + assertEquals(0, msg.repeatedPackedInt32.length); + msg.clear() + .repeatedPackedInt32 = new int[] { 456 }; + assertEquals(1, msg.repeatedPackedInt32.length); + assertEquals(456, msg.repeatedPackedInt32[0]); + msg.clear(); + assertEquals(0, msg.repeatedPackedInt32.length); + + // Test 1 entry + msg.clear() + .repeatedPackedInt32 = new int[] { 123 }; + assertEquals(1, msg.repeatedPackedInt32.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedPackedInt32.length); + assertEquals(123, newMsg.repeatedPackedInt32[0]); + + // Test 2 entries + msg.clear() + .repeatedPackedInt32 = new int[] { 123, 456 }; + assertEquals(2, msg.repeatedPackedInt32.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 9); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedPackedInt32.length); + assertEquals(123, newMsg.repeatedPackedInt32[0]); + assertEquals(456, newMsg.repeatedPackedInt32[1]); + } + + public void testNanoRepeatedPackedSfixed64() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + assertEquals(0, msg.repeatedPackedSfixed64.length); + msg.repeatedPackedSfixed64 = new long[] { 123, 789, 456 }; + assertEquals(789, msg.repeatedPackedSfixed64[1]); + assertEquals(456, msg.repeatedPackedSfixed64[2]); + msg.clear(); + assertEquals(0, msg.repeatedPackedSfixed64.length); + msg.clear() + .repeatedPackedSfixed64 = new long[] { 456 }; + assertEquals(1, msg.repeatedPackedSfixed64.length); + assertEquals(456, msg.repeatedPackedSfixed64[0]); + msg.clear(); + assertEquals(0, msg.repeatedPackedSfixed64.length); + + // Test 1 entry + msg.clear() + .repeatedPackedSfixed64 = new long[] { 123 }; + assertEquals(1, msg.repeatedPackedSfixed64.length); + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 14); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedPackedSfixed64.length); + assertEquals(123, newMsg.repeatedPackedSfixed64[0]); + + // Test 2 entries + msg.clear() + .repeatedPackedSfixed64 = new long[] { 123, 456 }; + assertEquals(2, msg.repeatedPackedSfixed64.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 22); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedPackedSfixed64.length); + assertEquals(123, newMsg.repeatedPackedSfixed64[0]); + assertEquals(456, newMsg.repeatedPackedSfixed64[1]); + } + + public void testNanoRepeatedPackedNestedEnum() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedPackedNestedEnum = new int[] { + TestAllTypesNano.FOO, + TestAllTypesNano.BAR, + TestAllTypesNano.BAZ + }; + assertEquals(3, msg.repeatedPackedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]); + assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]); + assertEquals(TestAllTypesNano.BAZ, msg.repeatedPackedNestedEnum[2]); + msg.clear(); + assertEquals(0, msg.repeatedPackedNestedEnum.length); + msg.clear() + .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.BAR }; + assertEquals(1, msg.repeatedPackedNestedEnum.length); + assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[0]); + msg.clear(); + assertEquals(0, msg.repeatedPackedNestedEnum.length); + + // Test 1 entry + msg.clear() + .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO }; + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 7); + assertEquals(result.length, msgSerializedSize); + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(1, newMsg.repeatedPackedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]); + + // Test 2 entries + msg.clear() + .repeatedPackedNestedEnum = new int[] { TestAllTypesNano.FOO, TestAllTypesNano.BAR }; + assertEquals(2, msg.repeatedPackedNestedEnum.length); + result = MessageNano.toByteArray(msg); + msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 8); + assertEquals(result.length, msgSerializedSize); + + newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(2, newMsg.repeatedPackedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, msg.repeatedPackedNestedEnum[0]); + assertEquals(TestAllTypesNano.BAR, msg.repeatedPackedNestedEnum[1]); + } + + public void testNanoRepeatedInt32ReMerge() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedInt32 = new int[] { 234 }; + byte [] result1 = MessageNano.toByteArray(msg); + + msg.clear().optionalInt32 = 789; + byte [] result2 = MessageNano.toByteArray(msg); + + msg.clear().repeatedInt32 = new int[] { 123, 456 }; + byte [] result3 = MessageNano.toByteArray(msg); + + // Concatenate the three serializations and read as one message. + byte [] result = new byte[result1.length + result2.length + result3.length]; + System.arraycopy(result1, 0, result, 0, result1.length); + System.arraycopy(result2, 0, result, result1.length, result2.length); + System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(789, newMsg.optionalInt32); + assertEquals(3, newMsg.repeatedInt32.length); + assertEquals(234, newMsg.repeatedInt32[0]); + assertEquals(123, newMsg.repeatedInt32[1]); + assertEquals(456, newMsg.repeatedInt32[2]); + } + + public void testNanoRepeatedNestedEnumReMerge() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + msg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO }; + byte [] result1 = MessageNano.toByteArray(msg); + + msg.clear().optionalInt32 = 789; + byte [] result2 = MessageNano.toByteArray(msg); + + msg.clear().repeatedNestedEnum = new int[] { TestAllTypesNano.BAR, TestAllTypesNano.FOO }; + byte [] result3 = MessageNano.toByteArray(msg); + + // Concatenate the three serializations and read as one message. + byte [] result = new byte[result1.length + result2.length + result3.length]; + System.arraycopy(result1, 0, result, 0, result1.length); + System.arraycopy(result2, 0, result, result1.length, result2.length); + System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(789, newMsg.optionalInt32); + assertEquals(3, newMsg.repeatedNestedEnum.length); + assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[0]); + assertEquals(TestAllTypesNano.BAR, newMsg.repeatedNestedEnum[1]); + assertEquals(TestAllTypesNano.FOO, newMsg.repeatedNestedEnum[2]); + } + + public void testNanoRepeatedNestedMessageReMerge() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + TestAllTypesNano.NestedMessage nestedMsg0 = + new TestAllTypesNano.NestedMessage(); + nestedMsg0.bb = 0; + TestAllTypesNano.NestedMessage nestedMsg1 = + new TestAllTypesNano.NestedMessage(); + nestedMsg1.bb = 1; + TestAllTypesNano.NestedMessage nestedMsg2 = + new TestAllTypesNano.NestedMessage(); + nestedMsg2.bb = 2; + + msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] { nestedMsg0 }; + byte [] result1 = MessageNano.toByteArray(msg); + + msg.clear().optionalInt32 = 789; + byte [] result2 = MessageNano.toByteArray(msg); + + msg.clear().repeatedNestedMessage = + new TestAllTypesNano.NestedMessage[] { nestedMsg1, nestedMsg2 }; + byte [] result3 = MessageNano.toByteArray(msg); + + // Concatenate the three serializations and read as one message. + byte [] result = new byte[result1.length + result2.length + result3.length]; + System.arraycopy(result1, 0, result, 0, result1.length); + System.arraycopy(result2, 0, result, result1.length, result2.length); + System.arraycopy(result3, 0, result, result1.length + result2.length, result3.length); + + TestAllTypesNano newMsg = TestAllTypesNano.parseFrom(result); + assertEquals(789, newMsg.optionalInt32); + assertEquals(3, newMsg.repeatedNestedMessage.length); + assertEquals(nestedMsg0.bb, newMsg.repeatedNestedMessage[0].bb); + assertEquals(nestedMsg1.bb, newMsg.repeatedNestedMessage[1].bb); + assertEquals(nestedMsg2.bb, newMsg.repeatedNestedMessage[2].bb); + } + + public void testNanoDefaults() throws Exception { + TestAllTypesNano msg = new TestAllTypesNano(); + for (int i = 0; i < 2; i++) { + assertEquals(41, msg.defaultInt32); + assertEquals(42, msg.defaultInt64); + assertEquals(43, msg.defaultUint32); + assertEquals(44, msg.defaultUint64); + assertEquals(-45, msg.defaultSint32); + assertEquals(46, msg.defaultSint64); + assertEquals(47, msg.defaultFixed32); + assertEquals(48, msg.defaultFixed64); + assertEquals(49, msg.defaultSfixed32); + assertEquals(-50, msg.defaultSfixed64); + assertTrue(51.5f == msg.defaultFloat); + assertTrue(52.0e3 == msg.defaultDouble); + assertEquals(true, msg.defaultBool); + assertEquals("hello", msg.defaultString); + assertEquals("world", new String(msg.defaultBytes, "UTF-8")); + assertEquals("dünya", msg.defaultStringNonascii); + assertEquals("dünyab", new String(msg.defaultBytesNonascii, "UTF-8")); + assertEquals(TestAllTypesNano.BAR, msg.defaultNestedEnum); + assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.defaultForeignEnum); + assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.defaultImportEnum); + + // Default values are not output, except for required fields. + byte [] result = MessageNano.toByteArray(msg); + int msgSerializedSize = msg.getSerializedSize(); + //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length); + assertTrue(msgSerializedSize == 3); + assertEquals(result.length, msgSerializedSize); + msg.clear(); + } + } + + /** + * Test that a bug in skipRawBytes() has been fixed: if the skip skips + * exactly up to a limit, this should not break things. + */ + public void testSkipRawBytesBug() throws Exception { + byte[] rawBytes = new byte[] { 1, 2 }; + CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes); + + int limit = input.pushLimit(1); + input.skipRawBytes(1); + input.popLimit(limit); + assertEquals(2, input.readRawByte()); + } + + /** + * Test that a bug in skipRawBytes() has been fixed: if the skip skips + * past the end of a buffer with a limit that has been set past the end of + * that buffer, this should not break things. + */ + public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception { + byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 }; + CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(rawBytes); + + int limit = input.pushLimit(4); + // In order to expose the bug we need to read at least one byte to prime the + // buffer inside the CodedInputStream. + assertEquals(1, input.readRawByte()); + // Skip to the end of the limit. + input.skipRawBytes(3); + assertTrue(input.isAtEnd()); + input.popLimit(limit); + assertEquals(5, input.readRawByte()); + } +} diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc new file mode 100644 index 00000000..5abd46e9 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 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 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 javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.h b/src/google/protobuf/compiler/javanano/javanano_enum.h new file mode 100644 index 00000000..d6f463ec --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include + +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +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 canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector aliases_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc new file mode 100644 index 00000000..68020db1 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc @@ -0,0 +1,266 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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* 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_, + "public int $name$ = $default$;\n"); +} + +void EnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$ = other.$name$;\n"); +} + +void EnumFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + " $name$ = input.readInt32();\n"); +} + +void EnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->is_required()) { + printer->Print(variables_, + "output.writeInt32($number$, $name$);\n"); + } else { + printer->Print(variables_, + "if ($name$ != $default$) {\n" + " output.writeInt32($number$, $name$);\n" + "}\n"); + } +} + +void EnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (descriptor_->is_required()) { + printer->Print(variables_, + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32Size($number$, $name$);\n"); + } else { + printer->Print(variables_, + "if ($name$ != $default$) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32Size($number$, $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_); +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "public int[] $name$ = com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.$name$.length > 0) {\n" + " int[] merged = java.util.Arrays.copyOf(result.$name$, result.$name$.length + other.$name$.length);\n" + " java.lang.System.arraycopy(other.$name$, 0, merged, results.$name$.length, other.$name$.length);\n" + " result.$name$ = merged;\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + // First, figure out the length of the array, then parse. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "// First pass to compute array length.\n" + "int arrayLength = 0;\n" + "int startPos = input.getPosition();\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " input.readInt32();\n" + " arrayLength++;\n" + "}\n" + "input.rewindToPosition(startPos);\n" + "$name$ = new $type$[arrayLength];\n" + "for (int i = 0; i < arrayLength; i++) {\n" + " $name$[i] = input.readInt32();\n" + "}\n" + "input.popLimit(limit);\n"); + } else { + printer->Print(variables_, + "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n" + "int i = $name$.length;\n" + "$name$ = java.util.Arrays.copyOf($name$, $name$.length + arrayLength);\n" + "for (; i < $name$.length - 1; i++) {\n" + " $name$[i] = input.readInt32();\n" + " input.readTag();\n" + "}\n" + "// Last one without readTag.\n" + "$name$[i] = input.readInt32();\n"); + } +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$.length > 0) {\n"); + printer->Indent(); + + if (descriptor_->options().packed()) { + printer->Print(variables_, + "output.writeRawVarint32($tag$);\n" + "output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "for (int element : $name$) {\n" + " output.writeRawVarint32(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int element : $name$) {\n" + " output.writeInt32($number$, element);\n" + "}\n"); + } + printer->Outdent(); + printer->Print(variables_, + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$.length > 0) {\n"); + printer->Indent(); + + printer->Print(variables_, + "int dataSize = 0;\n" + "for (int element : $name$) {\n" + " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32SizeNoTag(element);\n" + "}\n"); + + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + // cache the data size for packed fields. + printer->Print(variables_, + "size += $tag_size$;\n" + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeRawVarint32Size(dataSize);\n" + "$name$MemoizedSerializedSize = dataSize;\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * $name$.length;\n"); + } + + printer->Outdent(); + + // set cached size to 0 for empty packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "} else {\n" + " $name$MemoizedSerializedSize = 0;\n" + "}\n"); + } else { + printer->Print( + "}\n"); + } +} + +string RepeatedEnumFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->enum_type()); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h new file mode 100644 index 00000000..8985b0f0 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 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 variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_field.cc b/src/google/protobuf/compiler/javanano/javanano_field.cc new file mode 100644 index 00000000..ea25786c --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +FieldGenerator::~FieldGenerator() {} + +FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms) + : descriptor_(descriptor), + field_generators_( + new scoped_ptr[descriptor->field_count()]), + extension_generators_( + new scoped_ptr[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 javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h new file mode 100644 index 00000000..a0bf909a --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +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 > field_generators_; + scoped_array > extension_generators_; + + static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Params ¶ms); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc new file mode 100644 index 00000000..2f42fa0e --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 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 NANO_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 NANO_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 NANO_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 NANO_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 +static void GenerateSibling(const string& package_dir, + const string& java_package, + const DescriptorClass* descriptor, + OutputDirectory* output_directory, + vector* file_list, + const Params& params) { + string filename = package_dir + descriptor->name() + ".java"; + file_list->push_back(filename); + + scoped_ptr 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* file_list) { + if (params_.java_multiple_files()) { + for (int i = 0; i < file_->enum_type_count(); i++) { + GenerateSibling(package_dir, java_package_, + file_->enum_type(i), + output_directory, file_list, params_); + } + for (int i = 0; i < file_->message_type_count(); i++) { + GenerateSibling(package_dir, java_package_, + file_->message_type(i), + output_directory, file_list, params_); + } + } +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_file.h b/src/google/protobuf/compiler/javanano/javanano_file.h new file mode 100644 index 00000000..94727211 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include +#include + +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 javanano { + +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* 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 javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc new file mode 100644 index 00000000..554f6d4d --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -0,0 +1,170 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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)); + } +} + +JavaNanoGenerator::JavaNanoGenerator() {} +JavaNanoGenerator::~JavaNanoGenerator() {} + +bool JavaNanoGenerator::Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + vector > options; + + 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++) { + if (options[i].first == "output_list_file") { + output_list_file = options[i].second; + } else if (options[i].first == "java_package") { + vector 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 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 { + *error = "Ignore unknown javanano generator option: " + options[i].first; + } + } + + // ----------------------------------------------------------------- + + 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 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 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 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/javanano/javanano_generator.h b/src/google/protobuf/compiler/javanano/javanano_generator.h new file mode 100644 index 00000000..0c1e3a41 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 nano code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +// CodeGenerator implementation which generates Java nano code. If you create your +// own protocol compiler binary and you want it to support Java output for the +// nano runtime, you can do so by registering an instance of this CodeGenerator with +// the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT JavaNanoGenerator : public CodeGenerator { + public: + JavaNanoGenerator(); + ~JavaNanoGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaNanoGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_NANO_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc new file mode 100644 index 00000000..78395567 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -0,0 +1,404 @@ +// 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 + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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(); + + // Remove enum class name as we use int's for enums + string base_name = full_name.substr(0, full_name.find_last_of('.')); + + if (!file->package().empty()) { + if (file->package() == base_name.substr(0, file->package().size())) { + // Remove package name leaving just the parent class of the enum + int offset = file->package().size(); + if (base_name.size() > offset) { + // Remove period between package and class name if there is a classname + offset += 1; + } + base_name = base_name.substr(offset); + } else { + GOOGLE_LOG(FATAL) << "Expected package name to start an enum"; + } + } + + // Construct the path name from the package and outer class + + // Add the java package name if it exsits + if (params.has_java_package(file_name)) { + result += params.java_package(file_name); + } + + // Add the outer classname if it exists + if (params.has_java_outer_classname(file_name)) { + if (!result.empty()) { + result += "."; + } + result += params.java_outer_classname(file_name); + } + + // Create the full class name from the base and path + if (!base_name.empty()) { + if (!result.empty()) { + result += "."; + } + result += base_name; + } + return result; +} + +string FieldConstantName(const FieldDescriptor *field) { + string name = field->name() + "_FIELD_NUMBER"; + UpperString(&name); + return name; +} + +string FieldDefaultConstantName(const FieldDescriptor *field) { + string name = field->name() + "_DEFAULT"; + 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 "byte[]"; + 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; +} + +string EmptyArrayName(const Params& params, const FieldDescriptor* field) { + switch (GetJavaType(field)) { + case JAVATYPE_INT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; + case JAVATYPE_LONG : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY"; + case JAVATYPE_FLOAT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY"; + case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY"; + case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY"; + case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY"; + case JAVATYPE_BYTES : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY"; + case JAVATYPE_ENUM : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; + case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY"; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +string DefaultValue(const Params& params, const FieldDescriptor* field) { + if (field->label() == FieldDescriptor::LABEL_REPEATED) { + return EmptyArrayName(params, 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(field->default_value_uint32())); + case FieldDescriptor::CPPTYPE_INT64: + return SimpleItoa(field->default_value_int64()) + "L"; + case FieldDescriptor::CPPTYPE_UINT64: + return SimpleItoa(static_cast(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->default_value_string().empty()) { + // Point it to the static final in the generated code. + return FieldDefaultConstantName(field); + } else { + if (field->type() == FieldDescriptor::TYPE_BYTES) { + return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES"; + } else { + return "\"\""; + } + } + + case FieldDescriptor::CPPTYPE_ENUM: + return ClassName(params, field->enum_type()) + "." + + field->default_value_enum()->name(); + + case FieldDescriptor::CPPTYPE_MESSAGE: + return "null"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h new file mode 100644 index 00000000..04e0c2e9 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h @@ -0,0 +1,132 @@ +// 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 +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +// 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); + +string FieldDefaultConstantName(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 EmptyArrayName(const Params& params, const FieldDescriptor* field); + +string DefaultValue(const Params& params, const FieldDescriptor* field); + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc new file mode 100644 index 00000000..f8a4fe78 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message.cc @@ -0,0 +1,372 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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); +} + +} // 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 NANO_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 NANO_RUNTIME\n"; + } + + // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in + // the inner or outer class. This causes Java warnings, but is not fatal, so we suppress those + // warnings here in the class declaration. + printer->Print( + "@SuppressWarnings(\"hiding\")\n" + "public $modifiers$ final class $classname$ extends\n" + " com.google.protobuf.nano.MessageNano {\n", + "modifiers", is_own_file ? "" : "static", + "classname", descriptor_->name()); + printer->Indent(); + printer->Print( + "public static final $classname$ EMPTY_ARRAY[] = {};\n" + "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)); + field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); + printer->Print("\n"); + } + + GenerateClear(printer); + GenerateMessageSerializationMethods(printer); + GenerateMergeFromMethods(printer); + GenerateParseFromMethods(printer); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +// =================================================================== + +void MessageGenerator:: +GenerateMessageSerializationMethods(io::Printer* printer) { + scoped_array sorted_fields( + SortFieldsByNumber(descriptor_)); + + if (descriptor_->extension_range_count() != 0) { + GOOGLE_LOG(FATAL) << "Extensions not supported in NANO_RUNTIME\n"; + } + + // writeTo only throws an exception if it contains one or more fields to write + if (descriptor_->field_count() > 0) { + printer->Print( + "@Override\n" + "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n" + " throws java.io.IOException {\n"); + } else { + printer->Print( + "@Override\n" + "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) {\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" + "@Override\n" + "public int getCachedSize() {\n" + " if (cachedSize < 0) {\n" + " // getSerializedSize sets cachedSize\n" + " getSerializedSize();\n" + " }\n" + " return cachedSize;\n" + "}\n" + "\n" + "@Override\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 sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "@Override\n" + "public $classname$ mergeFrom(\n" + " com.google.protobuf.nano.CodedInputByteBufferNano 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 (!com.google.protobuf.nano.WireFormatNano.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.nano.InvalidProtocolBufferNanoException {\n" + " return ($classname$) com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n" + "}\n" + "\n" + "public $static$ $classname$ parseFrom(\n" + " com.google.protobuf.nano.CodedInputByteBufferNano input)\n" + " throws java.io.IOException {\n" + " return 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); + + if (field->type() == FieldDescriptor::TYPE_BYTES && + !field->default_value_string().empty()) { + // Need to clone the default value because it is of a mutable + // type. + printer->Print( + "$name$ = $default$.clone();\n", + "name", UnderscoresToCamelCase(field), + "default", DefaultValue(params_, field)); + } else { + printer->Print( + "$name$ = $default$;\n", + "name", UnderscoresToCamelCase(field), + "default", DefaultValue(params_, field)); + } + } + + printer->Outdent(); + printer->Print( + " cachedSize = -1;\n" + " return this;\n" + "}\n" + "\n"); +} + +// =================================================================== + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h new file mode 100644 index 00000000..d59ec9f0 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message.h @@ -0,0 +1,92 @@ +// 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 +#include +#include +#include + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +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); + + const Params& params_; + const Descriptor* descriptor_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc new file mode 100644 index 00000000..6d89bd52 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc @@ -0,0 +1,216 @@ +// 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 +#include + +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +using internal::WireFormat; +using internal::WireFormatLite; + +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* 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(); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); +} + +} // 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_, + "public $type$ $name$ = null;\n"); +} + +void MessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.$name$ != null) {\n" + " merge$capitalized_name$(other.$name$);\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup($name$, $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage($name$);\n"); + } +} + +void MessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$ != null) {\n" + " output.write$group_or_message$($number$, $name$);\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$ != null) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$group_or_message$Size($number$, $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 { + printer->Print(variables_, + "public $type$[] $name$ = $type$.EMPTY_ARRAY;\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.$name$.length > 0) {\n" + " $type$[] merged = java.util.Arrays.copyOf(result.$name$, result.$name$.length + other.$name$.length);\n" + " java.lang.System.arraycopy(other.$name$, 0, merged, results.$name$.length, other.$name$.length);\n" + " result.$name$ = merged;\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + // First, figure out the length of the array, then parse. + printer->Print(variables_, + "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n" + "int i = $name$.length;\n" + "$name$ = java.util.Arrays.copyOf($name$, i + arrayLength);\n" + "for (; i < $name$.length - 1; i++) {\n" + " $name$[i] = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + " input.readGroup($name$[i], $number$);\n"); + } else { + printer->Print(variables_, + " input.readMessage($name$[i]);\n"); + } + + printer->Print(variables_, + " input.readTag();\n" + "}\n" + "// Last one without readTag.\n" + "$name$[i] = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup($name$[i], $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage($name$[i]);\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "for ($type$ element : $name$) {\n" + " output.write$group_or_message$($number$, element);\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "for ($type$ element : $name$) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$group_or_message$Size($number$, element);\n" + "}\n"); +} + +string RepeatedMessageFieldGenerator::GetBoxedType() const { + return ClassName(params_, descriptor_->message_type()); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h new file mode 100644 index 00000000..5fb00617 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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 +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 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 variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h new file mode 100644 index 00000000..f6192eae --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_params.h @@ -0,0 +1,123 @@ +// 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_JAVANANO_JAVANANO_PARAMS_H_ +#define PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_ + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +// Parameters for used by the generators +class Params { + public: + typedef map NameMap; + private: + string empty_; + string base_name_; + bool java_multiple_files_; + NameMap java_packages_; + NameMap java_outer_classnames_; + + public: + Params(const string & base_name) : + empty_(""), + base_name_(base_name), + java_multiple_files_(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_java_multiple_files(bool value) { + java_multiple_files_ = value; + } + bool java_multiple_files() const { + return java_multiple_files_; + } + +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_ diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc new file mode 100644 index 00000000..041d22ff --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc @@ -0,0 +1,493 @@ +// 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 "byte[]"; + 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; +} + +bool IsArrayType(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 false; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return false; + + // 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 AllAscii(const string& text) { + for (int i = 0; i < text.size(); i++) { + if ((text[i] & 0x80) != 0) { + return false; + } + } + return true; +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, + map* variables) { + (*variables)["name"] = + UnderscoresToCamelCase(descriptor); + (*variables)["capitalized_name"] = + UnderscoresToCapitalizedCamelCase(descriptor); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["default"] = DefaultValue(params, descriptor); + (*variables)["default_constant"] = FieldDefaultConstantName(descriptor); + // For C++-string types (string and bytes), we might need to have + // the generated code do the unicode decoding (see comments in + // InternalNano.java for gory details.). We would like to do this + // once into a "private static final" field and re-use that from + // then on. + if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + !descriptor->default_value_string().empty()) { + string default_value; + if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { + default_value = strings::Substitute( + "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")", + CEscape(descriptor->default_value_string())); + } else { + if (AllAscii(descriptor->default_value_string())) { + // All chars are ASCII. In this case CEscape() works fine. + default_value = "\"" + CEscape(descriptor->default_value_string()) + "\""; + } else { + default_value = strings::Substitute( + "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")", + CEscape(descriptor->default_value_string())); + } + } + (*variables)["default_constant_value"] = default_value; + } + (*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(); + (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor); +} +} // 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 { + if (variables_.find("default_constant_value") != variables_.end()) { + // Those primitive types that need a saved default. + printer->Print(variables_, + "private static final $type$ $default_constant$ = $default_constant_value$;\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { + printer->Print(variables_, + "public $type$ $name$ = $default$.clone();\n"); + } else { + printer->Print(variables_, + "public $type$ $name$ = $default$;\n"); + } + } else { + printer->Print(variables_, + "public $type$ $name$ = $default$;\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, "$name$ = other.$name$;\n"); +} + +void PrimitiveFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = input.read$capitalized_type$();\n"); +} + +void PrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->is_required()) { + printer->Print(variables_, + "output.write$capitalized_type$($number$, $name$);\n"); + } else { + if (IsArrayType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "if (!java.util.Arrays.equals($name$, $default$)) {\n"); + } else if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "if (!$name$.equals($default$)) {\n"); + } else { + printer->Print(variables_, + "if ($name$ != $default$) {\n"); + } + + printer->Print(variables_, + " output.write$capitalized_type$($number$, $name$);\n" + "}\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (descriptor_->is_required()) { + printer->Print(variables_, + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$Size($number$, $name$);\n"); + } else { + if (IsArrayType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "if (!java.util.Arrays.equals($name$, $default$)) {\n"); + } else if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "if (!$name$.equals($default$)) {\n"); + } else { + printer->Print(variables_, + "if ($name$ != $default$) {\n"); + } + + printer->Print(variables_, + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$Size($number$, $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_); +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer) const { + printer->Print(variables_, + "public $type$[] $name$ = $default$;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "private int $name$MemoizedSerializedSize;\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (other.$name$.length > 0) {\n" + " $type$[] merged = java.util.Arrays.copyOf(result.$name$, result.$name$.length + other.$name$.length);\n" + " java.lang.System.arraycopy(other.$name$, 0, merged, results.$name$.length, other.$name$.length);\n" + " result.$name$ = merged;\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateParsingCode(io::Printer* printer) const { + // First, figure out the length of the array, then parse. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "// First pass to compute array length.\n" + "int arrayLength = 0;\n" + "int startPos = input.getPosition();\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " input.read$capitalized_type$();\n" + " arrayLength++;\n" + "}\n" + "input.rewindToPosition(startPos);\n" + "$name$ = new $type$[arrayLength];\n" + "for (int i = 0; i < arrayLength; i++) {\n" + " $name$[i] = input.read$capitalized_type$();\n" + "}\n" + "input.popLimit(limit);\n"); + } else { + printer->Print(variables_, + "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n" + "int i = $name$.length;\n" + "$name$ = java.util.Arrays.copyOf($name$, $name$.length + arrayLength);\n" + "for (; i < $name$.length - 1; i++) {\n" + " $name$[i] = input.read$capitalized_type$();\n" + " input.readTag();\n" + "}\n" + "// Last one without readTag.\n" + "$name$[i] = input.read$capitalized_type$();\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->options().packed()) { + printer->Print(variables_, + "if ($name$.length > 0) {\n" + " output.writeRawVarint32($tag$);\n" + " output.writeRawVarint32($name$MemoizedSerializedSize);\n" + "}\n"); + printer->Print(variables_, + "for ($type$ element : $name$) {\n" + " output.write$capitalized_type$NoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "for ($type$ element : $name$) {\n" + " output.write$capitalized_type$($number$, element);\n" + "}\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($name$.length > 0) {\n"); + printer->Indent(); + + if (FixedSize(descriptor_->type()) == -1) { + printer->Print(variables_, + "int dataSize = 0;\n" + "for ($type$ element : $name$) {\n" + " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$SizeNoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "int dataSize = $fixed_size$ * $name$.length;\n"); + } + + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + // cache the data size for packed fields. + printer->Print(variables_, + "size += $tag_size$;\n" + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeRawVarint32Size(dataSize);\n" + "$name$MemoizedSerializedSize = dataSize;\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * $name$.length;\n"); + } + + printer->Outdent(); + + // set cached size to 0 for empty packed fields. + if (descriptor_->options().packed()) { + printer->Print(variables_, + "} else {\n" + " $name$MemoizedSerializedSize = 0;\n" + "}\n"); + } else { + printer->Print( + "}\n"); + } +} + +string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { + return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h new file mode 100644 index 00000000..7c14e4c2 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_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_JAVANANO_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__ + +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +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 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 variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/unittest_import_nano.proto b/src/google/protobuf/unittest_import_nano.proto new file mode 100644 index 00000000..7813715b --- /dev/null +++ b/src/google/protobuf/unittest_import_nano.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 = NANO_RUNTIME. + +package protobuf_unittest_import; + +// java_package and java_outer_classname are specified on the command line. +//option java_package = "com.google.protobuf.nano"; +//option java_outer_classname = "UnittestImportNano"; + +message ImportMessageNano { + optional int32 d = 1; +} + +enum ImportEnumNano { + IMPORT_NANO_FOO = 7; + IMPORT_NANO_BAR = 8; + IMPORT_NANO_BAZ = 9; +} diff --git a/src/google/protobuf/unittest_nano.proto b/src/google/protobuf/unittest_nano.proto new file mode 100644 index 00000000..c689ac0e --- /dev/null +++ b/src/google/protobuf/unittest_nano.proto @@ -0,0 +1,171 @@ +// 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_nano.proto"; + +option java_package = "com.google.protobuf.nano"; +option java_outer_classname = "NanoOuterClass"; + +// Same as TestAllTypes but with the nano runtime. +message TestAllTypesNano { + + 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 ForeignMessageNano optional_foreign_message = 19; + optional protobuf_unittest_import.ImportMessageNano + optional_import_message = 20; + + optional NestedEnum optional_nested_enum = 21; + optional ForeignEnumNano optional_foreign_enum = 22; + optional protobuf_unittest_import.ImportEnumNano 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 ForeignMessageNano repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessageNano + repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnumNano repeated_foreign_enum = 52; + repeated protobuf_unittest_import.ImportEnumNano repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + // Repeated packed + repeated int32 repeated_packed_int32 = 87 [packed=true]; + repeated sfixed64 repeated_packed_sfixed64 = 88 [packed=true]; + + repeated NestedEnum repeated_packed_nested_enum = 89 [packed=true]; + + // 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 string default_string_nonascii = 76 [default = "dünya"]; + optional bytes default_bytes_nonascii = 77 [default = "dünyab"]; + + optional NestedEnum default_nested_enum = 81 [default = BAR]; + optional ForeignEnumNano default_foreign_enum = 82 + [default = FOREIGN_NANO_BAR]; + optional protobuf_unittest_import.ImportEnumNano + default_import_enum = 83 [default = IMPORT_NANO_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 ForeignMessageNano { + optional int32 c = 1; +} + +enum ForeignEnumNano { + FOREIGN_NANO_FOO = 4; + FOREIGN_NANO_BAR = 5; + FOREIGN_NANO_BAZ = 6; +} + +// Test that deprecated fields work. We only verify that they compile (at one +// point this failed). +message TestDeprecatedNano { + optional int32 deprecated_field = 1 [deprecated = true]; +} diff --git a/src/google/protobuf/unittest_recursive_nano.proto b/src/google/protobuf/unittest_recursive_nano.proto new file mode 100644 index 00000000..a62613ed --- /dev/null +++ b/src/google/protobuf/unittest_recursive_nano.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.nano"; + +message RecursiveMessageNano { + message NestedMessage { + optional RecursiveMessageNano a = 1; + } + + required int32 id = 1; + optional NestedMessage nested_message = 2; + optional RecursiveMessageNano optional_recursive_message_nano = 3; + repeated RecursiveMessageNano repeated_recursive_message_nano = 4; +} diff --git a/src/google/protobuf/unittest_simple_nano.proto b/src/google/protobuf/unittest_simple_nano.proto new file mode 100644 index 00000000..287e962f --- /dev/null +++ b/src/google/protobuf/unittest_simple_nano.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.nano"; + +message SimpleMessageNano { + 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_nano.proto b/src/google/protobuf/unittest_stringutf8_nano.proto new file mode 100644 index 00000000..da624b0e --- /dev/null +++ b/src/google/protobuf/unittest_stringutf8_nano.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.nano"; + +message StringUtf8 { + optional string id = 1; + repeated string rs = 2; +} -- cgit v1.2.3