aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-19 17:14:29 -0800
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-19 17:14:29 -0800
commit95c25918aa1550fcba50e1f76b9db6ebded25a80 (patch)
tree7a15bcee55b4dc9b85e84ec907ce8269b0ed1c02
parent6a51460b985bc715b32d43b8e8f284e36b051f36 (diff)
parentcd980d1c13c736b0f9fc453843f696a93c2c2a71 (diff)
Merge nano proto into protobuf repository.
-rw-r--r--Android.mk486
-rw-r--r--javanano/README.txt354
-rw-r--r--javanano/pom.xml164
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java641
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java879
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java187
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/Extension.java722
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldArray.java273
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/FieldData.java190
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InternalNano.java333
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java93
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNano.java190
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java257
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java84
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java124
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/NanoTest.java3797
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto118
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto28
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto33
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto29
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto34
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto34
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto82
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto48
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto41
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto63
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto186
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto49
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto116
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto47
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto95
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto54
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto38
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto43
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.cc111
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum.h87
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.cc520
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.h125
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc150
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.h74
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.cc143
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.h119
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_file.cc263
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_file.h94
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc219
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.h72
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc566
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.h189
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc555
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.h95
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.cc259
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.h96
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h240
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc910
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.h126
57 files changed, 15021 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 00000000..18bdd091
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,486 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+IGNORED_WARNINGS := -Wno-sign-compare -Wno-unused-parameter -Wno-sign-promo
+
+CC_LITE_SRC_FILES := \
+ src/google/protobuf/stubs/common.cc \
+ src/google/protobuf/stubs/once.cc \
+ src/google/protobuf/stubs/hash.cc \
+ src/google/protobuf/stubs/hash.h \
+ src/google/protobuf/stubs/map-util.h \
+ src/google/protobuf/stubs/stl_util-inl.h \
+ src/google/protobuf/extension_set.cc \
+ src/google/protobuf/generated_message_util.cc \
+ src/google/protobuf/message_lite.cc \
+ src/google/protobuf/repeated_field.cc \
+ src/google/protobuf/wire_format_lite.cc \
+ src/google/protobuf/io/coded_stream.cc \
+ src/google/protobuf/io/coded_stream_inl.h \
+ src/google/protobuf/io/zero_copy_stream.cc \
+ src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+
+JAVA_LITE_SRC_FILES := \
+ java/src/main/java/com/google/protobuf/UninitializedMessageException.java \
+ java/src/main/java/com/google/protobuf/MessageLite.java \
+ java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
+ java/src/main/java/com/google/protobuf/CodedOutputStream.java \
+ java/src/main/java/com/google/protobuf/ByteString.java \
+ java/src/main/java/com/google/protobuf/CodedInputStream.java \
+ java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java \
+ java/src/main/java/com/google/protobuf/AbstractMessageLite.java \
+ java/src/main/java/com/google/protobuf/FieldSet.java \
+ java/src/main/java/com/google/protobuf/Internal.java \
+ java/src/main/java/com/google/protobuf/WireFormat.java \
+ java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+
+COMPILER_SRC_FILES := \
+ src/google/protobuf/descriptor.cc \
+ src/google/protobuf/descriptor.pb.cc \
+ src/google/protobuf/descriptor_database.cc \
+ src/google/protobuf/dynamic_message.cc \
+ src/google/protobuf/extension_set.cc \
+ src/google/protobuf/extension_set_heavy.cc \
+ src/google/protobuf/generated_message_reflection.cc \
+ src/google/protobuf/generated_message_util.cc \
+ src/google/protobuf/message.cc \
+ src/google/protobuf/message_lite.cc \
+ src/google/protobuf/reflection_ops.cc \
+ src/google/protobuf/repeated_field.cc \
+ src/google/protobuf/service.cc \
+ src/google/protobuf/text_format.cc \
+ src/google/protobuf/unknown_field_set.cc \
+ src/google/protobuf/wire_format.cc \
+ src/google/protobuf/wire_format_lite.cc \
+ src/google/protobuf/compiler/code_generator.cc \
+ src/google/protobuf/compiler/command_line_interface.cc \
+ src/google/protobuf/compiler/importer.cc \
+ src/google/protobuf/compiler/main.cc \
+ src/google/protobuf/compiler/parser.cc \
+ src/google/protobuf/compiler/plugin.cc \
+ src/google/protobuf/compiler/plugin.pb.cc \
+ src/google/protobuf/compiler/subprocess.cc \
+ src/google/protobuf/compiler/zip_writer.cc \
+ src/google/protobuf/compiler/cpp/cpp_enum.cc \
+ src/google/protobuf/compiler/cpp/cpp_enum_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_extension.cc \
+ src/google/protobuf/compiler/cpp/cpp_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_file.cc \
+ src/google/protobuf/compiler/cpp/cpp_generator.cc \
+ src/google/protobuf/compiler/cpp/cpp_helpers.cc \
+ src/google/protobuf/compiler/cpp/cpp_message.cc \
+ src/google/protobuf/compiler/cpp/cpp_message_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_primitive_field.cc \
+ src/google/protobuf/compiler/cpp/cpp_service.cc \
+ src/google/protobuf/compiler/cpp/cpp_string_field.cc \
+ src/google/protobuf/compiler/java/java_enum.cc \
+ src/google/protobuf/compiler/java/java_enum_field.cc \
+ src/google/protobuf/compiler/java/java_extension.cc \
+ src/google/protobuf/compiler/java/java_field.cc \
+ src/google/protobuf/compiler/java/java_file.cc \
+ src/google/protobuf/compiler/java/java_generator.cc \
+ src/google/protobuf/compiler/java/java_helpers.cc \
+ src/google/protobuf/compiler/java/java_message.cc \
+ src/google/protobuf/compiler/java/java_message_field.cc \
+ src/google/protobuf/compiler/java/java_primitive_field.cc \
+ src/google/protobuf/compiler/java/java_service.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_enum.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_field.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_file.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_generator.cc \
+ src/google/protobuf/compiler/javamicro/javamicro_helpers.cc \
+ 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_extension.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 \
+ src/google/protobuf/io/printer.cc \
+ src/google/protobuf/io/tokenizer.cc \
+ src/google/protobuf/io/zero_copy_stream.cc \
+ src/google/protobuf/io/zero_copy_stream_impl.cc \
+ src/google/protobuf/io/zero_copy_stream_impl_lite.cc \
+ src/google/protobuf/stubs/common.cc \
+ src/google/protobuf/stubs/hash.cc \
+ src/google/protobuf/stubs/once.cc \
+ src/google/protobuf/stubs/structurally_valid.cc \
+ 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-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)
+LOCAL_SRC_FILES += $(call all-java-files-under, java/src/device/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-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)
+
+LOCAL_MODULE := libprotobuf-java-micro
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 8
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Java micro library (for host-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := host-libprotobuf-java-micro
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/main/java/com/google/protobuf/micro)
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Java lite library (for device-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-java-lite
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := 8
+
+LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# Java lite library (for host-side users)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := host-libprotobuf-java-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(JAVA_LITE_SRC_FILES)
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# C++ lite library
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ $(LOCAL_PATH)/src
+
+# Define the header files to be copied
+#LOCAL_COPY_HEADERS := \
+# src/google/protobuf/stubs/once.h \
+# src/google/protobuf/stubs/common.h \
+# src/google/protobuf/io/coded_stream.h \
+# src/google/protobuf/generated_message_util.h \
+# src/google/protobuf/repeated_field.h \
+# src/google/protobuf/extension_set.h \
+# src/google/protobuf/wire_format_lite_inl.h
+#
+#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+# These are the minimum versions and don't need to be update.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SDK_VERSION := 8
+else
+# x86/mips support only available from API 9.
+LOCAL_SDK_VERSION := 9
+endif
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ lite library (libc++ flavored for the platform)
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-lite
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+
+LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+include $(BUILD_SHARED_LIBRARY)
+
+# C++ full library
+# =======================================================
+protobuf_cc_full_src_files := \
+ $(CC_LITE_SRC_FILES) \
+ src/google/protobuf/stubs/strutil.cc \
+ src/google/protobuf/stubs/strutil.h \
+ src/google/protobuf/stubs/substitute.cc \
+ src/google/protobuf/stubs/substitute.h \
+ src/google/protobuf/stubs/structurally_valid.cc \
+ src/google/protobuf/descriptor.cc \
+ src/google/protobuf/descriptor.pb.cc \
+ src/google/protobuf/descriptor_database.cc \
+ src/google/protobuf/dynamic_message.cc \
+ src/google/protobuf/extension_set_heavy.cc \
+ src/google/protobuf/generated_message_reflection.cc \
+ src/google/protobuf/message.cc \
+ src/google/protobuf/reflection_ops.cc \
+ src/google/protobuf/service.cc \
+ src/google/protobuf/text_format.cc \
+ src/google/protobuf/unknown_field_set.cc \
+ src/google/protobuf/wire_format.cc \
+ src/google/protobuf/io/gzip_stream.cc \
+ src/google/protobuf/io/printer.cc \
+ src/google/protobuf/io/tokenizer.cc \
+ src/google/protobuf/io/zero_copy_stream_impl.cc \
+ src/google/protobuf/compiler/importer.cc \
+ src/google/protobuf/compiler/parser.cc
+
+# C++ full library - stlport version
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+# Define the header files to be copied
+#LOCAL_COPY_HEADERS := \
+# src/google/protobuf/stubs/once.h \
+# src/google/protobuf/stubs/common.h \
+# src/google/protobuf/io/coded_stream.h \
+# src/google/protobuf/generated_message_util.h \
+# src/google/protobuf/repeated_field.h \
+# src/google/protobuf/extension_set.h \
+# src/google/protobuf/wire_format_lite_inl.h
+#
+#LOCAL_COPY_HEADERS_TO := $(LOCAL_MODULE)
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+
+# These are the minimum versions and don't need to be update.
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SDK_VERSION := 8
+else
+# x86/mips support only available from API 9.
+LOCAL_SDK_VERSION := 9
+endif
+LOCAL_NDK_STL_VARIANT := stlport_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ full library - Gnustl+rtti version
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full-gnustl-rtti
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -frtti $(IGNORED_WARNINGS)
+LOCAL_SDK_VERSION := 14
+LOCAL_NDK_STL_VARIANT := gnustl_static
+
+include $(BUILD_STATIC_LIBRARY)
+
+# C++ full library - libc++ version for the platform
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libprotobuf-cpp-full
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(protobuf_cc_full_src_files)
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI $(IGNORED_WARNINGS)
+LOCAL_SHARED_LIBRARIES := libz
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Clean temp vars
+protobuf_cc_full_src_files :=
+
+
+# Android Protocol buffer compiler, aprotoc (host executable)
+# used by the build systems as $(PROTOC) defined in
+# build/core/config.mk
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aprotoc
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := $(COMPILER_SRC_FILES)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ external/zlib \
+ $(LOCAL_PATH)/src
+
+LOCAL_STATIC_LIBRARIES += libz
+
+ifneq ($(HOST_OS),windows)
+LOCAL_LDLIBS := -lpthread
+endif
+
+LOCAL_CFLAGS := $(IGNORED_WARNINGS)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+# To test java proto params build rules.
+# =======================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := aprotoc-test-nano-params
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := \
+ src/google/protobuf/unittest_import_nano.proto \
+ src/google/protobuf/unittest_simple_nano.proto \
+ src/google/protobuf/unittest_stringutf8_nano.proto \
+ src/google/protobuf/unittest_recursive_nano.proto
+
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ java_package = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|com.google.protobuf.nano, \
+ java_outer_classname = $(LOCAL_PATH)/src/google/protobuf/unittest_import_nano.proto|UnittestImportNano
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# To test Android-specific nanoproto features.
+# =======================================================
+include $(CLEAR_VARS)
+
+# Parcelable messages
+LOCAL_MODULE := android-nano-test-parcelable
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := src/google/protobuf/unittest_simple_nano.proto
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ parcelable_messages = true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# Parcelable and extendable messages
+LOCAL_MODULE := android-nano-test-parcelable-extendable
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+
+LOCAL_SRC_FILES := src/google/protobuf/unittest_extension_nano.proto
+
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/src
+
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
+ parcelable_messages = true, \
+ store_unknown_fields = true
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# Test APK
+LOCAL_PACKAGE_NAME := NanoAndroidTest
+
+LOCAL_SDK_VERSION := 8
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, java/src/device/test/java/com/google/protobuf/nano)
+
+LOCAL_MANIFEST_FILE := java/src/device/test/AndroidManifest.xml
+
+LOCAL_STATIC_JAVA_LIBRARIES := libprotobuf-java-nano \
+ android-nano-test-parcelable \
+ android-nano-test-parcelable-extendable
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_PACKAGE)
+
+# 2.3.0 prebuilts for backwards compatibility.
+include $(LOCAL_PATH)/prebuilts/Android.mk
diff --git a/javanano/README.txt b/javanano/README.txt
new file mode 100644
index 00000000..fae32927
--- /dev/null
+++ b/javanano/README.txt
@@ -0,0 +1,354 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers Nano runtime library.
+
+Installation - With Maven
+=========================
+
+The Protocol Buffers build is managed using Maven. If you would
+rather build without Maven, see below.
+
+1) Install Apache Maven if you don't have it:
+
+ http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ You will need to place the protoc executable in ../src. (If you
+ built it yourself, it should already be there.)
+
+3) Run the tests:
+
+ $ mvn test
+
+ If some tests fail, this library may not work correctly on your
+ system. Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+ $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+ .jar file to use:
+
+ $ mvn package
+
+ The .jar will be placed in the "target" directory.
+
+Installation - Without Maven
+============================
+
+If you would rather not install Maven to build the library, you may
+follow these instructions instead. Note that these instructions skip
+running unit tests.
+
+1) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ If you built the C++ code without installing, the compiler binary
+ should be located in ../src.
+
+2) Invoke protoc to build DescriptorProtos.java:
+
+ $ protoc --java_out=src/main/java -I../src \
+ ../src/google/protobuf/descriptor.proto
+
+3) Compile the code in src/main/java using whatever means you prefer.
+
+4) Install the classes wherever you prefer.
+
+Nano version
+============================
+
+Nano is a special code generator and runtime library designed specially
+for Android, and is very resource-friendly in both the amount of code
+and the runtime overhead. An overview of Nano features:
+
+- No descriptors or message builders.
+- All messages are mutable; fields are public Java fields.
+- For optional fields only, encapsulation behind setter/getter/hazzer/
+ clearer functions is opt-in, which provide proper 'has' state support.
+- If not opted in, has state is not available. Serialization outputs
+ all fields not equal to their defaults (see important implications
+ below).
+- Required fields are always serialized.
+- Enum constants are integers; protection against invalid values only
+ when parsing from the wire.
+- Enum constants can be generated into container interfaces bearing
+ the enum's name (so the referencing code is in Java style).
+- CodedInputByteBufferNano can only take byte[] (not InputStream).
+- Similarly CodedOutputByteBufferNano can only write to byte[].
+- Repeated fields are in arrays, not ArrayList or Vector. Null array
+ elements are allowed and silently ignored.
+- Full support of serializing/deserializing repeated packed fields.
+- Support of extensions.
+- Unset messages/groups are null, not an immutable empty default
+ instance.
+- toByteArray(...) and mergeFrom(...) are now static functions of
+ MessageNano.
+- The 'bytes' type translates to the Java type byte[].
+
+The generated messages are not thread-safe for writes, but may be
+used simultaneously from multiple threads in a read-only manner.
+In other words, an appropriate synchronization mechanism (such as
+a ReadWriteLock) must be used to ensure that a message, its
+ancestors, and descendants are not accessed by any other threads
+while the message is being modified. Field reads, getter methods
+(but not getExtension(...)), toByteArray(...), writeTo(...),
+getCachedSize(), and getSerializedSize() are all considered read-only
+operations.
+
+IMPORTANT: If you have fields with defaults and opt out of accessors
+
+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. Alternatively, turn on accessors and
+enjoy the benefit of the explicit has() checks.
+
+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.
+
+Nano Generator options
+
+java_package -> <file-name>|<package-name>
+java_outer_classname -> <file-name>|<package-name>
+java_multiple_files -> true or false
+java_nano_generate_has -> true or false [DEPRECATED]
+optional_field_style -> default or accessors
+enum_style -> c or java
+ignore_services -> true or false
+parcelable_messages -> true or false
+
+java_package=<file-name>|<package-name> (no default)
+ This allows overriding the 'java_package' option value
+ for the given file from the command line. Use multiple
+ java_package options to override the option for multiple
+ files. The final Java package for each file is the value
+ of this command line option if present, or the value of
+ the same option defined in the file if present, or the
+ proto package if present, or the default Java package.
+
+java_outer_classname=<file-name>|<outer-classname> (no default)
+ This allows overriding the 'java_outer_classname' option
+ for the given file from the command line. Use multiple
+ java_outer_classname options to override the option for
+ multiple files. The final Java outer class name for each
+ file is the value of this command line option if present,
+ or the value of the same option defined in the file if
+ present, or the file name converted to CamelCase. This
+ outer class will nest all classes and integer constants
+ generated from file-scope messages and enums.
+
+java_multiple_files={true,false} (no default)
+ This allows overriding the 'java_multiple_files' option
+ in all source files and their imported files from the
+ command line. The final value of this option for each
+ file is the value defined in this command line option, or
+ the value of the same option defined in the file if
+ present, or false. This specifies whether to generate
+ package-level classes for the file-scope messages in the
+ same Java package as the outer class (instead of nested
+ classes in the outer class). File-scope enum constants
+ are still generated as integer constants in the outer
+ class. This affects the fully qualified references in the
+ Java code. NOTE: because the command line option
+ overrides the value for all files and their imported
+ files, using this option inconsistently may result in
+ incorrect references to the imported messages and enum
+ constants.
+
+java_nano_generate_has={true,false} (default: false)
+ DEPRECATED. Use optional_field_style=accessors.
+
+ If true, generates a public boolean variable has<fieldname>
+ accompanying each optional or required field (not present for
+ repeated fields, groups or messages). It is set to false initially
+ and upon clear(). If parseFrom(...) reads the field from the wire,
+ it is set to true. This is a way for clients to inspect the "has"
+ value upon parse. If it is set to true, writeTo(...) will ALWAYS
+ output that field (even if field value is equal to its
+ default).
+
+ IMPORTANT: This option costs an extra 4 bytes per primitive field in
+ the message. Think carefully about whether you really need this. In
+ many cases reading the default works and determining whether the
+ field was received over the wire is irrelevant.
+
+optional_field_style={default,accessors,reftypes} (default: default)
+ Defines the style of the generated code for fields.
+
+ * default *
+
+ In the default style, optional fields translate into public mutable
+ Java fields, and the serialization process is as discussed in the
+ "IMPORTANT" section above.
+
+ * accessors *
+
+ When set to 'accessors', each optional field is encapsulated behind
+ 4 accessors, namely get<fieldname>(), set<fieldname>(), has<fieldname>()
+ and clear<fieldname>() methods, with the standard semantics. The hazzer's
+ return value determines whether a field is serialized, so this style is
+ useful when you need to serialize a field with the default value, or check
+ if a field has been explicitly set to its default value from the wire.
+
+ In the 'accessors' style, required and nested message fields are still
+ translated to one public mutable Java field each, repeated fields are still
+ translated to arrays. No accessors are generated for them.
+
+ IMPORTANT: When using the 'accessors' style, ProGuard should always
+ be enabled with optimization (don't use -dontoptimize) and allowing
+ access modification (use -allowaccessmodification). This removes the
+ unused accessors and maybe inline the rest at the call sites,
+ reducing the final code size.
+ TODO(maxtroy): find ProGuard config that would work the best.
+
+ * reftypes *
+
+ When set to 'reftypes', each proto field is generated as a public Java
+ field. For primitive types, these fields use the Java reference types
+ such as java.lang.Integer instead of primitive types such as int.
+
+ In the 'reftypes' style, fields are initialized to null (or empty
+ arrays for repeated fields), and their default values are not available.
+ They are serialized over the wire based on equality to null.
+
+ The 'reftypes' mode has some additional cost due to autoboxing and usage
+ of reference types. In practice, many boxed types are cached, and so don't
+ result in object creation. However, references do take slightly more memory
+ than primitives.
+
+ The 'reftypes' mode is useful when you want to be able to serialize fields
+ with default values, or check if a field has been explicitly set to the
+ default over the wire without paying the extra method cost of the
+ 'accessors' mode.
+
+ Note that if you attempt to write null to a required field in the reftypes
+ mode, serialization of the proto will cause a NullPointerException. This is
+ an intentional indicator that you must set required fields.
+
+ NOTE
+ optional_field_style=accessors or reftypes cannot be used together with
+ java_nano_generate_has=true. If you need the 'has' flag for any
+ required field (you have no reason to), you can only use
+ java_nano_generate_has=true.
+
+enum_style={c,java} (default: c)
+ Defines where to put the int constants generated from enum members.
+
+ * c *
+
+ Use C-style, so the enum constants are available at the scope where
+ the enum is defined. A file-scope enum's members are referenced like
+ 'FileOuterClass.ENUM_VALUE'; a message-scope enum's members are
+ referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
+ This complies with the Micro code generator's behavior.
+
+ * java *
+
+ Use Java-style, so the enum constants are available under the enum
+ name and referenced like 'EnumName.ENUM_VALUE' (they are still int
+ constants). The enum name becomes the name of a public interface, at
+ the scope where the enum is defined. If the enum is file-scope and
+ the java_multiple_files option is on, the interface will be defined
+ in its own file. To reduce code size, this interface should not be
+ implemented and ProGuard shrinking should be used, so after the Java
+ compiler inlines all referenced enum constants into the call sites,
+ the interface remains unused and can be removed by ProGuard.
+
+ignore_services={true,false} (default: false)
+ Skips services definitions.
+
+ Nano doesn't support services. By default, if a service is defined
+ it will generate a compilation error. If this flag is set to true,
+ services will be silently ignored, instead.
+
+parcelable_messages={true,false} (default: false)
+ Android-specific option to generate Parcelable messages.
+
+
+To use nano protobufs within the Android repo:
+
+- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
+ When building a Java library or an app (package) target, the build
+ system will add the Java nano runtime library to the
+ LOCAL_STATIC_JAVA_LIBRARIES variable, so you don't need to.
+- Set 'LOCAL_PROTO_JAVA_OUTPUT_PARAMS := ...' in your local .mk file
+ for any command-line options you need. Use commas to join multiple
+ options. In the nano flavor only, whitespace surrounding the option
+ names and values are ignored, so you can use backslash-newline or
+ '+=' to structure your make files nicely.
+- The options will be applied to *all* proto files in LOCAL_SRC_FILES
+ when you build a Java library or package. In case different options
+ are needed for different proto files, build separate Java libraries
+ and reference them in your main target. Note: you should make sure
+ that, for each separate target, all proto files imported from any
+ proto file in LOCAL_SRC_FILES are included in LOCAL_SRC_FILES. This
+ is because the generator has to assume that the imported files are
+ built using the same options, and will generate code that reference
+ the fields and enums from the imported files using the same code
+ style.
+- Hint: 'include $(CLEAR_VARS)' resets all LOCAL_ variables, including
+ the two above.
+
+To use nano protobufs outside of Android repo:
+
+- Link with the generated jar file
+ <protobuf-root>java/target/protobuf-java-2.3.0-nano.jar.
+- Invoke with --javanano_out, e.g.:
+
+./protoc '--javanano_out=\
+ java_package=src/proto/simple-data.proto|my_package,\
+ java_outer_classname=src/proto/simple-data.proto|OuterName\
+ :.' src/proto/simple-data.proto
+
+Contributing to nano:
+
+Please add/edit tests in NanoTest.java.
+
+Please run the following steps to test:
+
+- cd external/protobuf
+- ./configure
+- Run "make -j12 check" and verify all tests pass.
+- cd java
+- Run "mvn test" and verify all tests pass.
+- cd ../../..
+- . build/envsetup.sh
+- lunch 1
+- "make -j12 aprotoc libprotobuf-java-2.3.0-nano aprotoc-test-nano-params NanoAndroidTest" and
+ check for build errors.
+- Plug in an Android device or start an emulator.
+- adb install -r out/target/product/generic/data/app/NanoAndroidTest.apk
+- Run:
+ "adb shell am instrument -w com.google.protobuf.nano.test/android.test.InstrumentationTestRunner"
+ and verify all tests pass.
+- repo sync -c -j256
+- "make -j12" and check for build errors
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ http://code.google.com/apis/protocolbuffers://developers.google.com/protocol-buffers/
diff --git a/javanano/pom.xml b/javanano/pom.xml
new file mode 100644
index 00000000..3d98a5e0
--- /dev/null
+++ b/javanano/pom.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google</groupId>
+ <artifactId>google</artifactId>
+ <version>1</version>
+ </parent>
+ <groupId>com.google.protobuf.nano</groupId>
+ <artifactId>protobuf-javanano</artifactId>
+ <version>2.6.2-pre</version>
+ <packaging>bundle</packaging>
+ <name>Protocol Buffer JavaNano API</name>
+ <description>
+ Protocol Buffers are a way of encoding structured data in an efficient yet
+ extensible format.
+ </description>
+ <inceptionYear>2008</inceptionYear>
+ <url>https://developers.google.com/protocol-buffers/</url>
+ <licenses>
+ <license>
+ <name>New BSD license</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>https://github.com/google/protobuf</url>
+ <connection>
+ scm:git:https://github.com/google/protobuf.git
+ </connection>
+ </scm>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-test-sources</id>
+ <phase>generate-test-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-test-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_import_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_single_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_has_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=optional_field_style=accessors,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=enum_style=java:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=
+ optional_field_style=accessors,
+ java_outer_classname=google/protobuf/nano/unittest_enum_validity_nano.proto|EnumValidityAccessors
+ :target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=optional_field_style=reftypes,generate_equals=true:target/generated-test-sources" />
+ <arg value="--proto_path=src/test/java/com" />
+ <arg value="src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto" />
+ </exec>
+ </tasks>
+ <testSourceRoot>target/generated-test-sources</testSourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
+ <Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
+ <Export-Package>com.google.protobuf;version=2.6.2-pre</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
new file mode 100644
index 00000000..c5fea5ae
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -0,0 +1,641 @@
+// 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.
+ * <p>
+ * If you want to read several messages from a single CodedInputStream, you
+ * could call {@link #resetSizeCounter()} after each one to avoid hitting the
+ * size limit.
+ *
+ * @return the old limit.
+ */
+ public int setSizeLimit(final int limit) {
+ if (limit < 0) {
+ throw new IllegalArgumentException(
+ "Size limit cannot be negative: " + limit);
+ }
+ final int oldLimit = sizeLimit;
+ sizeLimit = limit;
+ return oldLimit;
+ }
+
+ /**
+ * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
+ */
+ public void resetSizeCounter() {
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Retrieves a subset of data in the buffer. The returned array is not backed by the original
+ * buffer array.
+ *
+ * @param offset the position (relative to the buffer start position) to start at.
+ * @param length the number of bytes to retrieve.
+ */
+ public byte[] getData(int offset, int length) {
+ if (length == 0) {
+ return WireFormatNano.EMPTY_BYTES;
+ }
+ byte[] copy = new byte[length];
+ int start = bufferStart + offset;
+ System.arraycopy(buffer, start, copy, 0, length);
+ return copy;
+ }
+
+ /**
+ * 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/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
new file mode 100644
index 00000000..88df38d7
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -0,0 +1,879 @@
+// 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.
+ *
+ * <p>This class contains two kinds of methods: methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class 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 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 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 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 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/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
new file mode 100644
index 00000000..46cd86f3
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -0,0 +1,187 @@
+// 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;
+
+/**
+ * Base class of those Protocol Buffer messages that need to store unknown fields,
+ * such as extensions.
+ */
+public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
+ extends MessageNano {
+ /**
+ * A container for fields unknown to the message, including extensions. Extension fields can
+ * can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
+ */
+ protected FieldArray unknownFieldData;
+
+ @Override
+ protected int computeSerializedSize() {
+ int size = 0;
+ if (unknownFieldData != null) {
+ for (int i = 0; i < unknownFieldData.size(); i++) {
+ FieldData field = unknownFieldData.dataAt(i);
+ size += field.computeSerializedSize();
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ if (unknownFieldData == null) {
+ return;
+ }
+ for (int i = 0; i < unknownFieldData.size(); i++) {
+ FieldData field = unknownFieldData.dataAt(i);
+ field.writeTo(output);
+ }
+ }
+
+ /**
+ * Checks if there is a value stored for the specified extension in this
+ * message.
+ */
+ public final boolean hasExtension(Extension<M, ?> extension) {
+ if (unknownFieldData == null) {
+ return false;
+ }
+ FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+ return field != null;
+ }
+
+ /**
+ * Gets the value stored in the specified extension of this message.
+ */
+ public final <T> T getExtension(Extension<M, T> extension) {
+ if (unknownFieldData == null) {
+ return null;
+ }
+ FieldData field = unknownFieldData.get(WireFormatNano.getTagFieldNumber(extension.tag));
+ return field == null ? null : field.getValue(extension);
+ }
+
+ /**
+ * Sets the value of the specified extension of this message.
+ */
+ public final <T> M setExtension(Extension<M, T> extension, T value) {
+ int fieldNumber = WireFormatNano.getTagFieldNumber(extension.tag);
+ if (value == null) {
+ if (unknownFieldData != null) {
+ unknownFieldData.remove(fieldNumber);
+ if (unknownFieldData.isEmpty()) {
+ unknownFieldData = null;
+ }
+ }
+ } else {
+ FieldData field = null;
+ if (unknownFieldData == null) {
+ unknownFieldData = new FieldArray();
+ } else {
+ field = unknownFieldData.get(fieldNumber);
+ }
+ if (field == null) {
+ unknownFieldData.put(fieldNumber, new FieldData(extension, value));
+ } else {
+ field.setValue(extension, value);
+ }
+ }
+
+ @SuppressWarnings("unchecked") // Generated code should guarantee type safety
+ M typedThis = (M) this;
+ return typedThis;
+ }
+
+ /**
+ * Stores the binary data of an unknown field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is on.
+ *
+ * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
+ * which case we do not want to add an unknown field entry.
+ *
+ * @param input the input buffer.
+ * @param tag the tag of the field.
+
+ * @return {@literal true} unless the tag is an end-group tag.
+ */
+ protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag)
+ throws IOException {
+ int startPos = input.getPosition();
+ if (!input.skipField(tag)) {
+ return false; // This wasn't an unknown field, it's an end-group tag.
+ }
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ int endPos = input.getPosition();
+ byte[] bytes = input.getData(startPos, endPos - startPos);
+ UnknownFieldData unknownField = new UnknownFieldData(tag, bytes);
+
+ FieldData field = null;
+ if (unknownFieldData == null) {
+ unknownFieldData = new FieldArray();
+ } else {
+ field = unknownFieldData.get(fieldNumber);
+ }
+ if (field == null) {
+ field = new FieldData();
+ unknownFieldData.put(fieldNumber, field);
+ }
+ field.addUnknownField(unknownField);
+ return true;
+ }
+
+ /**
+ * Returns whether the stored unknown field data in this message is equivalent to that in the
+ * other message.
+ *
+ * @param other the other message.
+ * @return whether the two sets of unknown field data are equal.
+ */
+ protected final boolean unknownFieldDataEquals(M other) {
+ if (unknownFieldData == null || unknownFieldData.isEmpty()) {
+ return other.unknownFieldData == null || other.unknownFieldData.isEmpty();
+ } else {
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ }
+
+ /**
+ * Computes the hashcode representing the unknown field data stored in this message.
+ *
+ * @return the hashcode for the unknown field data.
+ */
+ protected final int unknownFieldDataHashCode() {
+ return (unknownFieldData == null || unknownFieldData.isEmpty()
+ ? 0 : unknownFieldData.hashCode());
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
new file mode 100644
index 00000000..a851daf8
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -0,0 +1,722 @@
+// 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.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an extension.
+ *
+ * @author bduff@google.com (Brian Duff)
+ * @author maxtroy@google.com (Max Cai)
+ * @param <M> the type of the extendable message this extension is for.
+ * @param <T> the Java type of the extension; see {@link #clazz}.
+ */
+public class Extension<M extends ExtendableMessageNano<M>, T> {
+
+ /*
+ * Because we typically only define message-typed extensions, the Extension class hierarchy is
+ * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
+ *
+ * Extension // ready to use for message/group typed extensions
+ * Δ
+ * |
+ * PrimitiveExtension // for primitive/enum typed extensions
+ */
+
+ public static final int TYPE_DOUBLE = 1;
+ public static final int TYPE_FLOAT = 2;
+ public static final int TYPE_INT64 = 3;
+ public static final int TYPE_UINT64 = 4;
+ public static final int TYPE_INT32 = 5;
+ public static final int TYPE_FIXED64 = 6;
+ public static final int TYPE_FIXED32 = 7;
+ public static final int TYPE_BOOL = 8;
+ public static final int TYPE_STRING = 9;
+ public static final int TYPE_GROUP = 10;
+ public static final int TYPE_MESSAGE = 11;
+ public static final int TYPE_BYTES = 12;
+ public static final int TYPE_UINT32 = 13;
+ public static final int TYPE_ENUM = 14;
+ public static final int TYPE_SFIXED32 = 15;
+ public static final int TYPE_SFIXED64 = 16;
+ public static final int TYPE_SINT32 = 17;
+ public static final int TYPE_SINT64 = 18;
+
+ /**
+ * Creates an {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
+ return new Extension<M, T>(type, clazz, tag, false);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, int tag) {
+ return new Extension<M, T[]>(type, clazz, tag, true);
+ }
+
+ /**
+ * Creates an {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the boxed Java type of this extension
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, int tag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the Java array type of this extension, with an unboxed component type
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createRepeatedPrimitiveTyped(
+ int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag);
+ }
+
+ /**
+ * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
+ */
+ protected final int type;
+
+ /**
+ * Java type of this extension. For a singular extension, this is the boxed Java type for the
+ * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
+ * component type is the unboxed Java type for {@link #type}. For example, for a singular
+ * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
+ * repeated {@code int32} extension, this equals {@code int[].class}.
+ */
+ protected final Class<T> clazz;
+
+ /**
+ * Tag number of this extension.
+ */
+ public final int tag;
+
+ /**
+ * Whether this extension is repeated.
+ */
+ protected final boolean repeated;
+
+ private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
+ this.type = type;
+ this.clazz = clazz;
+ this.tag = tag;
+ this.repeated = repeated;
+ }
+
+ /**
+ * Returns the value of this extension stored in the given list of unknown fields, or
+ * {@code null} if no unknown fields matches this extension.
+ *
+ * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
+ * that matches this Extension's tag.
+ *
+ */
+ final T getValueFrom(List<UnknownFieldData> unknownFields) {
+ if (unknownFields == null) {
+ return null;
+ }
+ return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
+ }
+
+ private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
+ // For repeated extensions, read all matching unknown fields in their original order.
+ List<Object> resultList = new ArrayList<Object>();
+ for (int i = 0; i < unknownFields.size(); i++) {
+ UnknownFieldData data = unknownFields.get(i);
+ if (data.bytes.length != 0) {
+ readDataInto(data, resultList);
+ }
+ }
+
+ int resultSize = resultList.size();
+ if (resultSize == 0) {
+ return null;
+ } else {
+ T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
+ for (int i = 0; i < resultSize; i++) {
+ Array.set(result, i, resultList.get(i));
+ }
+ return result;
+ }
+ }
+
+ private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
+ // For singular extensions, get the last piece of data stored under this extension.
+ if (unknownFields.isEmpty()) {
+ return null;
+ }
+ UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
+ return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
+ }
+
+ protected Object readData(CodedInputByteBufferNano input) {
+ // This implementation is for message/group extensions.
+ Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
+ try {
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano group = (MessageNano) messageType.newInstance();
+ input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
+ return group;
+ case TYPE_MESSAGE:
+ MessageNano message = (MessageNano) messageType.newInstance();
+ input.readMessage(message);
+ return message;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for message/group extensions.
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+ }
+
+ void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
+ if (repeated) {
+ writeRepeatedData(value, output);
+ } else {
+ writeSingularData(value, output);
+ }
+ }
+
+ protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
+ // This implementation is for message/group extensions.
+ try {
+ out.writeRawVarint32(tag);
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ out.writeGroupNoTag(groupValue);
+ // The endgroup tag must be included in the data payload.
+ out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+ break;
+ case TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ out.writeMessageNoTag(messageValue);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ }
+
+ protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+ // This implementation is for non-packed extensions.
+ int arrayLength = Array.getLength(array);
+ for (int i = 0; i < arrayLength; i++) {
+ Object element = Array.get(array, i);
+ if (element != null) {
+ writeSingularData(element, output);
+ }
+ }
+ }
+
+ int computeSerializedSize(Object value) {
+ if (repeated) {
+ return computeRepeatedSerializedSize(value);
+ } else {
+ return computeSingularSerializedSize(value);
+ }
+ }
+
+ protected int computeRepeatedSerializedSize(Object array) {
+ // This implementation is for non-packed extensions.
+ int size = 0;
+ int arrayLength = Array.getLength(array);
+ for (int i = 0; i < arrayLength; i++) {
+ Object element = Array.get(array, i);
+ if (element != null) {
+ size += computeSingularSerializedSize(Array.get(array, i));
+ }
+ }
+ return size;
+ }
+
+ protected int computeSingularSerializedSize(Object value) {
+ // This implementation is for message/group extensions.
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
+ case TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+
+ /**
+ * Represents an extension of a primitive (including enum) type. If there is no primitive
+ * extensions, this subclass will be removable by ProGuard.
+ */
+ private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
+ extends Extension<M, T> {
+
+ /**
+ * Tag of a piece of non-packed data from the wire compatible with this extension.
+ */
+ private final int nonPackedTag;
+
+ /**
+ * Tag of a piece of packed data from the wire compatible with this extension.
+ * 0 if the type of this extension is not packable.
+ */
+ private final int packedTag;
+
+ public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
+ int nonPackedTag, int packedTag) {
+ super(type, clazz, tag, repeated);
+ this.nonPackedTag = nonPackedTag;
+ this.packedTag = packedTag;
+ }
+
+ @Override
+ protected Object readData(CodedInputByteBufferNano input) {
+ try {
+ switch (type) {
+ case TYPE_DOUBLE:
+ return input.readDouble();
+ case TYPE_FLOAT:
+ return input.readFloat();
+ case TYPE_INT64:
+ return input.readInt64();
+ case TYPE_UINT64:
+ return input.readUInt64();
+ case TYPE_INT32:
+ return input.readInt32();
+ case TYPE_FIXED64:
+ return input.readFixed64();
+ case TYPE_FIXED32:
+ return input.readFixed32();
+ case TYPE_BOOL:
+ return input.readBool();
+ case TYPE_STRING:
+ return input.readString();
+ case TYPE_BYTES:
+ return input.readBytes();
+ case TYPE_UINT32:
+ return input.readUInt32();
+ case TYPE_ENUM:
+ return input.readEnum();
+ case TYPE_SFIXED32:
+ return input.readSFixed32();
+ case TYPE_SFIXED64:
+ return input.readSFixed64();
+ case TYPE_SINT32:
+ return input.readSInt32();
+ case TYPE_SINT64:
+ return input.readSInt64();
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ @Override
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for primitive typed extensions,
+ // which can read both packed and non-packed data.
+ if (data.tag == nonPackedTag) {
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+ } else {
+ CodedInputByteBufferNano buffer =
+ CodedInputByteBufferNano.newInstance(data.bytes);
+ try {
+ buffer.pushLimit(buffer.readRawVarint32()); // length limit
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ while (!buffer.isAtEnd()) {
+ resultList.add(readData(buffer));
+ }
+ }
+ }
+
+ @Override
+ protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
+ try {
+ output.writeRawVarint32(tag);
+ switch (type) {
+ case TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ output.writeDoubleNoTag(doubleValue);
+ break;
+ case TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ output.writeFloatNoTag(floatValue);
+ break;
+ case TYPE_INT64:
+ Long int64Value = (Long) value;
+ output.writeInt64NoTag(int64Value);
+ break;
+ case TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ output.writeUInt64NoTag(uint64Value);
+ break;
+ case TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ output.writeInt32NoTag(int32Value);
+ break;
+ case TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ output.writeFixed64NoTag(fixed64Value);
+ break;
+ case TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ output.writeFixed32NoTag(fixed32Value);
+ break;
+ case TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ output.writeBoolNoTag(boolValue);
+ break;
+ case TYPE_STRING:
+ String stringValue = (String) value;
+ output.writeStringNoTag(stringValue);
+ break;
+ case TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ output.writeBytesNoTag(bytesValue);
+ break;
+ case TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ output.writeUInt32NoTag(uint32Value);
+ break;
+ case TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ output.writeEnumNoTag(enumValue);
+ break;
+ case TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ output.writeSFixed32NoTag(sfixed32Value);
+ break;
+ case TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ output.writeSFixed64NoTag(sfixed64Value);
+ break;
+ case TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ output.writeSInt32NoTag(sint32Value);
+ break;
+ case TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ output.writeSInt64NoTag(sint64Value);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
+ if (tag == nonPackedTag) {
+ // Use base implementation for non-packed data
+ super.writeRepeatedData(array, output);
+ } else if (tag == packedTag) {
+ // Packed. Note that the array element type is guaranteed to be primitive, so there
+ // won't be any null elements, so no null check in this block.
+ int arrayLength = Array.getLength(array);
+ int dataSize = computePackedDataSize(array);
+
+ try {
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(dataSize);
+ switch (type) {
+ case TYPE_BOOL:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeBoolNoTag(Array.getBoolean(array, i));
+ }
+ break;
+ case TYPE_FIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SFIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_FLOAT:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFloatNoTag(Array.getFloat(array, i));
+ }
+ break;
+ case TYPE_FIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SFIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_DOUBLE:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeDoubleNoTag(Array.getDouble(array, i));
+ }
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeEnumNoTag(Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unpackable type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ } else {
+ throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+ + ", unequal to both non-packed variant " + nonPackedTag
+ + " and packed variant " + packedTag);
+ }
+ }
+
+ private int computePackedDataSize(Object array) {
+ int dataSize = 0;
+ int arrayLength = Array.getLength(array);
+ switch (type) {
+ case TYPE_BOOL:
+ // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
+ dataSize = arrayLength;
+ break;
+ case TYPE_FIXED32:
+ case TYPE_SFIXED32:
+ case TYPE_FLOAT:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
+ break;
+ case TYPE_FIXED64:
+ case TYPE_SFIXED64:
+ case TYPE_DOUBLE:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected non-packable type " + type);
+ }
+ return dataSize;
+ }
+
+ @Override
+ protected int computeRepeatedSerializedSize(Object array) {
+ if (tag == nonPackedTag) {
+ // Use base implementation for non-packed data
+ return super.computeRepeatedSerializedSize(array);
+ } else if (tag == packedTag) {
+ // Packed.
+ int dataSize = computePackedDataSize(array);
+ int payloadSize =
+ dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
+ return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+ } else {
+ throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+ + ", unequal to both non-packed variant " + nonPackedTag
+ + " and packed variant " + packedTag);
+ }
+ }
+
+ @Override
+ protected final int computeSingularSerializedSize(Object value) {
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ switch (type) {
+ case TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
+ case TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
+ case TYPE_INT64:
+ Long int64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
+ case TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
+ case TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
+ case TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
+ case TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
+ case TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
+ case TYPE_STRING:
+ String stringValue = (String) value;
+ return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
+ case TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
+ case TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
+ case TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
+ case TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
+ sfixed32Value);
+ case TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
+ sfixed64Value);
+ case TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
+ case TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
new file mode 100644
index 00000000..ab923a4d
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldArray.java
@@ -0,0 +1,273 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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;
+
+
+/**
+ * A custom version of {@link android.util.SparseArray} with the minimal API
+ * for storing {@link FieldData} objects.
+ *
+ * Based on {@link android.support.v4.util.SpareArrayCompat}.
+ */
+class FieldArray {
+ private static final FieldData DELETED = new FieldData();
+ private boolean mGarbage = false;
+
+ private int[] mFieldNumbers;
+ private FieldData[] mData;
+ private int mSize;
+
+ /**
+ * Creates a new FieldArray containing no fields.
+ */
+ public FieldArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new FieldArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public FieldArray(int initialCapacity) {
+ initialCapacity = idealIntArraySize(initialCapacity);
+ mFieldNumbers = new int[initialCapacity];
+ mData = new FieldData[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the FieldData mapped from the specified fieldNumber, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public FieldData get(int fieldNumber) {
+ int i = binarySearch(fieldNumber);
+
+ if (i < 0 || mData[i] == DELETED) {
+ return null;
+ } else {
+ return mData[i];
+ }
+ }
+
+ /**
+ * Removes the data from the specified fieldNumber, if there was any.
+ */
+ public void remove(int fieldNumber) {
+ int i = binarySearch(fieldNumber);
+
+ if (i >= 0 && mData[i] != DELETED) {
+ mData[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+
+ private void gc() {
+ int n = mSize;
+ int o = 0;
+ int[] keys = mFieldNumbers;
+ FieldData[] values = mData;
+
+ for (int i = 0; i < n; i++) {
+ FieldData val = values[i];
+
+ if (val != DELETED) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ values[i] = null;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+ }
+
+ /**
+ * Adds a mapping from the specified fieldNumber to the specified data,
+ * replacing the previous mapping if there was one.
+ */
+ public void put(int fieldNumber, FieldData data) {
+ int i = binarySearch(fieldNumber);
+
+ if (i >= 0) {
+ mData[i] = data;
+ } else {
+ i = ~i;
+
+ if (i < mSize && mData[i] == DELETED) {
+ mFieldNumbers[i] = fieldNumber;
+ mData[i] = data;
+ return;
+ }
+
+ if (mGarbage && mSize >= mFieldNumbers.length) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~ binarySearch(fieldNumber);
+ }
+
+ if (mSize >= mFieldNumbers.length) {
+ int n = idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ FieldData[] nvalues = new FieldData[n];
+
+ System.arraycopy(mFieldNumbers, 0, nkeys, 0, mFieldNumbers.length);
+ System.arraycopy(mData, 0, nvalues, 0, mData.length);
+
+ mFieldNumbers = nkeys;
+ mData = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ System.arraycopy(mFieldNumbers, i, mFieldNumbers, i + 1, mSize - i);
+ System.arraycopy(mData, i, mData, i + 1, mSize - i);
+ }
+
+ mFieldNumbers[i] = fieldNumber;
+ mData[i] = data;
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this FieldArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * FieldArray stores.
+ */
+ public FieldData dataAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mData[index];
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof FieldArray)) {
+ return false;
+ }
+
+ FieldArray other = (FieldArray) o;
+ if (size() != other.size()) { // size() will call gc() if necessary.
+ return false;
+ }
+ return arrayEquals(mFieldNumbers, other.mFieldNumbers, mSize) &&
+ arrayEquals(mData, other.mData, mSize);
+ }
+
+ @Override
+ public int hashCode() {
+ if (mGarbage) {
+ gc();
+ }
+ int result = 17;
+ for (int i = 0; i < mSize; i++) {
+ result = 31 * result + mFieldNumbers[i];
+ result = 31 * result + mData[i].hashCode();
+ }
+ return result;
+ }
+
+ private int idealIntArraySize(int need) {
+ return idealByteArraySize(need * 4) / 4;
+ }
+
+ private int idealByteArraySize(int need) {
+ for (int i = 4; i < 32; i++)
+ if (need <= (1 << i) - 12)
+ return (1 << i) - 12;
+
+ return need;
+ }
+
+ private int binarySearch(int value) {
+ int lo = 0;
+ int hi = mSize - 1;
+
+ while (lo <= hi) {
+ int mid = (lo + hi) >>> 1;
+ int midVal = mFieldNumbers[mid];
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return mid; // value found
+ }
+ }
+ return ~lo; // value not present
+ }
+
+ private boolean arrayEquals(int[] a, int[] b, int size) {
+ for (int i = 0; i < size; i++) {
+ if (a[i] != b[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean arrayEquals(FieldData[] a, FieldData[] b, int size) {
+ for (int i = 0; i < size; i++) {
+ if (!a[i].equals(b[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/FieldData.java b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
new file mode 100644
index 00000000..e5b69aad
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/FieldData.java
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 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.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated API doesn't
+ * know about yet.
+ */
+class FieldData {
+ private Extension<?, ?> cachedExtension;
+ private Object value;
+ /** The serialised values for this object. Will be cleared if getValue is called */
+ private List<UnknownFieldData> unknownFieldData;
+
+ <T> FieldData(Extension<?, T> extension, T newValue) {
+ cachedExtension = extension;
+ value = newValue;
+ }
+
+ FieldData() {
+ unknownFieldData = new ArrayList<UnknownFieldData>();
+ }
+
+ void addUnknownField(UnknownFieldData unknownField) {
+ unknownFieldData.add(unknownField);
+ }
+
+ UnknownFieldData getUnknownField(int index) {
+ if (unknownFieldData == null) {
+ return null;
+ }
+ if (index < unknownFieldData.size()) {
+ return unknownFieldData.get(index);
+ }
+ return null;
+ }
+
+ int getUnknownFieldSize() {
+ if (unknownFieldData == null) {
+ return 0;
+ }
+ return unknownFieldData.size();
+ }
+
+ <T> T getValue(Extension<?, T> extension) {
+ if (value != null){
+ if (cachedExtension != extension) { // Extension objects are singletons.
+ throw new IllegalStateException(
+ "Tried to getExtension with a differernt Extension.");
+ }
+ } else {
+ cachedExtension = extension;
+ value = extension.getValueFrom(unknownFieldData);
+ unknownFieldData = null;
+ }
+ return (T) value;
+ }
+
+ <T> void setValue(Extension<?, T> extension, T newValue) {
+ cachedExtension = extension;
+ value = newValue;
+ unknownFieldData = null;
+ }
+
+ int computeSerializedSize() {
+ int size = 0;
+ if (value != null) {
+ size = cachedExtension.computeSerializedSize(value);
+ } else {
+ for (UnknownFieldData unknownField : unknownFieldData) {
+ size += unknownField.computeSerializedSize();
+ }
+ }
+ return size;
+ }
+
+ void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ if (value != null) {
+ cachedExtension.writeTo(value, output);
+ } else {
+ for (UnknownFieldData unknownField : unknownFieldData) {
+ unknownField.writeTo(output);
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof FieldData)) {
+ return false;
+ }
+
+ FieldData other = (FieldData) o;
+ if (value != null && other.value != null) {
+ // If both objects have deserialized values, compare those.
+ // Since unknown fields are only compared if messages have generated equals methods
+ // we know this will be a meaningful comparison (not identity) for all values.
+ if (cachedExtension != other.cachedExtension) { // Extension objects are singletons.
+ return false;
+ }
+ if (!cachedExtension.clazz.isArray()) {
+ // Can't test (!cachedExtension.repeated) due to 'bytes' -> 'byte[]'
+ return value.equals(other.value);
+ }
+ if (value instanceof byte[]) {
+ return Arrays.equals((byte[]) value, (byte[]) other.value);
+ } else if (value instanceof int[]) {
+ return Arrays.equals((int[]) value, (int[]) other.value);
+ } else if (value instanceof long[]) {
+ return Arrays.equals((long[]) value, (long[]) other.value);
+ } else if (value instanceof float[]) {
+ return Arrays.equals((float[]) value, (float[]) other.value);
+ } else if (value instanceof double[]) {
+ return Arrays.equals((double[]) value, (double[]) other.value);
+ } else if (value instanceof boolean[]) {
+ return Arrays.equals((boolean[]) value, (boolean[]) other.value);
+ } else {
+ return Arrays.deepEquals((Object[]) value, (Object[]) other.value);
+ }
+ }
+ if (unknownFieldData != null && other.unknownFieldData != null) {
+ // If both objects have byte arrays compare those directly.
+ return unknownFieldData.equals(other.unknownFieldData);
+ }
+ try {
+ // As a last resort, serialize and compare the resulting byte arrays.
+ return Arrays.equals(toByteArray(), other.toByteArray());
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ try {
+ // The only way to generate a consistent hash is to use the serialized form.
+ result = 31 * result + Arrays.hashCode(toByteArray());
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ return result;
+ }
+
+ private byte[] toByteArray() throws IOException {
+ byte[] result = new byte[computeSerializedSize()];
+ CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(result);
+ writeTo(output);
+ return result;
+ }
+
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
new file mode 100644
index 00000000..90ca11d5
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -0,0 +1,333 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.nano;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+/**
+ * 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 final class InternalNano {
+
+ private InternalNano() {}
+
+ /**
+ * An object to provide synchronization when lazily initializing static fields
+ * of {@link MessageNano} subclasses.
+ * <p>
+ * To enable earlier versions of ProGuard to inline short methods from a
+ * generated MessageNano subclass to the call sites, that class must not have
+ * a class initializer, which will be created if there is any static variable
+ * initializers. To lazily initialize the static variables in a thread-safe
+ * manner, the initialization code will synchronize on this object.
+ */
+ public static final Object LAZY_INIT_LOCK = new Object();
+
+ /**
+ * Helper called by generated code to construct default values for string
+ * fields.
+ * <p>
+ * The protocol compiler does not actually contain a UTF-8 decoder -- it
+ * just pushes UTF-8-encoded text around without touching it. The one place
+ * where this presents a problem is when generating Java string literals.
+ * Unicode characters in the string literal would normally need to be encoded
+ * using a Unicode escape sequence, which would require decoding them.
+ * To get around this, protoc instead embeds the UTF-8 bytes into the
+ * generated code and leaves it to the runtime library to decode them.
+ * <p>
+ * It gets worse, though. If protoc just generated a byte array, like:
+ * new byte[] {0x12, 0x34, 0x56, 0x78}
+ * Java actually generates *code* which allocates an array and then fills
+ * in each value. This is much less efficient than just embedding the bytes
+ * directly into the bytecode. To get around this, we need another
+ * work-around. String literals are embedded directly, so protoc actually
+ * generates a string literal corresponding to the bytes. The easiest way
+ * to do this is to use the ISO-8859-1 character set, which corresponds to
+ * the first 256 characters of the Unicode range. Protoc can then use
+ * good old CEscape to generate the string.
+ * <p>
+ * So we have a string literal which represents a set of bytes which
+ * represents another string. This function -- stringDefaultValue --
+ * converts from the generated string to the string we actually want. The
+ * generated code calls this automatically.
+ */
+ public static String stringDefaultValue(String bytes) {
+ try {
+ return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // both of the above character sets.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Helper called by generated code to construct default values for bytes
+ * fields.
+ * <p>
+ * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+ * In this case we only need the second of the two hacks -- allowing us to
+ * embed raw bytes as a string literal with ISO-8859-1 encoding.
+ */
+ public static 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 byte[] copyFromUtf8(final String text) {
+ try {
+ return text.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?");
+ }
+ }
+
+ /**
+ * Checks repeated int field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(int[] field1, int[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated long field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(long[] field1, long[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated float field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(float[] field1, float[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated double field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(double[] field1, double[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated boolean field equality; null-value and 0-length fields are
+ * considered equal.
+ */
+ public static boolean equals(boolean[] field1, boolean[] field2) {
+ if (field1 == null || field1.length == 0) {
+ return field2 == null || field2.length == 0;
+ } else {
+ return Arrays.equals(field1, field2);
+ }
+ }
+
+ /**
+ * Checks repeated bytes field equality. Only non-null elements are tested.
+ * Returns true if the two fields have the same sequence of non-null
+ * elements. Null-value fields and fields of any length with only null
+ * elements are considered equal.
+ */
+ public static boolean equals(byte[][] field1, byte[][] field2) {
+ int index1 = 0;
+ int length1 = field1 == null ? 0 : field1.length;
+ int index2 = 0;
+ int length2 = field2 == null ? 0 : field2.length;
+ while (true) {
+ while (index1 < length1 && field1[index1] == null) {
+ index1++;
+ }
+ while (index2 < length2 && field2[index2] == null) {
+ index2++;
+ }
+ boolean atEndOf1 = index1 >= length1;
+ boolean atEndOf2 = index2 >= length2;
+ if (atEndOf1 && atEndOf2) {
+ // no more non-null elements to test in both arrays
+ return true;
+ } else if (atEndOf1 != atEndOf2) {
+ // one of the arrays have extra non-null elements
+ return false;
+ } else if (!Arrays.equals(field1[index1], field2[index2])) {
+ // element mismatch
+ return false;
+ }
+ index1++;
+ index2++;
+ }
+ }
+
+ /**
+ * Checks repeated string/message field equality. Only non-null elements are
+ * tested. Returns true if the two fields have the same sequence of non-null
+ * elements. Null-value fields and fields of any length with only null
+ * elements are considered equal.
+ */
+ public static boolean equals(Object[] field1, Object[] field2) {
+ int index1 = 0;
+ int length1 = field1 == null ? 0 : field1.length;
+ int index2 = 0;
+ int length2 = field2 == null ? 0 : field2.length;
+ while (true) {
+ while (index1 < length1 && field1[index1] == null) {
+ index1++;
+ }
+ while (index2 < length2 && field2[index2] == null) {
+ index2++;
+ }
+ boolean atEndOf1 = index1 >= length1;
+ boolean atEndOf2 = index2 >= length2;
+ if (atEndOf1 && atEndOf2) {
+ // no more non-null elements to test in both arrays
+ return true;
+ } else if (atEndOf1 != atEndOf2) {
+ // one of the arrays have extra non-null elements
+ return false;
+ } else if (!field1[index1].equals(field2[index2])) {
+ // element mismatch
+ return false;
+ }
+ index1++;
+ index2++;
+ }
+ }
+
+ /**
+ * Computes the hash code of a repeated int field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(int[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated long field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(long[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated float field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(float[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated double field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(double[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated boolean field. Null-value and 0-length
+ * fields have the same hash code.
+ */
+ public static int hashCode(boolean[] field) {
+ return field == null || field.length == 0 ? 0 : Arrays.hashCode(field);
+ }
+
+ /**
+ * Computes the hash code of a repeated bytes field. Only the sequence of all
+ * non-null elements are used in the computation. Null-value fields and fields
+ * of any length with only null elements have the same hash code.
+ */
+ public static int hashCode(byte[][] field) {
+ int result = 0;
+ for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+ byte[] element = field[i];
+ if (element != null) {
+ result = 31 * result + Arrays.hashCode(element);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Computes the hash code of a repeated string/message field. Only the
+ * sequence of all non-null elements are used in the computation. Null-value
+ * fields and fields of any length with only null elements have the same hash
+ * code.
+ */
+ public static int hashCode(Object[] field) {
+ int result = 0;
+ for (int i = 0, size = field == null ? 0 : field.length; i < size; i++) {
+ Object element = field[i];
+ if (element != null) {
+ result = 31 * result + element.hashCode();
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java b/javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
new file mode 100644
index 00000000..ff0af9df
--- /dev/null
+++ b/javanano/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/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
new file mode 100644
index 00000000..164f317f
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -0,0 +1,190 @@
+// 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.util.Arrays;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public abstract class MessageNano {
+ protected volatile int cachedSize = -1;
+
+ /**
+ * 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.
+ */
+ public int getCachedSize() {
+ if (cachedSize < 0) {
+ // getSerializedSize sets cachedSize
+ getSerializedSize();
+ }
+ return cachedSize;
+ }
+
+ /**
+ * Computes the number of bytes required to encode this message.
+ * The size is cached and the cached result can be retrieved
+ * using getCachedSize().
+ */
+ public int getSerializedSize() {
+ int size = computeSerializedSize();
+ cachedSize = size;
+ return size;
+ }
+
+ /**
+ * Computes the number of bytes required to encode this message. This does not update the
+ * cached size.
+ */
+ protected int computeSerializedSize() {
+ // This is overridden if the generated message has serialized fields.
+ return 0;
+ }
+
+ /**
+ * Serializes the message and writes it to {@code output}.
+ *
+ * @param output the output to receive the serialized form.
+ * @throws IOException if an error occurred writing to {@code output}.
+ */
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ // Does nothing by default. Overridden by subclasses which have data to write.
+ }
+
+ /**
+ * Parse {@code input} as a message of this type and merge it with the
+ * message being built.
+ */
+ public abstract MessageNano mergeFrom(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.
+ */
+ 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).", e);
+ }
+ }
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built.
+ */
+ public static final <T extends MessageNano> T mergeFrom(T 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 <T extends MessageNano> T mergeFrom(T 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).");
+ }
+ }
+
+ /**
+ * Compares two {@code MessageNano}s and returns true if the message's are the same class and
+ * have serialized form equality (i.e. all of the field values are the same).
+ */
+ public static final boolean messageNanoEquals(MessageNano a, MessageNano b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ if (a.getClass() != b.getClass()) {
+ return false;
+ }
+ final int serializedSize = a.getSerializedSize();
+ if (b.getSerializedSize() != serializedSize) {
+ return false;
+ }
+ final byte[] aByteArray = new byte[serializedSize];
+ final byte[] bByteArray = new byte[serializedSize];
+ toByteArray(a, aByteArray, 0, serializedSize);
+ toByteArray(b, bByteArray, 0, serializedSize);
+ return Arrays.equals(aByteArray, bByteArray);
+ }
+
+ /**
+ * Returns a string that is (mostly) compatible with ProtoBuffer's TextFormat. Note that groups
+ * (which are deprecated) are not serialized with the correct field name.
+ *
+ * <p>This is implemented using reflection, so it is not especially fast nor is it guaranteed
+ * to find all fields if you have method removal turned on for proguard.
+ */
+ @Override
+ public String toString() {
+ return MessageNanoPrinter.print(this);
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
new file mode 100644
index 00000000..4cca3d5e
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -0,0 +1,257 @@
+// 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.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Static helper methods for printing nano protos.
+ *
+ * @author flynn@google.com Andrew Flynn
+ */
+public final class MessageNanoPrinter {
+ // Do not allow instantiation
+ private MessageNanoPrinter() {}
+
+ private static final String INDENT = " ";
+ private static final int MAX_STRING_LEN = 200;
+
+ /**
+ * Returns an text representation of a MessageNano suitable for debugging. The returned string
+ * is mostly compatible with Protocol Buffer's TextFormat (as provided by non-nano protocol
+ * buffers) -- groups (which are deprecated) are output with an underscore name (e.g. foo_bar
+ * instead of FooBar) and will thus not parse.
+ *
+ * <p>Employs Java reflection on the given object and recursively prints primitive fields,
+ * groups, and messages.</p>
+ */
+ public static <T extends MessageNano> String print(T message) {
+ if (message == null) {
+ return "";
+ }
+
+ StringBuffer buf = new StringBuffer();
+ try {
+ print(null, message, new StringBuffer(), buf);
+ } catch (IllegalAccessException e) {
+ return "Error printing proto: " + e.getMessage();
+ } catch (InvocationTargetException e) {
+ return "Error printing proto: " + e.getMessage();
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Function that will print the given message/field into the StringBuffer.
+ * Meant to be called recursively.
+ *
+ * @param identifier the identifier to use, or {@code null} if this is the root message to
+ * print.
+ * @param object the value to print. May in fact be a primitive value or byte array and not a
+ * message.
+ * @param indentBuf the indentation each line should begin with.
+ * @param buf the output buffer.
+ */
+ private static void print(String identifier, Object object,
+ StringBuffer indentBuf, StringBuffer buf) throws IllegalAccessException,
+ InvocationTargetException {
+ if (object == null) {
+ // This can happen if...
+ // - we're about to print a message, String, or byte[], but it not present;
+ // - we're about to print a primitive, but "reftype" optional style is enabled, and
+ // the field is unset.
+ // In both cases the appropriate behavior is to output nothing.
+ } else if (object instanceof MessageNano) { // Nano proto message
+ int origIndentBufLength = indentBuf.length();
+ if (identifier != null) {
+ buf.append(indentBuf).append(deCamelCaseify(identifier)).append(" <\n");
+ indentBuf.append(INDENT);
+ }
+ Class<?> clazz = object.getClass();
+
+ // Proto fields follow one of two formats:
+ //
+ // 1) Public, non-static variables that do not begin or end with '_'
+ // Find and print these using declared public fields
+ for (Field field : clazz.getFields()) {
+ int modifiers = field.getModifiers();
+ String fieldName = field.getName();
+
+ if ((modifiers & Modifier.PUBLIC) == Modifier.PUBLIC
+ && (modifiers & Modifier.STATIC) != Modifier.STATIC
+ && !fieldName.startsWith("_")
+ && !fieldName.endsWith("_")) {
+ Class<?> fieldType = field.getType();
+ Object value = field.get(object);
+
+ if (fieldType.isArray()) {
+ Class<?> arrayType = fieldType.getComponentType();
+
+ // bytes is special since it's not repeated, but is represented by an array
+ if (arrayType == byte.class) {
+ print(fieldName, value, indentBuf, buf);
+ } else {
+ int len = value == null ? 0 : Array.getLength(value);
+ for (int i = 0; i < len; i++) {
+ Object elem = Array.get(value, i);
+ print(fieldName, elem, indentBuf, buf);
+ }
+ }
+ } else {
+ print(fieldName, value, indentBuf, buf);
+ }
+ }
+ }
+
+ // 2) Fields that are accessed via getter methods (when accessors
+ // mode is turned on)
+ // Find and print these using getter methods.
+ for (Method method : clazz.getMethods()) {
+ String name = method.getName();
+ // Check for the setter accessor method since getters and hazzers both have
+ // non-proto-field name collisions (hashCode() and getSerializedSize())
+ if (name.startsWith("set")) {
+ String subfieldName = name.substring(3);
+
+ Method hazzer = null;
+ try {
+ hazzer = clazz.getMethod("has" + subfieldName);
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+ // If hazzer does't exist or returns false, no need to continue
+ if (!(Boolean) hazzer.invoke(object)) {
+ continue;
+ }
+
+ Method getter = null;
+ try {
+ getter = clazz.getMethod("get" + subfieldName);
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+
+ print(subfieldName, getter.invoke(object), indentBuf, buf);
+ }
+ }
+ if (identifier != null) {
+ indentBuf.setLength(origIndentBufLength);
+ buf.append(indentBuf).append(">\n");
+ }
+ } else {
+ // Non-null primitive value
+ identifier = deCamelCaseify(identifier);
+ buf.append(indentBuf).append(identifier).append(": ");
+ if (object instanceof String) {
+ String stringMessage = sanitizeString((String) object);
+ buf.append("\"").append(stringMessage).append("\"");
+ } else if (object instanceof byte[]) {
+ appendQuotedBytes((byte[]) object, buf);
+ } else {
+ buf.append(object);
+ }
+ buf.append("\n");
+ }
+ }
+
+ /**
+ * Converts an identifier of the format "FieldName" into "field_name".
+ */
+ private static String deCamelCaseify(String identifier) {
+ StringBuffer out = new StringBuffer();
+ for (int i = 0; i < identifier.length(); i++) {
+ char currentChar = identifier.charAt(i);
+ if (i == 0) {
+ out.append(Character.toLowerCase(currentChar));
+ } else if (Character.isUpperCase(currentChar)) {
+ out.append('_').append(Character.toLowerCase(currentChar));
+ } else {
+ out.append(currentChar);
+ }
+ }
+ return out.toString();
+ }
+
+ /**
+ * Shortens and escapes the given string.
+ */
+ private static String sanitizeString(String str) {
+ if (!str.startsWith("http") && str.length() > MAX_STRING_LEN) {
+ // Trim non-URL strings.
+ str = str.substring(0, MAX_STRING_LEN) + "[...]";
+ }
+ return escapeString(str);
+ }
+
+ /**
+ * Escape everything except for low ASCII code points.
+ */
+ private static String escapeString(String str) {
+ int strLen = str.length();
+ StringBuilder b = new StringBuilder(strLen);
+ for (int i = 0; i < strLen; i++) {
+ char original = str.charAt(i);
+ if (original >= ' ' && original <= '~' && original != '"' && original != '\'') {
+ b.append(original);
+ } else {
+ b.append(String.format("\\u%04x", (int) original));
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * Appends a quoted byte array to the provided {@code StringBuffer}.
+ */
+ private static void appendQuotedBytes(byte[] bytes, StringBuffer builder) {
+ if (bytes == null) {
+ builder.append("\"\"");
+ return;
+ }
+
+ builder.append('"');
+ for (int i = 0; i < bytes.length; ++i) {
+ int ch = bytes[i] & 0xff;
+ if (ch == '\\' || ch == '"') {
+ builder.append('\\').append((char) ch);
+ } else if (ch >= 32 && ch < 127) {
+ builder.append((char) ch);
+ } else {
+ builder.append(String.format("\\%03o", ch));
+ }
+ }
+ builder.append('"');
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
new file mode 100644
index 00000000..2032e1a6
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -0,0 +1,84 @@
+// 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.util.Arrays;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated
+ * API doesn't know about yet.
+ *
+ * @author bduff@google.com (Brian Duff)
+ */
+final class UnknownFieldData {
+
+ final int tag;
+ final byte[] bytes;
+
+ UnknownFieldData(int tag, byte[] bytes) {
+ this.tag = tag;
+ this.bytes = bytes;
+ }
+
+ int computeSerializedSize() {
+ int size = 0;
+ size += CodedOutputByteBufferNano.computeRawVarint32Size(tag);
+ size += bytes.length;
+ return size;
+ }
+
+ void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ output.writeRawVarint32(tag);
+ output.writeRawBytes(bytes);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof UnknownFieldData)) {
+ return false;
+ }
+
+ UnknownFieldData other = (UnknownFieldData) o;
+ return tag == other.tag && Arrays.equals(bytes, other.bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + tag;
+ result = 31 * result + Arrays.hashCode(bytes);
+ return result;
+ }
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
new file mode 100644
index 00000000..a3405e55
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/WireFormatNano.java
@@ -0,0 +1,124 @@
+// 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;
+ }
+
+ 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 = {};
+
+ /**
+ * Parses an unknown field. This implementation skips the field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is off.
+ *
+ * @return {@literal 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.readTag() == tag) {
+ input.skipField(tag);
+ arrayLength++;
+ }
+ input.rewindToPosition(startPos);
+ return arrayLength;
+ }
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
new file mode 100644
index 00000000..5ac7edb6
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -0,0 +1,3797 @@
+// 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 com.google.protobuf.nano.CodedInputByteBufferNano;
+import com.google.protobuf.nano.EnumClassNanoMultiple;
+import com.google.protobuf.nano.EnumClassNanos;
+import com.google.protobuf.nano.EnumValidity;
+import com.google.protobuf.nano.EnumValidityAccessors;
+import com.google.protobuf.nano.FileScopeEnumMultiple;
+import com.google.protobuf.nano.FileScopeEnumRefNano;
+import com.google.protobuf.nano.InternalNano;
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.nano.MessageScopeEnumRefNano;
+import com.google.protobuf.nano.MultipleImportingNonMultipleNano1;
+import com.google.protobuf.nano.MultipleImportingNonMultipleNano2;
+import com.google.protobuf.nano.MultipleNameClashNano;
+import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
+import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
+import com.google.protobuf.nano.NanoOuterClass;
+import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
+import com.google.protobuf.nano.NanoReferenceTypes;
+import com.google.protobuf.nano.NanoRepeatedPackables;
+import com.google.protobuf.nano.PackedExtensions;
+import com.google.protobuf.nano.RepeatedExtensions;
+import com.google.protobuf.nano.SingularExtensions;
+import com.google.protobuf.nano.TestRepeatedMergeNano;
+import com.google.protobuf.nano.UnittestMultipleNano;
+import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
+import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
+import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
+import com.google.protobuf.nano.testext.Extensions;
+import com.google.protobuf.nano.testext.Extensions.AnotherMessage;
+import com.google.protobuf.nano.testext.Extensions.MessageWithGroup;
+import com.google.protobuf.nano.testimport.UnittestImportNano;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+/**
+ * Test nano runtime.
+ *
+ * @author ulas@google.com Ulas Kirazci
+ */
+public class NanoTest extends TestCase {
+ @Override
+ 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);
+
+ msg.nestedMsg = null;
+ assertTrue(msgSerializedSize != msg.getSerializedSize());
+
+ msg.clear();
+ assertEquals(0, msg.getSerializedSize());
+ }
+
+ 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 testMessageNoFields() {
+ SingleMessageNano msg = new SingleMessageNano();
+ assertEquals(0, msg.getSerializedSize());
+ assertEquals(0, MessageNano.toByteArray(msg).length);
+ }
+
+ 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 testNanoOptionalGroupWithUnknownFieldsEnabled() throws Exception {
+ MessageWithGroup msg = new MessageWithGroup();
+ MessageWithGroup.Group grp = new MessageWithGroup.Group();
+ grp.a = 1;
+ msg.group = grp;
+ byte [] serialized = MessageNano.toByteArray(msg);
+
+ MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
+ assertEquals(1, parsed.group.a);
+
+ byte [] serialized2 = MessageNano.toByteArray(parsed);
+ assertEquals(serialized.length, serialized2.length);
+ MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
+ assertEquals(1, parsed2.group.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 testNanoRepeatedPackedSerializedSize() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+ int msgSerializedSize = msg.getSerializedSize();
+ byte [] result = MessageNano.toByteArray(msg);
+ //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+ assertTrue(msgSerializedSize == 11);
+ assertEquals(result.length, msgSerializedSize);
+ TestAllTypesNano msg2 = new TestAllTypesNano();
+ msg2.repeatedPackedInt32 = new int[] { 123, 789, 456 };
+ byte [] result2 = new byte[msgSerializedSize];
+ MessageNano.toByteArray(msg2, result2, 0, msgSerializedSize);
+
+ // Check equal size and content.
+ assertEquals(msgSerializedSize, msg2.getSerializedSize());
+ assertTrue(Arrays.equals(result, result2));
+ }
+
+ 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);
+ }
+
+ /**
+ * Tests that invalid enum values from the wire are not accepted.
+ */
+ public void testNanoEnumValidity() throws Exception {
+ final int invalid = 120;
+ final int alsoInvalid = 121;
+
+ EnumValidity.M m = new EnumValidity.M();
+ // Sanity check & baseline of the assertions for the first case below.
+ assertEquals(EnumValidity.E.default_, m.optionalE);
+ assertEquals(EnumValidity.E.BAZ, m.defaultE);
+
+ m.optionalE = invalid;
+ m.defaultE = invalid;
+ // E contains all valid values
+ m.repeatedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR};
+ m.packedE = new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ};
+ // E2 contains some invalid values
+ m.repeatedE2 = new int[] {invalid, EnumValidity.E.BAR, alsoInvalid};
+ m.packedE2 = new int[] {EnumValidity.E.FOO, invalid, alsoInvalid};
+ // E3 contains all invalid values
+ m.repeatedE3 = new int[] {invalid, invalid};
+ m.packedE3 = new int[] {alsoInvalid, alsoInvalid};
+ byte[] serialized = MessageNano.toByteArray(m);
+ // Sanity check that we do have all data in the byte array.
+ assertEquals(31, serialized.length);
+
+ // Test 1: tests that invalid values aren't included in the deserialized message.
+ EnumValidity.M deserialized = MessageNano.mergeFrom(new EnumValidity.M(), serialized);
+ assertEquals(EnumValidity.E.default_, deserialized.optionalE);
+ assertEquals(EnumValidity.E.BAZ, deserialized.defaultE);
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO, EnumValidity.E.BAR}, deserialized.repeatedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO, EnumValidity.E.BAZ}, deserialized.packedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAR}, deserialized.repeatedE2));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.FOO}, deserialized.packedE2));
+ assertEquals(0, deserialized.repeatedE3.length);
+ assertEquals(0, deserialized.packedE3.length);
+
+ // Test 2: tests that invalid values do not override previous values in the field, including
+ // arrays, including pre-existing invalid values.
+ deserialized.optionalE = EnumValidity.E.BAR;
+ deserialized.defaultE = alsoInvalid;
+ deserialized.repeatedE = new int[] {EnumValidity.E.BAZ};
+ deserialized.packedE = new int[] {EnumValidity.E.BAZ, alsoInvalid};
+ deserialized.repeatedE2 = new int[] {invalid, alsoInvalid};
+ deserialized.packedE2 = null;
+ deserialized.repeatedE3 = null;
+ deserialized.packedE3 = new int[0];
+ MessageNano.mergeFrom(deserialized, serialized);
+ assertEquals(EnumValidity.E.BAR, deserialized.optionalE);
+ assertEquals(alsoInvalid, deserialized.defaultE);
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAZ, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAR},
+ deserialized.repeatedE));
+ assertTrue(Arrays.equals(
+ new int[] {EnumValidity.E.BAZ, alsoInvalid, /* + */ EnumValidity.E.FOO, EnumValidity.E.BAZ},
+ deserialized.packedE));
+ assertTrue(Arrays.equals(
+ new int[] {invalid, alsoInvalid, /* + */ EnumValidity.E.BAR},
+ deserialized.repeatedE2));
+ assertTrue(Arrays.equals(
+ new int[] {/* <null> + */ EnumValidity.E.FOO},
+ deserialized.packedE2));
+ assertNull(deserialized.repeatedE3); // null + all invalid == null
+ assertEquals(0, deserialized.packedE3.length); // empty + all invalid == empty
+
+ // Test 3: reading by alternative forms
+ EnumValidity.Alt alt = MessageNano.mergeFrom(new EnumValidity.Alt(), serialized);
+ assertEquals(EnumValidity.E.BAR, // last valid value in m.repeatedE2
+ alt.repeatedE2AsOptional);
+ assertTrue(Arrays.equals(new int[] {EnumValidity.E.FOO}, alt.packedE2AsNonPacked));
+ assertEquals(0, alt.nonPackedE3AsPacked.length);
+ }
+
+ /**
+ * Tests the same as {@link #testNanoEnumValidity()} with accessor style. Repeated fields are
+ * not re-tested here because they are not affected by the accessor style.
+ */
+ public void testNanoEnumValidityAccessors() throws Exception {
+ final int invalid = 120;
+ final int alsoInvalid = 121;
+
+ EnumValidityAccessors.M m = new EnumValidityAccessors.M();
+ // Sanity check & baseline of the assertions for the first case below.
+ assertEquals(EnumValidityAccessors.default_, m.getOptionalE());
+ assertEquals(EnumValidityAccessors.BAZ, m.getDefaultE());
+
+ m.setOptionalE(invalid);
+ m.setDefaultE(invalid);
+ // Set repeatedE2 for Alt.repeatedE2AsOptional
+ m.repeatedE2 = new int[] {invalid, EnumValidityAccessors.BAR, alsoInvalid};
+ byte[] serialized = MessageNano.toByteArray(m);
+ // Sanity check that we do have all data in the byte array.
+ assertEquals(10, serialized.length);
+
+ // Test 1: tests that invalid values aren't included in the deserialized message.
+ EnumValidityAccessors.M deserialized =
+ MessageNano.mergeFrom(new EnumValidityAccessors.M(), serialized);
+ assertEquals(EnumValidityAccessors.default_, deserialized.getOptionalE());
+ assertEquals(EnumValidityAccessors.BAZ, deserialized.getDefaultE());
+
+ // Test 2: tests that invalid values do not override previous values in the field, including
+ // pre-existing invalid values.
+ deserialized.setOptionalE(EnumValidityAccessors.BAR);
+ deserialized.setDefaultE(alsoInvalid);
+ MessageNano.mergeFrom(deserialized, serialized);
+ assertEquals(EnumValidityAccessors.BAR, deserialized.getOptionalE());
+ assertEquals(alsoInvalid, deserialized.getDefaultE());
+
+ // Test 3: reading by alternative forms
+ EnumValidityAccessors.Alt alt =
+ MessageNano.mergeFrom(new EnumValidityAccessors.Alt(), serialized);
+ assertEquals(EnumValidityAccessors.BAR, // last valid value in m.repeatedE2
+ alt.getRepeatedE2AsOptional());
+ }
+
+ /**
+ * Tests that code generation correctly wraps a single message into its outer
+ * class. The class {@code SingleMessageNano} is imported from the outer
+ * class {@code UnittestSingleNano}, whose name is implicit. Any error would
+ * cause this method to fail compilation.
+ */
+ public void testNanoSingle() throws Exception {
+ SingleMessageNano msg = new SingleMessageNano();
+ assertNotNull(msg);
+ }
+
+ /**
+ * Tests that code generation correctly skips generating the outer class if
+ * unnecessary, letting a file-scope entity have the same name. The class
+ * {@code MultipleNameClashNano} shares the same name with the file's outer
+ * class defined explicitly, but the file contains no other entities and has
+ * java_multiple_files set. Any error would cause this method to fail
+ * compilation.
+ */
+ public void testNanoMultipleNameClash() throws Exception {
+ MultipleNameClashNano msg = new MultipleNameClashNano();
+ msg.field = 0;
+ }
+
+ /**
+ * Tests that code generation correctly handles enums in different scopes in
+ * a source file with the option java_multiple_files set to true. Any error
+ * would cause this method to fail compilation.
+ */
+ public void testNanoMultipleEnumScoping() throws Exception {
+ FileScopeEnumRefNano msg1 = new FileScopeEnumRefNano();
+ msg1.enumField = UnittestMultipleNano.ONE;
+ MessageScopeEnumRefNano msg2 = new MessageScopeEnumRefNano();
+ msg2.enumField = MessageScopeEnumRefNano.TWO;
+ }
+
+ /**
+ * Tests that code generation with mixed values of the java_multiple_files
+ * options between the main source file and the imported source files would
+ * generate correct references. Any error would cause this method to fail
+ * compilation.
+ */
+ public void testNanoMultipleImportingNonMultiple() throws Exception {
+ UnittestImportNano.ImportMessageNano importMsg = new UnittestImportNano.ImportMessageNano();
+ MultipleImportingNonMultipleNano1 nano1 = new MultipleImportingNonMultipleNano1();
+ nano1.field = importMsg;
+ MultipleImportingNonMultipleNano2 nano2 = new MultipleImportingNonMultipleNano2();
+ nano2.nano1 = nano1;
+ }
+
+ 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);
+ assertEquals(Float.POSITIVE_INFINITY, msg.defaultFloatInf);
+ assertEquals(Float.NEGATIVE_INFINITY, msg.defaultFloatNegInf);
+ assertEquals(Float.NaN, msg.defaultFloatNan);
+ assertEquals(Double.POSITIVE_INFINITY, msg.defaultDoubleInf);
+ assertEquals(Double.NEGATIVE_INFINITY, msg.defaultDoubleNegInf);
+ assertEquals(Double.NaN, msg.defaultDoubleNan);
+
+ // 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();
+ }
+ }
+
+ public void testNanoWithHasParseFrom() throws Exception {
+ TestAllTypesNanoHas msg = null;
+ // Test false on creation, after clear and upon empty parse.
+ for (int i = 0; i < 3; i++) {
+ if (i == 0) {
+ msg = new TestAllTypesNanoHas();
+ } else if (i == 1) {
+ msg.clear();
+ } else if (i == 2) {
+ msg = TestAllTypesNanoHas.parseFrom(new byte[0]);
+ }
+ assertFalse(msg.hasOptionalInt32);
+ assertFalse(msg.hasOptionalString);
+ assertFalse(msg.hasOptionalBytes);
+ assertFalse(msg.hasOptionalNestedEnum);
+ assertFalse(msg.hasDefaultInt32);
+ assertFalse(msg.hasDefaultString);
+ assertFalse(msg.hasDefaultBytes);
+ assertFalse(msg.hasDefaultFloatNan);
+ assertFalse(msg.hasDefaultNestedEnum);
+ assertFalse(msg.hasId);
+ assertFalse(msg.hasRequiredEnum);
+ msg.optionalInt32 = 123;
+ msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ msg.optionalNestedMessage.bb = 2;
+ msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+ }
+
+ 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);
+
+ // Has fields true upon parse.
+ TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+ assertEquals(123, newMsg.optionalInt32);
+ assertTrue(newMsg.hasOptionalInt32);
+ assertEquals(2, newMsg.optionalNestedMessage.bb);
+ assertTrue(newMsg.optionalNestedMessage.hasBb);
+ assertEquals(TestAllTypesNanoHas.BAZ, newMsg.optionalNestedEnum);
+ assertTrue(newMsg.hasOptionalNestedEnum);
+ }
+
+ public void testNanoWithHasSerialize() throws Exception {
+ TestAllTypesNanoHas msg = new TestAllTypesNanoHas();
+ msg.hasOptionalInt32 = true;
+ msg.hasOptionalString = true;
+ msg.hasOptionalBytes = true;
+ msg.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ msg.optionalNestedMessage.hasBb = true;
+ msg.hasOptionalNestedEnum = true;
+ msg.hasDefaultInt32 = true;
+ msg.hasDefaultString = true;
+ msg.hasDefaultBytes = true;
+ msg.hasDefaultFloatNan = true;
+ msg.hasDefaultNestedEnum = true;
+ msg.hasId = true;
+ msg.hasRequiredEnum = true;
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertEquals(result.length, msgSerializedSize);
+
+ // Now deserialize and find that all fields are set and equal to their defaults.
+ TestAllTypesNanoHas newMsg = TestAllTypesNanoHas.parseFrom(result);
+ assertTrue(newMsg.hasOptionalInt32);
+ assertTrue(newMsg.hasOptionalString);
+ assertTrue(newMsg.hasOptionalBytes);
+ assertTrue(newMsg.optionalNestedMessage.hasBb);
+ assertTrue(newMsg.hasOptionalNestedEnum);
+ assertTrue(newMsg.hasDefaultInt32);
+ assertTrue(newMsg.hasDefaultString);
+ assertTrue(newMsg.hasDefaultBytes);
+ assertTrue(newMsg.hasDefaultFloatNan);
+ assertTrue(newMsg.hasDefaultNestedEnum);
+ assertTrue(newMsg.hasId);
+ assertTrue(newMsg.hasRequiredEnum);
+ assertEquals(0, newMsg.optionalInt32);
+ assertEquals(0, newMsg.optionalString.length());
+ assertEquals(0, newMsg.optionalBytes.length);
+ assertEquals(0, newMsg.optionalNestedMessage.bb);
+ assertEquals(TestAllTypesNanoHas.FOO, newMsg.optionalNestedEnum);
+ assertEquals(41, newMsg.defaultInt32);
+ assertEquals("hello", newMsg.defaultString);
+ assertEquals("world", new String(newMsg.defaultBytes, "UTF-8"));
+ assertEquals(TestAllTypesNanoHas.BAR, newMsg.defaultNestedEnum);
+ assertEquals(Float.NaN, newMsg.defaultFloatNan);
+ assertEquals(0, newMsg.id);
+ assertEquals(TestAllTypesNanoHas.FOO, newMsg.requiredEnum);
+ }
+
+ public void testNanoWithAccessorsBasic() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+
+ // Makes sure required, repeated, and message fields are still public
+ msg.id = 3;
+ msg.repeatedBytes = new byte[2][3];
+ msg.optionalNestedMessage = null;
+
+ // Test accessors
+ assertEquals(0, msg.getOptionalInt32());
+ assertFalse(msg.hasOptionalInt32());
+ msg.setOptionalInt32(135);
+ assertEquals(135, msg.getOptionalInt32());
+ assertTrue(msg.hasOptionalInt32());
+ msg.clearOptionalInt32();
+ assertFalse(msg.hasOptionalInt32());
+ msg.setOptionalInt32(0); // default value
+ assertTrue(msg.hasOptionalInt32());
+
+ // Test NPE
+ try {
+ msg.setOptionalBytes(null);
+ fail();
+ } catch (NullPointerException expected) {}
+ try {
+ msg.setOptionalString(null);
+ fail();
+ } catch (NullPointerException expected) {}
+
+ // Test has bit on bytes field with defaults and clear() re-clones the default array
+ assertFalse(msg.hasDefaultBytes());
+ byte[] defaultBytes = msg.getDefaultBytes();
+ msg.setDefaultBytes(defaultBytes);
+ assertTrue(msg.hasDefaultBytes());
+ msg.clearDefaultBytes();
+ assertFalse(msg.hasDefaultBytes());
+ defaultBytes[0]++; // modify original array
+ assertFalse(Arrays.equals(defaultBytes, msg.getDefaultBytes()));
+
+ // Test has bits that require additional bit fields
+ assertFalse(msg.hasBitFieldCheck());
+ msg.setBitFieldCheck(0);
+ assertTrue(msg.hasBitFieldCheck());
+ assertFalse(msg.hasBeforeBitFieldCheck()); // checks bit field does not leak
+ assertFalse(msg.hasAfterBitFieldCheck());
+
+ // Test clear() clears has bits
+ msg.setOptionalString("hi");
+ msg.setDefaultString("there");
+ msg.clear();
+ assertFalse(msg.hasOptionalString());
+ assertFalse(msg.hasDefaultString());
+ assertFalse(msg.hasBitFieldCheck());
+
+ // Test set() and clear() returns itself (compiles = success)
+ msg.clear()
+ .setOptionalInt32(3)
+ .clearDefaultBytes()
+ .setOptionalString("4");
+ }
+
+ public void testNanoWithAccessorsParseFrom() throws Exception {
+ TestNanoAccessors msg = null;
+ // Test false on creation, after clear and upon empty parse.
+ for (int i = 0; i < 3; i++) {
+ if (i == 0) {
+ msg = new TestNanoAccessors();
+ } else if (i == 1) {
+ msg.clear();
+ } else if (i == 2) {
+ msg = TestNanoAccessors.parseFrom(new byte[0]);
+ }
+ assertFalse(msg.hasOptionalInt32());
+ assertFalse(msg.hasOptionalString());
+ assertFalse(msg.hasOptionalBytes());
+ assertFalse(msg.hasOptionalNestedEnum());
+ assertFalse(msg.hasDefaultInt32());
+ assertFalse(msg.hasDefaultString());
+ assertFalse(msg.hasDefaultBytes());
+ assertFalse(msg.hasDefaultFloatNan());
+ assertFalse(msg.hasDefaultNestedEnum());
+ msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+ msg.optionalNestedMessage.setBb(2);
+ msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+ msg.setDefaultInt32(msg.getDefaultInt32());
+ }
+
+ 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);
+
+ // Has fields true upon parse.
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+ assertEquals(2, newMsg.optionalNestedMessage.getBb());
+ assertTrue(newMsg.optionalNestedMessage.hasBb());
+ assertEquals(TestNanoAccessors.BAZ, newMsg.getOptionalNestedEnum());
+ assertTrue(newMsg.hasOptionalNestedEnum());
+
+ // Has field true on fields with explicit default values from wire.
+ assertTrue(newMsg.hasDefaultInt32());
+ assertEquals(41, newMsg.getDefaultInt32());
+ }
+
+ public void testNanoWithAccessorsPublicFieldTypes() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ assertNull(msg.optionalNestedMessage);
+ assertEquals(0, msg.id);
+ assertEquals(0, msg.repeatedNestedEnum.length);
+
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(MessageNano.toByteArray(msg));
+ assertNull(newMsg.optionalNestedMessage);
+ assertEquals(0, newMsg.id);
+ assertEquals(0, newMsg.repeatedNestedEnum.length);
+
+ TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+ nestedMessage.setBb(5);
+ newMsg.optionalNestedMessage = nestedMessage;
+ newMsg.id = -1;
+ newMsg.repeatedNestedEnum = new int[] { TestAllTypesNano.FOO };
+
+ TestNanoAccessors newMsg2 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg));
+ assertEquals(nestedMessage.getBb(), newMsg2.optionalNestedMessage.getBb());
+ assertEquals(-1, newMsg2.id);
+ assertEquals(TestAllTypesNano.FOO, newMsg2.repeatedNestedEnum[0]);
+
+ newMsg2.optionalNestedMessage = null;
+ newMsg2.id = 0;
+ newMsg2.repeatedNestedEnum = null;
+
+ TestNanoAccessors newMsg3 = TestNanoAccessors.parseFrom(MessageNano.toByteArray(newMsg2));
+ assertNull(newMsg3.optionalNestedMessage);
+ assertEquals(0, newMsg3.id);
+ assertEquals(0, newMsg3.repeatedNestedEnum.length);
+ }
+
+ public void testNanoWithAccessorsSerialize() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ msg.setOptionalInt32(msg.getOptionalInt32());
+ msg.setOptionalString(msg.getOptionalString());
+ msg.setOptionalBytes(msg.getOptionalBytes());
+ TestNanoAccessors.NestedMessage nestedMessage = new TestNanoAccessors.NestedMessage();
+ nestedMessage.setBb(nestedMessage.getBb());
+ msg.optionalNestedMessage = nestedMessage;
+ msg.setOptionalNestedEnum(msg.getOptionalNestedEnum());
+ msg.setDefaultInt32(msg.getDefaultInt32());
+ msg.setDefaultString(msg.getDefaultString());
+ msg.setDefaultBytes(msg.getDefaultBytes());
+ msg.setDefaultFloatNan(msg.getDefaultFloatNan());
+ msg.setDefaultNestedEnum(msg.getDefaultNestedEnum());
+
+ byte [] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertEquals(result.length, msgSerializedSize);
+
+ // Now deserialize and find that all fields are set and equal to their defaults.
+ TestNanoAccessors newMsg = TestNanoAccessors.parseFrom(result);
+ assertTrue(newMsg.hasOptionalInt32());
+ assertTrue(newMsg.hasOptionalString());
+ assertTrue(newMsg.hasOptionalBytes());
+ assertTrue(newMsg.optionalNestedMessage.hasBb());
+ assertTrue(newMsg.hasOptionalNestedEnum());
+ assertTrue(newMsg.hasDefaultInt32());
+ assertTrue(newMsg.hasDefaultString());
+ assertTrue(newMsg.hasDefaultBytes());
+ assertTrue(newMsg.hasDefaultFloatNan());
+ assertTrue(newMsg.hasDefaultNestedEnum());
+ assertEquals(0, newMsg.getOptionalInt32());
+ assertEquals(0, newMsg.getOptionalString().length());
+ assertEquals(0, newMsg.getOptionalBytes().length);
+ assertEquals(0, newMsg.optionalNestedMessage.getBb());
+ assertEquals(TestNanoAccessors.FOO, newMsg.getOptionalNestedEnum());
+ assertEquals(41, newMsg.getDefaultInt32());
+ assertEquals("hello", newMsg.getDefaultString());
+ assertEquals("world", new String(newMsg.getDefaultBytes(), "UTF-8"));
+ assertEquals(TestNanoAccessors.BAR, newMsg.getDefaultNestedEnum());
+ assertEquals(Float.NaN, newMsg.getDefaultFloatNan());
+ assertEquals(0, newMsg.id);
+ }
+
+ public void testNanoJavaEnumStyle() throws Exception {
+ EnumClassNanos.EnumClassNano msg = new EnumClassNanos.EnumClassNano();
+ assertEquals(EnumClassNanos.FileScopeEnum.ONE, msg.one);
+ assertEquals(EnumClassNanos.EnumClassNano.MessageScopeEnum.TWO, msg.two);
+
+ EnumClassNanoMultiple msg2 = new EnumClassNanoMultiple();
+ assertEquals(FileScopeEnumMultiple.THREE, msg2.three);
+ assertEquals(EnumClassNanoMultiple.MessageScopeEnumMultiple.FOUR, msg2.four);
+ }
+
+ /**
+ * Tests that fields with a default value of NaN are not serialized when
+ * set to NaN. This is a special case as NaN != NaN, so normal equality
+ * checks don't work.
+ */
+ public void testNanoNotANumberDefaults() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.defaultDoubleNan = 0;
+ msg.defaultFloatNan = 0;
+ byte[] result = MessageNano.toByteArray(msg);
+ int msgSerializedSize = msg.getSerializedSize();
+ assertTrue(result.length == msgSerializedSize);
+ assertTrue(msgSerializedSize > 3);
+
+ msg.defaultDoubleNan = Double.NaN;
+ msg.defaultFloatNan = Float.NaN;
+ result = MessageNano.toByteArray(msg);
+ msgSerializedSize = msg.getSerializedSize();
+ assertEquals(3, result.length);
+ assertEquals(3, msgSerializedSize);
+ }
+
+ /**
+ * 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());
+ }
+
+ // Test a smattering of various proto types for printing
+ public void testMessageNanoPrinter() {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.optionalInt32 = 14;
+ msg.optionalFloat = 42.3f;
+ msg.optionalString = "String \"with' both quotes";
+ msg.optionalBytes = new byte[] {'"', '\0', 1, 8};
+ msg.optionalGroup = new TestAllTypesNano.OptionalGroup();
+ msg.optionalGroup.a = 15;
+ msg.repeatedInt64 = new long[2];
+ msg.repeatedInt64[0] = 1L;
+ msg.repeatedInt64[1] = -1L;
+ msg.repeatedBytes = new byte[2][];
+ msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+ msg.repeatedGroup = new TestAllTypesNano.RepeatedGroup[2];
+ msg.repeatedGroup[0] = new TestAllTypesNano.RepeatedGroup();
+ msg.repeatedGroup[0].a = -27;
+ msg.repeatedGroup[1] = new TestAllTypesNano.RepeatedGroup();
+ msg.repeatedGroup[1].a = -72;
+ msg.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+ msg.optionalNestedMessage.bb = 7;
+ msg.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[2];
+ msg.repeatedNestedMessage[0] = new TestAllTypesNano.NestedMessage();
+ msg.repeatedNestedMessage[0].bb = 77;
+ msg.repeatedNestedMessage[1] = new TestAllTypesNano.NestedMessage();
+ msg.repeatedNestedMessage[1].bb = 88;
+ msg.optionalNestedEnum = TestAllTypesNano.BAZ;
+ msg.repeatedNestedEnum = new int[2];
+ msg.repeatedNestedEnum[0] = TestAllTypesNano.BAR;
+ msg.repeatedNestedEnum[1] = TestAllTypesNano.FOO;
+ msg.repeatedStringPiece = new String[] {null, "world"};
+
+ String protoPrint = msg.toString();
+ assertTrue(protoPrint.contains("optional_int32: 14"));
+ assertTrue(protoPrint.contains("optional_float: 42.3"));
+ assertTrue(protoPrint.contains("optional_double: 0.0"));
+ assertTrue(protoPrint.contains("optional_string: \"String \\u0022with\\u0027 both quotes\""));
+ assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+ assertTrue(protoPrint.contains("optional_group <\n a: 15\n>"));
+
+ assertTrue(protoPrint.contains("repeated_int64: 1\nrepeated_int64: -1"));
+ assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+ assertTrue(protoPrint.contains("repeated_group <\n a: -27\n>\n"
+ + "repeated_group <\n a: -72\n>"));
+ assertTrue(protoPrint.contains("optional_nested_message <\n bb: 7\n>"));
+ assertTrue(protoPrint.contains("repeated_nested_message <\n bb: 77\n>\n"
+ + "repeated_nested_message <\n bb: 88\n>"));
+ assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+ assertTrue(protoPrint.contains("repeated_nested_enum: 2\nrepeated_nested_enum: 1"));
+ assertTrue(protoPrint.contains("default_int32: 41"));
+ assertTrue(protoPrint.contains("default_string: \"hello\""));
+ assertFalse(protoPrint.contains("repeated_string_piece: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_string_piece: \"world\""));
+ }
+
+ public void testMessageNanoPrinterAccessors() throws Exception {
+ TestNanoAccessors msg = new TestNanoAccessors();
+ msg.setOptionalInt32(13);
+ msg.setOptionalString("foo");
+ msg.setOptionalBytes(new byte[] {'"', '\0', 1, 8});
+ msg.optionalNestedMessage = new TestNanoAccessors.NestedMessage();
+ msg.optionalNestedMessage.setBb(7);
+ msg.setOptionalNestedEnum(TestNanoAccessors.BAZ);
+ msg.repeatedInt32 = new int[] { 1, -1 };
+ msg.repeatedString = new String[] { "Hello", "world" };
+ msg.repeatedBytes = new byte[2][];
+ msg.repeatedBytes[1] = new byte[] {'h', 'e', 'l', 'l', 'o'};
+ msg.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[2];
+ msg.repeatedNestedMessage[0] = new TestNanoAccessors.NestedMessage();
+ msg.repeatedNestedMessage[0].setBb(5);
+ msg.repeatedNestedMessage[1] = new TestNanoAccessors.NestedMessage();
+ msg.repeatedNestedMessage[1].setBb(6);
+ msg.repeatedNestedEnum = new int[] { TestNanoAccessors.FOO, TestNanoAccessors.BAR };
+ msg.id = 33;
+
+ String protoPrint = msg.toString();
+ assertTrue(protoPrint.contains("optional_int32: 13"));
+ assertTrue(protoPrint.contains("optional_string: \"foo\""));
+ assertTrue(protoPrint.contains("optional_bytes: \"\\\"\\000\\001\\010\""));
+ assertTrue(protoPrint.contains("optional_nested_message <\n bb: 7\n>"));
+ assertTrue(protoPrint.contains("optional_nested_enum: 3"));
+ assertTrue(protoPrint.contains("repeated_int32: 1\nrepeated_int32: -1"));
+ assertTrue(protoPrint.contains("repeated_string: \"Hello\"\nrepeated_string: \"world\""));
+ assertFalse(protoPrint.contains("repeated_bytes: \"\"")); // null should be dropped
+ assertTrue(protoPrint.contains("repeated_bytes: \"hello\""));
+ assertTrue(protoPrint.contains("repeated_nested_message <\n bb: 5\n>\n"
+ + "repeated_nested_message <\n bb: 6\n>"));
+ assertTrue(protoPrint.contains("repeated_nested_enum: 1\nrepeated_nested_enum: 2"));
+ assertTrue(protoPrint.contains("id: 33"));
+ }
+
+ public void testExtensions() throws Exception {
+ Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+ message.field = 5;
+ int[] int32s = {1, 2};
+ int[] uint32s = {3, 4};
+ int[] sint32s = {-5, -6};
+ long[] int64s = {7, 8};
+ long[] uint64s = {9, 10};
+ long[] sint64s = {-11, -12};
+ int[] fixed32s = {13, 14};
+ int[] sfixed32s = {-15, -16};
+ long[] fixed64s = {17, 18};
+ long[] sfixed64s = {-19, -20};
+ boolean[] bools = {true, false};
+ float[] floats = {2.1f, 2.2f};
+ double[] doubles = {2.3, 2.4};
+ int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+ String[] strings = {"vijfentwintig", "twenty-six"};
+ byte[][] bytess = {{2, 7}, {2, 8}};
+ AnotherMessage another1 = new AnotherMessage();
+ another1.string = "er shi jiu";
+ another1.value = false;
+ AnotherMessage another2 = new AnotherMessage();
+ another2.string = "trente";
+ another2.value = true;
+ AnotherMessage[] messages = {another1, another2};
+ RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+ group1.a = 31;
+ RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+ group2.a = 32;
+ RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt32));
+ message.setExtension(RepeatedExtensions.repeatedInt32, int32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint32));
+ message.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint32));
+ message.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedInt64));
+ message.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedInt64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedUint64));
+ message.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedUint64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSint64));
+ message.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSint64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+ message.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+ message.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed32));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+ message.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFixed64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+ message.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedSfixed64));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedBool));
+ message.setExtension(RepeatedExtensions.repeatedBool, bools);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedBool));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedFloat));
+ message.setExtension(RepeatedExtensions.repeatedFloat, floats);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedFloat));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedDouble));
+ message.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedDouble));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedEnum));
+ message.setExtension(RepeatedExtensions.repeatedEnum, enums);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedEnum));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedString));
+ message.setExtension(RepeatedExtensions.repeatedString, strings);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedString));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedBytes));
+ message.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedBytes));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedMessage));
+ message.setExtension(RepeatedExtensions.repeatedMessage, messages);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedMessage));
+ assertFalse(message.hasExtension(RepeatedExtensions.repeatedGroup));
+ message.setExtension(RepeatedExtensions.repeatedGroup, groups);
+ assertTrue(message.hasExtension(RepeatedExtensions.repeatedGroup));
+
+ byte[] data = MessageNano.toByteArray(message);
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+
+ // Test reading back using SingularExtensions: the retrieved value should equal the last
+ // in each array.
+ assertEquals(int32s[1], (int) message.getExtension(SingularExtensions.someInt32));
+ assertEquals(uint32s[1], (int) message.getExtension(SingularExtensions.someUint32));
+ assertEquals(sint32s[1], (int) message.getExtension(SingularExtensions.someSint32));
+ assertEquals(int64s[1], (long) message.getExtension(SingularExtensions.someInt64));
+ assertEquals(uint64s[1], (long) message.getExtension(SingularExtensions.someUint64));
+ assertEquals(sint64s[1], (long) message.getExtension(SingularExtensions.someSint64));
+ assertEquals(fixed32s[1], (int) message.getExtension(SingularExtensions.someFixed32));
+ assertEquals(sfixed32s[1], (int) message.getExtension(SingularExtensions.someSfixed32));
+ assertEquals(fixed64s[1], (long) message.getExtension(SingularExtensions.someFixed64));
+ assertEquals(sfixed64s[1], (long) message.getExtension(SingularExtensions.someSfixed64));
+ assertEquals(bools[1], (boolean) message.getExtension(SingularExtensions.someBool));
+ assertEquals(floats[1], (float) message.getExtension(SingularExtensions.someFloat));
+ assertEquals(doubles[1], (double) message.getExtension(SingularExtensions.someDouble));
+ assertEquals(enums[1], (int) message.getExtension(SingularExtensions.someEnum));
+ assertEquals(strings[1], message.getExtension(SingularExtensions.someString));
+ assertTrue(Arrays.equals(bytess[1], message.getExtension(SingularExtensions.someBytes)));
+ AnotherMessage deserializedMessage = message.getExtension(SingularExtensions.someMessage);
+ assertEquals(another2.string, deserializedMessage.string);
+ assertEquals(another2.value, deserializedMessage.value);
+ assertEquals(group2.a, message.getExtension(SingularExtensions.someGroup).a);
+
+ // Test reading back using RepeatedExtensions: the arrays should be equal.
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+ assertTrue(Arrays.equals(strings, message.getExtension(RepeatedExtensions.repeatedString)));
+ byte[][] deserializedRepeatedBytes = message.getExtension(RepeatedExtensions.repeatedBytes);
+ assertEquals(2, deserializedRepeatedBytes.length);
+ assertTrue(Arrays.equals(bytess[0], deserializedRepeatedBytes[0]));
+ assertTrue(Arrays.equals(bytess[1], deserializedRepeatedBytes[1]));
+ AnotherMessage[] deserializedRepeatedMessage =
+ message.getExtension(RepeatedExtensions.repeatedMessage);
+ assertEquals(2, deserializedRepeatedMessage.length);
+ assertEquals(another1.string, deserializedRepeatedMessage[0].string);
+ assertEquals(another1.value, deserializedRepeatedMessage[0].value);
+ assertEquals(another2.string, deserializedRepeatedMessage[1].string);
+ assertEquals(another2.value, deserializedRepeatedMessage[1].value);
+ RepeatedExtensions.RepeatedGroup[] deserializedRepeatedGroup =
+ message.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(2, deserializedRepeatedGroup.length);
+ assertEquals(group1.a, deserializedRepeatedGroup[0].a);
+ assertEquals(group2.a, deserializedRepeatedGroup[1].a);
+
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+ // Test hasExtension using PackedExtensions.
+ assertTrue(message.hasExtension(PackedExtensions.packedInt32));
+ assertTrue(message.hasExtension(PackedExtensions.packedUint32));
+ assertTrue(message.hasExtension(PackedExtensions.packedSint32));
+ assertTrue(message.hasExtension(PackedExtensions.packedInt64));
+ assertTrue(message.hasExtension(PackedExtensions.packedUint64));
+ assertTrue(message.hasExtension(PackedExtensions.packedSint64));
+ assertTrue(message.hasExtension(PackedExtensions.packedFixed32));
+ assertTrue(message.hasExtension(PackedExtensions.packedSfixed32));
+ assertTrue(message.hasExtension(PackedExtensions.packedFixed64));
+ assertTrue(message.hasExtension(PackedExtensions.packedSfixed64));
+ assertTrue(message.hasExtension(PackedExtensions.packedBool));
+ assertTrue(message.hasExtension(PackedExtensions.packedFloat));
+ assertTrue(message.hasExtension(PackedExtensions.packedDouble));
+ assertTrue(message.hasExtension(PackedExtensions.packedEnum));
+
+ // Test reading back using PackedExtensions: the arrays should be equal, even the fields
+ // are non-packed.
+ assertTrue(Arrays.equals(int32s, message.getExtension(PackedExtensions.packedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(PackedExtensions.packedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(PackedExtensions.packedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(PackedExtensions.packedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(PackedExtensions.packedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(PackedExtensions.packedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(PackedExtensions.packedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(PackedExtensions.packedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(PackedExtensions.packedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(PackedExtensions.packedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(PackedExtensions.packedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(PackedExtensions.packedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(PackedExtensions.packedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(PackedExtensions.packedEnum)));
+
+ // Now set the packable extension values using PackedExtensions so they're serialized packed.
+ message.setExtension(PackedExtensions.packedInt32, int32s);
+ message.setExtension(PackedExtensions.packedUint32, uint32s);
+ message.setExtension(PackedExtensions.packedSint32, sint32s);
+ message.setExtension(PackedExtensions.packedInt64, int64s);
+ message.setExtension(PackedExtensions.packedUint64, uint64s);
+ message.setExtension(PackedExtensions.packedSint64, sint64s);
+ message.setExtension(PackedExtensions.packedFixed32, fixed32s);
+ message.setExtension(PackedExtensions.packedSfixed32, sfixed32s);
+ message.setExtension(PackedExtensions.packedFixed64, fixed64s);
+ message.setExtension(PackedExtensions.packedSfixed64, sfixed64s);
+ message.setExtension(PackedExtensions.packedBool, bools);
+ message.setExtension(PackedExtensions.packedFloat, floats);
+ message.setExtension(PackedExtensions.packedDouble, doubles);
+ message.setExtension(PackedExtensions.packedEnum, enums);
+
+ // And read back using non-packed RepeatedExtensions.
+ byte[] data2 = MessageNano.toByteArray(message);
+ message = MessageNano.mergeFrom(new Extensions.ExtendableMessage(), data2);
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+ }
+
+ public void testNullExtensions() throws Exception {
+ // Check that clearing the extension on an empty message is a no-op.
+ Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ message.setExtension(SingularExtensions.someMessage, null);
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ assertEquals(0, MessageNano.toByteArray(message).length);
+
+ // Check that the message is empty after setting and clearing an extension.
+ AnotherMessage another = new AnotherMessage();
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ message.setExtension(SingularExtensions.someMessage, another);
+ assertTrue(message.hasExtension(SingularExtensions.someMessage));
+ assertTrue(MessageNano.toByteArray(message).length > 0);
+ message.setExtension(SingularExtensions.someMessage, null);
+ assertFalse(message.hasExtension(SingularExtensions.someMessage));
+ assertEquals(0, MessageNano.toByteArray(message).length);
+ }
+
+ public void testExtensionsMutation() {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.setExtension(SingularExtensions.someMessage,
+ new Extensions.AnotherMessage());
+
+ extendableMessage.getExtension(SingularExtensions.someMessage).string = "not empty";
+
+ assertEquals("not empty",
+ extendableMessage.getExtension(SingularExtensions.someMessage).string);
+ }
+
+ public void testExtensionsMutation_Equals() throws InvalidProtocolBufferNanoException {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.field = 5;
+ int int32 = 42;
+ int[] uint32s = {3, 4};
+ int[] sint32s = {-5, -6};
+ long[] int64s = {7, 8};
+ long[] uint64s = {9, 10};
+ long[] sint64s = {-11, -12};
+ int[] fixed32s = {13, 14};
+ int[] sfixed32s = {-15, -16};
+ long[] fixed64s = {17, 18};
+ long[] sfixed64s = {-19, -20};
+ boolean[] bools = {true, false};
+ float[] floats = {2.1f, 2.2f};
+ double[] doubles = {2.3, 2.4};
+ int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+ String[] strings = {"vijfentwintig", "twenty-six"};
+ byte[][] bytess = {{2, 7}, {2, 8}};
+ AnotherMessage another1 = new AnotherMessage();
+ another1.string = "er shi jiu";
+ another1.value = false;
+ AnotherMessage another2 = new AnotherMessage();
+ another2.string = "trente";
+ another2.value = true;
+ AnotherMessage[] messages = {another1, another2};
+ RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+ group1.a = 31;
+ RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+ group2.a = 32;
+ RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+ extendableMessage.setExtension(SingularExtensions.someInt32, int32);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedBool, bools);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedFloat, floats);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedEnum, enums);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedString, strings);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedMessage, messages);
+ extendableMessage.setExtension(RepeatedExtensions.repeatedGroup, groups);
+
+ byte[] data = MessageNano.toByteArray(extendableMessage);
+
+ extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+ Extensions.ExtendableMessage messageCopy = Extensions.ExtendableMessage.parseFrom(data);
+
+ // Without deserialising.
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Only one deserialized.
+ extendableMessage.getExtension(SingularExtensions.someInt32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedUint32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSint32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedInt64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedUint64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSint64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFixed32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed32);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFixed64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedSfixed64);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedBool);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedFloat);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedDouble);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedEnum);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedString);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedBytes);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedMessage);
+ extendableMessage.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Both deserialized.
+ messageCopy.getExtension(SingularExtensions.someInt32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedUint32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSint32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedInt64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedUint64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSint64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFixed32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSfixed32);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFixed64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedSfixed64);
+ messageCopy.getExtension(RepeatedExtensions.repeatedBool);
+ messageCopy.getExtension(RepeatedExtensions.repeatedFloat);
+ messageCopy.getExtension(RepeatedExtensions.repeatedDouble);
+ messageCopy.getExtension(RepeatedExtensions.repeatedEnum);
+ messageCopy.getExtension(RepeatedExtensions.repeatedString);
+ messageCopy.getExtension(RepeatedExtensions.repeatedBytes);
+ messageCopy.getExtension(RepeatedExtensions.repeatedMessage);
+ messageCopy.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(extendableMessage, messageCopy);
+ assertEquals(extendableMessage.hashCode(), messageCopy.hashCode());
+
+ // Change one, make sure they are still different.
+ messageCopy.getExtension(RepeatedExtensions.repeatedMessage)[0].string = "not empty";
+ assertFalse(extendableMessage.equals(messageCopy));
+
+ // Even if the extension hasn't been deserialized.
+ extendableMessage = Extensions.ExtendableMessage.parseFrom(data);
+ assertFalse(extendableMessage.equals(messageCopy));
+ }
+
+ public void testExtensionsCaching() {
+ Extensions.ExtendableMessage extendableMessage = new Extensions.ExtendableMessage();
+ extendableMessage.setExtension(SingularExtensions.someMessage,
+ new Extensions.AnotherMessage());
+ assertSame("Consecutive calls to getExtensions should return the same object",
+ extendableMessage.getExtension(SingularExtensions.someMessage),
+ extendableMessage.getExtension(SingularExtensions.someMessage));
+ }
+
+ public void testUnknownFields() throws Exception {
+ // Check that we roundtrip (serialize and deserialize) unrecognized fields.
+ AnotherMessage message = new AnotherMessage();
+ message.string = "Hello World";
+ message.value = false;
+
+ byte[] bytes = MessageNano.toByteArray(message);
+ int extraFieldSize = CodedOutputByteBufferNano.computeStringSize(
+ 1001, "This is an unknown field");
+ byte[] newBytes = new byte[bytes.length + extraFieldSize];
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
+ CodedOutputByteBufferNano.newInstance(newBytes, bytes.length, extraFieldSize)
+ .writeString(1001, "This is an unknown field");
+
+ // Deserialize with an unknown field.
+ AnotherMessage deserialized = AnotherMessage.parseFrom(newBytes);
+ byte[] serialized = MessageNano.toByteArray(deserialized);
+
+ assertEquals(newBytes.length, serialized.length);
+
+ // Clear, and make sure it clears everything.
+ deserialized.clear();
+ assertEquals(0, MessageNano.toByteArray(deserialized).length);
+ }
+
+ public void testMergeFrom() throws Exception {
+ SimpleMessageNano message = new SimpleMessageNano();
+ message.d = 123;
+ byte[] bytes = MessageNano.toByteArray(message);
+
+ SimpleMessageNano newMessage = MessageNano.mergeFrom(new SimpleMessageNano(), bytes);
+ assertEquals(message.d, newMessage.d);
+ }
+
+ public void testJavaKeyword() throws Exception {
+ TestAllTypesNano msg = new TestAllTypesNano();
+ msg.synchronized_ = 123;
+ assertEquals(123, msg.synchronized_);
+ }
+
+ public void testReferenceTypesForPrimitives() throws Exception {
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+
+ // Base check - when nothing is set, we serialize nothing.
+ assertHasWireData(message, false);
+
+ message.defaultBool = true;
+ assertHasWireData(message, true);
+
+ message.defaultBool = false;
+ assertHasWireData(message, true);
+
+ message.defaultBool = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt32 = 5;
+ assertHasWireData(message, true);
+
+ message.defaultInt32 = null;
+ assertHasWireData(message, false);
+
+ message.defaultInt64 = 123456L;
+ assertHasWireData(message, true);
+
+ message.defaultInt64 = null;
+ assertHasWireData(message, false);
+
+ message.defaultFloat = 1f;
+ assertHasWireData(message, true);
+
+ message.defaultFloat = null;
+ assertHasWireData(message, false);
+
+ message.defaultDouble = 2.1;
+ assertHasWireData(message, true);
+
+ message.defaultDouble = null;
+ assertHasWireData(message, false);
+
+ message.defaultString = "hello";
+ assertHasWireData(message, true);
+
+ message.defaultString = null;
+ assertHasWireData(message, false);
+
+ message.defaultBytes = new byte[] { 1, 2, 3 };
+ assertHasWireData(message, true);
+
+ message.defaultBytes = null;
+ assertHasWireData(message, false);
+ }
+
+ public void testHashCodeEquals() throws Exception {
+ // Complete equality:
+ TestAllTypesNano a = createMessageForHashCodeEqualsTest();
+ TestAllTypesNano aEquivalent = createMessageForHashCodeEqualsTest();
+
+ assertTrue(MessageNano.messageNanoEquals(a, aEquivalent));
+ assertFalse(MessageNano.messageNanoEquals(a, new TestAllTypesNano()));
+
+ // Null and empty array for repeated fields equality:
+ TestAllTypesNano b = createMessageForHashCodeEqualsTest();
+ b.repeatedBool = null;
+ b.repeatedFloat = new float[0];
+ TestAllTypesNano bEquivalent = createMessageForHashCodeEqualsTest();
+ bEquivalent.repeatedBool = new boolean[0];
+ bEquivalent.repeatedFloat = null;
+
+ // Ref-element-type repeated fields use non-null subsequence equality:
+ TestAllTypesNano c = createMessageForHashCodeEqualsTest();
+ c.repeatedString = null;
+ c.repeatedStringPiece = new String[] {null, "one", null, "two"};
+ c.repeatedBytes = new byte[][] {{3, 4}, null};
+ TestAllTypesNano cEquivalent = createMessageForHashCodeEqualsTest();
+ cEquivalent.repeatedString = new String[3];
+ cEquivalent.repeatedStringPiece = new String[] {"one", "two", null};
+ cEquivalent.repeatedBytes = new byte[][] {{3, 4}};
+
+ // Complete equality for messages with has fields:
+ TestAllTypesNanoHas d = createMessageWithHasForHashCodeEqualsTest();
+ TestAllTypesNanoHas dEquivalent = createMessageWithHasForHashCodeEqualsTest();
+
+ // If has-fields exist, fields with the same default values but
+ // different has-field values are different.
+ TestAllTypesNanoHas e = createMessageWithHasForHashCodeEqualsTest();
+ e.optionalInt32++; // make different from d
+ e.hasDefaultString = false;
+ TestAllTypesNanoHas eDifferent = createMessageWithHasForHashCodeEqualsTest();
+ eDifferent.optionalInt32 = e.optionalInt32;
+ eDifferent.hasDefaultString = true;
+
+ // Complete equality for messages with accessors:
+ TestNanoAccessors f = createMessageWithAccessorsForHashCodeEqualsTest();
+ TestNanoAccessors fEquivalent = createMessageWithAccessorsForHashCodeEqualsTest();
+
+ // If using accessors, explicitly setting a field to its default value
+ // should make the message different.
+ TestNanoAccessors g = createMessageWithAccessorsForHashCodeEqualsTest();
+ g.setOptionalInt32(g.getOptionalInt32() + 1); // make different from f
+ g.clearDefaultString();
+ TestNanoAccessors gDifferent = createMessageWithAccessorsForHashCodeEqualsTest();
+ gDifferent.setOptionalInt32(g.getOptionalInt32());
+ gDifferent.setDefaultString(g.getDefaultString());
+
+ // Complete equality for reference typed messages:
+ NanoReferenceTypes.TestAllTypesNano h = createRefTypedMessageForHashCodeEqualsTest();
+ NanoReferenceTypes.TestAllTypesNano hEquivalent = createRefTypedMessageForHashCodeEqualsTest();
+
+ // Inequality of null and default value for reference typed messages:
+ NanoReferenceTypes.TestAllTypesNano i = createRefTypedMessageForHashCodeEqualsTest();
+ i.optionalInt32 = 1; // make different from h
+ i.optionalFloat = null;
+ NanoReferenceTypes.TestAllTypesNano iDifferent = createRefTypedMessageForHashCodeEqualsTest();
+ iDifferent.optionalInt32 = i.optionalInt32;
+ iDifferent.optionalFloat = 0.0f;
+
+ HashMap<MessageNano, String> hashMap = new HashMap<MessageNano, String>();
+ hashMap.put(a, "a");
+ hashMap.put(b, "b");
+ hashMap.put(c, "c");
+ hashMap.put(d, "d");
+ hashMap.put(e, "e");
+ hashMap.put(f, "f");
+ hashMap.put(g, "g");
+ hashMap.put(h, "h");
+ hashMap.put(i, "i");
+
+ assertEquals(9, hashMap.size()); // a-i should be different from each other.
+
+ assertEquals("a", hashMap.get(a));
+ assertEquals("a", hashMap.get(aEquivalent));
+
+ assertEquals("b", hashMap.get(b));
+ assertEquals("b", hashMap.get(bEquivalent));
+
+ assertEquals("c", hashMap.get(c));
+ assertEquals("c", hashMap.get(cEquivalent));
+
+ assertEquals("d", hashMap.get(d));
+ assertEquals("d", hashMap.get(dEquivalent));
+
+ assertEquals("e", hashMap.get(e));
+ assertNull(hashMap.get(eDifferent));
+
+ assertEquals("f", hashMap.get(f));
+ assertEquals("f", hashMap.get(fEquivalent));
+
+ assertEquals("g", hashMap.get(g));
+ assertNull(hashMap.get(gDifferent));
+
+ assertEquals("h", hashMap.get(h));
+ assertEquals("h", hashMap.get(hEquivalent));
+
+ assertEquals("i", hashMap.get(i));
+ assertNull(hashMap.get(iDifferent));
+ }
+
+ private TestAllTypesNano createMessageForHashCodeEqualsTest() {
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.optionalInt32 = 5;
+ message.optionalInt64 = 777;
+ message.optionalFloat = 1.0f;
+ message.optionalDouble = 2.0;
+ message.optionalBool = true;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
+ message.optionalNestedMessage.bb = 27;
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
+ message.repeatedBool = new boolean[] { true, false, true };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ private TestAllTypesNanoHas createMessageWithHasForHashCodeEqualsTest() {
+ TestAllTypesNanoHas message = new TestAllTypesNanoHas();
+ message.optionalInt32 = 5;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
+ message.optionalNestedMessage.bb = 27;
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestAllTypesNanoHas.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ private TestNanoAccessors createMessageWithAccessorsForHashCodeEqualsTest() {
+ TestNanoAccessors message = new TestNanoAccessors()
+ .setOptionalInt32(5)
+ .setOptionalString("Hello")
+ .setOptionalBytes(new byte[] {1, 2, 3})
+ .setOptionalNestedEnum(TestNanoAccessors.BAR);
+ message.optionalNestedMessage = new TestNanoAccessors.NestedMessage().setBb(27);
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.BAR,
+ TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ private NanoReferenceTypes.TestAllTypesNano createRefTypedMessageForHashCodeEqualsTest() {
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
+ message.optionalInt32 = 5;
+ message.optionalInt64 = 777L;
+ message.optionalFloat = 1.0f;
+ message.optionalDouble = 2.0;
+ message.optionalBool = true;
+ message.optionalString = "Hello";
+ message.optionalBytes = new byte[] { 1, 2, 3 };
+ message.optionalNestedMessage =
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage();
+ message.optionalNestedMessage.foo = 27;
+ message.optionalNestedEnum = NanoReferenceTypes.TestAllTypesNano.BAR;
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
+ message.repeatedBool = new boolean[] { true, false, true };
+ message.repeatedString = new String[] { "One", "Two" };
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
+ message.repeatedNestedMessage =
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage[] {
+ message.optionalNestedMessage,
+ message.optionalNestedMessage
+ };
+ message.repeatedNestedEnum = new int[] {
+ NanoReferenceTypes.TestAllTypesNano.BAR,
+ NanoReferenceTypes.TestAllTypesNano.BAZ
+ };
+ return message;
+ }
+
+ public void testEqualsWithSpecialFloatingPointValues() throws Exception {
+ // Checks that the nano implementation complies with Object.equals() when treating
+ // floating point numbers, i.e. NaN == NaN and +0.0 != -0.0.
+ // This test assumes that the generated equals() implementations are symmetric, so
+ // there will only be one direction for each equality check.
+
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ m1.optionalFloat = Float.NaN;
+ m1.optionalDouble = Double.NaN;
+ TestAllTypesNano m2 = new TestAllTypesNano();
+ m2.optionalFloat = Float.NaN;
+ m2.optionalDouble = Double.NaN;
+ assertTrue(m1.equals(m2));
+ assertTrue(m1.equals(
+ MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+ m1.optionalFloat = +0f;
+ m2.optionalFloat = -0f;
+ assertFalse(m1.equals(m2));
+
+ m1.optionalFloat = -0f;
+ m1.optionalDouble = +0d;
+ m2.optionalDouble = -0d;
+ assertFalse(m1.equals(m2));
+
+ m1.optionalDouble = -0d;
+ assertTrue(m1.equals(m2));
+ assertFalse(m1.equals(new TestAllTypesNano())); // -0 does not equals() the default +0
+ assertTrue(m1.equals(
+ MessageNano.mergeFrom(new TestAllTypesNano(), MessageNano.toByteArray(m1))));
+
+ // -------
+
+ TestAllTypesNanoHas m3 = new TestAllTypesNanoHas();
+ m3.optionalFloat = Float.NaN;
+ m3.hasOptionalFloat = true;
+ m3.optionalDouble = Double.NaN;
+ m3.hasOptionalDouble = true;
+ TestAllTypesNanoHas m4 = new TestAllTypesNanoHas();
+ m4.optionalFloat = Float.NaN;
+ m4.hasOptionalFloat = true;
+ m4.optionalDouble = Double.NaN;
+ m4.hasOptionalDouble = true;
+ assertTrue(m3.equals(m4));
+ assertTrue(m3.equals(
+ MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+
+ m3.optionalFloat = +0f;
+ m4.optionalFloat = -0f;
+ assertFalse(m3.equals(m4));
+
+ m3.optionalFloat = -0f;
+ m3.optionalDouble = +0d;
+ m4.optionalDouble = -0d;
+ assertFalse(m3.equals(m4));
+
+ m3.optionalDouble = -0d;
+ m3.hasOptionalFloat = false; // -0 does not equals() the default +0,
+ m3.hasOptionalDouble = false; // so these incorrect 'has' flags should be disregarded.
+ assertTrue(m3.equals(m4)); // note: m4 has the 'has' flags set.
+ assertFalse(m3.equals(new TestAllTypesNanoHas())); // note: the new message has +0 defaults
+ assertTrue(m3.equals(
+ MessageNano.mergeFrom(new TestAllTypesNanoHas(), MessageNano.toByteArray(m3))));
+ // note: the deserialized message has the 'has' flags set.
+
+ // -------
+
+ TestNanoAccessors m5 = new TestNanoAccessors();
+ m5.setOptionalFloat(Float.NaN);
+ m5.setOptionalDouble(Double.NaN);
+ TestNanoAccessors m6 = new TestNanoAccessors();
+ m6.setOptionalFloat(Float.NaN);
+ m6.setOptionalDouble(Double.NaN);
+ assertTrue(m5.equals(m6));
+ assertTrue(m5.equals(
+ MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+ m5.setOptionalFloat(+0f);
+ m6.setOptionalFloat(-0f);
+ assertFalse(m5.equals(m6));
+
+ m5.setOptionalFloat(-0f);
+ m5.setOptionalDouble(+0d);
+ m6.setOptionalDouble(-0d);
+ assertFalse(m5.equals(m6));
+
+ m5.setOptionalDouble(-0d);
+ assertTrue(m5.equals(m6));
+ assertFalse(m5.equals(new TestNanoAccessors()));
+ assertTrue(m5.equals(
+ MessageNano.mergeFrom(new TestNanoAccessors(), MessageNano.toByteArray(m6))));
+
+ // -------
+
+ NanoReferenceTypes.TestAllTypesNano m7 = new NanoReferenceTypes.TestAllTypesNano();
+ m7.optionalFloat = Float.NaN;
+ m7.optionalDouble = Double.NaN;
+ NanoReferenceTypes.TestAllTypesNano m8 = new NanoReferenceTypes.TestAllTypesNano();
+ m8.optionalFloat = Float.NaN;
+ m8.optionalDouble = Double.NaN;
+ assertTrue(m7.equals(m8));
+ assertTrue(m7.equals(MessageNano.mergeFrom(
+ new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+
+ m7.optionalFloat = +0f;
+ m8.optionalFloat = -0f;
+ assertFalse(m7.equals(m8));
+
+ m7.optionalFloat = -0f;
+ m7.optionalDouble = +0d;
+ m8.optionalDouble = -0d;
+ assertFalse(m7.equals(m8));
+
+ m7.optionalDouble = -0d;
+ assertTrue(m7.equals(m8));
+ assertFalse(m7.equals(new NanoReferenceTypes.TestAllTypesNano()));
+ assertTrue(m7.equals(MessageNano.mergeFrom(
+ new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
+ }
+
+ public void testNullRepeatedFields() throws Exception {
+ // Check that serialization after explicitly setting a repeated field
+ // to null doesn't NPE.
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.repeatedInt32 = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedNestedEnum = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedBytes = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedNestedMessage = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedPackedInt32 = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ message.repeatedPackedNestedEnum = null;
+ MessageNano.toByteArray(message); // should not NPE
+ message.toString(); // should not NPE
+
+ // Create a second message to merge into message.
+ TestAllTypesNano secondMessage = new TestAllTypesNano();
+ secondMessage.repeatedInt32 = new int[] {1, 2, 3};
+ secondMessage.repeatedNestedEnum = new int[] {
+ TestAllTypesNano.FOO, TestAllTypesNano.BAR
+ };
+ secondMessage.repeatedBytes = new byte[][] {{1, 2}, {3, 4}};
+ TestAllTypesNano.NestedMessage nested =
+ new TestAllTypesNano.NestedMessage();
+ nested.bb = 55;
+ secondMessage.repeatedNestedMessage =
+ new TestAllTypesNano.NestedMessage[] {nested};
+ secondMessage.repeatedPackedInt32 = new int[] {1, 2, 3};
+ secondMessage.repeatedPackedNestedEnum = new int[] {
+ TestAllTypesNano.FOO, TestAllTypesNano.BAR
+ };
+
+ // Should not NPE
+ message.mergeFrom(CodedInputByteBufferNano.newInstance(
+ MessageNano.toByteArray(secondMessage)));
+ assertEquals(3, message.repeatedInt32.length);
+ assertEquals(3, message.repeatedInt32[2]);
+ assertEquals(2, message.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.FOO, message.repeatedNestedEnum[0]);
+ assertEquals(2, message.repeatedBytes.length);
+ assertEquals(4, message.repeatedBytes[1][1]);
+ assertEquals(1, message.repeatedNestedMessage.length);
+ assertEquals(55, message.repeatedNestedMessage[0].bb);
+ assertEquals(3, message.repeatedPackedInt32.length);
+ assertEquals(2, message.repeatedPackedInt32[1]);
+ assertEquals(2, message.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, message.repeatedPackedNestedEnum[1]);
+ }
+
+ public void testNullRepeatedFieldElements() throws Exception {
+ // Check that serialization with null array elements doesn't NPE.
+ String string1 = "1";
+ String string2 = "2";
+ byte[] bytes1 = {3, 4};
+ byte[] bytes2 = {5, 6};
+ TestAllTypesNano.NestedMessage msg1 = new TestAllTypesNano.NestedMessage();
+ msg1.bb = 7;
+ TestAllTypesNano.NestedMessage msg2 = new TestAllTypesNano.NestedMessage();
+ msg2.bb = 8;
+
+ TestAllTypesNano message = new TestAllTypesNano();
+ message.repeatedString = new String[] {null, string1, string2};
+ message.repeatedBytes = new byte[][] {bytes1, null, bytes2};
+ message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {msg1, msg2, null};
+ message.repeatedGroup = new TestAllTypesNano.RepeatedGroup[] {null, null, null};
+
+ byte[] serialized = MessageNano.toByteArray(message); // should not NPE
+ TestAllTypesNano deserialized = MessageNano.mergeFrom(new TestAllTypesNano(), serialized);
+ assertEquals(2, deserialized.repeatedString.length);
+ assertEquals(string1, deserialized.repeatedString[0]);
+ assertEquals(string2, deserialized.repeatedString[1]);
+ assertEquals(2, deserialized.repeatedBytes.length);
+ assertTrue(Arrays.equals(bytes1, deserialized.repeatedBytes[0]));
+ assertTrue(Arrays.equals(bytes2, deserialized.repeatedBytes[1]));
+ assertEquals(2, deserialized.repeatedNestedMessage.length);
+ assertEquals(msg1.bb, deserialized.repeatedNestedMessage[0].bb);
+ assertEquals(msg2.bb, deserialized.repeatedNestedMessage[1].bb);
+ assertEquals(0, deserialized.repeatedGroup.length);
+ }
+
+ public void testRepeatedMerge() throws Exception {
+ // Check that merging repeated fields cause the arrays to expand with
+ // new data.
+ TestAllTypesNano first = new TestAllTypesNano();
+ first.repeatedInt32 = new int[] {1, 2, 3};
+ TestAllTypesNano second = new TestAllTypesNano();
+ second.repeatedInt32 = new int[] {4, 5};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(5, first.repeatedInt32.length);
+ assertEquals(1, first.repeatedInt32[0]);
+ assertEquals(4, first.repeatedInt32[3]);
+
+ first = new TestAllTypesNano();
+ first.repeatedNestedEnum = new int[] {TestAllTypesNano.BAR};
+ second = new TestAllTypesNano();
+ second.repeatedNestedEnum = new int[] {TestAllTypesNano.FOO};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, first.repeatedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.FOO, first.repeatedNestedEnum[1]);
+
+ first = new TestAllTypesNano();
+ first.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ new TestAllTypesNano.NestedMessage()
+ };
+ first.repeatedNestedMessage[0].bb = 3;
+ second = new TestAllTypesNano();
+ second.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
+ new TestAllTypesNano.NestedMessage()
+ };
+ second.repeatedNestedMessage[0].bb = 5;
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedNestedMessage.length);
+ assertEquals(3, first.repeatedNestedMessage[0].bb);
+ assertEquals(5, first.repeatedNestedMessage[1].bb);
+
+ first = new TestAllTypesNano();
+ first.repeatedPackedSfixed64 = new long[] {-1, -2, -3};
+ second = new TestAllTypesNano();
+ second.repeatedPackedSfixed64 = new long[] {-4, -5};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(5, first.repeatedPackedSfixed64.length);
+ assertEquals(-1, first.repeatedPackedSfixed64[0]);
+ assertEquals(-4, first.repeatedPackedSfixed64[3]);
+
+ first = new TestAllTypesNano();
+ first.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.BAR};
+ second = new TestAllTypesNano();
+ second.repeatedPackedNestedEnum = new int[] {TestAllTypesNano.FOO};
+ MessageNano.mergeFrom(first, MessageNano.toByteArray(second));
+ assertEquals(2, first.repeatedPackedNestedEnum.length);
+ assertEquals(TestAllTypesNano.BAR, first.repeatedPackedNestedEnum[0]);
+ assertEquals(TestAllTypesNano.FOO, first.repeatedPackedNestedEnum[1]);
+
+ // Now test repeated merging in a nested scope
+ TestRepeatedMergeNano firstContainer = new TestRepeatedMergeNano();
+ firstContainer.contained = new TestAllTypesNano();
+ firstContainer.contained.repeatedInt32 = new int[] {10, 20};
+ TestRepeatedMergeNano secondContainer = new TestRepeatedMergeNano();
+ secondContainer.contained = new TestAllTypesNano();
+ secondContainer.contained.repeatedInt32 = new int[] {30};
+ MessageNano.mergeFrom(firstContainer, MessageNano.toByteArray(secondContainer));
+ assertEquals(3, firstContainer.contained.repeatedInt32.length);
+ assertEquals(20, firstContainer.contained.repeatedInt32[1]);
+ assertEquals(30, firstContainer.contained.repeatedInt32[2]);
+ }
+
+ public void testRepeatedPackables() throws Exception {
+ // Check that repeated fields with packable types can accept both packed and unpacked
+ // serialized forms.
+ NanoRepeatedPackables.NonPacked nonPacked = new NanoRepeatedPackables.NonPacked();
+ // Exaggerates the first values of varint-typed arrays. This is to test that the parsing code
+ // of packed fields handles non-packed data correctly. If the code incorrectly thinks it is
+ // reading from a packed tag, it will read the first value as the byte length of the field,
+ // and the large number will cause the input to go out of bounds, thus capturing the error.
+ nonPacked.int32S = new int[] {1000, 2, 3};
+ nonPacked.int64S = new long[] {4000, 5, 6};
+ nonPacked.uint32S = new int[] {7000, 8, 9};
+ nonPacked.uint64S = new long[] {10000, 11, 12};
+ nonPacked.sint32S = new int[] {13000, 14, 15};
+ nonPacked.sint64S = new long[] {16000, 17, 18};
+ nonPacked.fixed32S = new int[] {19, 20, 21};
+ nonPacked.fixed64S = new long[] {22, 23, 24};
+ nonPacked.sfixed32S = new int[] {25, 26, 27};
+ nonPacked.sfixed64S = new long[] {28, 29, 30};
+ nonPacked.floats = new float[] {31, 32, 33};
+ nonPacked.doubles = new double[] {34, 35, 36};
+ nonPacked.bools = new boolean[] {false, true};
+ nonPacked.enums = new int[] {
+ NanoRepeatedPackables.Enum.OPTION_ONE,
+ NanoRepeatedPackables.Enum.OPTION_TWO,
+ };
+ nonPacked.noise = 13579;
+
+ byte[] nonPackedSerialized = MessageNano.toByteArray(nonPacked);
+
+ NanoRepeatedPackables.Packed packed =
+ MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), nonPackedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+
+ byte[] packedSerialized = MessageNano.toByteArray(packed);
+ // Just a cautious check that the two serialized forms are different,
+ // to make sure the remaining of this test is useful:
+ assertFalse(Arrays.equals(nonPackedSerialized, packedSerialized));
+
+ nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), packedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+
+ // Test mixed serialized form.
+ byte[] mixedSerialized = new byte[nonPackedSerialized.length + packedSerialized.length];
+ System.arraycopy(nonPackedSerialized, 0, mixedSerialized, 0, nonPackedSerialized.length);
+ System.arraycopy(packedSerialized, 0,
+ mixedSerialized, nonPackedSerialized.length, packedSerialized.length);
+
+ nonPacked = MessageNano.mergeFrom(new NanoRepeatedPackables.NonPacked(), mixedSerialized);
+ packed = MessageNano.mergeFrom(new NanoRepeatedPackables.Packed(), mixedSerialized);
+ assertRepeatedPackablesEqual(nonPacked, packed);
+ assertTrue(Arrays.equals(new int[] {1000, 2, 3, 1000, 2, 3}, nonPacked.int32S));
+ assertTrue(Arrays.equals(new int[] {13000, 14, 15, 13000, 14, 15}, nonPacked.sint32S));
+ assertTrue(Arrays.equals(new int[] {25, 26, 27, 25, 26, 27}, nonPacked.sfixed32S));
+ assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
+ }
+
+ private void assertRepeatedPackablesEqual(
+ NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
+ // Not using MessageNano.equals() -- that belongs to a separate test.
+ assertTrue(Arrays.equals(nonPacked.int32S, packed.int32S));
+ assertTrue(Arrays.equals(nonPacked.int64S, packed.int64S));
+ assertTrue(Arrays.equals(nonPacked.uint32S, packed.uint32S));
+ assertTrue(Arrays.equals(nonPacked.uint64S, packed.uint64S));
+ assertTrue(Arrays.equals(nonPacked.sint32S, packed.sint32S));
+ assertTrue(Arrays.equals(nonPacked.sint64S, packed.sint64S));
+ assertTrue(Arrays.equals(nonPacked.fixed32S, packed.fixed32S));
+ assertTrue(Arrays.equals(nonPacked.fixed64S, packed.fixed64S));
+ assertTrue(Arrays.equals(nonPacked.sfixed32S, packed.sfixed32S));
+ assertTrue(Arrays.equals(nonPacked.sfixed64S, packed.sfixed64S));
+ assertTrue(Arrays.equals(nonPacked.floats, packed.floats));
+ assertTrue(Arrays.equals(nonPacked.doubles, packed.doubles));
+ assertTrue(Arrays.equals(nonPacked.bools, packed.bools));
+ assertTrue(Arrays.equals(nonPacked.enums, packed.enums));
+ }
+
+ private void assertHasWireData(MessageNano message, boolean expected) {
+ byte[] bytes = MessageNano.toByteArray(message);
+ int wireLength = bytes.length;
+ if (expected) {
+ assertFalse(wireLength == 0);
+ } else {
+ if (wireLength != 0) {
+ fail("Expected no wire data for message \n" + message
+ + "\nBut got:\n"
+ + hexDump(bytes));
+ }
+ }
+ }
+
+ private static String hexDump(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x ", b));
+ }
+ return sb.toString();
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
new file mode 100644
index 00000000..f1d4d343
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_accessors_nano.proto
@@ -0,0 +1,118 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoAccessorsOuterClass";
+
+message TestNanoAccessors {
+
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // Singular
+ optional int32 optional_int32 = 1;
+ optional float optional_float = 11;
+ optional double optional_double = 12;
+ optional string optional_string = 14;
+ optional bytes optional_bytes = 15;
+
+ optional NestedMessage optional_nested_message = 18;
+
+ optional NestedEnum optional_nested_enum = 21;
+
+ // Repeated
+ repeated int32 repeated_int32 = 31;
+ repeated string repeated_string = 44;
+ repeated bytes repeated_bytes = 45;
+
+ repeated NestedMessage repeated_nested_message = 48;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+
+ // Singular with defaults
+ optional int32 default_int32 = 61 [default = 41 ];
+ optional string default_string = 74 [default = "hello"];
+ optional bytes default_bytes = 75 [default = "world"];
+
+ optional float default_float_nan = 99 [default = nan];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+ // Required
+ required int32 id = 86;
+
+ // Add enough optional fields to make 2 bit fields in total
+ optional int32 filler100 = 100;
+ optional int32 filler101 = 101;
+ optional int32 filler102 = 102;
+ optional int32 filler103 = 103;
+ optional int32 filler104 = 104;
+ optional int32 filler105 = 105;
+ optional int32 filler106 = 106;
+ optional int32 filler107 = 107;
+ optional int32 filler108 = 108;
+ optional int32 filler109 = 109;
+ optional int32 filler110 = 110;
+ optional int32 filler111 = 111;
+ optional int32 filler112 = 112;
+ optional int32 filler113 = 113;
+ optional int32 filler114 = 114;
+ optional int32 filler115 = 115;
+ optional int32 filler116 = 116;
+ optional int32 filler117 = 117;
+ optional int32 filler118 = 118;
+ optional int32 filler119 = 119;
+ optional int32 filler120 = 120;
+ optional int32 filler121 = 121;
+ optional int32 filler122 = 122;
+ optional int32 filler123 = 123;
+ optional int32 filler124 = 124;
+ optional int32 filler125 = 125;
+ optional int32 filler126 = 126;
+ optional int32 filler127 = 127;
+ optional int32 filler128 = 128;
+ optional int32 filler129 = 129;
+ optional int32 filler130 = 130;
+
+ optional int32 before_bit_field_check = 139;
+ optional int32 bit_field_check = 140;
+ optional int32 after_bit_field_check = 141;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
new file mode 100644
index 00000000..8adb7560
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_multiple_nano.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+enum FileScopeEnumMultiple {
+ THREE = 3;
+}
+
+message EnumClassNanoMultiple {
+ enum MessageScopeEnumMultiple {
+ FOUR = 4;
+ }
+ optional FileScopeEnumMultiple three = 3 [ default = THREE ];
+ optional MessageScopeEnumMultiple four = 4 [ default = FOUR ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
new file mode 100644
index 00000000..3727d68d
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "EnumClassNanos";
+
+enum FileScopeEnum {
+ ONE = 1;
+}
+
+message EnumClassNano {
+ enum MessageScopeEnum {
+ TWO = 2;
+ }
+ optional FileScopeEnum one = 1 [ default = ONE ];
+ optional MessageScopeEnum two = 2 [ default = TWO ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
new file mode 100644
index 00000000..f7f57427
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_enum_validity_nano.proto
@@ -0,0 +1,28 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "EnumValidity";
+
+enum E {
+ default = 1; // test java keyword renaming
+ FOO = 2;
+ BAR = 3;
+ BAZ = 4;
+}
+
+message M {
+ optional E optional_e = 1;
+ optional E default_e = 2 [ default = BAZ ];
+ repeated E repeated_e = 3;
+ repeated E packed_e = 4 [ packed = true ];
+ repeated E repeated_e2 = 5;
+ repeated E packed_e2 = 6 [ packed = true ];
+ repeated E repeated_e3 = 7;
+ repeated E packed_e3 = 8 [ packed = true ];
+}
+
+message Alt {
+ optional E repeated_e2_as_optional = 5;
+ repeated E packed_e2_as_non_packed = 6;
+ repeated E non_packed_e3_as_packed = 7 [ packed = true ];
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
new file mode 100644
index 00000000..2a678a80
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_nano.proto
@@ -0,0 +1,33 @@
+syntax = "proto2";
+
+option java_outer_classname = "Extensions";
+option java_package = "com.google.protobuf.nano.testext";
+
+message ExtendableMessage {
+ optional int32 field = 1;
+ extensions 10 to max;
+}
+
+enum AnEnum {
+ FIRST_VALUE = 1;
+ SECOND_VALUE = 2;
+}
+
+message AnotherMessage {
+ optional string string = 1;
+ optional bool value = 2;
+}
+
+message ContainerMessage {
+ extend ExtendableMessage {
+ optional bool another_thing = 100;
+ }
+}
+
+// For testNanoOptionalGroupWithUnknownFieldsEnabled;
+// not part of the extensions tests.
+message MessageWithGroup {
+ optional group Group = 1 {
+ optional int32 a = 2;
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
new file mode 100644
index 00000000..7d47682d
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_packed_nano.proto
@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message PackedExtensions {
+ extend ExtendableMessage {
+ repeated int32 packed_int32 = 10 [ packed = true ];
+ repeated uint32 packed_uint32 = 11 [ packed = true ];
+ repeated sint32 packed_sint32 = 12 [ packed = true ];
+ repeated int64 packed_int64 = 13 [ packed = true ];
+ repeated uint64 packed_uint64 = 14 [ packed = true ];
+ repeated sint64 packed_sint64 = 15 [ packed = true ];
+ repeated fixed32 packed_fixed32 = 16 [ packed = true ];
+ repeated sfixed32 packed_sfixed32 = 17 [ packed = true ];
+ repeated fixed64 packed_fixed64 = 18 [ packed = true ];
+ repeated sfixed64 packed_sfixed64 = 19 [ packed = true ];
+ repeated bool packed_bool = 20 [ packed = true ];
+ repeated float packed_float = 21 [ packed = true ];
+ repeated double packed_double = 22 [ packed = true ];
+ repeated AnEnum packed_enum = 23 [ packed = true ];
+ // Non-packable types omitted.
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
new file mode 100644
index 00000000..6d4b5dfb
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_repeated_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message RepeatedExtensions {
+ extend ExtendableMessage {
+ repeated int32 repeated_int32 = 10;
+ repeated uint32 repeated_uint32 = 11;
+ repeated sint32 repeated_sint32 = 12;
+ repeated int64 repeated_int64 = 13;
+ repeated uint64 repeated_uint64 = 14;
+ repeated sint64 repeated_sint64 = 15;
+ repeated fixed32 repeated_fixed32 = 16;
+ repeated sfixed32 repeated_sfixed32 = 17;
+ repeated fixed64 repeated_fixed64 = 18;
+ repeated sfixed64 repeated_sfixed64 = 19;
+ repeated bool repeated_bool = 20;
+ repeated float repeated_float = 21;
+ repeated double repeated_double = 22;
+ repeated AnEnum repeated_enum = 23;
+ repeated string repeated_string = 24;
+ repeated bytes repeated_bytes = 25;
+ repeated AnotherMessage repeated_message = 26;
+ repeated group RepeatedGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
new file mode 100644
index 00000000..589754e7
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_extension_singular_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/nano/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message SingularExtensions {
+ extend ExtendableMessage {
+ optional int32 some_int32 = 10;
+ optional uint32 some_uint32 = 11;
+ optional sint32 some_sint32 = 12;
+ optional int64 some_int64 = 13;
+ optional uint64 some_uint64 = 14;
+ optional sint64 some_sint64 = 15;
+ optional fixed32 some_fixed32 = 16;
+ optional sfixed32 some_sfixed32 = 17;
+ optional fixed64 some_fixed64 = 18;
+ optional sfixed64 some_sfixed64 = 19;
+ optional bool some_bool = 20;
+ optional float some_float = 21;
+ optional double some_double = 22;
+ optional AnEnum some_enum = 23;
+ optional string some_string = 24;
+ optional bytes some_bytes = 25;
+ optional AnotherMessage some_message = 26;
+ optional group SomeGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
new file mode 100644
index 00000000..289d08ae
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_has_nano.proto
@@ -0,0 +1,82 @@
+// 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: ulas@google.com (Ulas Kirazci)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoHasOuterClass";
+
+message TestAllTypesNanoHas {
+
+ message NestedMessage {
+ optional int32 bb = 1;
+ }
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ // Singular
+ optional int32 optional_int32 = 1;
+ optional float optional_float = 11;
+ optional double optional_double = 12;
+ optional string optional_string = 14;
+ optional bytes optional_bytes = 15;
+
+ optional NestedMessage optional_nested_message = 18;
+
+ optional NestedEnum optional_nested_enum = 21;
+
+ // Repeated
+ repeated int32 repeated_int32 = 31;
+ repeated string repeated_string = 44;
+ repeated bytes repeated_bytes = 45;
+
+ repeated NestedMessage repeated_nested_message = 48;
+
+ repeated NestedEnum repeated_nested_enum = 51;
+
+ // Singular with defaults
+ optional int32 default_int32 = 61 [default = 41 ];
+ optional string default_string = 74 [default = "hello"];
+ optional bytes default_bytes = 75 [default = "world"];
+
+ optional float default_float_nan = 99 [default = nan];
+
+ optional NestedEnum default_nested_enum = 81 [default = BAR];
+
+ required int32 id = 86;
+ required NestedEnum required_enum = 87;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
new file mode 100644
index 00000000..bcd4db7b
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_import_nano.proto
@@ -0,0 +1,48 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest_import.proto but with optimize_for = NANO_RUNTIME.
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano.testimport";
+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/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto
new file mode 100644
index 00000000..f2f62c4e
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "MultipleNameClashNano";
+option java_multiple_files = true;
+
+message MultipleNameClashNano {
+ optional int32 field = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto
new file mode 100644
index 00000000..be84cad1
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_multiple_nano.proto
@@ -0,0 +1,63 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+import "google/protobuf/nano/unittest_import_nano.proto";
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+enum FileScopeEnum {
+ ONE = 1;
+ TWO = 2;
+}
+
+message FileScopeEnumRefNano {
+ optional FileScopeEnum enum_field = 1;
+}
+
+message MessageScopeEnumRefNano {
+ enum MessageScopeEnum {
+ ONE = 1;
+ TWO = 2;
+ }
+ optional MessageScopeEnum enum_field = 1;
+}
+
+message MultipleImportingNonMultipleNano1 {
+ optional ImportMessageNano field = 1;
+}
+
+message MultipleImportingNonMultipleNano2 {
+ optional MultipleImportingNonMultipleNano1 nano1 = 1;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
new file mode 100644
index 00000000..cba52c02
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
@@ -0,0 +1,186 @@
+// 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/nano/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 float default_float_inf = 97 [default = inf];
+ optional float default_float_neg_inf = 98 [default = -inf];
+ optional float default_float_nan = 99 [default = nan];
+ optional double default_double_inf = 100 [default = inf];
+ optional double default_double_neg_inf = 101 [default = -inf];
+ optional double default_double_nan = 102 [default = nan];
+
+ 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;
+
+ // Try to cause conflicts.
+ optional int32 tag = 93;
+ optional int32 get_serialized_size = 94;
+ optional int32 write_to = 95;
+
+ // Try to fail with java reserved keywords
+ optional int32 synchronized = 96;
+}
+
+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/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_nano.proto
new file mode 100644
index 00000000..3d3a6aa4
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_recursive_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: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestRecursiveNano";
+
+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/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
new file mode 100644
index 00000000..2b246150
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_reference_types_nano.proto
@@ -0,0 +1,116 @@
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoReferenceTypes";
+
+message TestAllTypesNano {
+
+ enum NestedEnum {
+ FOO = 1;
+ BAR = 2;
+ BAZ = 3;
+ }
+
+ message NestedMessage {
+ optional int32 foo = 1;
+ }
+
+ // 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 NestedEnum optional_nested_enum = 21;
+
+ 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 NestedEnum repeated_nested_enum = 51;
+
+ 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 float default_float_inf = 97 [default = inf];
+ optional float default_float_neg_inf = 98 [default = -inf];
+ optional float default_float_nan = 99 [default = nan];
+ optional double default_double_inf = 100 [default = inf];
+ optional double default_double_neg_inf = 101 [default = -inf];
+ optional double default_double_nan = 102 [default = nan];
+
+}
+
+message ForeignMessageNano {
+ optional int32 c = 1;
+}
+
+enum ForeignEnumNano {
+ FOREIGN_NANO_FOO = 4;
+ FOREIGN_NANO_BAR = 5;
+ FOREIGN_NANO_BAZ = 6;
+}
+
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto
new file mode 100644
index 00000000..aea48ef7
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_merge_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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+import "google/protobuf/nano/unittest_nano.proto";
+
+option java_package = "com.google.protobuf.nano";
+option java_multiple_files = true;
+
+// A container message for testing the merging of repeated fields at a
+// nested level. Other tests will be done using the repeated fields in
+// TestAllTypesNano.
+message TestRepeatedMergeNano {
+
+ optional TestAllTypesNano contained = 1;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
new file mode 100644
index 00000000..1c78918f
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_repeated_packables_nano.proto
@@ -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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "NanoRepeatedPackables";
+
+enum Enum {
+ OPTION_ONE = 1;
+ OPTION_TWO = 2;
+}
+
+// Two almost identical messages with all packable repeated field types.
+// One with none marked as packed and the other all packed. For
+// compatibility, they should be able to parse each other's serialized
+// forms.
+
+message NonPacked {
+
+ // All packable types, none marked as packed.
+
+ repeated int32 int32s = 1;
+ repeated int64 int64s = 2;
+ repeated uint32 uint32s = 3;
+ repeated uint64 uint64s = 4;
+ repeated sint32 sint32s = 5;
+ repeated sint64 sint64s = 6;
+ repeated fixed32 fixed32s = 7;
+ repeated fixed64 fixed64s = 8;
+ repeated sfixed32 sfixed32s = 9;
+ repeated sfixed64 sfixed64s = 10;
+ repeated float floats = 11;
+ repeated double doubles = 12;
+ repeated bool bools = 13;
+ repeated Enum enums = 14;
+
+ // Noise for testing merged deserialization.
+ optional int32 noise = 15;
+
+}
+
+message Packed {
+
+ // All packable types, all matching the field numbers in NonPacked,
+ // all marked as packed.
+
+ repeated int32 int32s = 1 [ packed = true ];
+ repeated int64 int64s = 2 [ packed = true ];
+ repeated uint32 uint32s = 3 [ packed = true ];
+ repeated uint64 uint64s = 4 [ packed = true ];
+ repeated sint32 sint32s = 5 [ packed = true ];
+ repeated sint64 sint64s = 6 [ packed = true ];
+ repeated fixed32 fixed32s = 7 [ packed = true ];
+ repeated fixed64 fixed64s = 8 [ packed = true ];
+ repeated sfixed32 sfixed32s = 9 [ packed = true ];
+ repeated sfixed64 sfixed64s = 10 [ packed = true ];
+ repeated float floats = 11 [ packed = true ];
+ repeated double doubles = 12 [ packed = true ];
+ repeated bool bools = 13 [ packed = true ];
+ repeated Enum enums = 14 [ packed = true ];
+
+ // Noise for testing merged deserialization.
+ optional int32 noise = 15;
+
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
new file mode 100644
index 00000000..0c780c72
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_simple_nano.proto
@@ -0,0 +1,54 @@
+// 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";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestSimpleNano";
+
+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/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
new file mode 100644
index 00000000..fcb1539d
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_single_nano.proto
@@ -0,0 +1,38 @@
+// 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: maxtroy@google.com (Max Cai)
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.nano";
+
+message SingleMessageNano {
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
new file mode 100644
index 00000000..2bbf2b7b
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_stringutf8_nano.proto
@@ -0,0 +1,43 @@
+// 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";
+// Explicit outer classname to suppress legacy info.
+option java_outer_classname = "UnittestStringutf8Nano";
+
+message StringUtf8 {
+ optional string id = 1;
+ repeated string rs = 2;
+}
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..f934b05f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc
@@ -0,0 +1,111 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace 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(
+ "\n"
+ "// enum $classname$\n",
+ "classname", descriptor_->name());
+
+ // Start of container interface
+ bool use_shell_class = params_.java_enum_style();
+ if (use_shell_class) {
+ printer->Print(
+ "public interface $classname$ {\n",
+ "classname", RenameJavaKeywords(descriptor_->name()));
+ printer->Indent();
+ }
+
+ // Canonical values
+ for (int i = 0; i < canonical_values_.size(); i++) {
+ printer->Print(
+ "public static final int $name$ = $canonical_value$;\n",
+ "name", RenameJavaKeywords(canonical_values_[i]->name()),
+ "canonical_value", SimpleItoa(canonical_values_[i]->number()));
+ }
+
+ // Aliases
+ for (int i = 0; i < aliases_.size(); i++) {
+ printer->Print(
+ "public static final int $name$ = $canonical_name$;\n",
+ "name", RenameJavaKeywords(aliases_[i].value->name()),
+ "canonical_name", RenameJavaKeywords(aliases_[i].canonical_value->name()));
+ }
+
+ // End of container interface
+ if (use_shell_class) {
+ printer->Outdent();
+ 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..10dd3648
--- /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_JAVANANO_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.h>
+
+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<const EnumValueDescriptor*> canonical_values_;
+
+ struct Alias {
+ const EnumValueDescriptor* value;
+ const EnumValueDescriptor* canonical_value;
+ };
+ vector<Alias> aliases_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..8a59d323
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -0,0 +1,520 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace 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<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ if (params.use_reference_types_for_primitives()
+ && !params.reftypes_primitive_enums()
+ && !descriptor->is_repeated()) {
+ (*variables)["type"] = "java.lang.Integer";
+ (*variables)["default"] = "null";
+ } else {
+ (*variables)["type"] = "int";
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ }
+ (*variables)["repeated_default"] =
+ "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
+ (*variables)["non_packed_tag"] = SimpleItoa(
+ internal::WireFormatLite::MakeTag(descriptor->number(),
+ internal::WireFormat::WireTypeForFieldType(descriptor->type())));
+ (*variables)["message_name"] = descriptor->containing_type()->name();
+}
+
+void LoadEnumValues(const Params& params,
+ const EnumDescriptor* enum_descriptor, vector<string>* canonical_values) {
+ string enum_class_name = ClassName(params, enum_descriptor);
+ for (int i = 0; i < enum_descriptor->value_count(); i++) {
+ const EnumValueDescriptor* value = enum_descriptor->value(i);
+ const EnumValueDescriptor* canonical_value =
+ enum_descriptor->FindValueByNumber(value->number());
+ if (value == canonical_value) {
+ canonical_values->push_back(
+ enum_class_name + "." + RenameJavaKeywords(value->name()));
+ }
+ }
+}
+
+void PrintCaseLabels(
+ io::Printer* printer, const vector<string>& canonical_values) {
+ for (int i = 0; i < canonical_values.size(); i++) {
+ printer->Print(
+ " case $value$:\n",
+ "value", canonical_values[i]);
+ }
+}
+
+} // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::
+EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$;\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = false;\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value = input.readInt32();\n"
+ "switch (value) {\n");
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Print(variables_,
+ " this.$name$ = value;\n");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ " has$capitalized_name$ = true;\n");
+ }
+ printer->Print(
+ " break;\n"
+ "}\n");
+ // No default case: in case of invalid value from the wire, preserve old
+ // field value. Also we are not storing the invalid value into the unknown
+ // fields, because there is no way to get the value out.
+}
+
+void EnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ // Always serialize a required field if we don't have the 'has' signal.
+ printer->Print(variables_,
+ "output.writeInt32($number$, this.$name$);\n");
+ } else {
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$) {\n");
+ }
+ printer->Print(variables_,
+ " output.writeInt32($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ printer->Print(variables_,
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, this.$name$);\n");
+ } else {
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != $default$) {\n");
+ }
+ printer->Print(variables_,
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const {
+ if (params_.use_reference_types_for_primitives()
+ && !params_.reftypes_primitive_enums()) {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else if (!this.$name$.equals(other.$name$)) {\n"
+ " return false;"
+ "}\n");
+ } else {
+ // We define equality as serialized form equality. If generate_has(),
+ // then if the field value equals the default value in both messages,
+ // but one's 'has' field is set and the other's is not, the serialized
+ // forms are different and we should return false.
+ printer->Print(variables_,
+ "if (this.$name$ != other.$name$");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$ == $default$\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ }
+}
+
+void EnumFieldGenerator::GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(
+ "result = 31 * result + ");
+ if (params_.use_reference_types_for_primitives()
+ && !params_.reftypes_primitive_enums()) {
+ printer->Print(variables_,
+ "(this.$name$ == null ? 0 : this.$name$)");
+ } else {
+ printer->Print(variables_,
+ "this.$name$");
+ }
+ printer->Print(";\n");
+}
+
+// ===================================================================
+
+AccessorEnumFieldGenerator::
+AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+ SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
+
+void AccessorEnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "private int $name$_;\n"
+ "public int get$capitalized_name$() {\n"
+ " return $name$_;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$(int value) {\n"
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " return this;\n"
+ "}\n"
+ "public boolean has$capitalized_name$() {\n"
+ " return $get_has$;\n"
+ "}\n"
+ "public $message_name$ clear$capitalized_name$() {\n"
+ " $name$_ = $default$;\n"
+ " $clear_has$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = $default$;\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int value = input.readInt32();\n"
+ "switch (value) {\n");
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Print(variables_,
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " break;\n"
+ "}\n");
+ // No default case: in case of invalid value from the wire, preserve old
+ // field value. Also we are not storing the invalid value into the unknown
+ // fields, because there is no way to get the value out.
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " output.writeInt32($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32Size($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || $name$_ != other.$name$_) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void AccessorEnumFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result + $name$_;\n");
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetEnumVariables(params, descriptor, &variables_);
+ LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $repeated_default$;\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the maximum length of the array, then parse,
+ // and finally copy the valid values to the field.
+ printer->Print(variables_,
+ "int length = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n"
+ "int[] validValues = new int[length];\n"
+ "int validCount = 0;\n"
+ "for (int i = 0; i < length; i++) {\n"
+ " if (i != 0) { // tag for first value already consumed.\n"
+ " input.readTag();\n"
+ " }\n"
+ " int value = input.readInt32();\n"
+ " switch (value) {\n");
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Print(variables_,
+ " validValues[validCount++] = value;\n"
+ " break;\n"
+ " }\n"
+ "}\n"
+ "if (validCount != 0) {\n"
+ " int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ " if (i == 0 && validCount == validValues.length) {\n"
+ " this.$name$ = validValues;\n"
+ " } else {\n"
+ " int[] newArray = new int[i + validCount];\n"
+ " if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ " }\n"
+ " java.lang.System.arraycopy(validValues, 0, newArray, i, validCount);\n"
+ " this.$name$ = newArray;\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(variables_,
+ "int bytes = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(bytes);\n"
+ "// First pass to compute array length.\n"
+ "int arrayLength = 0;\n"
+ "int startPos = input.getPosition();\n"
+ "while (input.getBytesUntilLimit() > 0) {\n"
+ " switch (input.readInt32()) {\n");
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Print(variables_,
+ " arrayLength++;\n"
+ " break;\n"
+ " }\n"
+ "}\n"
+ "if (arrayLength != 0) {\n"
+ " input.rewindToPosition(startPos);\n"
+ " int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ " int[] newArray = new int[i + arrayLength];\n"
+ " if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ " }\n"
+ " while (input.getBytesUntilLimit() > 0) {\n"
+ " int value = input.readInt32();\n"
+ " switch (value) {\n");
+ printer->Indent();
+ printer->Indent();
+ PrintCaseLabels(printer, canonical_values_);
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(variables_,
+ " newArray[i++] = value;\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " this.$name$ = newArray;\n"
+ "}\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateRepeatedDataSizeCode(io::Printer* printer) const {
+ // Creates a variable dataSize and puts the serialized size in there.
+ printer->Print(variables_,
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " int element = this.$name$[i];\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeInt32SizeNoTag(element);\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ if (descriptor_->options().packed()) {
+ GenerateRepeatedDataSizeCode(printer);
+ printer->Print(variables_,
+ "output.writeRawVarint32($tag$);\n"
+ "output.writeRawVarint32(dataSize);\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.writeRawVarint32(this.$name$[i]);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.writeInt32($number$, this.$name$[i]);\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Print(variables_,
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ GenerateRepeatedDataSizeCode(printer);
+
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "size += $tag_size$;\n"
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeRawVarint32Size(dataSize);\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * this.$name$.length;\n");
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // 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..00adc61f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -0,0 +1,125 @@
+// 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_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+#include <vector>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+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, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class AccessorEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index);
+ ~AccessorEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorEnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedEnumFieldGenerator(
+ const FieldDescriptor* descriptor, const Params& params);
+ ~RepeatedEnumFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+ vector<string> canonical_values_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
new file mode 100644
index 00000000..754ed550
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -0,0 +1,150 @@
+// 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: bduff@google.com (Brian Duff)
+
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* GetTypeConstantName(const FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return "TYPE_INT32" ;
+ case FieldDescriptor::TYPE_UINT32 : return "TYPE_UINT32" ;
+ case FieldDescriptor::TYPE_SINT32 : return "TYPE_SINT32" ;
+ case FieldDescriptor::TYPE_FIXED32 : return "TYPE_FIXED32" ;
+ case FieldDescriptor::TYPE_SFIXED32: return "TYPE_SFIXED32";
+ case FieldDescriptor::TYPE_INT64 : return "TYPE_INT64" ;
+ case FieldDescriptor::TYPE_UINT64 : return "TYPE_UINT64" ;
+ case FieldDescriptor::TYPE_SINT64 : return "TYPE_SINT64" ;
+ case FieldDescriptor::TYPE_FIXED64 : return "TYPE_FIXED64" ;
+ case FieldDescriptor::TYPE_SFIXED64: return "TYPE_SFIXED64";
+ case FieldDescriptor::TYPE_FLOAT : return "TYPE_FLOAT" ;
+ case FieldDescriptor::TYPE_DOUBLE : return "TYPE_DOUBLE" ;
+ case FieldDescriptor::TYPE_BOOL : return "TYPE_BOOL" ;
+ case FieldDescriptor::TYPE_STRING : return "TYPE_STRING" ;
+ case FieldDescriptor::TYPE_BYTES : return "TYPE_BYTES" ;
+ case FieldDescriptor::TYPE_ENUM : return "TYPE_ENUM" ;
+ case FieldDescriptor::TYPE_GROUP : return "TYPE_GROUP" ;
+ case FieldDescriptor::TYPE_MESSAGE : return "TYPE_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;
+}
+
+} // namespace
+
+void SetVariables(const FieldDescriptor* descriptor, const Params params,
+ map<string, string>* variables) {
+ (*variables)["extends"] = ClassName(params, descriptor->containing_type());
+ (*variables)["name"] = RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ bool repeated = descriptor->is_repeated();
+ (*variables)["repeated"] = repeated ? "Repeated" : "";
+ (*variables)["type"] = GetTypeConstantName(descriptor->type());
+ JavaType java_type = GetJavaType(descriptor->type());
+ string tag = SimpleItoa(WireFormat::MakeTag(descriptor));
+ if (java_type == JAVATYPE_MESSAGE) {
+ (*variables)["ext_type"] = "MessageTyped";
+ string message_type = ClassName(params, descriptor->message_type());
+ if (repeated) {
+ message_type += "[]";
+ }
+ (*variables)["class"] = message_type;
+ // For message typed extensions, tags_params contains a single tag
+ // for both singular and repeated cases.
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["ext_type"] = "PrimitiveTyped";
+ if (!repeated) {
+ (*variables)["class"] = BoxedPrimitiveTypeName(java_type);
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["class"] = PrimitiveTypeName(java_type) + "[]";
+ if (!descriptor->is_packable()) {
+ // Non-packable: nonPackedTag == tag, packedTag == 0
+ (*variables)["tag_params"] = tag + ", " + tag + ", 0";
+ } else if (descriptor->options().packed()) {
+ // Packable and packed: tag == packedTag
+ string non_packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(),
+ WireFormat::WireTypeForFieldType(descriptor->type())));
+ (*variables)["tag_params"] = tag + ", " + non_packed_tag + ", " + tag;
+ } else {
+ // Packable and not packed: tag == nonPackedTag
+ string packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+ (*variables)["tag_params"] = tag + ", " + tag + ", " + packed_tag;
+ }
+ }
+ }
+}
+
+ExtensionGenerator::
+ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : params_(params), descriptor_(descriptor) {
+ SetVariables(descriptor, params, &variables_);
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::Generate(io::Printer* printer) const {
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_);
+ printer->Print(variables_,
+ "public static final com.google.protobuf.nano.Extension<\n"
+ " $extends$,\n"
+ " $class$> $name$ =\n"
+ " com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
+ " com.google.protobuf.nano.Extension.$type$,\n"
+ " $class$.class,\n"
+ " $tag_params$);\n");
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.h b/src/google/protobuf/compiler/javanano/javanano_extension.h
new file mode 100644
index 00000000..4843e296
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.h
@@ -0,0 +1,74 @@
+// 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: bduff@google.com (Brian Duff)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class ExtensionGenerator {
+ public:
+ explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params);
+ ~ExtensionGenerator();
+
+ void Generate(io::Printer* printer) const;
+
+ private:
+ const Params& params_;
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_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..e3e4cefe
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_field.cc
@@ -0,0 +1,143 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
+#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
+#include <google/protobuf/compiler/javanano/javanano_message_field.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+FieldGenerator::~FieldGenerator() {}
+
+bool FieldGenerator::SavedDefaultNeeded() const {
+ // No saved default for this field by default.
+ // Subclasses whose instances may need saved defaults will override this
+ // and return the appropriate value.
+ return false;
+}
+
+void FieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ // No saved default for this field by default.
+ // Subclasses whose instances may need saved defaults will override this
+ // and generate the appropriate init code to the printer.
+}
+
+void FieldGenerator::GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ // Reaching here indicates a bug. Cases are:
+ // - This FieldGenerator should support packing, but this method should be
+ // overridden.
+ // - This FieldGenerator doesn't support packing, and this method should
+ // never have been called.
+ GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
+ << "called on field generator that does not support packing.";
+}
+
+// =============================================
+
+FieldGeneratorMap::FieldGeneratorMap(
+ const Descriptor* descriptor, const Params &params)
+ : descriptor_(descriptor),
+ field_generators_(
+ new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+
+ int next_has_bit_index = 0;
+ bool saved_defaults_needed = false;
+ // Construct all the FieldGenerators.
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ FieldGenerator* field_generator = MakeGenerator(
+ descriptor->field(i), params, &next_has_bit_index);
+ saved_defaults_needed = saved_defaults_needed
+ || field_generator->SavedDefaultNeeded();
+ field_generators_[i].reset(field_generator);
+ }
+ total_bits_ = next_has_bit_index;
+ saved_defaults_needed_ = saved_defaults_needed;
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
+ const Params &params, int* next_has_bit_index) {
+ JavaType java_type = GetJavaType(field);
+ if (field->is_repeated()) {
+ switch (java_type) {
+ case JAVATYPE_MESSAGE:
+ return new RepeatedMessageFieldGenerator(field, params);
+ case JAVATYPE_ENUM:
+ return new RepeatedEnumFieldGenerator(field, params);
+ default:
+ return new RepeatedPrimitiveFieldGenerator(field, params);
+ }
+ } else if (params.optional_field_accessors() && field->is_optional()
+ && java_type != JAVATYPE_MESSAGE) {
+ // We need a has-bit for each primitive/enum field because their default
+ // values could be same as explicitly set values. But we don't need it
+ // for a message field because they have no defaults and Nano uses 'null'
+ // for unset messages, which cannot be set explicitly.
+ switch (java_type) {
+ case JAVATYPE_ENUM:
+ return new AccessorEnumFieldGenerator(
+ field, params, (*next_has_bit_index)++);
+ default:
+ return new AccessorPrimitiveFieldGenerator(
+ field, params, (*next_has_bit_index)++);
+ }
+ } else {
+ switch (java_type) {
+ 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()];
+}
+
+} // 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..6170c2c0
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -0,0 +1,119 @@
+// 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_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class FieldGenerator {
+ public:
+ FieldGenerator(const Params& params) : params_(params) {}
+ virtual ~FieldGenerator();
+
+ virtual bool SavedDefaultNeeded() const;
+ virtual void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+
+ // Generates code for Java fields and methods supporting this field.
+ // If this field needs a saved default (SavedDefaultNeeded() is true),
+ // then @lazy_init controls how the static field for that default value
+ // and its initialization code should be generated. If @lazy_init is
+ // true, the static field is not declared final and the initialization
+ // code is generated only when GenerateInitSavedDefaultCode is called;
+ // otherwise, the static field is declared final and initialized inline.
+ // GenerateInitSavedDefaultCode will not be called in the latter case.
+ virtual void GenerateMembers(
+ io::Printer* printer, bool lazy_init) const = 0;
+
+ virtual void GenerateClearCode(io::Printer* printer) const = 0;
+ virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+
+ // Generates code to merge from packed serialized form. The default
+ // implementation will fail; subclasses which can handle packed serialized
+ // forms will override this and print appropriate code to the printer.
+ virtual void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+
+ virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+ virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+ virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+ virtual void GenerateHashCodeCode(io::Printer* printer) 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 &params);
+ ~FieldGeneratorMap();
+
+ const FieldGenerator& get(const FieldDescriptor* field) const;
+ int total_bits() const { return total_bits_; }
+ bool saved_defaults_needed() const { return saved_defaults_needed_; }
+
+ private:
+ const Descriptor* descriptor_;
+ scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ int total_bits_;
+ bool saved_defaults_needed_;
+
+ static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
+ const Params &params, int* next_has_bit_index);
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..3676ab9d
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_file.cc
@@ -0,0 +1,263 @@
+// 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 <iostream>
+
+#include <google/protobuf/compiler/javanano/javanano_file.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_message.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace 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<const FieldDescriptor*> fields;
+ reflection->ListFields(message, &fields);
+
+ for (int i = 0; i < fields.size(); i++) {
+ if (fields[i]->is_extension()) return true;
+
+ if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ if (fields[i]->is_repeated()) {
+ int size = reflection->FieldSize(message, fields[i]);
+ for (int j = 0; j < size; j++) {
+ const Message& sub_message =
+ reflection->GetRepeatedMessage(message, fields[i], j);
+ if (UsesExtensions(sub_message)) return true;
+ }
+ } else {
+ const Message& sub_message = reflection->GetMessage(message, fields[i]);
+ if (UsesExtensions(sub_message)) return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params)
+ : file_(file),
+ params_(params),
+ java_package_(FileJavaPackage(params, file)),
+ classname_(FileClassName(params, file)) {}
+
+FileGenerator::~FileGenerator() {}
+
+bool FileGenerator::Validate(string* error) {
+ // Check for extensions
+ FileDescriptorProto file_proto;
+ file_->CopyTo(&file_proto);
+ if (UsesExtensions(file_proto) && !params_.store_unknown_fields()) {
+ error->assign(file_->name());
+ error->append(
+ ": Java NANO_RUNTIME only supports extensions when the "
+ "'store_unknown_fields' generator option is 'true'.");
+ return false;
+ }
+
+ if (file_->service_count() != 0 && !params_.ignore_services()) {
+ error->assign(file_->name());
+ error->append(
+ ": Java NANO_RUNTIME does not support services\"");
+ return false;
+ }
+
+ if (!IsOuterClassNeeded(params_, file_)) {
+ return true;
+ }
+
+ // Check whether legacy javanano generator would omit the outer class.
+ if (!params_.has_java_outer_classname(file_->name())
+ && file_->message_type_count() == 1
+ && file_->enum_type_count() == 0 && file_->extension_count() == 0) {
+ cout << "INFO: " << file_->name() << ":" << endl;
+ cout << "Javanano generator has changed to align with java generator. "
+ "An outer class will be created for this file and the single message "
+ "in the file will become a nested class. Use java_multiple_files to "
+ "skip generating the outer class, or set an explicit "
+ "java_outer_classname to suppress this message." << endl;
+ }
+
+ // 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.
+ bool found_conflict = false;
+ for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) {
+ if (file_->message_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ if (params_.java_enum_style()) {
+ for (int i = 0; !found_conflict && i < file_->enum_type_count(); i++) {
+ if (file_->enum_type(i)->name() == classname_) {
+ found_conflict = true;
+ }
+ }
+ }
+ if (found_conflict) {
+ error->assign(file_->name());
+ error->append(
+ ": Cannot generate Java output because the file's outer 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.");
+ 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");
+ if (!java_package_.empty()) {
+ printer->Print(
+ "\n"
+ "package $package$;\n",
+ "package", java_package_);
+ }
+
+ // Note: constants (from enums, emitted in the loop below) may have the same names as constants
+ // in the nested classes. This causes Java warnings, but is not fatal, so we suppress those
+ // warnings here in the top-most class declaration.
+ printer->Print(
+ "\n"
+ "@SuppressWarnings(\"hiding\")\n"
+ "public interface $classname$ {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // -----------------------------------------------------------------
+
+ // Extensions.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ ExtensionGenerator(file_->extension(i), params_).Generate(printer);
+ }
+
+ // Enums.
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ EnumGenerator(file_->enum_type(i), params_).Generate(printer);
+ }
+
+ // Messages.
+ if (!params_.java_multiple_files(file_->name())) {
+ 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);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+}
+
+template<typename GeneratorClass, typename DescriptorClass>
+static void GenerateSibling(const string& package_dir,
+ const string& java_package,
+ const DescriptorClass* descriptor,
+ GeneratorContext* output_directory,
+ vector<string>* file_list,
+ const Params& params) {
+ string filename = package_dir + descriptor->name() + ".java";
+ file_list->push_back(filename);
+
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(filename));
+ io::Printer printer(output.get(), '$');
+
+ printer.Print(
+ "// Generated by the protocol buffer compiler. DO NOT EDIT!\n");
+ if (!java_package.empty()) {
+ printer.Print(
+ "\n"
+ "package $package$;\n",
+ "package", java_package);
+ }
+
+ GeneratorClass(descriptor, params).Generate(&printer);
+}
+
+void FileGenerator::GenerateSiblings(const string& package_dir,
+ GeneratorContext* output_directory,
+ vector<string>* file_list) {
+ if (params_.java_multiple_files(file_->name())) {
+ for (int i = 0; i < file_->message_type_count(); i++) {
+ GenerateSibling<MessageGenerator>(package_dir, java_package_,
+ file_->message_type(i),
+ output_directory, file_list, params_);
+ }
+
+ if (params_.java_enum_style()) {
+ for (int i = 0; i < file_->enum_type_count(); i++) {
+ GenerateSibling<EnumGenerator>(package_dir, java_package_,
+ file_->enum_type(i),
+ output_directory, file_list, params_);
+ }
+ }
+ }
+}
+
+} // 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..217eafe2
--- /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_JAVANANO_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__
+
+#include <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+
+namespace google {
+namespace protobuf {
+ class FileDescriptor; // descriptor.h
+ namespace io {
+ class Printer; // printer.h
+ }
+ namespace compiler {
+ class GeneratorContext; // 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,
+ GeneratorContext* output_directory,
+ vector<string>* file_list);
+
+ const string& java_package() { return java_package_; }
+ const string& classname() { return classname_; }
+
+ private:
+ const FileDescriptor* file_;
+ const Params& params_;
+ string java_package_;
+ string classname_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..b5fbcd5f
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -0,0 +1,219 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/compiler/javanano/javanano_generator.h>
+#include <google/protobuf/compiler/javanano/javanano_file.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+namespace {
+
+string TrimString(const string& s) {
+ string::size_type start = s.find_first_not_of(" \n\r\t");
+ if (start == string::npos) {
+ return "";
+ }
+ string::size_type end = s.find_last_not_of(" \n\r\t") + 1;
+ return s.substr(start, end - start);
+}
+
+} // namespace
+
+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());
+ }
+ if (file->options().has_java_multiple_files()) {
+ params.set_java_multiple_files(
+ file->name(), file->options().java_multiple_files());
+ }
+
+ // 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,
+ GeneratorContext* output_directory,
+ string* error) const {
+ vector<pair<string, string> > 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());
+
+ // Update per file params
+ UpdateParamsRecursively(params, file);
+
+ // Replace any existing options with ones from command line
+ for (int i = 0; i < options.size(); i++) {
+ string option_name = TrimString(options[i].first);
+ string option_value = TrimString(options[i].second);
+ if (option_name == "output_list_file") {
+ output_list_file = option_value;
+ } else if (option_name == "java_package") {
+ vector<string> parts;
+ SplitStringUsing(option_value, "|", &parts);
+ if (parts.size() != 2) {
+ *error = "Bad java_package, expecting filename|PackageName found '"
+ + option_value + "'";
+ return false;
+ }
+ params.set_java_package(parts[0], parts[1]);
+ } else if (option_name == "java_outer_classname") {
+ vector<string> parts;
+ SplitStringUsing(option_value, "|", &parts);
+ if (parts.size() != 2) {
+ *error = "Bad java_outer_classname, "
+ "expecting filename|ClassName found '"
+ + option_value + "'";
+ return false;
+ }
+ params.set_java_outer_classname(parts[0], parts[1]);
+ } else if (option_name == "store_unknown_fields") {
+ params.set_store_unknown_fields(option_value == "true");
+ } else if (option_name == "java_multiple_files") {
+ params.set_override_java_multiple_files(option_value == "true");
+ } else if (option_name == "java_nano_generate_has") {
+ params.set_generate_has(option_value == "true");
+ } else if (option_name == "enum_style") {
+ params.set_java_enum_style(option_value == "java");
+ } else if (option_name == "optional_field_style") {
+ params.set_optional_field_accessors(option_value == "accessors");
+ params.set_use_reference_types_for_primitives(option_value == "reftypes"
+ || option_value == "reftypes_compat_mode");
+ params.set_reftypes_primitive_enums(
+ option_value == "reftypes_compat_mode");
+ if (option_value == "reftypes_compat_mode") {
+ params.set_generate_clear(false);
+ }
+ } else if (option_name == "generate_equals") {
+ params.set_generate_equals(option_value == "true");
+ } else if (option_name == "ignore_services") {
+ params.set_ignore_services(option_value == "true");
+ } else if (option_name == "parcelable_messages") {
+ params.set_parcelable_messages(option_value == "true");
+ } else {
+ *error = "Ignore unknown javanano generator option: " + option_name;
+ }
+ }
+
+ // Check illegal parameter combinations
+ // Note: the enum-like optional_field_style generator param ensures
+ // that we can never have illegal combinations of field styles
+ // (e.g. reftypes and accessors can't be on at the same time).
+ if (params.generate_has()
+ && (params.optional_field_accessors()
+ || params.use_reference_types_for_primitives())) {
+ error->assign("java_nano_generate_has=true cannot be used in conjunction"
+ " with optional_field_style=accessors or optional_field_style=reftypes");
+ return false;
+ }
+
+ // -----------------------------------------------------------------
+
+ FileGenerator file_generator(file, params);
+ if (!file_generator.Validate(error)) {
+ return false;
+ }
+
+ string package_dir =
+ StringReplace(file_generator.java_package(), ".", "/", true);
+ if (!package_dir.empty()) package_dir += "/";
+
+ vector<string> all_files;
+
+ if (IsOuterClassNeeded(params, file)) {
+ string java_filename = package_dir;
+ java_filename += file_generator.classname();
+ java_filename += ".java";
+ all_files.push_back(java_filename);
+
+ // Generate main java file.
+ scoped_ptr<io::ZeroCopyOutputStream> output(
+ output_directory->Open(java_filename));
+ io::Printer printer(output.get(), '$');
+ file_generator.Generate(&printer);
+ }
+
+ // Generate sibling files.
+ file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
+
+ // Generate output list if requested.
+ if (!output_list_file.empty()) {
+ // Generate output list. This is just a simple text file placed in a
+ // deterministic location which lists the .java files being generated.
+ scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+ output_directory->Open(output_list_file));
+ io::Printer srclist_printer(srclist_raw_output.get(), '$');
+ for (int i = 0; i < all_files.size(); i++) {
+ srclist_printer.Print("$filename$\n", "filename", all_files[i]);
+ }
+ }
+
+ return true;
+}
+
+} // namespace java
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.h b/src/google/protobuf/compiler/javanano/javanano_generator.h
new file mode 100644
index 00000000..6f9f7f2a
--- /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_JAVANANO_NANO_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+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,
+ GeneratorContext* output_directory,
+ string* error) const;
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaNanoGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..2149418a
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -0,0 +1,566 @@
+// 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 <limits>
+#include <vector>
+
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+const char kThickSeparator[] =
+ "// ===================================================================\n";
+const char kThinSeparator[] =
+ "// -------------------------------------------------------------------\n";
+
+class RenameKeywords {
+ private:
+ hash_set<string> java_keywords_set_;
+
+ public:
+ RenameKeywords() {
+ static const char* kJavaKeywordsList[] = {
+ // Reserved Java Keywords
+ "abstract", "assert", "boolean", "break", "byte", "case", "catch",
+ "char", "class", "const", "continue", "default", "do", "double", "else",
+ "enum", "extends", "final", "finally", "float", "for", "goto", "if",
+ "implements", "import", "instanceof", "int", "interface", "long",
+ "native", "new", "package", "private", "protected", "public", "return",
+ "short", "static", "strictfp", "super", "switch", "synchronized",
+ "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
+
+ // Reserved Keywords for Literals
+ "false", "null", "true"
+ };
+
+ for (int i = 0; i < GOOGLE_ARRAYSIZE(kJavaKeywordsList); i++) {
+ java_keywords_set_.insert(kJavaKeywordsList[i]);
+ }
+ }
+
+ // Used to rename the a field name if it's a java keyword. Specifically
+ // this is used to rename the ["name"] or ["capitalized_name"] field params.
+ // (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html)
+ string RenameJavaKeywordsImpl(const string& input) {
+ string result = input;
+
+ if (java_keywords_set_.find(result) != java_keywords_set_.end()) {
+ result += "_";
+ }
+
+ return result;
+ }
+
+};
+
+static RenameKeywords sRenameKeywords;
+
+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 RenameJavaKeywords(const string& input) {
+ return sRenameKeywords.RenameJavaKeywordsImpl(input);
+}
+
+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) {
+ if (params.has_java_outer_classname(file->name())) {
+ return params.java_outer_classname(file->name());
+ } else {
+ // Use the filename itself 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);
+ }
+ return UnderscoresToCamelCaseImpl(StripProto(basename), true);
+ }
+}
+
+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;
+ }
+}
+
+bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) {
+ // If java_multiple_files is false, the outer class is always needed.
+ if (!params.java_multiple_files(file->name())) {
+ return true;
+ }
+
+ // File-scope extensions need the outer class as the scope.
+ if (file->extension_count() != 0) {
+ return true;
+ }
+
+ // If container interfaces are not generated, file-scope enums need the
+ // outer class as the scope.
+ if (file->enum_type_count() != 0 && !params.java_enum_style()) {
+ return true;
+ }
+
+ return false;
+}
+
+string ToJavaName(const Params& params, const string& name, bool is_class,
+ const Descriptor* parent, const FileDescriptor* file) {
+ string result;
+ if (parent != NULL) {
+ result.append(ClassName(params, parent));
+ } else if (is_class && params.java_multiple_files(file->name())) {
+ result.append(FileJavaPackage(params, file));
+ } else {
+ result.append(ClassName(params, file));
+ }
+ if (!result.empty()) result.append(1, '.');
+ result.append(RenameJavaKeywords(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) {
+ const Descriptor* parent = descriptor->containing_type();
+ // When using Java enum style, an enum's class name contains the enum name.
+ // Use the standard ToJavaName translation.
+ if (params.java_enum_style()) {
+ return ToJavaName(params, descriptor->name(), true, parent,
+ descriptor->file());
+ }
+ // Otherwise the enum members are accessed from the enclosing class.
+ if (parent != NULL) {
+ return ClassName(params, parent);
+ } else {
+ return ClassName(params, descriptor->file());
+ }
+}
+
+string FieldConstantName(const FieldDescriptor *field) {
+ string name = field->name() + "_FIELD_NUMBER";
+ UpperString(&name);
+ return name;
+}
+
+string FieldDefaultConstantName(const FieldDescriptor *field) {
+ return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
+}
+
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+ // We don't want to print group bodies so we cut off after the first line
+ // (the second line for extensions).
+ string def = field->DebugString();
+ string::size_type first_line_end = def.find_first_of('\n');
+ printer->Print("// $def$\n",
+ "def", def.substr(0, first_line_end));
+ if (field->is_extension()) {
+ string::size_type second_line_start = first_line_end + 1;
+ string::size_type second_line_length =
+ def.find('\n', second_line_start) - second_line_start;
+ printer->Print("// $def$\n",
+ "def", def.substr(second_line_start, second_line_length));
+ }
+}
+
+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;
+}
+
+string 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 "int";
+ case JAVATYPE_MESSAGE: return "";
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+string 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 "";
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return "";
+}
+
+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);
+ }
+
+ if (params.use_reference_types_for_primitives()) {
+ if (params.reftypes_primitive_enums()
+ && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
+ return "Integer.MIN_VALUE";
+ }
+ return "null";
+ }
+
+ // Switch on cpp_type since we need to know which default_value_* method
+ // of FieldDescriptor to call.
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return SimpleItoa(field->default_value_int32());
+ case FieldDescriptor::CPPTYPE_UINT32:
+ // Need to print as a signed int since Java has no unsigned.
+ return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
+ case FieldDescriptor::CPPTYPE_INT64:
+ return SimpleItoa(field->default_value_int64()) + "L";
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
+ "L";
+ case FieldDescriptor::CPPTYPE_DOUBLE: {
+ double value = field->default_value_double();
+ if (value == numeric_limits<double>::infinity()) {
+ return "Double.POSITIVE_INFINITY";
+ } else if (value == -numeric_limits<double>::infinity()) {
+ return "Double.NEGATIVE_INFINITY";
+ } else if (value != value) {
+ return "Double.NaN";
+ } else {
+ return SimpleDtoa(value) + "D";
+ }
+ }
+ case FieldDescriptor::CPPTYPE_FLOAT: {
+ float value = field->default_value_float();
+ if (value == numeric_limits<float>::infinity()) {
+ return "Float.POSITIVE_INFINITY";
+ } else if (value == -numeric_limits<float>::infinity()) {
+ return "Float.NEGATIVE_INFINITY";
+ } else if (value != value) {
+ return "Float.NaN";
+ } else {
+ return SimpleFtoa(value) + "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()) + "." +
+ RenameJavaKeywords(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 "";
+}
+
+
+static const char* kBitMasks[] = {
+ "0x00000001",
+ "0x00000002",
+ "0x00000004",
+ "0x00000008",
+ "0x00000010",
+ "0x00000020",
+ "0x00000040",
+ "0x00000080",
+
+ "0x00000100",
+ "0x00000200",
+ "0x00000400",
+ "0x00000800",
+ "0x00001000",
+ "0x00002000",
+ "0x00004000",
+ "0x00008000",
+
+ "0x00010000",
+ "0x00020000",
+ "0x00040000",
+ "0x00080000",
+ "0x00100000",
+ "0x00200000",
+ "0x00400000",
+ "0x00800000",
+
+ "0x01000000",
+ "0x02000000",
+ "0x04000000",
+ "0x08000000",
+ "0x10000000",
+ "0x20000000",
+ "0x40000000",
+ "0x80000000",
+};
+
+string GetBitFieldName(int index) {
+ string var_name = "bitField";
+ var_name += SimpleItoa(index);
+ var_name += "_";
+ return var_name;
+}
+
+string GetBitFieldNameForBit(int bit_index) {
+ return GetBitFieldName(bit_index / 32);
+}
+
+string GenerateGetBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = "((" + var_name + " & " + mask + ") != 0)";
+ return result;
+}
+
+string GenerateSetBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = var_name + " |= " + mask;
+ return result;
+}
+
+string GenerateClearBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = var_name + " = (" + var_name + " & ~" + mask + ")";
+ return result;
+}
+
+string GenerateDifferentBit(int bit_index) {
+ string var_name = GetBitFieldNameForBit(bit_index);
+ int bit_in_var_index = bit_index % 32;
+
+ string mask = kBitMasks[bit_in_var_index];
+ string result = "((" + var_name + " & " + mask
+ + ") != (other." + var_name + " & " + mask + "))";
+ return result;
+}
+
+void SetBitOperationVariables(const string name,
+ int bitIndex, map<string, string>* variables) {
+ (*variables)["get_" + name] = GenerateGetBit(bitIndex);
+ (*variables)["set_" + name] = GenerateSetBit(bitIndex);
+ (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
+ (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
+}
+
+} // 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..29310743
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -0,0 +1,189 @@
+// 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_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__
+
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
+
+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);
+
+// Appends an "_" to the end of a field where the name is a reserved java
+// keyword. For example int32 public = 1 will generate int public_.
+string RenameJavaKeywords(const string& input);
+
+// 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);
+
+// Returns whether the Java outer class is needed, i.e. whether the option
+// java_multiple_files is false, or the proto file contains any file-scope
+// enums/extensions.
+bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file);
+
+// Converts the given simple name of a proto entity to its fully-qualified name
+// in the Java namespace, given that it is in the given file enclosed in the
+// given parent message (or NULL for file-scope entities). Whether the file's
+// outer class name should be included in the return value depends on factors
+// inferrable from the given arguments, including is_class which indicates
+// whether the entity translates to a Java class.
+string ToJavaName(const Params& params, const string& name, bool is_class,
+ const Descriptor* parent, 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->name(), true,
+ descriptor->containing_type(), descriptor->file());
+}
+string ClassName(const Params& params, const EnumDescriptor* descriptor);
+inline string ClassName(const Params& params,
+ const ServiceDescriptor* descriptor) {
+ return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file());
+}
+inline string ExtensionIdentifierName(const Params& params,
+ const FieldDescriptor* descriptor) {
+ return ToJavaName(params, descriptor->name(), false,
+ descriptor->extension_scope(), 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);
+
+// Print the field's proto-syntax definition as a comment.
+void PrintFieldComment(io::Printer* printer, 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());
+}
+
+string PrimitiveTypeName(JavaType 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.
+string BoxedPrimitiveTypeName(JavaType type);
+
+string EmptyArrayName(const Params& params, const FieldDescriptor* field);
+
+string DefaultValue(const Params& params, const FieldDescriptor* field);
+
+
+// Methods for shared bitfields.
+
+// Gets the name of the shared bitfield for the given field index.
+string GetBitFieldName(int index);
+
+// Gets the name of the shared bitfield for the given bit index.
+// Effectively, GetBitFieldName(bit_index / 32)
+string GetBitFieldNameForBit(int bit_index);
+
+// Generates the java code for the expression that returns whether the bit at
+// the given bit index is set.
+// Example: "((bitField1_ & 0x04000000) != 0)"
+string GenerateGetBit(int bit_index);
+
+// Generates the java code for the expression that sets the bit at the given
+// bit index.
+// Example: "bitField1_ |= 0x04000000"
+string GenerateSetBit(int bit_index);
+
+// Generates the java code for the expression that clears the bit at the given
+// bit index.
+// Example: "bitField1_ = (bitField1_ & ~0x04000000)"
+string GenerateClearBit(int bit_index);
+
+// Generates the java code for the expression that returns whether the bit at
+// the given bit index contains different values in the current object and
+// another object accessible via the variable 'other'.
+// Example: "((bitField1_ & 0x04000000) != (other.bitField1_ & 0x04000000))"
+string GenerateDifferentBit(int bit_index);
+
+// Sets the 'get_*', 'set_*', 'clear_*' and 'different_*' variables, where * is
+// the given name of the bit, to the appropriate Java expressions for the given
+// bit index.
+void SetBitOperationVariables(const string name,
+ int bitIndex, map<string, string>* variables);
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..7c52ca31
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -0,0 +1,555 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/javanano/javanano_message.h>
+#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+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;
+}
+
+} // 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);
+ }
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+ if (!params_.store_unknown_fields() &&
+ (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
+ GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
+ "'store_unknown_fields' generator option is 'true'\n";
+ }
+
+ const string& file_name = descriptor_->file()->name();
+ bool is_own_file =
+ params_.java_multiple_files(file_name)
+ && descriptor_->containing_type() == NULL;
+
+ if (is_own_file) {
+ // Note: constants (from enums and fields requiring stored defaults, emitted in the loop below)
+ // may have the same names as constants in the nested classes. This causes Java warnings, but
+ // is not fatal, so we suppress those warnings here in the top-most class declaration.
+ printer->Print(
+ "\n"
+ "@SuppressWarnings(\"hiding\")\n"
+ "public final class $classname$ extends\n",
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "\n"
+ "public static final class $classname$ extends\n",
+ "classname", descriptor_->name());
+ }
+ if (params_.store_unknown_fields() && params_.parcelable_messages()) {
+ printer->Print(
+ " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n",
+ "classname", descriptor_->name());
+ } else if (params_.store_unknown_fields()) {
+ printer->Print(
+ " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+ "classname", descriptor_->name());
+ } else if (params_.parcelable_messages()) {
+ printer->Print(
+ " com.google.protobuf.nano.android.ParcelableMessageNano {\n");
+ } else {
+ printer->Print(
+ " com.google.protobuf.nano.MessageNano {\n");
+ }
+ printer->Indent();
+
+ // Nested types and extensions
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
+ }
+
+ 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);
+ }
+
+ // Lazy initialization of otherwise static final fields can help prevent the
+ // class initializer from being generated. We want to prevent it because it
+ // stops ProGuard from inlining any methods in this class into call sites and
+ // therefore reducing the method count. However, extensions are best kept as
+ // public static final fields with initializers, so with their existence we
+ // won't bother with lazy initialization.
+ bool lazy_init = descriptor_->extension_count() == 0;
+
+ // Empty array
+ if (lazy_init) {
+ printer->Print(
+ "\n"
+ "private static volatile $classname$[] _emptyArray;\n"
+ "public static $classname$[] emptyArray() {\n"
+ " // Lazily initializes the empty array\n"
+ " if (_emptyArray == null) {\n"
+ " synchronized (\n"
+ " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+ " if (_emptyArray == null) {\n"
+ " _emptyArray = new $classname$[0];\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " return _emptyArray;\n"
+ "}\n",
+ "classname", descriptor_->name());
+ } else {
+ printer->Print(
+ "\n"
+ "private static final $classname$[] EMPTY_ARRAY = {};\n"
+ "public static $classname$[] emptyArray() {\n"
+ " return EMPTY_ARRAY;\n"
+ "}\n",
+ "classname", descriptor_->name());
+ }
+
+ // Integers for bit fields
+ int totalInts = (field_generators_.total_bits() + 31) / 32;
+ if (totalInts > 0) {
+ printer->Print("\n");
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("private int $bit_field_name$;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+ }
+
+ // Fields and maybe their default values
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_->field(i));
+ field_generators_.get(descriptor_->field(i)).GenerateMembers(
+ printer, lazy_init);
+ }
+
+ // Constructor, with lazy init code if needed
+ if (lazy_init && field_generators_.saved_defaults_needed()) {
+ printer->Print(
+ "\n"
+ "private static volatile boolean _classInitialized;\n"
+ "\n"
+ "public $classname$() {\n"
+ " // Lazily initializes the field defaults\n"
+ " if (!_classInitialized) {\n"
+ " synchronized (\n"
+ " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n"
+ " if (!_classInitialized) {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(descriptor_->field(i))
+ .GenerateInitSavedDefaultCode(printer);
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " _classInitialized = true;\n"
+ " }\n"
+ " }\n"
+ " }\n");
+ if (params_.generate_clear()) {
+ printer->Print(" clear();\n");
+ }
+ printer->Print("}\n");
+ } else {
+ if (params_.generate_clear()) {
+ printer->Print(
+ "\n"
+ "public $classname$() {\n"
+ " clear();\n"
+ "}\n",
+ "classname", descriptor_->name());
+ }
+ }
+
+ // Other methods in this class
+
+ GenerateClear(printer);
+
+ if (params_.generate_equals()) {
+ GenerateEquals(printer);
+ GenerateHashCode(printer);
+ }
+
+ GenerateMessageSerializationMethods(printer);
+ GenerateMergeFromMethods(printer);
+ GenerateParseFromMethods(printer);
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+// ===================================================================
+
+void MessageGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+ // Rely on the parent implementations of writeTo() and getSerializedSize()
+ // if there are no fields to serialize in this message.
+ if (descriptor_->field_count() == 0) {
+ return;
+ }
+
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
+ " throws java.io.IOException {\n");
+ printer->Indent();
+
+ // Output the fields in sorted order
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ GenerateSerializeOneField(printer, sorted_fields[i]);
+ }
+
+ // The parent implementation will write any unknown fields if necessary.
+ printer->Print(
+ "super.writeTo(output);\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+
+ // The parent implementation will get the serialized size for unknown
+ // fields if necessary.
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "protected int computeSerializedSize() {\n"
+ " int size = super.computeSerializedSize();\n");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " return size;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
+ scoped_array<const FieldDescriptor*> sorted_fields(
+ SortFieldsByNumber(descriptor_));
+
+ printer->Print(
+ "\n"
+ "@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");
+
+ printer->Indent();
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "if (!storeUnknownField(input, tag)) {\n"
+ " return this;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
+ " return this;\n" // it's an endgroup tag
+ "}\n");
+ }
+ printer->Print("break;\n");
+ printer->Outdent();
+ printer->Print("}\n");
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = sorted_fields[i];
+ uint32 tag = WireFormatLite::MakeTag(field->number(),
+ WireFormat::WireTypeForFieldType(field->type()));
+
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergingCode(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+
+ if (field->is_packable()) {
+ // To make packed = true wire compatible, we generate parsing code from a
+ // packed version of this field regardless of field->options().packed().
+ uint32 packed_tag = WireFormatLite::MakeTag(field->number(),
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ printer->Print(
+ "case $tag$: {\n",
+ "tag", SimpleItoa(packed_tag));
+ printer->Indent();
+
+ field_generators_.get(field).GenerateMergingCodeFromPacked(printer);
+
+ printer->Outdent();
+ printer->Print(
+ " break;\n"
+ "}\n");
+ }
+ }
+
+ printer->Outdent();
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n" // switch (tag)
+ " }\n" // while (true)
+ "}\n");
+}
+
+void MessageGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+ printer->Print(
+ "\n"
+ "public static $classname$ parseFrom(byte[] data)\n"
+ " throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
+ " return 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",
+ "classname", descriptor_->name());
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+ io::Printer* printer, const FieldDescriptor* field) {
+ field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void MessageGenerator::GenerateClear(io::Printer* printer) {
+ if (!params_.generate_clear()) {
+ return;
+ }
+ printer->Print(
+ "\n"
+ "public $classname$ clear() {\n",
+ "classname", descriptor_->name());
+ printer->Indent();
+
+ // Clear bit fields.
+ int totalInts = (field_generators_.total_bits() + 31) / 32;
+ for (int i = 0; i < totalInts; i++) {
+ printer->Print("$bit_field_name$ = 0;\n",
+ "bit_field_name", GetBitFieldName(i));
+ }
+
+ // Call clear for all of the fields.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateClearCode(printer);
+ }
+
+ // Clear unknown fields.
+ if (params_.store_unknown_fields()) {
+ printer->Print("unknownFieldData = null;\n");
+ }
+
+ printer->Outdent();
+ printer->Print(
+ " cachedSize = -1;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void MessageGenerator::GenerateEquals(io::Printer* printer) {
+ // Don't override if there are no fields. We could generate an
+ // equals method that compares types, but often empty messages
+ // are used as namespaces.
+ if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
+ return;
+ }
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public boolean equals(Object o) {\n");
+ printer->Indent();
+ printer->Print(
+ "if (o == this) {\n"
+ " return true;\n"
+ "}\n"
+ "if (!(o instanceof $classname$)) {\n"
+ " return false;\n"
+ "}\n"
+ "$classname$ other = ($classname$) o;\n",
+ "classname", descriptor_->name());
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateEqualsCode(printer);
+ }
+
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "return unknownFieldDataEquals(other);\n");
+ } else {
+ printer->Print(
+ "return true;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::GenerateHashCode(io::Printer* printer) {
+ if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) {
+ return;
+ }
+
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public int hashCode() {\n");
+ printer->Indent();
+
+ printer->Print("int result = 17;\n");
+ printer->Print("result = 31 * result + getClass().getName().hashCode();\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateHashCodeCode(printer);
+ }
+
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "result = 31 * result + unknownFieldDataHashCode();\n");
+ }
+
+ printer->Print("return result;\n");
+
+ printer->Outdent();
+ printer->Print("}\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..6f25a3a0
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message.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_JAVANANO_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__
+
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/stubs/common.h>
+
+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);
+ void GenerateEquals(io::Printer* printer);
+ void GenerateHashCode(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_JAVANANO_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..a46081d0
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -0,0 +1,259 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_message_field.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace 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<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(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, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+}
+
+void MessageFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = null;\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " this.$name$ = new $type$();\n"
+ "}\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup(this.$name$, $number$);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(this.$name$);\n");
+ }
+}
+
+void MessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " output.write$group_or_message$($number$, this.$name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$group_or_message$Size($number$, this.$name$);\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ == null) { \n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else {\n"
+ " if (!this.$name$.equals(other.$name$)) {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetMessageVariables(params, descriptor, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $type$.emptyArray();\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the length of the array, then parse.
+ printer->Print(variables_,
+ "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $tag$);\n"
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ "$type$[] newArray =\n"
+ " new $type$[i + arrayLength];\n"
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length - 1; i++) {\n"
+ " newArray[i] = new $type$();\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ " input.readGroup(newArray[i], $number$);\n");
+ } else {
+ printer->Print(variables_,
+ " input.readMessage(newArray[i]);\n");
+ }
+
+ printer->Print(variables_,
+ " input.readTag();\n"
+ "}\n"
+ "// Last one without readTag.\n"
+ "newArray[i] = new $type$();\n");
+
+ if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+ printer->Print(variables_,
+ "input.readGroup(newArray[i], $number$);\n");
+ } else {
+ printer->Print(variables_,
+ "input.readMessage(newArray[i]);\n");
+ }
+
+ printer->Print(variables_,
+ "this.$name$ = newArray;\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " output.write$group_or_message$($number$, element);\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n"
+ " for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$group_or_message$Size($number$, element);\n"
+ " }\n"
+ " }\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // 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..5d35fd24
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+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, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params);
+ ~RepeatedMessageFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_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..4691f360
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -0,0 +1,240 @@
+// 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 <map>
+#include <set>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+enum eMultipleFiles { JAVANANO_MUL_UNSET, JAVANANO_MUL_FALSE, JAVANANO_MUL_TRUE };
+
+// Parameters for used by the generators
+class Params {
+ public:
+ typedef map<string, string> NameMap;
+ typedef set<string> NameSet;
+ private:
+ string empty_;
+ string base_name_;
+ eMultipleFiles override_java_multiple_files_;
+ bool store_unknown_fields_;
+ NameMap java_packages_;
+ NameMap java_outer_classnames_;
+ NameSet java_multiple_files_;
+ bool generate_has_;
+ bool java_enum_style_;
+ bool optional_field_accessors_;
+ bool use_reference_types_for_primitives_;
+ bool generate_equals_;
+ bool ignore_services_;
+ bool parcelable_messages_;
+ bool reftypes_primitive_enums_;
+ bool generate_clear_;
+
+ public:
+ Params(const string & base_name) :
+ empty_(""),
+ base_name_(base_name),
+ override_java_multiple_files_(JAVANANO_MUL_UNSET),
+ store_unknown_fields_(false),
+ generate_has_(false),
+ java_enum_style_(false),
+ optional_field_accessors_(false),
+ use_reference_types_for_primitives_(false),
+ generate_equals_(false),
+ ignore_services_(false),
+ parcelable_messages_(false),
+ reftypes_primitive_enums_(false),
+ generate_clear_(true) {
+ }
+
+ 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_override_java_multiple_files(bool java_multiple_files) {
+ if (java_multiple_files) {
+ override_java_multiple_files_ = JAVANANO_MUL_TRUE;
+ } else {
+ override_java_multiple_files_ = JAVANANO_MUL_FALSE;
+ }
+ }
+ void clear_override_java_multiple_files() {
+ override_java_multiple_files_ = JAVANANO_MUL_UNSET;
+ }
+
+ void set_java_multiple_files(const string& file_name, bool value) {
+ if (value) {
+ java_multiple_files_.insert(file_name);
+ } else {
+ java_multiple_files_.erase(file_name);
+ }
+ }
+ bool java_multiple_files(const string& file_name) const {
+ switch (override_java_multiple_files_) {
+ case JAVANANO_MUL_FALSE:
+ return false;
+ case JAVANANO_MUL_TRUE:
+ return true;
+ default:
+ return java_multiple_files_.find(file_name)
+ != java_multiple_files_.end();
+ }
+ }
+
+ void set_store_unknown_fields(bool value) {
+ store_unknown_fields_ = value;
+ }
+ bool store_unknown_fields() const {
+ return store_unknown_fields_;
+ }
+
+ void set_generate_has(bool value) {
+ generate_has_ = value;
+ }
+ bool generate_has() const {
+ return generate_has_;
+ }
+
+ void set_java_enum_style(bool value) {
+ java_enum_style_ = value;
+ }
+ bool java_enum_style() const {
+ return java_enum_style_;
+ }
+
+ void set_optional_field_accessors(bool value) {
+ optional_field_accessors_ = value;
+ }
+ bool optional_field_accessors() const {
+ return optional_field_accessors_;
+ }
+
+ void set_use_reference_types_for_primitives(bool value) {
+ use_reference_types_for_primitives_ = value;
+ }
+ bool use_reference_types_for_primitives() const {
+ return use_reference_types_for_primitives_;
+ }
+
+ void set_generate_equals(bool value) {
+ generate_equals_ = value;
+ }
+ bool generate_equals() const {
+ return generate_equals_;
+ }
+
+ void set_ignore_services(bool value) {
+ ignore_services_ = value;
+ }
+ bool ignore_services() const {
+ return ignore_services_;
+ }
+
+ void set_parcelable_messages(bool value) {
+ parcelable_messages_ = value;
+ }
+ bool parcelable_messages() const {
+ return parcelable_messages_;
+ }
+
+ void set_reftypes_primitive_enums(bool value) {
+ reftypes_primitive_enums_ = value;
+ }
+ bool reftypes_primitive_enums() const {
+ return reftypes_primitive_enums_;
+ }
+
+ void set_generate_clear(bool value) {
+ generate_clear_ = value;
+ }
+ bool generate_clear() const {
+ return generate_clear_;
+ }
+};
+
+} // 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..a3bc3a84
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -0,0 +1,910 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <math.h>
+#include <string>
+
+#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+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<string, string>* variables) {
+ (*variables)["name"] =
+ RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ (*variables)["capitalized_name"] =
+ RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ if (params.use_reference_types_for_primitives()
+ && !descriptor->is_repeated()) {
+ (*variables)["type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+ } else {
+ (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+ }
+ // Deals with defaults. 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 static field and re-use that from
+ // then on.
+ if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
+ !descriptor->default_value_string().empty() &&
+ !params.use_reference_types_for_primitives()) {
+ if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+ (*variables)["default_constant_value"] = strings::Substitute(
+ "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")",
+ CEscape(descriptor->default_value_string()));
+ (*variables)["default_copy_if_needed"] =
+ (*variables)["default"] + ".clone()";
+ } else if (AllAscii(descriptor->default_value_string())) {
+ // All chars are ASCII. In this case directly referencing a
+ // CEscape()'d string literal works fine.
+ (*variables)["default"] =
+ "\"" + CEscape(descriptor->default_value_string()) + "\"";
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ } else {
+ // Strings where some chars are non-ASCII. We need to save the
+ // default value.
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_constant"] = FieldDefaultConstantName(descriptor);
+ (*variables)["default_constant_value"] = strings::Substitute(
+ "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")",
+ CEscape(descriptor->default_value_string()));
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ }
+ } else {
+ // Non-string, non-bytes field. Defaults are literals.
+ (*variables)["default"] = DefaultValue(params, descriptor);
+ (*variables)["default_copy_if_needed"] = (*variables)["default"];
+ }
+ (*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()));
+ (*variables)["non_packed_tag"] = SimpleItoa(
+ internal::WireFormatLite::MakeTag(descriptor->number(),
+ internal::WireFormat::WireTypeForFieldType(descriptor->type())));
+ 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() {}
+
+bool PrimitiveFieldGenerator::SavedDefaultNeeded() const {
+ return variables_.find("default_constant") != variables_.end();
+}
+
+void PrimitiveFieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ printer->Print(variables_,
+ "$default_constant$ = $default_constant_value$;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ // Those primitive types that need a saved default.
+ if (lazy_init) {
+ printer->Print(variables_,
+ "private static $type$ $default_constant$;\n");
+ } else {
+ printer->Print(variables_,
+ "private static final $type$ $default_constant$ =\n"
+ " $default_constant_value$;\n");
+ }
+ }
+
+ printer->Print(variables_,
+ "public $type$ $name$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "public boolean has$capitalized_name$;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default_copy_if_needed$;\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = false;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "this.$name$ = input.read$capitalized_type$();\n");
+
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "has$capitalized_name$ = true;\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationConditional(io::Printer* printer) const {
+ if (params_.use_reference_types_for_primitives()) {
+ // For reference type mode, serialize based on equality
+ // to null.
+ printer->Print(variables_,
+ "if (this.$name$ != null) {\n");
+ return;
+ }
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "if (has$capitalized_name$ || ");
+ } else {
+ printer->Print(variables_,
+ "if (");
+ }
+ JavaType java_type = GetJavaType(descriptor_);
+ if (IsArrayType(java_type)) {
+ printer->Print(variables_,
+ "!java.util.Arrays.equals(this.$name$, $default$)) {\n");
+ } else if (IsReferenceType(java_type)) {
+ printer->Print(variables_,
+ "!this.$name$.equals($default$)) {\n");
+ } else if (java_type == JAVATYPE_FLOAT) {
+ printer->Print(variables_,
+ "java.lang.Float.floatToIntBits(this.$name$)\n"
+ " != java.lang.Float.floatToIntBits($default$)) {\n");
+ } else if (java_type == JAVATYPE_DOUBLE) {
+ printer->Print(variables_,
+ "java.lang.Double.doubleToLongBits(this.$name$)\n"
+ " != java.lang.Double.doubleToLongBits($default$)) {\n");
+ } else {
+ printer->Print(variables_,
+ "this.$name$ != $default$) {\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ // Always serialize a required field if we don't have the 'has' signal.
+ printer->Print(variables_,
+ "output.write$capitalized_type$($number$, this.$name$);\n");
+ } else {
+ GenerateSerializationConditional(printer);
+ printer->Print(variables_,
+ " output.write$capitalized_type$($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ if (descriptor_->is_required() && !params_.generate_has()) {
+ printer->Print(variables_,
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, this.$name$);\n");
+ } else {
+ GenerateSerializationConditional(printer);
+ printer->Print(variables_,
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, this.$name$);\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ // We define equality as serialized form equality. If generate_has(),
+ // then if the field value equals the default value in both messages,
+ // but one's 'has' field is set and the other's is not, the serialized
+ // forms are different and we should return false.
+ JavaType java_type = GetJavaType(descriptor_);
+ if (java_type == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "if (!java.util.Arrays.equals(this.$name$, other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (java.util.Arrays.equals(this.$name$, $default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_STRING
+ || params_.use_reference_types_for_primitives()) {
+ printer->Print(variables_,
+ "if (this.$name$ == null) {\n"
+ " if (other.$name$ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else if (!this.$name$.equals(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$.equals($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_FLOAT) {
+ printer->Print(variables_,
+ "{\n"
+ " int bits = java.lang.Float.floatToIntBits(this.$name$);\n"
+ " if (bits != java.lang.Float.floatToIntBits(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (bits == java.lang.Float.floatToIntBits($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else if (java_type == JAVATYPE_DOUBLE) {
+ printer->Print(variables_,
+ "{\n"
+ " long bits = java.lang.Double.doubleToLongBits(this.$name$);\n"
+ " if (bits != java.lang.Double.doubleToLongBits(other.$name$)");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (bits == java.lang.Double.doubleToLongBits($default$)\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "if (this.$name$ != other.$name$");
+ if (params_.generate_has()) {
+ printer->Print(variables_,
+ "\n"
+ " || (this.$name$ == $default$\n"
+ " && this.has$capitalized_name$ != other.has$capitalized_name$)");
+ }
+ printer->Print(") {\n"
+ " return false;\n"
+ "}\n");
+ }
+}
+
+void PrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ JavaType java_type = GetJavaType(descriptor_);
+ if (java_type == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "result = 31 * result + java.util.Arrays.hashCode(this.$name$);\n");
+ } else if (java_type == JAVATYPE_STRING
+ || params_.use_reference_types_for_primitives()) {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + (this.$name$ == null ? 0 : this.$name$.hashCode());\n");
+ } else {
+ switch (java_type) {
+ // For all Java primitive types below, the hash codes match the
+ // results of BoxedType.valueOf(primitiveValue).hashCode().
+ case JAVATYPE_INT:
+ printer->Print(variables_,
+ "result = 31 * result + this.$name$;\n");
+ break;
+ case JAVATYPE_LONG:
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + (int) (this.$name$ ^ (this.$name$ >>> 32));\n");
+ break;
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + java.lang.Float.floatToIntBits(this.$name$);\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "{\n"
+ " long v = java.lang.Double.doubleToLongBits(this.$name$);\n"
+ " result = 31 * result + (int) (v ^ (v >>> 32));\n"
+ "}\n");
+ break;
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "result = 31 * result + (this.$name$ ? 1231 : 1237);\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+ }
+}
+
+// ===================================================================
+
+AccessorPrimitiveFieldGenerator::
+AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params& params, int has_bit_index)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+ SetBitOperationVariables("has", has_bit_index, &variables_);
+}
+
+AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {}
+
+bool AccessorPrimitiveFieldGenerator::SavedDefaultNeeded() const {
+ return variables_.find("default_constant") != variables_.end();
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateInitSavedDefaultCode(io::Printer* printer) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ printer->Print(variables_,
+ "$default_constant$ = $default_constant_value$;\n");
+ }
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool lazy_init) const {
+ if (variables_.find("default_constant") != variables_.end()) {
+ // Those primitive types that need a saved default.
+ if (lazy_init) {
+ printer->Print(variables_,
+ "private static $type$ $default_constant$;\n");
+ } else {
+ printer->Print(variables_,
+ "private static final $type$ $default_constant$ =\n"
+ " $default_constant_value$;\n");
+ }
+ }
+ printer->Print(variables_,
+ "private $type$ $name$_;\n"
+ "public $type$ get$capitalized_name$() {\n"
+ " return $name$_;\n"
+ "}\n"
+ "public $message_name$ set$capitalized_name$($type$ value) {\n");
+ if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ " if (value == null) {\n"
+ " throw new java.lang.NullPointerException();\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " $name$_ = value;\n"
+ " $set_has$;\n"
+ " return this;\n"
+ "}\n"
+ "public boolean has$capitalized_name$() {\n"
+ " return $get_has$;\n"
+ "}\n"
+ "public $message_name$ clear$capitalized_name$() {\n"
+ " $name$_ = $default_copy_if_needed$;\n"
+ " $clear_has$;\n"
+ " return this;\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = $default_copy_if_needed$;\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$_ = input.read$capitalized_type$();\n"
+ "$set_has$;\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " output.write$capitalized_type$($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($get_has$) {\n"
+ " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$Size($number$, $name$_);\n"
+ "}\n");
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ switch (GetJavaType(descriptor_)) {
+ // For all Java primitive types below, the equality checks match the
+ // results of BoxedType.valueOf(primitiveValue).equals(otherValue).
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || java.lang.Float.floatToIntBits($name$_)\n"
+ " != java.lang.Float.floatToIntBits(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || java.lang.Double.doubleToLongBits($name$_)\n"
+ " != java.lang.Double.doubleToLongBits(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_INT:
+ case JAVATYPE_LONG:
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || $name$_ != other.$name$_) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_STRING:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || !$name$_.equals(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ case JAVATYPE_BYTES:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "if ($different_has$\n"
+ " || !java.util.Arrays.equals($name$_, other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+}
+
+void AccessorPrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ switch (GetJavaType(descriptor_)) {
+ // For all Java primitive types below, the hash codes match the
+ // results of BoxedType.valueOf(primitiveValue).hashCode().
+ case JAVATYPE_INT:
+ printer->Print(variables_,
+ "result = 31 * result + $name$_;\n");
+ break;
+ case JAVATYPE_LONG:
+ printer->Print(variables_,
+ "result = 31 * result + (int) ($name$_ ^ ($name$_ >>> 32));\n");
+ break;
+ case JAVATYPE_FLOAT:
+ printer->Print(variables_,
+ "result = 31 * result +\n"
+ " java.lang.Float.floatToIntBits($name$_);\n");
+ break;
+ case JAVATYPE_DOUBLE:
+ printer->Print(variables_,
+ "{\n"
+ " long v = java.lang.Double.doubleToLongBits($name$_);\n"
+ " result = 31 * result + (int) (v ^ (v >>> 32));\n"
+ "}\n");
+ break;
+ case JAVATYPE_BOOLEAN:
+ printer->Print(variables_,
+ "result = 31 * result + ($name$_ ? 1231 : 1237);\n");
+ break;
+ case JAVATYPE_STRING:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "result = 31 * result + $name$_.hashCode();\n");
+ break;
+ case JAVATYPE_BYTES:
+ // Accessor style would guarantee $name$_ non-null
+ printer->Print(variables_,
+ "result = 31 * result + java.util.Arrays.hashCode($name$_);\n");
+ break;
+ default:
+ GOOGLE_LOG(ERROR) << "unknown java type for primitive field";
+ break;
+ }
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : FieldGenerator(params), descriptor_(descriptor) {
+ SetPrimitiveVariables(descriptor, params, &variables_);
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer, bool /*unused init_defaults*/) const {
+ printer->Print(variables_,
+ "public $type$[] $name$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateClearCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "$name$ = $default$;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ // First, figure out the length of the array, then parse.
+ printer->Print(variables_,
+ "int arrayLength = com.google.protobuf.nano.WireFormatNano\n"
+ " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n"
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n");
+
+ if (GetJavaType(descriptor_) == JAVATYPE_BYTES) {
+ printer->Print(variables_,
+ "byte[][] newArray = new byte[i + arrayLength][];\n");
+ } else {
+ printer->Print(variables_,
+ "$type$[] newArray = new $type$[i + arrayLength];\n");
+ }
+ printer->Print(variables_,
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length - 1; i++) {\n"
+ " newArray[i] = input.read$capitalized_type$();\n"
+ " input.readTag();\n"
+ "}\n"
+ "// Last one without readTag.\n"
+ "newArray[i] = input.read$capitalized_type$();\n"
+ "this.$name$ = newArray;\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCodeFromPacked(io::Printer* printer) const {
+ printer->Print(
+ "int length = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(length);\n");
+
+ // If we know the elements will all be of the same size, the arrayLength
+ // can be calculated much more easily. However, FixedSize() returns 1 for
+ // repeated bool fields, which are guaranteed to have the fixed size of
+ // 1 byte per value only if we control the output. On the wire they can
+ // legally appear as variable-size integers, so we need to use the slow
+ // way for repeated bool fields.
+ if (descriptor_->type() == FieldDescriptor::TYPE_BOOL
+ || FixedSize(descriptor_->type()) == -1) {
+ printer->Print(variables_,
+ "// 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");
+ } else {
+ printer->Print(variables_,
+ "int arrayLength = length / $fixed_size$;\n");
+ }
+
+ printer->Print(variables_,
+ "int i = this.$name$ == null ? 0 : this.$name$.length;\n"
+ "$type$[] newArray = new $type$[i + arrayLength];\n"
+ "if (i != 0) {\n"
+ " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
+ "}\n"
+ "for (; i < newArray.length; i++) {\n"
+ " newArray[i] = input.read$capitalized_type$();\n"
+ "}\n"
+ "this.$name$ = newArray;\n"
+ "input.popLimit(limit);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateRepeatedDataSizeCode(io::Printer* printer) const {
+ // Creates a variable dataSize and puts the serialized size in there.
+ // If the element type is a Java reference type, also generates
+ // dataCount which stores the number of non-null elements in the field.
+ if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "int dataCount = 0;\n"
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " dataCount++;\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$SizeNoTag(element);\n"
+ " }\n"
+ "}\n");
+ } else if (FixedSize(descriptor_->type()) == -1) {
+ printer->Print(variables_,
+ "int dataSize = 0;\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .compute$capitalized_type$SizeNoTag(element);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "int dataSize = $fixed_size$ * this.$name$.length;\n");
+ }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ if (descriptor_->is_packable() && descriptor_->options().packed()) {
+ GenerateRepeatedDataSizeCode(printer);
+ printer->Print(variables_,
+ "output.writeRawVarint32($tag$);\n"
+ "output.writeRawVarint32(dataSize);\n"
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.write$capitalized_type$NoTag(this.$name$[i]);\n"
+ "}\n");
+ } else if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " $type$ element = this.$name$[i];\n"
+ " if (element != null) {\n"
+ " output.write$capitalized_type$($number$, element);\n"
+ " }\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for (int i = 0; i < this.$name$.length; i++) {\n"
+ " output.write$capitalized_type$($number$, this.$name$[i]);\n"
+ "}\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (this.$name$ != null && this.$name$.length > 0) {\n");
+ printer->Indent();
+
+ GenerateRepeatedDataSizeCode(printer);
+
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->is_packable() && descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "size += $tag_size$;\n"
+ "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
+ " .computeRawVarint32Size(dataSize);\n");
+ } else if (IsReferenceType(GetJavaType(descriptor_))) {
+ printer->Print(variables_,
+ "size += $tag_size$ * dataCount;\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * this.$name$.length;\n");
+ }
+
+ printer->Outdent();
+
+ printer->Print(
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if (!com.google.protobuf.nano.InternalNano.equals(\n"
+ " this.$name$, other.$name$)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result\n"
+ " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
+}
+
+} // 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..c04a19b7
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -0,0 +1,126 @@
+// 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 <map>
+#include <string>
+#include <google/protobuf/compiler/javanano/javanano_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit PrimitiveFieldGenerator(
+ const FieldDescriptor* descriptor, const Params &params);
+ ~PrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ bool SavedDefaultNeeded() const;
+ void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateSerializationConditional(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class AccessorPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor,
+ const Params &params, int has_bit_index);
+ ~AccessorPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ bool SavedDefaultNeeded() const;
+ void GenerateInitSavedDefaultCode(io::Printer* printer) const;
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+ explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+ ~RepeatedPrimitiveFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GenerateMembers(io::Printer* printer, bool lazy_init) const;
+ void GenerateClearCode(io::Printer* printer) const;
+ void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateMergingCodeFromPacked(io::Printer* printer) const;
+ void GenerateSerializationCode(io::Printer* printer) const;
+ void GenerateSerializedSizeCode(io::Printer* printer) const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
+
+ private:
+ void GenerateRepeatedDataSizeCode(io::Printer* printer) const;
+
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__