From 23f148138654a564b5690f6a5453aab480a6a049 Mon Sep 17 00:00:00 2001 From: Mike Kruskal Date: Mon, 10 Oct 2022 21:05:53 -0700 Subject: [PATCH] Sync from Piper @480194141 PROTOBUF_SYNC_PIPER --- .gitmodules | 3 + CHANGES.txt | 17 + conformance/third_party/jsoncpp/json.h | 2075 ------- conformance/third_party/jsoncpp/jsoncpp.cpp | 5192 ----------------- .../google/protobuf/CanIgnoreReturnValue.java | 3 +- .../com/google/protobuf/proto2_message.proto | 1 - .../google/protobuf/proto2_message_lite.proto | 1 - kokoro/linux/32-bit/test_php.sh | 2 +- objectivec/.clang-format | 6 - pkg/BUILD.bazel | 16 + protobuf.bzl | 22 +- python/BUILD.bazel | 9 +- python/google/protobuf/internal/field_mask.py | 333 ++ .../protobuf/internal/field_mask_test.py | 400 ++ .../internal/missing_enum_values.proto | 2 - .../protobuf/internal/well_known_types.py | 304 +- .../internal/well_known_types_test.py | 360 -- python/mox.py | 1401 ----- python/stubout.py | 143 - src/file_lists.cmake | 29 +- src/google/protobuf/BUILD.bazel | 2 + src/google/protobuf/any.proto | 1 - src/google/protobuf/api.proto | 1 - src/google/protobuf/arenastring.cc | 1 - .../compiler/command_line_interface.cc | 6 +- .../compiler/cpp/bootstrap_unittest.cc | 1 - .../protobuf/compiler/cpp/cpp_generator.h | 30 + .../compiler/cpp/parse_function_generator.cc | 33 +- src/google/protobuf/compiler/cpp/unittest.inc | 82 +- .../csharp/csharp_bootstrap_unittest.cc | 1 - .../protobuf/compiler/java/java_generator.h | 30 + .../protobuf/compiler/objectivec/enum.cc | 96 +- .../protobuf/compiler/objectivec/enum.h | 3 +- .../compiler/objectivec/enum_field.cc | 20 +- .../protobuf/compiler/objectivec/enum_field.h | 1 + .../protobuf/compiler/objectivec/extension.cc | 45 +- .../protobuf/compiler/objectivec/field.cc | 77 +- .../protobuf/compiler/objectivec/field.h | 25 +- .../protobuf/compiler/objectivec/file.cc | 128 +- .../protobuf/compiler/objectivec/file.h | 4 +- .../protobuf/compiler/objectivec/generator.cc | 33 +- .../protobuf/compiler/objectivec/generator.h | 1 + .../protobuf/compiler/objectivec/helpers.cc | 26 +- .../protobuf/compiler/objectivec/helpers.h | 26 +- .../compiler/objectivec/import_writer.cc | 82 +- .../compiler/objectivec/import_writer.h | 9 +- .../compiler/objectivec/line_consumer.cc | 26 +- .../compiler/objectivec/line_consumer.h | 3 +- .../objectivec/line_consumer_unittest.cc | 92 +- .../protobuf/compiler/objectivec/map_field.cc | 26 +- .../protobuf/compiler/objectivec/message.cc | 103 +- .../protobuf/compiler/objectivec/message.h | 3 +- .../compiler/objectivec/message_field.cc | 27 +- .../compiler/objectivec/message_field.h | 3 +- .../protobuf/compiler/objectivec/names.cc | 426 +- .../protobuf/compiler/objectivec/names.h | 16 +- .../compiler/objectivec/names_unittest.cc | 3 +- .../compiler/objectivec/nsobject_methods.h | 378 +- .../protobuf/compiler/objectivec/oneof.cc | 30 +- .../compiler/objectivec/primitive_field.cc | 2 +- .../compiler/objectivec/primitive_field.h | 3 +- .../objectivec/text_format_decode_data.cc | 27 +- .../objectivec/text_format_decode_data.h | 1 - .../text_format_decode_data_unittest.cc | 1 - src/google/protobuf/compiler/plugin.proto | 1 - .../compiler/python/python_generator.h | 30 + src/google/protobuf/descriptor.proto | 14 - src/google/protobuf/descriptor_database.cc | 1 - src/google/protobuf/duration.proto | 1 - src/google/protobuf/extension_set_unittest.cc | 9 +- .../protobuf/generated_message_reflection.cc | 2 +- .../protobuf/generated_message_tctable_decl.h | 6 +- .../protobuf/generated_message_tctable_gen.cc | 17 +- .../protobuf/generated_message_tctable_impl.h | 1 + src/google/protobuf/io/tokenizer.cc | 1 - .../protobuf/io/zero_copy_stream_impl.cc | 1 - .../protobuf/io/zero_copy_stream_impl_lite.h | 15 - src/google/protobuf/json/BUILD.bazel | 11 +- src/google/protobuf/lite_unittest.cc | 5 +- src/google/protobuf/map_test.inc | 10 +- src/google/protobuf/map_unittest.proto | 1 - src/google/protobuf/message.cc | 1 - .../protobuf/repeated_field_unittest.cc | 1 - src/google/protobuf/stubs/BUILD.bazel | 2 - src/google/protobuf/stubs/callback.h | 30 + src/google/protobuf/stubs/stl_util.h | 68 - src/google/protobuf/stubs/strutil.cc | 6 +- src/google/protobuf/stubs/strutil_unittest.cc | 1 - src/google/protobuf/text_format.cc | 1 - src/google/protobuf/timestamp.proto | 3 - src/google/protobuf/unittest.proto | 5 - src/google/protobuf/unittest_import.proto | 1 - .../protobuf/unknown_field_set_unittest.cc | 7 +- src/google/protobuf/util/json_format.proto | 2 - .../protobuf/util/message_differencer.h | 14 +- .../util/message_differencer_unittest.cc | 3 + .../protobuf/well_known_types_unittest.cc | 1 - src/google/protobuf/wire_format_unittest.inc | 7 +- third_party/jsoncpp | 1 + third_party/jsoncpp.BUILD | 37 + 100 files changed, 2088 insertions(+), 10482 deletions(-) delete mode 100644 conformance/third_party/jsoncpp/json.h delete mode 100644 conformance/third_party/jsoncpp/jsoncpp.cpp create mode 100644 python/google/protobuf/internal/field_mask.py create mode 100644 python/google/protobuf/internal/field_mask_test.py delete mode 100755 python/mox.py delete mode 100755 python/stubout.py delete mode 100644 src/google/protobuf/stubs/stl_util.h create mode 160000 third_party/jsoncpp create mode 100644 third_party/jsoncpp.BUILD diff --git a/.gitmodules b/.gitmodules index e05b57bfbc..7a46a17f1a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = third_party/abseil-cpp url = https://github.com/abseil/abseil-cpp.git branch = lts_2022_06_23 +[submodule "third_party/jsoncpp"] + path = third_party/jsoncpp + url = https://github.com/open-source-parsers/jsoncpp.git diff --git a/CHANGES.txt b/CHANGES.txt index ff30066758..4d9d344336 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -26,6 +26,17 @@ * Save code space by avoiding inlining of large-in-aggregate code-space MessageLite::~MessageLite destructor. * Breaking change: delete Arena::Init * Make a PROTOBUF_POISON/UNPOISON to reduce noise in the source + * Put alignment functions in "arena_align.h" + * Split off `cleanup` arena functions into "arena_cleanup.h" + * Fix signed / unsigned match in CHECK_EQ + * Kill Atomic<>. it's not pulling it's weight + * Move AllocationPolicy out of arena_impl, and unify arena_config for bazel + * Fix failure case in table-driven parser. + * Add a new JSON parser. + * Removed old JSON parsing code. + * Introduce the Printer::{SetRedactDebugString,SetRandomizeDebugString} private flags. + * Introduce global flags to control Printer::{SetRedactDebugString, SetRandomizeDebugString}. + * proto3 string fields no longer trigger clang-tidy warning bugprone-branch-clone. Kotlin @@ -41,11 +52,17 @@ * More thoroughly annotate public generated code in Java lite protocol buffers. * Fixed Bug in proto3 java lite repeated enum fields. Failed to call copyOnWrite before modifying previously built message. Causes modification to already "built" messages that should be immutable. * Fix Java reflection serialization of empty packed fields. + * Refactoring java full runtime to reuse sub-message builders and prepare to migrate parsing logic from parse constructor to builder. + * Fix TextFormat parser to build up recurring (but supposedly not repeated) sub-messages directly from text rather than building a new sub-message and merging the fully formed message into the existing field. + * Make message-type extensions merge from wire-format instead of building up instances and merging afterwards. This has much better performance. + * Change the Lite runtime to prefer merging from the wireformat into mutable messages rather than building up a new immutable object before merging. This way results in fewer allocations and copy operations. + * Move proto wireformat parsing functionality from the private "parsing constructor" to the Builder class. Python * Changes ordering of printed fields in .pyi files from lexicographic to the same ordering found in the proto descriptor. * Adds GeneratedCodeInfo annotations to python proto .pyi outputs as a base64 encoded docstring in the last line of the .pyi file for code analysis tools. * Fix message factory's behavior in python cpp extension to return same message classes for same descriptor, even if the factories are different. + * Add type annotation for enum value fields in enum classes. Compiler * Print full path name of source .proto file on error diff --git a/conformance/third_party/jsoncpp/json.h b/conformance/third_party/jsoncpp/json.h deleted file mode 100644 index 373ec98bde..0000000000 --- a/conformance/third_party/jsoncpp/json.h +++ /dev/null @@ -1,2075 +0,0 @@ -/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - -#ifndef JSON_AMALGATED_H_INCLUDED -# define JSON_AMALGATED_H_INCLUDED -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -#define JSON_IS_AMALGAMATION - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - -// DO NOT EDIT. This file (and "version") is generated by CMake. -// Run CMake configure step to update it. -#ifndef JSON_VERSION_H_INCLUDED -# define JSON_VERSION_H_INCLUDED - -# define JSONCPP_VERSION_STRING "1.6.5" -# define JSONCPP_VERSION_MAJOR 1 -# define JSONCPP_VERSION_MINOR 6 -# define JSONCPP_VERSION_PATCH 5 -# define JSONCPP_VERSION_QUALIFIER -# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) - -#endif // JSON_VERSION_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/version.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_CONFIG_H_INCLUDED -#define JSON_CONFIG_H_INCLUDED - -/// If defined, indicates that json library is embedded in CppTL library. -//# define JSON_IN_CPPTL 1 - -/// If defined, indicates that json may leverage CppTL library -//# define JSON_USE_CPPTL 1 -/// If defined, indicates that cpptl vector based map should be used instead of -/// std::map -/// as Value container. -//# define JSON_USE_CPPTL_SMALLMAP 1 - -// If non-zero, the library uses exceptions to report bad input instead of C -// assertion macros. The default is to use exceptions. -#ifndef JSON_USE_EXCEPTION -#define JSON_USE_EXCEPTION 1 -#endif - -/// If defined, indicates that the source file is amalgated -/// to prevent private header inclusion. -/// Remarks: it is automatically defined in the generated amalgated header. -// #define JSON_IS_AMALGAMATION - -#ifdef JSON_IN_CPPTL -#include -#ifndef JSON_USE_CPPTL -#define JSON_USE_CPPTL 1 -#endif -#endif - -#ifdef JSON_IN_CPPTL -#define JSON_API CPPTL_API -#elif defined(JSON_DLL_BUILD) -#if defined(_MSC_VER) -#define JSON_API __declspec(dllexport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#elif defined(JSON_DLL) -#if defined(_MSC_VER) -#define JSON_API __declspec(dllimport) -#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING -#endif // if defined(_MSC_VER) -#endif // ifdef JSON_IN_CPPTL -#if !defined(JSON_API) -#define JSON_API -#endif - -// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for -// integer -// Storages, and 64 bits integer support is disabled. -// #define JSON_NO_INT64 1 - -#if defined(_MSC_VER) // MSVC -# if _MSC_VER <= 1200 // MSVC 6 - // Microsoft Visual Studio 6 only support conversion from __int64 to double - // (no conversion from unsigned __int64). -# define JSON_USE_INT64_DOUBLE_CONVERSION 1 - // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' - // characters in the debug information) - // All projects I've ever seen with VS6 were using this globally (not bothering - // with pragma push/pop). -# pragma warning(disable : 4786) -# endif // MSVC 6 - -# if _MSC_VER >= 1500 // MSVC 2008 - /// Indicates that the following function is deprecated. -# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) -# endif - -#endif // defined(_MSC_VER) - - -#ifndef JSON_HAS_RVALUE_REFERENCES - -#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // MSVC >= 2010 - -#ifdef __clang__ -#if __has_feature(cxx_rvalue_references) -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // has_feature - -#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) -#define JSON_HAS_RVALUE_REFERENCES 1 -#endif // GXX_EXPERIMENTAL - -#endif // __clang__ || __GNUC__ - -#endif // not defined JSON_HAS_RVALUE_REFERENCES - -#ifndef JSON_HAS_RVALUE_REFERENCES -#define JSON_HAS_RVALUE_REFERENCES 0 -#endif - -#ifdef __clang__ -#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) -# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) -# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) -# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) -# endif // GNUC version -#endif // __clang__ || __GNUC__ - -#if !defined(JSONCPP_DEPRECATED) -#define JSONCPP_DEPRECATED(message) -#endif // if !defined(JSONCPP_DEPRECATED) - -namespace Json { -typedef int Int; -typedef unsigned int UInt; -#if defined(JSON_NO_INT64) -typedef int LargestInt; -typedef unsigned int LargestUInt; -#undef JSON_HAS_INT64 -#else // if defined(JSON_NO_INT64) -// For Microsoft Visual use specific types as long long is not supported -#if defined(_MSC_VER) // Microsoft Visual Studio -typedef __int64 Int64; -typedef unsigned __int64 UInt64; -#else // if defined(_MSC_VER) // Other platforms, use long long -typedef long long int Int64; -typedef unsigned long long int UInt64; -#endif // if defined(_MSC_VER) -typedef Int64 LargestInt; -typedef UInt64 LargestUInt; -#define JSON_HAS_INT64 -#endif // if defined(JSON_NO_INT64) -} // end namespace Json - -#endif // JSON_CONFIG_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/config.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_FORWARDS_H_INCLUDED -#define JSON_FORWARDS_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -// writer.h -class FastWriter; -class StyledWriter; - -// reader.h -class Reader; - -// features.h -class Features; - -// value.h -typedef unsigned int ArrayIndex; -class StaticString; -class Path; -class PathArgument; -class Value; -class ValueIteratorBase; -class ValueIterator; -class ValueConstIterator; - -} // namespace Json - -#endif // JSON_FORWARDS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/forwards.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_FEATURES_H_INCLUDED -#define CPPTL_JSON_FEATURES_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -/** \brief Configuration passed to reader and writer. - * This configuration object can be used to force the Reader or Writer - * to behave in a standard conforming way. - */ -class JSON_API Features { -public: - /** \brief A configuration that allows all features and assumes all strings - * are UTF-8. - * - C & C++ comments are allowed - * - Root object can be any JSON value - * - Assumes Value strings are encoded in UTF-8 - */ - static Features all(); - - /** \brief A configuration that is strictly compatible with the JSON - * specification. - * - Comments are forbidden. - * - Root object must be either an array or an object value. - * - Assumes Value strings are encoded in UTF-8 - */ - static Features strictMode(); - - /** \brief Initialize the configuration like JsonConfig::allFeatures; - */ - Features(); - - /// \c true if comments are allowed. Default: \c true. - bool allowComments_; - - /// \c true if root must be either an array or an object value. Default: \c - /// false. - bool strictRoot_; - - /// \c true if dropped null placeholders are allowed. Default: \c false. - bool allowDroppedNullPlaceholders_; - - /// \c true if numeric object key are allowed. Default: \c false. - bool allowNumericKeys_; -}; - -} // namespace Json - -#endif // CPPTL_JSON_FEATURES_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/features.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_H_INCLUDED -#define CPPTL_JSON_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "forwards.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include - -#ifndef JSON_USE_CPPTL_SMALLMAP -#include -#else -#include -#endif -#ifdef JSON_USE_CPPTL -#include -#endif - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -/** \brief JSON (JavaScript Object Notation). - */ -namespace Json { - -/** Base class for all exceptions we throw. - * - * We use nothing but these internally. Of course, STL can throw others. - */ -class JSON_API Exception : public std::exception { -public: - Exception(std::string const& msg); - ~Exception() throw() override; - char const* what() const throw() override; -protected: - std::string msg_; -}; - -/** Exceptions which the user cannot easily avoid. - * - * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input - * - * \remark derived from Json::Exception - */ -class JSON_API RuntimeError : public Exception { -public: - RuntimeError(std::string const& msg); -}; - -/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. - * - * These are precondition-violations (user bugs) and internal errors (our bugs). - * - * \remark derived from Json::Exception - */ -class JSON_API LogicError : public Exception { -public: - LogicError(std::string const& msg); -}; - -/// used internally -void throwRuntimeError(std::string const& msg); -/// used internally -void throwLogicError(std::string const& msg); - -/** \brief Type of the value held by a Value object. - */ -enum ValueType { - nullValue = 0, ///< 'null' value - intValue, ///< signed integer value - uintValue, ///< unsigned integer value - realValue, ///< double value - stringValue, ///< UTF-8 string value - booleanValue, ///< bool value - arrayValue, ///< array value (ordered list) - objectValue ///< object value (collection of name/value pairs). -}; - -enum CommentPlacement { - commentBefore = 0, ///< a comment placed on the line before a value - commentAfterOnSameLine, ///< a comment just after a value on the same line - commentAfter, ///< a comment on the line after a value (only make sense for - /// root value) - numberOfCommentPlacement -}; - -//# ifdef JSON_USE_CPPTL -// typedef CppTL::AnyEnumerator EnumMemberNames; -// typedef CppTL::AnyEnumerator EnumValues; -//# endif - -/** \brief Lightweight wrapper to tag static string. - * - * Value constructor and objectValue member assignement takes advantage of the - * StaticString and avoid the cost of string duplication when storing the - * string or the member name. - * - * Example of usage: - * \code - * Json::Value aValue( StaticString("some text") ); - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ -class JSON_API StaticString { -public: - explicit StaticString(const char* czstring) : c_str_(czstring) {} - - operator const char*() const { return c_str_; } - - const char* c_str() const { return c_str_; } - -private: - const char* c_str_; -}; - -/** \brief Represents a JSON value. - * - * This class is a discriminated union wrapper that can represents a: - * - signed integer [range: Value::minInt - Value::maxInt] - * - unsigned integer (range: 0 - Value::maxUInt) - * - double - * - UTF-8 string - * - boolean - * - 'null' - * - an ordered list of Value - * - collection of name/value pairs (javascript object) - * - * The type of the held value is represented by a #ValueType and - * can be obtained using type(). - * - * Values of an #objectValue or #arrayValue can be accessed using operator[]() - * methods. - * Non-const methods will automatically create the a #nullValue element - * if it does not exist. - * The sequence of an #arrayValue will be automatically resized and initialized - * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. - * - * The get() methods can be used to obtain default value in the case the - * required element does not exist. - * - * It is possible to iterate over the list of a #objectValue values using - * the getMemberNames() method. - * - * \note #Value string-length fit in size_t, but keys must be < 2^30. - * (The reason is an implementation detail.) A #CharReader will raise an - * exception if a bound is exceeded to avoid security holes in your app, - * but the Value API does *not* check bounds. That is the responsibility - * of the caller. - */ -class JSON_API Value { - friend class ValueIteratorBase; -public: - typedef std::vector Members; - typedef ValueIterator iterator; - typedef ValueConstIterator const_iterator; - typedef Json::UInt UInt; - typedef Json::Int Int; -#if defined(JSON_HAS_INT64) - typedef Json::UInt64 UInt64; - typedef Json::Int64 Int64; -#endif // defined(JSON_HAS_INT64) - typedef Json::LargestInt LargestInt; - typedef Json::LargestUInt LargestUInt; - typedef Json::ArrayIndex ArrayIndex; - - static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). - static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null - /// Minimum signed integer value that can be stored in a Json::Value. - static const LargestInt minLargestInt; - /// Maximum signed integer value that can be stored in a Json::Value. - static const LargestInt maxLargestInt; - /// Maximum unsigned integer value that can be stored in a Json::Value. - static const LargestUInt maxLargestUInt; - - /// Minimum signed int value that can be stored in a Json::Value. - static const Int minInt; - /// Maximum signed int value that can be stored in a Json::Value. - static const Int maxInt; - /// Maximum unsigned int value that can be stored in a Json::Value. - static const UInt maxUInt; - -#if defined(JSON_HAS_INT64) - /// Minimum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 minInt64; - /// Maximum signed 64 bits int value that can be stored in a Json::Value. - static const Int64 maxInt64; - /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. - static const UInt64 maxUInt64; -#endif // defined(JSON_HAS_INT64) - -private: -#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - class CZString { - public: - enum DuplicationPolicy { - noDuplication = 0, - duplicate, - duplicateOnCopy - }; - CZString(ArrayIndex index); - CZString(char const* str, unsigned length, DuplicationPolicy allocate); - CZString(CZString const& other); -#if JSON_HAS_RVALUE_REFERENCES - CZString(CZString&& other); -#endif - ~CZString(); - CZString& operator=(CZString other); - bool operator<(CZString const& other) const; - bool operator==(CZString const& other) const; - ArrayIndex index() const; - //const char* c_str() const; ///< \deprecated - char const* data() const; - unsigned length() const; - bool isStaticString() const; - - private: - void swap(CZString& other); - - struct StringStorage { - unsigned policy_: 2; - unsigned length_: 30; // 1GB max - }; - - char const* cstr_; // actually, a prefixed string, unless policy is noDup - union { - ArrayIndex index_; - StringStorage storage_; - }; - }; - -public: -#ifndef JSON_USE_CPPTL_SMALLMAP - typedef std::map ObjectValues; -#else - typedef CppTL::SmallMap ObjectValues; -#endif // ifndef JSON_USE_CPPTL_SMALLMAP -#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION - -public: - /** \brief Create a default Value of the given type. - - This is a very useful constructor. - To create an empty array, pass arrayValue. - To create an empty object, pass objectValue. - Another Value can then be set to this one by assignment. -This is useful since clear() and resize() will not alter types. - - Examples: -\code -Json::Value null_value; // null -Json::Value arr_value(Json::arrayValue); // [] -Json::Value obj_value(Json::objectValue); // {} -\endcode - */ - Value(ValueType type = nullValue); - Value(Int value); - Value(UInt value); -#if defined(JSON_HAS_INT64) - Value(Int64 value); - Value(UInt64 value); -#endif // if defined(JSON_HAS_INT64) - Value(double value); - Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) - Value(const char* begin, const char* end); ///< Copy all, incl zeroes. - /** \brief Constructs a value from a static string. - - * Like other value string constructor but do not duplicate the string for - * internal storage. The given string must remain alive after the call to this - * constructor. - * \note This works only for null-terminated strings. (We cannot change the - * size of this class, so we have nowhere to store the length, - * which might be computed later for various operations.) - * - * Example of usage: - * \code - * static StaticString foo("some text"); - * Json::Value aValue(foo); - * \endcode - */ - Value(const StaticString& value); - Value(const std::string& value); ///< Copy data() til size(). Embedded zeroes too. -#ifdef JSON_USE_CPPTL - Value(const CppTL::ConstString& value); -#endif - Value(bool value); - /// Deep copy. - Value(const Value& other); -#if JSON_HAS_RVALUE_REFERENCES - /// Move constructor - Value(Value&& other); -#endif - ~Value(); - - /// Deep copy, then swap(other). - /// \note Over-write existing comments. To preserve comments, use #swapPayload(). - Value& operator=(Value other); - /// Swap everything. - void swap(Value& other); - /// Swap values but leave comments and source offsets in place. - void swapPayload(Value& other); - - ValueType type() const; - - /// Compare payload only, not comments etc. - bool operator<(const Value& other) const; - bool operator<=(const Value& other) const; - bool operator>=(const Value& other) const; - bool operator>(const Value& other) const; - bool operator==(const Value& other) const; - bool operator!=(const Value& other) const; - int compare(const Value& other) const; - - const char* asCString() const; ///< Embedded zeroes could cause you trouble! - std::string asString() const; ///< Embedded zeroes are possible. - /** Get raw char* of string-value. - * \return false if !string. (Seg-fault if str or end are NULL.) - */ - bool getString( - char const** begin, char const** end) const; -#ifdef JSON_USE_CPPTL - CppTL::ConstString asConstString() const; -#endif - Int asInt() const; - UInt asUInt() const; -#if defined(JSON_HAS_INT64) - Int64 asInt64() const; - UInt64 asUInt64() const; -#endif // if defined(JSON_HAS_INT64) - LargestInt asLargestInt() const; - LargestUInt asLargestUInt() const; - float asFloat() const; - double asDouble() const; - bool asBool() const; - - bool isNull() const; - bool isBool() const; - bool isInt() const; - bool isInt64() const; - bool isUInt() const; - bool isUInt64() const; - bool isIntegral() const; - bool isDouble() const; - bool isNumeric() const; - bool isString() const; - bool isArray() const; - bool isObject() const; - - bool isConvertibleTo(ValueType other) const; - - /// Number of values in array or object - ArrayIndex size() const; - - /// \brief Return true if empty array, empty object, or null; - /// otherwise, false. - bool empty() const; - - /// Return isNull() - bool operator!() const; - - /// Remove all object members and array elements. - /// \pre type() is arrayValue, objectValue, or nullValue - /// \post type() is unchanged - void clear(); - - /// Resize the array to size elements. - /// New elements are initialized to null. - /// May only be called on nullValue or arrayValue. - /// \pre type() is arrayValue or nullValue - /// \post type() is arrayValue - void resize(ArrayIndex size); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are - /// inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](ArrayIndex index); - - /// Access an array element (zero based index ). - /// If the array contains less than index element, then null value are - /// inserted - /// in the array so that its size is index+1. - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - Value& operator[](int index); - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](ArrayIndex index) const; - - /// Access an array element (zero based index ) - /// (You may need to say 'value[0u]' to get your compiler to distinguish - /// this from the operator[] which takes a string.) - const Value& operator[](int index) const; - - /// If the array contains at least index+1 elements, returns the element - /// value, - /// otherwise returns defaultValue. - Value get(ArrayIndex index, const Value& defaultValue) const; - /// Return true if index < size(). - bool isValidIndex(ArrayIndex index) const; - /// \brief Append value to array at the end. - /// - /// Equivalent to jsonvalue[jsonvalue.size()] = value; - Value& append(const Value& value); - - /// Access an object value by name, create a null member if it does not exist. - /// \note Because of our implementation, keys are limited to 2^30 -1 chars. - /// Exceeding that will cause an exception. - Value& operator[](const char* key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const char* key) const; - /// Access an object value by name, create a null member if it does not exist. - /// \param key may contain embedded nulls. - Value& operator[](const std::string& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - /// \param key may contain embedded nulls. - const Value& operator[](const std::string& key) const; - /** \brief Access an object value by name, create a null member if it does not - exist. - - * If the object has no entry for that name, then the member name used to store - * the new entry is not duplicated. - * Example of use: - * \code - * Json::Value object; - * static const StaticString code("code"); - * object[code] = 1234; - * \endcode - */ - Value& operator[](const StaticString& key); -#ifdef JSON_USE_CPPTL - /// Access an object value by name, create a null member if it does not exist. - Value& operator[](const CppTL::ConstString& key); - /// Access an object value by name, returns null if there is no member with - /// that name. - const Value& operator[](const CppTL::ConstString& key) const; -#endif - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const char* key, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \note key may contain embedded nulls. - Value get(const char* begin, const char* end, const Value& defaultValue) const; - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - /// \param key may contain embedded nulls. - Value get(const std::string& key, const Value& defaultValue) const; -#ifdef JSON_USE_CPPTL - /// Return the member named key if it exist, defaultValue otherwise. - /// \note deep copy - Value get(const CppTL::ConstString& key, const Value& defaultValue) const; -#endif - /// Most general and efficient version of isMember()const, get()const, - /// and operator[]const - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - Value const* find(char const* begin, char const* end) const; - /// Most general and efficient version of object-mutators. - /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 - /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. - Value const* demand(char const* begin, char const* end); - /// \brief Remove and return the named member. - /// - /// Do nothing if it did not exist. - /// \return the removed Value, or null. - /// \pre type() is objectValue or nullValue - /// \post type() is unchanged - /// \deprecated - Value removeMember(const char* key); - /// Same as removeMember(const char*) - /// \param key may contain embedded nulls. - /// \deprecated - Value removeMember(const std::string& key); - /// Same as removeMember(const char* begin, const char* end, Value* removed), - /// but 'key' is null-terminated. - bool removeMember(const char* key, Value* removed); - /** \brief Remove the named map member. - - Update 'removed' iff removed. - \param key may contain embedded nulls. - \return true iff removed (no exceptions) - */ - bool removeMember(std::string const& key, Value* removed); - /// Same as removeMember(std::string const& key, Value* removed) - bool removeMember(const char* begin, const char* end, Value* removed); - /** \brief Remove the indexed array element. - - O(n) expensive operations. - Update 'removed' iff removed. - \return true iff removed (no exceptions) - */ - bool removeIndex(ArrayIndex i, Value* removed); - - /// Return true if the object has a member named key. - /// \note 'key' must be null-terminated. - bool isMember(const char* key) const; - /// Return true if the object has a member named key. - /// \param key may contain embedded nulls. - bool isMember(const std::string& key) const; - /// Same as isMember(std::string const& key)const - bool isMember(const char* begin, const char* end) const; -#ifdef JSON_USE_CPPTL - /// Return true if the object has a member named key. - bool isMember(const CppTL::ConstString& key) const; -#endif - - /// \brief Return a list of the member names. - /// - /// If null, return an empty list. - /// \pre type() is objectValue or nullValue - /// \post if type() was nullValue, it remains nullValue - Members getMemberNames() const; - - //# ifdef JSON_USE_CPPTL - // EnumMemberNames enumMemberNames() const; - // EnumValues enumValues() const; - //# endif - - /// \deprecated Always pass len. - JSONCPP_DEPRECATED("Use setComment(std::string const&) instead.") - void setComment(const char* comment, CommentPlacement placement); - /// Comments must be //... or /* ... */ - void setComment(const char* comment, size_t len, CommentPlacement placement); - /// Comments must be //... or /* ... */ - void setComment(const std::string& comment, CommentPlacement placement); - bool hasComment(CommentPlacement placement) const; - /// Include delimiters and embedded newlines. - std::string getComment(CommentPlacement placement) const; - - std::string toStyledString() const; - - const_iterator begin() const; - const_iterator end() const; - - iterator begin(); - iterator end(); - - // Accessors for the [start, limit) range of bytes within the JSON text from - // which this value was parsed, if any. - void setOffsetStart(size_t start); - void setOffsetLimit(size_t limit); - size_t getOffsetStart() const; - size_t getOffsetLimit() const; - -private: - void initBasic(ValueType type, bool allocated = false); - - Value& resolveReference(const char* key); - Value& resolveReference(const char* key, const char* end); - - struct CommentInfo { - CommentInfo(); - ~CommentInfo(); - - void setComment(const char* text, size_t len); - - char* comment_; - }; - - // struct MemberNamesTransform - //{ - // typedef const char *result_type; - // const char *operator()( const CZString &name ) const - // { - // return name.c_str(); - // } - //}; - - union ValueHolder { - LargestInt int_; - LargestUInt uint_; - double real_; - bool bool_; - char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ - ObjectValues* map_; - } value_; - ValueType type_ : 8; - unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. - // If not allocated_, string_ must be null-terminated. - CommentInfo* comments_; - - // [start, limit) byte offsets in the source JSON text from which this Value - // was extracted. - size_t start_; - size_t limit_; -}; - -/** \brief Experimental and untested: represents an element of the "path" to - * access a node. - */ -class JSON_API PathArgument { -public: - friend class Path; - - PathArgument(); - PathArgument(ArrayIndex index); - PathArgument(const char* key); - PathArgument(const std::string& key); - -private: - enum Kind { - kindNone = 0, - kindIndex, - kindKey - }; - std::string key_; - ArrayIndex index_; - Kind kind_; -}; - -/** \brief Experimental and untested: represents a "path" to access a node. - * - * Syntax: - * - "." => root node - * - ".[n]" => elements at index 'n' of root node (an array value) - * - ".name" => member named 'name' of root node (an object value) - * - ".name1.name2.name3" - * - ".[0][1][2].name1[3]" - * - ".%" => member name is provided as parameter - * - ".[%]" => index is provided as parameter - */ -class JSON_API Path { -public: - Path(const std::string& path, - const PathArgument& a1 = PathArgument(), - const PathArgument& a2 = PathArgument(), - const PathArgument& a3 = PathArgument(), - const PathArgument& a4 = PathArgument(), - const PathArgument& a5 = PathArgument()); - - const Value& resolve(const Value& root) const; - Value resolve(const Value& root, const Value& defaultValue) const; - /// Creates the "path" to access the specified node and returns a reference on - /// the node. - Value& make(Value& root) const; - -private: - typedef std::vector InArgs; - typedef std::vector Args; - - void makePath(const std::string& path, const InArgs& in); - void addPathInArg(const std::string& path, - const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind); - void invalidPath(const std::string& path, int location); - - Args args_; -}; - -/** \brief base class for Value iterators. - * - */ -class JSON_API ValueIteratorBase { -public: - typedef std::bidirectional_iterator_tag iterator_category; - typedef unsigned int size_t; - typedef int difference_type; - typedef ValueIteratorBase SelfType; - - bool operator==(const SelfType& other) const { return isEqual(other); } - - bool operator!=(const SelfType& other) const { return !isEqual(other); } - - difference_type operator-(const SelfType& other) const { - return other.computeDistance(*this); - } - - /// Return either the index or the member name of the referenced value as a - /// Value. - Value key() const; - - /// Return the index of the referenced Value, or -1 if it is not an arrayValue. - UInt index() const; - - /// Return the member name of the referenced Value, or "" if it is not an - /// objectValue. - /// \note Avoid `c_str()` on result, as embedded zeroes are possible. - std::string name() const; - - /// Return the member name of the referenced Value. "" if it is not an - /// objectValue. - /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. - JSONCPP_DEPRECATED("Use `key = name();` instead.") - char const* memberName() const; - /// Return the member name of the referenced Value, or NULL if it is not an - /// objectValue. - /// \note Better version than memberName(). Allows embedded nulls. - char const* memberName(char const** end) const; - -protected: - Value& deref() const; - - void increment(); - - void decrement(); - - difference_type computeDistance(const SelfType& other) const; - - bool isEqual(const SelfType& other) const; - - void copy(const SelfType& other); - -private: - Value::ObjectValues::iterator current_; - // Indicates that iterator is for a null value. - bool isNull_; - -public: - // For some reason, BORLAND needs these at the end, rather - // than earlier. No idea why. - ValueIteratorBase(); - explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); -}; - -/** \brief const iterator for object and array value. - * - */ -class JSON_API ValueConstIterator : public ValueIteratorBase { - friend class Value; - -public: - typedef const Value value_type; - //typedef unsigned int size_t; - //typedef int difference_type; - typedef const Value& reference; - typedef const Value* pointer; - typedef ValueConstIterator SelfType; - - ValueConstIterator(); - ValueConstIterator(ValueIterator const& other); - -private: -/*! \internal Use by Value to create an iterator. - */ - explicit ValueConstIterator(const Value::ObjectValues::iterator& current); -public: - SelfType& operator=(const ValueIteratorBase& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -/** \brief Iterator for object and array value. - */ -class JSON_API ValueIterator : public ValueIteratorBase { - friend class Value; - -public: - typedef Value value_type; - typedef unsigned int size_t; - typedef int difference_type; - typedef Value& reference; - typedef Value* pointer; - typedef ValueIterator SelfType; - - ValueIterator(); - explicit ValueIterator(const ValueConstIterator& other); - ValueIterator(const ValueIterator& other); - -private: -/*! \internal Use by Value to create an iterator. - */ - explicit ValueIterator(const Value::ObjectValues::iterator& current); -public: - SelfType& operator=(const SelfType& other); - - SelfType operator++(int) { - SelfType temp(*this); - ++*this; - return temp; - } - - SelfType operator--(int) { - SelfType temp(*this); - --*this; - return temp; - } - - SelfType& operator--() { - decrement(); - return *this; - } - - SelfType& operator++() { - increment(); - return *this; - } - - reference operator*() const { return deref(); } - - pointer operator->() const { return &deref(); } -}; - -} // namespace Json - - -namespace std { -/// Specialize std::swap() for Json::Value. -template<> -inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } -} - - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // CPPTL_JSON_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/value.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_READER_H_INCLUDED -#define CPPTL_JSON_READER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "features.h" -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -namespace Json { - -/** \brief Unserialize a JSON document into a - *Value. - * - * \deprecated Use CharReader and CharReaderBuilder. - */ -class JSON_API Reader { -public: - typedef char Char; - typedef const Char* Location; - - /** \brief An error tagged with where in the JSON text it was encountered. - * - * The offsets give the [start, limit) range of bytes within the text. Note - * that this is bytes, not codepoints. - * - */ - struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; - }; - - /** \brief Constructs a Reader allowing all features - * for parsing. - */ - Reader(); - - /** \brief Constructs a Reader allowing the specified feature set - * for parsing. - */ - Reader(const Features& features); - - /** \brief Read a Value from a JSON - * document. - * \param document UTF-8 encoded string containing the document to read. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them - * back during - * serialization, \c false to discard comments. - * This parameter is ignored if - * Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an - * error occurred. - */ - bool - parse(const std::string& document, Value& root, bool collectComments = true); - - /** \brief Read a Value from a JSON - document. - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the - document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - document to read. - * Must be >= beginDoc. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param collectComments \c true to collect comment and allow writing them - back during - * serialization, \c false to discard comments. - * This parameter is ignored if - Features::allowComments_ - * is \c false. - * \return \c true if the document was successfully parsed, \c false if an - error occurred. - */ - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments = true); - - /// \brief Parse from input stream. - /// \see Json::operator>>(std::istream&, Json::Value&). - bool parse(std::istream& is, Value& root, bool collectComments = true); - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * \return Formatted error message with the list of errors with their location - * in - * the parsed document. An empty string is returned if no error - * occurred - * during parsing. - * \deprecated Use getFormattedErrorMessages() instead (typo fix). - */ - JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") - std::string getFormatedErrorMessages() const; - - /** \brief Returns a user friendly string that list errors in the parsed - * document. - * \return Formatted error message with the list of errors with their location - * in - * the parsed document. An empty string is returned if no error - * occurred - * during parsing. - */ - std::string getFormattedErrorMessages() const; - - /** \brief Returns a vector of structured errors encountered while parsing. - * \return A (possibly empty) vector of StructuredError objects. Currently - * only one error can be returned, but the caller should tolerate - * multiple - * errors. This can occur if the parser recovers from a non-fatal - * parse error and then encounters additional errors. - */ - std::vector getStructuredErrors() const; - - /** \brief Add a semantic error message. - * \param value JSON Value location associated with the error - * \param message The error message. - * \return \c true if the error was successfully added, \c false if the - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const std::string& message); - - /** \brief Add a semantic error message with extra context. - * \param value JSON Value location associated with the error - * \param message The error message. - * \param extra Additional JSON Value location to contextualize the error - * \return \c true if the error was successfully added, \c false if either - * Value offset exceeds the document size. - */ - bool pushError(const Value& value, const std::string& message, const Value& extra); - - /** \brief Return whether there are any errors. - * \return \c true if there are no errors to report \c false if - * errors have occurred. - */ - bool good() const; - -private: - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool readToken(Token& token); - void skipSpaces(); - bool match(Location pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - void readNumber(); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, std::string& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const std::string& message, Token& token, Location extra = 0); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - std::string getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - std::string commentsBefore_; - Features features_; - bool collectComments_; -}; // Reader - -/** Interface for reading JSON from a char array. - */ -class JSON_API CharReader { -public: - virtual ~CharReader() {} - /** \brief Read a Value from a JSON - document. - * The document must be a UTF-8 encoded string containing the document to read. - * - * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the - document to read. - * \param endDoc Pointer on the end of the UTF-8 encoded string of the - document to read. - * Must be >= beginDoc. - * \param root [out] Contains the root value of the document if it was - * successfully parsed. - * \param errs [out] Formatted error messages (if not NULL) - * a user friendly string that lists errors in the parsed - * document. - * \return \c true if the document was successfully parsed, \c false if an - error occurred. - */ - virtual bool parse( - char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) = 0; - - class JSON_API Factory { - public: - virtual ~Factory() {} - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual CharReader* newCharReader() const = 0; - }; // Factory -}; // CharReader - -/** \brief Build a CharReader implementation. - -Usage: -\code - using namespace Json; - CharReaderBuilder builder; - builder["collectComments"] = false; - Value value; - std::string errs; - bool ok = parseFromStream(builder, std::cin, &value, &errs); -\endcode -*/ -class JSON_API CharReaderBuilder : public CharReader::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - These are case-sensitive. - Available settings (case-sensitive): - - `"collectComments": false or true` - - true to collect comment and allow writing them - back during serialization, false to discard comments. - This parameter is ignored if allowComments is false. - - `"allowComments": false or true` - - true if comments are allowed. - - `"strictRoot": false or true` - - true if root must be either an array or an object value - - `"allowDroppedNullPlaceholders": false or true` - - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) - - `"allowNumericKeys": false or true` - - true if numeric object keys are allowed. - - `"allowSingleQuotes": false or true` - - true if '' are allowed for strings (both keys and values) - - `"stackLimit": integer` - - Exceeding stackLimit (recursive depth of `readValue()`) will - cause an exception. - - This is a security issue (seg-faults caused by deeply nested JSON), - so the default is low. - - `"failIfExtra": false or true` - - If true, `parse()` returns false when extra non-whitespace trails - the JSON value in the input string. - - `"rejectDupKeys": false or true` - - If true, `parse()` returns false when a key is duplicated within an object. - - `"allowSpecialFloats": false or true` - - If true, special float values (NaNs and infinities) are allowed - and their values are lossfree restorable. - - You can examine 'settings_` yourself - to see the defaults. You can also write and read them just like any - JSON Value. - \sa setDefaults() - */ - Json::Value settings_; - - CharReaderBuilder(); - ~CharReaderBuilder() override; - - CharReader* newCharReader() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - - /** A simple way to update a specific setting. - */ - Value& operator[](std::string key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults - */ - static void setDefaults(Json::Value* settings); - /** Same as old Features::strictMode(). - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode - */ - static void strictMode(Json::Value* settings); -}; - -/** Consume entire stream and use its begin/end. - * Someday we might have a real StreamReader, but for now this - * is convenient. - */ -bool JSON_API parseFromStream( - CharReader::Factory const&, - std::istream&, - Value* root, std::string* errs); - -/** \brief Read from 'sin' into 'root'. - - Always keep comments from the input JSON. - - This can be used to read a file into a particular sub-object. - For example: - \code - Json::Value root; - cin >> root["dir"]["file"]; - cout << root; - \endcode - Result: - \verbatim - { - "dir": { - "file": { - // The input stream JSON would be nested here. - } - } - } - \endverbatim - \throw std::exception on parse error. - \see Json::operator<<() -*/ -JSON_API std::istream& operator>>(std::istream&, Value&); - -} // namespace Json - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // CPPTL_JSON_READER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/reader.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef JSON_WRITER_H_INCLUDED -#define JSON_WRITER_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include "value.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include - -// Disable warning C4251: : needs to have dll-interface to -// be used by... -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(push) -#pragma warning(disable : 4251) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -namespace Json { - -class Value; - -/** - -Usage: -\code - using namespace Json; - void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { - std::unique_ptr const writer( - factory.newStreamWriter()); - writer->write(value, &std::cout); - std::cout << std::endl; // add lf and flush - } -\endcode -*/ -class JSON_API StreamWriter { -protected: - std::ostream* sout_; // not owned; will not delete -public: - StreamWriter(); - virtual ~StreamWriter(); - /** Write Value into document as configured in sub-class. - Do not take ownership of sout, but maintain a reference during function. - \pre sout != NULL - \return zero on success (For now, we always return zero, so check the stream instead.) - \throw std::exception possibly, depending on configuration - */ - virtual int write(Value const& root, std::ostream* sout) = 0; - - /** \brief A simple abstract factory. - */ - class JSON_API Factory { - public: - virtual ~Factory(); - /** \brief Allocate a CharReader via operator new(). - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - virtual StreamWriter* newStreamWriter() const = 0; - }; // Factory -}; // StreamWriter - -/** \brief Write into stringstream, then return string, for convenience. - * A StreamWriter will be created from the factory, used, and then deleted. - */ -std::string JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); - - -/** \brief Build a StreamWriter implementation. - -Usage: -\code - using namespace Json; - Value value = ...; - StreamWriterBuilder builder; - builder["commentStyle"] = "None"; - builder["indentation"] = " "; // or whatever you like - std::unique_ptr writer( - builder.newStreamWriter()); - writer->write(value, &std::cout); - std::cout << std::endl; // add lf and flush -\endcode -*/ -class JSON_API StreamWriterBuilder : public StreamWriter::Factory { -public: - // Note: We use a Json::Value so that we can add data-members to this class - // without a major version bump. - /** Configuration of this builder. - Available settings (case-sensitive): - - "commentStyle": "None" or "All" - - "indentation": "" - - "enableYAMLCompatibility": false or true - - slightly change the whitespace around colons - - "dropNullPlaceholders": false or true - - Drop the "null" string from the writer's output for nullValues. - Strictly speaking, this is not valid JSON. But when the output is being - fed to a browser's Javascript, it makes for smaller output and the - browser can handle the output just fine. - - "useSpecialFloats": false or true - - If true, outputs non-finite floating point values in the following way: - NaN values as "NaN", positive infinity as "Infinity", and negative infinity - as "-Infinity". - - You can examine 'settings_` yourself - to see the defaults. You can also write and read them just like any - JSON Value. - \sa setDefaults() - */ - Json::Value settings_; - - StreamWriterBuilder(); - ~StreamWriterBuilder() override; - - /** - * \throw std::exception if something goes wrong (e.g. invalid settings) - */ - StreamWriter* newStreamWriter() const override; - - /** \return true if 'settings' are legal and consistent; - * otherwise, indicate bad settings via 'invalid'. - */ - bool validate(Json::Value* invalid) const; - /** A simple way to update a specific setting. - */ - Value& operator[](std::string key); - - /** Called by ctor, but you can use this to reset settings_. - * \pre 'settings' != NULL (but Json::null is fine) - * \remark Defaults: - * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults - */ - static void setDefaults(Json::Value* settings); -}; - -/** \brief Abstract class for writers. - * \deprecated Use StreamWriter. (And really, this is an implementation detail.) - */ -class JSON_API Writer { -public: - virtual ~Writer(); - - virtual std::string write(const Value& root) = 0; -}; - -/** \brief Outputs a Value in JSON format - *without formatting (not human friendly). - * - * The JSON document is written in a single line. It is not intended for 'human' - *consumption, - * but may be useful to support feature such as RPC where bandwidth is limited. - * \sa Reader, Value - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API FastWriter : public Writer { - -public: - FastWriter(); - ~FastWriter() override {} - - void enableYAMLCompatibility(); - - /** \brief Drop the "null" string from the writer's output for nullValues. - * Strictly speaking, this is not valid JSON. But when the output is being - * fed to a browser's Javascript, it makes for smaller output and the - * browser can handle the output just fine. - */ - void dropNullPlaceholders(); - - void omitEndingLineFeed(); - -public: // overridden from Writer - std::string write(const Value& root) override; - -private: - void writeValue(const Value& value); - - std::string document_; - bool yamlCompatiblityEnabled_; - bool dropNullPlaceholders_; - bool omitEndingLineFeed_; -}; - -/** \brief Writes a Value in JSON format in a - *human friendly way. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - *line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - *types, - * and all the values fit on one lines, then print the array on a single - *line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - *#CommentPlacement. - * - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API StyledWriter : public Writer { -public: - StyledWriter(); - ~StyledWriter() override {} - -public: // overridden from Writer - /** \brief Serialize a Value in JSON format. - * \param root Value to serialize. - * \return String containing the JSON document that represents the root value. - */ - std::string write(const Value& root) override; - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const std::string& value); - void writeIndent(); - void writeWithIndent(const std::string& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string document_; - std::string indentString_; - int rightMargin_; - int indentSize_; - bool addChildValues_; -}; - -/** \brief Writes a Value in JSON format in a - human friendly way, - to a stream rather than to a string. - * - * The rules for line break and indent are as follow: - * - Object value: - * - if empty then print {} without indent and line break - * - if not empty the print '{', line break & indent, print one value per - line - * and then unindent and line break and print '}'. - * - Array value: - * - if empty then print [] without indent and line break - * - if the array contains no object value, empty array or some other value - types, - * and all the values fit on one lines, then print the array on a single - line. - * - otherwise, it the values do not fit on one line, or the array contains - * object or non empty array, then print one value per line. - * - * If the Value have comments then they are outputted according to their - #CommentPlacement. - * - * \param indentation Each level will be indented by this amount extra. - * \sa Reader, Value, Value::setComment() - * \deprecated Use StreamWriterBuilder. - */ -class JSON_API StyledStreamWriter { -public: - StyledStreamWriter(std::string indentation = "\t"); - ~StyledStreamWriter() {} - -public: - /** \brief Serialize a Value in JSON format. - * \param out Stream to write to. (Can be ostringstream, e.g.) - * \param root Value to serialize. - * \note There is no point in deriving from Writer, since write() should not - * return a value. - */ - void write(std::ostream& out, const Value& root); - -private: - void writeValue(const Value& value); - void writeArrayValue(const Value& value); - bool isMultineArray(const Value& value); - void pushValue(const std::string& value); - void writeIndent(); - void writeWithIndent(const std::string& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(const Value& root); - void writeCommentAfterValueOnSameLine(const Value& root); - bool hasCommentForValue(const Value& value); - static std::string normalizeEOL(const std::string& text); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::ostream* document_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - bool addChildValues_ : 1; - bool indented_ : 1; -}; - -#if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(Int value); -std::string JSON_API valueToString(UInt value); -#endif // if defined(JSON_HAS_INT64) -std::string JSON_API valueToString(LargestInt value); -std::string JSON_API valueToString(LargestUInt value); -std::string JSON_API valueToString(double value); -std::string JSON_API valueToString(bool value); -std::string JSON_API valueToQuotedString(const char* value); - -/// \brief Output using the StyledStreamWriter. -/// \see Json::operator>>() -JSON_API std::ostream& operator<<(std::ostream&, const Value& root); - -} // namespace Json - -#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) -#pragma warning(pop) -#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) - -#endif // JSON_WRITER_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/writer.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED -#define CPPTL_JSON_ASSERTIONS_H_INCLUDED - -#include -#include - -#if !defined(JSON_IS_AMALGAMATION) -#include "config.h" -#endif // if !defined(JSON_IS_AMALGAMATION) - -/** It should not be possible for a maliciously designed file to - * cause an abort() or seg-fault, so these macros are used only - * for pre-condition violations and internal logic errors. - */ -#if JSON_USE_EXCEPTION - -// @todo <= add detail about condition in exception -# define JSON_ASSERT(condition) \ - {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} - -# define JSON_FAIL_MESSAGE(message) \ - { \ - std::ostringstream oss; oss << message; \ - Json::throwLogicError(oss.str()); \ - abort(); \ - } - -#else // JSON_USE_EXCEPTION - -# define JSON_ASSERT(condition) assert(condition) - -// The call to assert() will show the failure message in debug builds. In -// release builds we abort, for a core-dump or debugger. -# define JSON_FAIL_MESSAGE(message) \ - { \ - std::ostringstream oss; oss << message; \ - assert(false && oss.str().c_str()); \ - abort(); \ - } - - -#endif - -#define JSON_ASSERT_MESSAGE(condition, message) \ - if (!(condition)) { \ - JSON_FAIL_MESSAGE(message); \ - } - -#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: include/json/assertions.h -// ////////////////////////////////////////////////////////////////////// - - - - - -#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/conformance/third_party/jsoncpp/jsoncpp.cpp b/conformance/third_party/jsoncpp/jsoncpp.cpp deleted file mode 100644 index 78919eac0f..0000000000 --- a/conformance/third_party/jsoncpp/jsoncpp.cpp +++ /dev/null @@ -1,5192 +0,0 @@ -/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - - -#include "third_party/jsoncpp/json.h" - -#ifndef JSON_IS_AMALGAMATION -#error "Compile with -I PATH_TO_JSON_DIRECTORY" -#endif - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { - -/// Converts a unicode code-point to UTF-8. -static inline std::string codePointToUTF8(unsigned int cp) { - std::string result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -/// Returns true if ch is a control character (in range [1,31]). -static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -typedef char UIntToStringBuffer[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned integer to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = static_cast(value % 10U + static_cast('0')); - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -static inline void fixNumericLocale(char* begin, char* end) { - while (begin < end) { - if (*begin == ',') { - *begin = '.'; - } - ++begin; - } -} - -} // namespace Json { - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#define snprintf std::snprintf -#endif - -#if defined(__QNXNTO__) -#define sscanf std::sscanf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -static int const stackLimit_g = 1000; -static int stackDepth_g = 0; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr CharReaderPtr; -#else -typedef std::auto_ptr CharReaderPtr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() - : allowComments_(true), strictRoot_(false), - allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} - -Features Features::all() { return Features(); } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -static bool containsNewLine(Reader::Location begin, Reader::Location end) { - for (; begin < end; ++begin) - if (*begin == '\n' || *begin == '\r') - return true; - return false; -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(Features::all()), - collectComments_() {} - -Reader::Reader(const Features& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), features_(features), collectComments_() { -} - -bool -Reader::parse(const std::string& document, Value& root, bool collectComments) { - document_ = document; - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { - // std::istream_iterator begin(sin); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since std::string is reference-counted, this at least does not - // create an extra copy. - std::string doc; - std::getline(sin, doc, (char)EOF); - return parse(doc, root, collectComments); -} - -bool Reader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - stackDepth_g = 0; // Yes, this is bad coding, but options are limited. - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // This is a non-reentrant way to support a stackLimit. Terrible! - // But this deprecated class has a security problem: Bad input can - // cause a seg-fault. This seems like a fair, binary-compatible way - // to prevent the problem. - if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_g; - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - --stackDepth_g; - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -static std::string normalizeEOL(Reader::Location begin, Reader::Location end) { - std::string normalized; - normalized.reserve(end - begin); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void -Reader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - const char *p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } -} - -bool Reader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& tokenStart) { - Token tokenName; - std::string name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name = ""; - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool Reader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (*current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative && value == maxIntegerValue) - decoded = Value::minLargestInt; - else if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - std::string buffer(token.start_, token.end_); - std::istringstream is(buffer); - if (!(is >> value)) - return addError("'" + std::string(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - std::string decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - return true; -} - -bool -Reader::addError(const std::string& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -std::string Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -// Deprecated. Preserved for backward compatibility -std::string Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -std::string Reader::getFormattedErrorMessages() const { - std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { - return !errors_.size(); -} - -// exact copy of Features -class OurFeatures { -public: - static OurFeatures all(); - bool allowComments_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - bool allowSpecialFloats_; - int stackLimit_; -}; // OurFeatures - -// exact copy of Implementation of class Features -// //////////////////////////////// - -OurFeatures OurFeatures::all() { return OurFeatures(); } - -// Implementation of class Reader -// //////////////////////////////// - -// exact copy of Reader, renamed to OurReader -class OurReader { -public: - typedef char Char; - typedef const Char* Location; - struct StructuredError { - size_t offset_start; - size_t offset_limit; - std::string message; - }; - - OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments = true); - std::string getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; - bool pushError(const Value& value, const std::string& message); - bool pushError(const Value& value, const std::string& message, const Value& extra); - bool good() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenNaN, - tokenPosInf, - tokenNegInf, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - std::string message_; - Location extra_; - }; - - typedef std::deque Errors; - - bool readToken(Token& token); - void skipSpaces(); - bool match(Location pattern, int patternLength); - bool readComment(); - bool readCStyleComment(); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - bool readNumber(bool checkInf); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, std::string& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode); - bool addError(const std::string& message, Token& token, Location extra = 0); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void - getLocationLineAndColumn(Location location, int& line, int& column) const; - std::string getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - typedef std::stack Nodes; - Nodes nodes_; - Errors errors_; - std::string document_; - Location begin_; - Location end_; - Location current_; - Location lastValueEnd_; - Value* lastValue_; - std::string commentsBefore_; - int stackDepth_; - - OurFeatures const features_; - bool collectComments_; -}; // OurReader - -// complete copy of Read impl, for OurReader - -OurReader::OurReader(OurFeatures const& features) - : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), - lastValue_(), commentsBefore_(), - stackDepth_(0), - features_(features), collectComments_() { -} - -bool OurReader::parse(const char* beginDoc, - const char* endDoc, - Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = 0; - lastValue_ = 0; - commentsBefore_ = ""; - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - stackDepth_ = 0; - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_) { - if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); - ++stackDepth_; - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_ = ""; - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: - { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenFalse: - { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNull: - { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNaN: - { - Value v(std::numeric_limits::quiet_NaN()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenPosInf: - { - Value v(std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenNegInf: - { - Value v(-std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } - break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - --stackDepth_; - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - break; - } // else continue - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token.type_ = tokenNumber; - readNumber(false); - break; - case '-': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenNegInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case 'N': - if (features_.allowSpecialFloats_) { - token.type_ = tokenNaN; - ok = match("aN", 2); - } else { - ok = false; - } - break; - case 'I': - if (features_.allowSpecialFloats_) { - token.type_ = tokenPosInf; - ok = match("nfinity", 7); - } else { - ok = false; - } - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return true; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool OurReader::match(Location pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -void -OurReader::addComment(Location begin, Location end, CommentPlacement placement) { - assert(collectComments_); - const std::string& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != 0); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -bool OurReader::readNumber(bool checkInf) { - const char *p = current_; - if (checkInf && p != end_ && *p == 'I') { - current_ = ++p; - return false; - } - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : 0; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : 0; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : 0; - } - return true; -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& tokenStart) { - Token tokenName; - std::string name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name = ""; - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover( - "Missing ':' after object member name", colon, tokenObjectEnd); - } - if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - std::string msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover( - msg, tokenName, tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover( - "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover( - "Missing '}' or object member name", tokenName, tokenObjectEnd); -} - -bool OurReader::readArray(Token& tokenStart) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(tokenStart.start_ - begin_); - skipSpaces(); - if (*current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token token; - // Accept Comment after last item in the array. - ok = readToken(token); - while (token.type_ == tokenComment && ok) { - ok = readToken(token); - } - bool badTokenType = - (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover( - "Missing ',' or ']' in array declaration", token, tokenArrayEnd); - } - if (token.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(-Value::minLargestInt) - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - Value::UInt digit(c - '0'); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const int bufferSize = 32; - int count; - int length = int(token.end_ - token.start_); - - // Sanity check to avoid buffer overflow exploits. - if (length < 0) { - return addError("Unable to parse token length", token); - } - - // Avoid using a string constant for the format control string given to - // sscanf, as this can cause hard to debug crashes on OS X. See here for more - // info: - // - // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html - char format[] = "%lf"; - - if (length <= bufferSize) { - Char buffer[bufferSize + 1]; - memcpy(buffer, token.start_, length); - buffer[length] = 0; - count = sscanf(buffer, format, &value); - } else { - std::string buffer(token.start_, token.end_); - count = sscanf(buffer.c_str(), format, &value); - } - - if (count != 1) - return addError("'" + std::string(token.start_, token.end_) + - "' is not a number.", - token); - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - std::string decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, std::string& decoded) { - decoded.reserve(token.end_ - token.start_ - 2); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - else if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, - current); - unsigned int surrogatePair; - if (*(current++) == '\\' && *(current++) == 'u') { - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, - current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, - Location& current, - Location end, - unsigned int& unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", - token, - current); - unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, - current); - } - return true; -} - -bool -OurReader::addError(const std::string& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - int errorCount = int(errors_.size()); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const std::string& message, - Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, - int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -std::string OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -std::string OurReader::getFormattedErrorMessages() const { - std::string formattedMessage; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (Errors::const_iterator itError = errors_.begin(); - itError != errors_.end(); - ++itError) { - const ErrorInfo& error = *itError; - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool OurReader::pushError(const Value& value, const std::string& message) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = end_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = 0; - errors_.push_back(info); - return true; -} - -bool OurReader::pushError(const Value& value, const std::string& message, const Value& extra) { - size_t length = end_ - begin_; - if(value.getOffsetStart() > length - || value.getOffsetLimit() > length - || extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool OurReader::good() const { - return !errors_.size(); -} - - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; -public: - OurCharReader( - bool collectComments, - OurFeatures const& features) - : collectComments_(collectComments) - , reader_(features) - {} - bool parse( - char const* beginDoc, char const* endDoc, - Value* root, std::string* errs) override { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() -{ - setDefaults(&settings_); -} -CharReaderBuilder::~CharReaderBuilder() -{} -CharReader* CharReaderBuilder::newCharReader() const -{ - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - features.stackLimit_ = settings_["stackLimit"].asInt(); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - return new OurCharReader(collectComments, features); -} -static void getValidReaderKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("collectComments"); - valid_keys->insert("allowComments"); - valid_keys->insert("strictRoot"); - valid_keys->insert("allowDroppedNullPlaceholders"); - valid_keys->insert("allowNumericKeys"); - valid_keys->insert("allowSingleQuotes"); - valid_keys->insert("stackLimit"); - valid_keys->insert("failIfExtra"); - valid_keys->insert("rejectDupKeys"); - valid_keys->insert("allowSpecialFloats"); -} -bool CharReaderBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidReaderKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& CharReaderBuilder::operator[](std::string key) -{ - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) -{ -//! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; - (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) -{ -//! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; - (*settings)["allowSpecialFloats"] = false; -//! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream( - CharReader::Factory const& fact, std::istream& sin, - Value* root, std::string* errs) -{ - std::ostringstream ssin; - ssin << sin.rdbuf(); - std::string doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -std::istream& operator>>(std::istream& sin, Value& root) { - CharReaderBuilder b; - std::string errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - fprintf(stderr, - "Error from reader: %s", - errs.c_str()); - - throwRuntimeError(errs); - } - return sin; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() - : current_(), isNull_(true) { -} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() const { - return current_->second; -} - -void ValueIteratorBase::increment() { - ++current_; -} - -void ValueIteratorBase::decrement() { - --current_; -} - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { -#ifdef JSON_USE_CPPTL_SMALLMAP - return other.current_ - current_; -#else - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -#endif -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -std::string ValueIteratorBase::name() const { - char const* keey; - char const* end; - keey = memberName(&end); - if (!keey) return std::string(); - return std::string(keey, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* cname = (*current_).first.data(); - return cname ? cname : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* cname = (*current_).first.data(); - if (!cname) { - *end = NULL; - return NULL; - } - *end = cname + (*current_).first.length(); - return cname; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() {} - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator::ValueConstIterator(ValueIterator const& other) - : ValueIteratorBase(other) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() {} - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) { - throwRuntimeError("ConstIterator to Iterator should never be allowed."); -} - -ValueIterator::ValueIterator(const ValueIterator& other) - : ValueIteratorBase(other) {} - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#ifdef JSON_USE_CPPTL -#include -#endif -#include // size_t -#include // min() - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif -static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; -const unsigned char& kNullRef = kNull[0]; -const Value& Value::null = reinterpret_cast(kNullRef); -const Value& Value::nullRef = null; - -const Int Value::minInt = Int(~(UInt(-1) / 2)); -const Int Value::maxInt = Int(UInt(-1) / 2); -const UInt Value::maxUInt = UInt(-1); -#if defined(JSON_HAS_INT64) -const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); -const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); -const UInt64 Value::maxUInt64 = UInt64(-1); -// The constant is hard-coded because some compiler have trouble -// converting Value::maxUInt64 to a double correctly (AIX/xlC). -// Assumes that UInt64 is a 64 bits integer. -static const double maxUInt64AsDouble = 18446744073709551615.0; -#endif // defined(JSON_HAS_INT64) -const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); -const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); -const LargestUInt Value::maxLargestUInt = LargestUInt(-1); - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template -static inline bool InRange(double d, T min, U max) { - return d >= min && d <= max; -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + Int64(value & 1); -} - -template static inline double integerToDouble(T value) { - return static_cast(value); -} - -template -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, - size_t length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= (size_t)Value::maxInt) - length = Value::maxInt - 1; - - char* newString = static_cast(malloc(length + 1)); - if (newString == NULL) { - throwRuntimeError( - "in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue( - const char* value, - unsigned int length) -{ - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= (unsigned)Value::maxInt - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; - char* newString = static_cast(malloc(actualLength)); - if (newString == 0) { - throwRuntimeError( - "in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString( - bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) -{ - if (!isPrefixed) { - *length = static_cast(strlen(prefixed)); - *value = prefixed; - } else { - *length = *reinterpret_cast(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -static inline void releaseStringValue(char* value) { free(value); } - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -Exception::Exception(std::string const& msg) - : msg_(msg) -{} -Exception::~Exception() throw() -{} -char const* Exception::what() const throw() -{ - return msg_.c_str(); -} -RuntimeError::RuntimeError(std::string const& msg) - : Exception(msg) -{} -LogicError::LogicError(std::string const& msg) - : Exception(msg) -{} -void throwRuntimeError(std::string const& msg) -{ - throw RuntimeError(msg); -} -void throwLogicError(std::string const& msg) -{ - throw LogicError(msg); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CommentInfo -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -Value::CommentInfo::CommentInfo() : comment_(0) {} - -Value::CommentInfo::~CommentInfo() { - if (comment_) - releaseStringValue(comment_); -} - -void Value::CommentInfo::setComment(const char* text, size_t len) { - if (comment_) { - releaseStringValue(comment_); - comment_ = 0; - } - JSON_ASSERT(text != 0); - JSON_ASSERT_MESSAGE( - text[0] == '\0' || text[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - // It seems that /**/ style comments are acceptable as well. - comment_ = duplicateStringValue(text, len); -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} - -Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) - : cstr_(str) { - // allocate != duplicate - storage_.policy_ = allocate & 0x3; - storage_.length_ = ulength & 0x3FFFFFFF; -} - -Value::CZString::CZString(const CZString& other) - : cstr_(other.storage_.policy_ != noDuplication && other.cstr_ != 0 - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_) { - storage_.policy_ = (other.cstr_ - ? (static_cast(other.storage_.policy_) == noDuplication - ? noDuplication : duplicate) - : static_cast(other.storage_.policy_)); - storage_.length_ = other.storage_.length_; -} - -#if JSON_HAS_RVALUE_REFERENCES -Value::CZString::CZString(CZString&& other) - : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = nullptr; -} -#endif - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) - releaseStringValue(const_cast(cstr_)); -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(CZString other) { - swap(other); - return *this; -} - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) return index_ < other.index_; - //return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) return index_ == other.index_; - //return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) return false; - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -//const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType vtype) { - initBasic(vtype); - switch (vtype) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - value_.string_ = 0; - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); -} - -Value::Value(const char* beginValue, const char* endValue) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); -} - -Value::Value(const std::string& value) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast(value.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value::Value(const CppTL::ConstString& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); -} -#endif - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(Value const& other) - : type_(other.type_), allocated_(false) - , - comments_(0), start_(other.start_), limit_(other.limit_) -{ - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.allocated_) { - unsigned len; - char const* str; - decodePrefixedString(other.allocated_, other.value_.string_, - &len, &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - allocated_ = true; - } else { - value_.string_ = other.value_.string_; - allocated_ = false; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } - if (other.comments_) { - comments_ = new CommentInfo[numberOfCommentPlacement]; - for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { - const CommentInfo& otherComment = other.comments_[comment]; - if (otherComment.comment_) - comments_[comment].setComment( - otherComment.comment_, strlen(otherComment.comment_)); - } - } -} - -#if JSON_HAS_RVALUE_REFERENCES -// Move constructor -Value::Value(Value&& other) { - initBasic(nullValue); - swap(other); -} -#endif - -Value::~Value() { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (allocated_) - releaseStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } - - if (comments_) - delete[] comments_; -} - -Value& Value::operator=(Value other) { - swap(other); - return *this; -} - -void Value::swapPayload(Value& other) { - ValueType temp = type_; - type_ = other.type_; - other.type_ = temp; - std::swap(value_, other.value_); - int temp2 = allocated_; - allocated_ = other.allocated_; - other.allocated_ = temp2 & 0x1; -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -ValueType Value::type() const { return type_; } - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type_ - other.type_; - if (typeDelta) - return typeDelta < 0 ? true : false; - switch (type_) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - if (other.value_.string_) return true; - else return false; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - unsigned min_len = std::min(this_len, other_len); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) return true; - if (comp > 0) return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - int delta = int(value_.map_->size() - other.value_.map_->size()); - if (delta) - return delta < 0; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - // if ( type_ != other.type_ ) - // GCC 2.95.3 says: - // attempt to take address of bit-field structure member `Json::Value::type_' - // Beats me, but a temp solves the problem. - int temp = other.type_; - if (type_ != temp) - return false; - switch (type_) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: - { - if ((value_.string_ == 0) || (other.value_.string_ == 0)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); - if (this_len != other_len) return false; - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type_ == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return this_str; -} - -bool Value::getString(char const** str, char const** cend) const { - if (type_ != stringValue) return false; - if (value_.string_ == 0) return false; - unsigned length; - decodePrefixedString(this->allocated_, this->value_.string_, &length, str); - *cend = *str + length; - return true; -} - -std::string Value::asString() const { - switch (type_) { - case nullValue: - return ""; - case stringValue: - { - if (value_.string_ == 0) return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); - return std::string(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -#ifdef JSON_USE_CPPTL -CppTL::ConstString Value::asConstString() const { - unsigned len; - char const* str; - decodePrefixedString(allocated_, value_.string_, - &len, &str); - return CppTL::ConstString(str, len); -} -#endif - -Value::Int Value::asInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type_) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type_) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type_) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type_) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0f : 0.0f; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type_) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ ? true : false; - case uintValue: - return value_.uint_ ? true : false; - case realValue: - // This is kind of strange. Not recommended. - return (value_.real_ != 0.0) ? true : false; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type_ == booleanValue && value_.bool_ == false) || - (type_ == stringValue && asString() == "") || - (type_ == arrayValue && value_.map_->size() == 0) || - (type_ == objectValue && value_.map_->size() == 0) || - type_ == nullValue; - case intValue: - return isInt() || - (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || - type_ == booleanValue || type_ == nullValue; - case uintValue: - return isUInt() || - (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || - type_ == booleanValue || type_ == nullValue; - case realValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case booleanValue: - return isNumeric() || type_ == booleanValue || type_ == nullValue; - case stringValue: - return isNumeric() || type_ == booleanValue || type_ == stringValue || - type_ == nullValue; - case arrayValue: - return type_ == arrayValue || type_ == nullValue; - case objectValue: - return type_ == objectValue || type_ == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type_) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0u; - else - return false; -} - -bool Value::operator!() const { return isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || - type_ == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type_) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - (*this)[newSize - 1]; - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - assert(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type_ == nullValue) - *this = Value(arrayValue); - CZString key(index); - ObjectValues::iterator it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullRef); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type_ == nullValue) - return nullRef; - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullRef; - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType vtype, bool allocated) { - type_ = vtype; - allocated_ = allocated; - comments_ = 0; - start_ = 0; - limit_ = 0; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullRef); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* cend) -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type_ == nullValue) - *this = Value(objectValue); - CZString actualKey( - key, static_cast(cend-key), CZString::duplicateOnCopy); - ObjectValues::iterator it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullRef); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullRef ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* key, char const* cend) const -{ - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::find(key, end, found): requires objectValue or nullValue"); - if (type_ == nullValue) return NULL; - CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) return NULL; - return &(*it).second; -} -const Value& Value::operator[](const char* key) const -{ - Value const* found = find(key, key + strlen(key)); - if (!found) return nullRef; - return *found; -} -Value const& Value::operator[](std::string const& key) const -{ - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) return nullRef; - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const std::string& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -#ifdef JSON_USE_CPPTL -Value& Value::operator[](const CppTL::ConstString& key) { - return resolveReference(key.c_str(), key.end_c_str()); -} -Value const& Value::operator[](CppTL::ConstString const& key) const -{ - Value const* found = find(key.c_str(), key.end_c_str()); - if (!found) return nullRef; - return *found; -} -#endif - -Value& Value::append(const Value& value) { return (*this)[size()] = value; } - -Value Value::get(char const* key, char const* cend, Value const& defaultValue) const -{ - Value const* found = find(key, cend); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const -{ - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(std::string const& key, Value const& defaultValue) const -{ - return get(key.data(), key.data() + key.length(), defaultValue); -} - - -bool Value::removeMember(const char* key, const char* cend, Value* removed) -{ - if (type_ != objectValue) { - return false; - } - CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); - ObjectValues::iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - *removed = it->second; - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) -{ - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(std::string const& key, Value* removed) -{ - return removeMember(key.data(), key.data() + key.length(), removed); -} -Value Value::removeMember(const char* key) -{ - JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type_ == nullValue) - return nullRef; - - Value removed; // null - removeMember(key, key + strlen(key), &removed); - return removed; // still null if removeMember() did nothing -} -Value Value::removeMember(const std::string& key) -{ - return removeMember(key.c_str()); -} - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type_ != arrayValue) { - return false; - } - CZString key(index); - ObjectValues::iterator it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i){ - CZString keey(i); - (*value_.map_)[keey] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - ObjectValues::iterator itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -#ifdef JSON_USE_CPPTL -Value Value::get(const CppTL::ConstString& key, - const Value& defaultValue) const { - return get(key.c_str(), key.end_c_str(), defaultValue); -} -#endif - -bool Value::isMember(char const* key, char const* cend) const -{ - Value const* value = find(key, cend); - return NULL != value; -} -bool Value::isMember(char const* key) const -{ - return isMember(key, key + strlen(key)); -} -bool Value::isMember(std::string const& key) const -{ - return isMember(key.data(), key.data() + key.length()); -} - -#ifdef JSON_USE_CPPTL -bool Value::isMember(const CppTL::ConstString& key) const { - return isMember(key.c_str(), key.end_c_str()); -} -#endif - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type_ == nullValue || type_ == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type_ == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(std::string((*it).first.data(), - (*it).first.length())); - } - return members; -} -// -//# ifdef JSON_USE_CPPTL -// EnumMemberNames -// Value::enumMemberNames() const -//{ -// if ( type_ == objectValue ) -// { -// return CppTL::Enum::any( CppTL::Enum::transform( -// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), -// MemberNamesTransform() ) ); -// } -// return EnumMemberNames(); -//} -// -// -// EnumValues -// Value::enumValues() const -//{ -// if ( type_ == objectValue || type_ == arrayValue ) -// return CppTL::Enum::anyValues( *(value_.map_), -// CppTL::Type() ); -// return EnumValues(); -//} -// -//# endif - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type_ == nullValue; } - -bool Value::isBool() const { return type_ == booleanValue; } - -bool Value::isInt() const { - switch (type_) { - case intValue: - return value_.int_ >= minInt && value_.int_ <= maxInt; - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type_) { - case intValue: - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); - case uintValue: - return value_.uint_ <= maxUInt; - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type_) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { -#if defined(JSON_HAS_INT64) - return isInt64() || isUInt64(); -#else - return isInt() || isUInt(); -#endif -} - -bool Value::isDouble() const { return type_ == realValue || isIntegral(); } - -bool Value::isNumeric() const { return isIntegral() || isDouble(); } - -bool Value::isString() const { return type_ == stringValue; } - -bool Value::isArray() const { return type_ == arrayValue; } - -bool Value::isObject() const { return type_ == objectValue; } - -void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { - if (!comments_) - comments_ = new CommentInfo[numberOfCommentPlacement]; - if ((len > 0) && (comment[len-1] == '\n')) { - // Always discard trailing newline, to aid indentation. - len -= 1; - } - comments_[placement].setComment(comment, len); -} - -void Value::setComment(const char* comment, CommentPlacement placement) { - setComment(comment, strlen(comment), placement); -} - -void Value::setComment(const std::string& comment, CommentPlacement placement) { - setComment(comment.c_str(), comment.length(), placement); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_ != 0 && comments_[placement].comment_ != 0; -} - -std::string Value::getComment(CommentPlacement placement) const { - if (hasComment(placement)) - return comments_[placement].comment_; - return ""; -} - -void Value::setOffsetStart(size_t start) { start_ = start; } - -void Value::setOffsetLimit(size_t limit) { limit_ = limit; } - -size_t Value::getOffsetStart() const { return start_; } - -size_t Value::getOffsetLimit() const { return limit_; } - -std::string Value::toStyledString() const { - StyledWriter writer; - return writer.write(*this); -} - -Value::const_iterator Value::begin() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return const_iterator(); -} - -Value::const_iterator Value::end() const { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return const_iterator(); -} - -Value::iterator Value::begin() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type_) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} - -PathArgument::PathArgument(ArrayIndex index) - : key_(), index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) - : key_(key), index_(), kind_(kindKey) {} - -PathArgument::PathArgument(const std::string& key) - : key_(key.c_str()), index_(), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const std::string& path, - const PathArgument& a1, - const PathArgument& a2, - const PathArgument& a3, - const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const std::string& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - InArgs::const_iterator itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *current++ != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(std::string(beginName, current)); - } - } -} - -void Path::addPathInArg(const std::string& /*path*/, - const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg); - } -} - -void Path::invalidPath(const std::string& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - } - node = &((*node)[arg.key_]); - if (node == &Value::nullRef) { - // Error: unable to resolve path (object has no member named '' at - // position...) - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullRef) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { - const PathArgument& arg = *it; - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include "json_tool.h" -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 -#include -#define isfinite _finite -#elif defined(__sun) && defined(__SVR4) //Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#elif defined(_AIX) -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#elif defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ - _Isfinitef(x) : _IsFinite(x))) -#else -#include -#define isfinite finite -#endif -#endif -#else -#include -#if !(defined(__QNXNTO__)) // QNX already defines isfinite -#define isfinite std::isfinite -#endif -#endif - -#if defined(_MSC_VER) -#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above -#define snprintf sprintf_s -#elif _MSC_VER >= 1900 // VC++ 14.0 and above -#define snprintf std::snprintf -#else -#define snprintf _snprintf -#endif -#elif defined(__ANDROID__) || defined(__QNXNTO__) -#define snprintf snprintf -#elif __cplusplus >= 201103L -#define snprintf std::snprintf -#endif - -#if defined(__BORLANDC__) -#include -#define isfinite _finite -#define snprintf _snprintf -#endif - -#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -typedef std::unique_ptr StreamWriterPtr; -#else -typedef std::auto_ptr StreamWriterPtr; -#endif - -static bool containsControlCharacter(const char* str) { - while (*str) { - if (isControlCharacter(*(str++))) - return true; - } - return false; -} - -static bool containsControlCharacter0(const char* str, unsigned len) { - char const* end = str + len; - while (end != str) { - if (isControlCharacter(*str) || 0==*str) - return true; - ++str; - } - return false; -} - -std::string valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - if (value == Value::minLargestInt) { - uintToString(LargestUInt(Value::maxLargestInt) + 1, current); - *--current = '-'; - } else if (value < 0) { - uintToString(LargestUInt(-value), current); - *--current = '-'; - } else { - uintToString(LargestUInt(value), current); - } - assert(current >= buffer); - return current; -} - -std::string valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -std::string valueToString(Int value) { - return valueToString(LargestInt(value)); -} - -std::string valueToString(UInt value) { - return valueToString(LargestUInt(value)); -} - -#endif // # if defined(JSON_HAS_INT64) - -std::string valueToString(double value, bool useSpecialFloats, unsigned int precision) { - // Allocate a buffer that is more than large enough to store the 16 digits of - // precision requested below. - char buffer[32]; - int len = -1; - - char formatString[6]; - sprintf(formatString, "%%.%dg", precision); - - // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distinguish the - // concepts of reals and integers. - if (isfinite(value)) { - len = snprintf(buffer, sizeof(buffer), formatString, value); - } else { - // IEEE standard states that NaN values will not compare to themselves - if (value != value) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); - } else if (value < 0) { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); - } else { - len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); - } - // For those, we do not need to call fixNumLoc, but it is fast. - } - assert(len >= 0); - fixNumericLocale(buffer, buffer + len); - return buffer; -} - -std::string valueToString(double value) { return valueToString(value, false, 17); } - -std::string valueToString(bool value) { return value ? "true" : "false"; } - -std::string valueToQuotedString(const char* value) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && - !containsControlCharacter(value)) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = - strlen(value) * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - for (const char* c = value; *c != 0; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something. - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp -static char const* strnpbrk(char const* s, char const* accept, size_t n) { - assert((s || !n) && accept); - - char const* const end = s + n; - for (char const* cur = s; cur < end; ++cur) { - int const c = *cur; - for (char const* a = accept; *a; ++a) { - if (*a == c) { - return cur; - } - } - } - return NULL; -} -static std::string valueToQuotedStringN(const char* value, unsigned length) { - if (value == NULL) - return ""; - // Not sure how to handle unicode... - if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && - !containsControlCharacter0(value, length)) - return std::string("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to std::string is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - std::string::size_type maxsize = - length * 2 + 3; // allescaped+quotes+NULL - std::string result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - result += oss.str(); - } else { - result += *c; - } - break; - } - } - result += "\""; - return result; -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() {} - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), - omitEndingLineFeed_(false) {} - -void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -std::string FastWriter::write(const Value& root) { - document_ = ""; - writeValue(root); - if (!omitEndingLineFeed_) - document_ += "\n"; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - int size = value.size(); - for (int index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (Value::Members::iterator it = members.begin(); it != members.end(); - ++it) { - const std::string& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); - document_ += yamlCompatiblityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() - : rightMargin_(74), indentSize_(3), addChildValues_() {} - -std::string StyledWriter::write(const Value& root) { - document_ = ""; - addChildValues_ = false; - indentString_ = ""; - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += "\n"; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const std::string& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultineArray(const Value& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const std::string& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const std::string& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += "\n"; - writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += "\n"; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += "\n"; - document_ += root.getComment(commentAfter); - document_ += "\n"; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(std::string indentation) - : document_(NULL), rightMargin_(74), indentation_(indentation), - addChildValues_() {} - -void StyledStreamWriter::write(std::ostream& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_ = ""; - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = NULL; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: - { - // Is NULL possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - const std::string& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultineArray(const Value& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const std::string& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const std::string& value) { - if (!indented_) writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter -{ - BuiltStyledStreamWriter( - std::string const& indentation, - CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision); - int write(Value const& root, std::ostream* sout) override; -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultineArray(Value const& value); - void pushValue(std::string const& value); - void writeIndent(); - void writeWithIndent(std::string const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - typedef std::vector ChildValues; - - ChildValues childValues_; - std::string indentString_; - int rightMargin_; - std::string indentation_; - CommentStyle::Enum cs_; - std::string colonSymbol_; - std::string nullSymbol_; - std::string endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; - bool useSpecialFloats_ : 1; - unsigned int precision_; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - std::string const& indentation, - CommentStyle::Enum cs, - std::string const& colonSymbol, - std::string const& nullSymbol, - std::string const& endingLineFeedSymbol, - bool useSpecialFloats, - unsigned int precision) - : rightMargin_(74) - , indentation_(indentation) - , cs_(cs) - , colonSymbol_(colonSymbol) - , nullSymbol_(nullSymbol) - , endingLineFeedSymbol_(endingLineFeedSymbol) - , addChildValues_(false) - , indented_(false) - , useSpecialFloats_(useSpecialFloats) - , precision_(precision) -{ -} -int BuiltStyledStreamWriter::write(Value const& root, std::ostream* sout) -{ - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_ = ""; - writeCommentBeforeValue(root); - if (!indented_) writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = NULL; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); - break; - case stringValue: - { - // Is NULL is possible for value.string_? - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); - else pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - Value::Members::iterator it = members.begin(); - for (;;) { - std::string const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ", "; - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { - int size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (int index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - childValue.size() > 0); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (int index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += int(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(std::string const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(std::string const& value) { - if (!indented_) writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) writeIndent(); - const std::string& comment = root.getComment(commentBefore); - std::string::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && - (iter != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { - if (cs_ == CommentStyle::None) return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() - : sout_(NULL) -{ -} -StreamWriter::~StreamWriter() -{ -} -StreamWriter::Factory::~Factory() -{} -StreamWriterBuilder::StreamWriterBuilder() -{ - setDefaults(&settings_); -} -StreamWriterBuilder::~StreamWriterBuilder() -{} -StreamWriter* StreamWriterBuilder::newStreamWriter() const -{ - std::string indentation = settings_["indentation"].asString(); - std::string cs_str = settings_["commentStyle"].asString(); - bool eyc = settings_["enableYAMLCompatibility"].asBool(); - bool dnp = settings_["dropNullPlaceholders"].asBool(); - bool usf = settings_["useSpecialFloats"].asBool(); - unsigned int pre = settings_["precision"].asUInt(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - std::string colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - std::string nullSymbol = "null"; - if (dnp) { - nullSymbol = ""; - } - if (pre > 17) pre = 17; - std::string endingLineFeedSymbol = ""; - return new BuiltStyledStreamWriter( - indentation, cs, - colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); -} -static void getValidWriterKeys(std::set* valid_keys) -{ - valid_keys->clear(); - valid_keys->insert("indentation"); - valid_keys->insert("commentStyle"); - valid_keys->insert("enableYAMLCompatibility"); - valid_keys->insert("dropNullPlaceholders"); - valid_keys->insert("useSpecialFloats"); - valid_keys->insert("precision"); -} -bool StreamWriterBuilder::validate(Json::Value* invalid) const -{ - Json::Value my_invalid; - if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL - Json::Value& inv = *invalid; - std::set valid_keys; - getValidWriterKeys(&valid_keys); - Value::Members keys = settings_.getMemberNames(); - size_t n = keys.size(); - for (size_t i = 0; i < n; ++i) { - std::string const& key = keys[i]; - if (valid_keys.find(key) == valid_keys.end()) { - inv[key] = settings_[key]; - } - } - return 0u == inv.size(); -} -Value& StreamWriterBuilder::operator[](std::string key) -{ - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) -{ - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - (*settings)["useSpecialFloats"] = false; - (*settings)["precision"] = 17; - //! [StreamWriterBuilderDefaults] -} - -std::string writeString(StreamWriter::Factory const& builder, Value const& root) { - std::ostringstream sout; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -std::ostream& operator<<(std::ostream& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - diff --git a/java/core/src/main/java/com/google/protobuf/CanIgnoreReturnValue.java b/java/core/src/main/java/com/google/protobuf/CanIgnoreReturnValue.java index 9e84432aab..d31f1edf32 100644 --- a/java/core/src/main/java/com/google/protobuf/CanIgnoreReturnValue.java +++ b/java/core/src/main/java/com/google/protobuf/CanIgnoreReturnValue.java @@ -31,7 +31,6 @@ package com.google.protobuf; import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.CLASS; import java.lang.annotation.Documented; @@ -45,6 +44,6 @@ import java.lang.annotation.Target; * annotated with {@code @CheckReturnValue} to exempt specific methods from the default. */ @Documented -@Target({METHOD, TYPE}) +@Target(METHOD) // TODO(kak): consider adding CONSTRUCTOR later if necessary @Retention(CLASS) @interface CanIgnoreReturnValue {} diff --git a/java/core/src/test/proto/com/google/protobuf/proto2_message.proto b/java/core/src/test/proto/com/google/protobuf/proto2_message.proto index 86c48b0986..dad00ed7a4 100644 --- a/java/core/src/test/proto/com/google/protobuf/proto2_message.proto +++ b/java/core/src/test/proto/com/google/protobuf/proto2_message.proto @@ -36,7 +36,6 @@ package protobuf.experimental; option java_package = "com.google.protobuf.testing"; option java_outer_classname = "Proto2Testing"; - message Proto2SpecialFieldName { optional double regular_name = 1; optional int32 cached_size = 2; diff --git a/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto b/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto index 7dfd40eea3..57efc171de 100644 --- a/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto +++ b/java/core/src/test/proto/com/google/protobuf/proto2_message_lite.proto @@ -36,7 +36,6 @@ package protobuf.experimental.lite; option java_package = "com.google.protobuf.testing"; option java_outer_classname = "Proto2TestingLite"; - message Proto2MessageLite { enum TestEnum { diff --git a/kokoro/linux/32-bit/test_php.sh b/kokoro/linux/32-bit/test_php.sh index 739467b20c..746ed4c2f1 100644 --- a/kokoro/linux/32-bit/test_php.sh +++ b/kokoro/linux/32-bit/test_php.sh @@ -36,7 +36,7 @@ build_php_c() { test_php_c } -mkdir build +mkdir -p build pushd build cmake .. cmake --build . -- -j20 diff --git a/objectivec/.clang-format b/objectivec/.clang-format index d3ff76bb20..f6cb8ad931 100644 --- a/objectivec/.clang-format +++ b/objectivec/.clang-format @@ -1,7 +1 @@ BasedOnStyle: Google - -# Ignore pddm directives. -CommentPragmas: '^%' - -# Following the rest of the protobuf code. -ColumnLimit: 80 diff --git a/pkg/BUILD.bazel b/pkg/BUILD.bazel index ee300f6334..2d321512d9 100644 --- a/pkg/BUILD.bazel +++ b/pkg/BUILD.bazel @@ -340,6 +340,10 @@ cc_dist_library( tags = ["manual"], deps = [ "//src/google/protobuf:arena", + "//src/google/protobuf:arena_align", + "//src/google/protobuf:arena_allocation_policy", + "//src/google/protobuf:arena_cleanup", + "//src/google/protobuf:arena_config", "//src/google/protobuf:protobuf_lite", "//src/google/protobuf/io", "//src/google/protobuf/io:io_win32", @@ -361,6 +365,10 @@ cc_dist_library( "//src/google/protobuf:wkt_cc_proto", "//src/google/protobuf:protobuf_nowkt", "//src/google/protobuf:arena", + "//src/google/protobuf:arena_align", + "//src/google/protobuf:arena_allocation_policy", + "//src/google/protobuf:arena_cleanup", + "//src/google/protobuf:arena_config", "//src/google/protobuf:protobuf_lite", "//src/google/protobuf:port_def", "//src/google/protobuf/compiler:importer", @@ -371,6 +379,14 @@ cc_dist_library( "//src/google/protobuf/io:tokenizer", "//src/google/protobuf/io:zero_copy_sink", "//src/google/protobuf/json", + "//src/google/protobuf/json:descriptor_traits", + "//src/google/protobuf/json:lexer", + "//src/google/protobuf/json:message_path", + "//src/google/protobuf/json:parser", + "//src/google/protobuf/json:unparser", + "//src/google/protobuf/json:untyped_message", + "//src/google/protobuf/json:writer", + "//src/google/protobuf/json:zero_copy_buffered_stream", "//src/google/protobuf/stubs", "//src/google/protobuf/stubs:lite", "//src/google/protobuf/util:delimited_message_util", diff --git a/protobuf.bzl b/protobuf.bzl index 8ed2cfa442..f638f39a98 100644 --- a/protobuf.bzl +++ b/protobuf.bzl @@ -1,8 +1,7 @@ load("@bazel_skylib//lib:versions.bzl", "versions") -load("@bazel_skylib//lib:collections.bzl", "collections") -load("@rules_cc//cc:defs.bzl", "cc_library", "objc_library") +load("@rules_cc//cc:defs.bzl", "objc_library") load("@rules_proto//proto:defs.bzl", "ProtoInfo") -load("@rules_python//python:defs.bzl", "py_library", "py_test") +load("@rules_python//python:defs.bzl", "py_library") def _GetPath(ctx, path): if ctx.label.workspace_root: @@ -41,13 +40,14 @@ def _SourceDir(ctx): def _ObjcBase(srcs): return [ "".join([token.capitalize() for token in src[:-len(".proto")].split("_")]) - for src in srcs] + for src in srcs + ] def _ObjcHdrs(srcs): - return[src + ".pbobjc.h" for src in _ObjcBase(srcs)] + return [src + ".pbobjc.h" for src in _ObjcBase(srcs)] def _ObjcSrcs(srcs): - return[src + ".pbobjc.m" for src in _ObjcBase(srcs)] + return [src + ".pbobjc.m" for src in _ObjcBase(srcs)] def _ObjcOuts(srcs, out_type): if out_type == "hdrs": @@ -68,7 +68,8 @@ def _RubyOuts(srcs): def _CsharpOuts(srcs): return [ "".join([token.capitalize() for token in src[:-len(".proto")].split("_")]) + ".cs" - for src in srcs] + for src in srcs + ] ProtoGenInfo = provider( fields = ["srcs", "import_flags", "deps"], @@ -97,7 +98,7 @@ def _proto_gen_impl(ctx): if ctx.attr.includes: for include in ctx.attr.includes: - import_flags += ["-I"+_GetPath(ctx,include)] + import_flags += ["-I" + _GetPath(ctx, include)] import_flags = depset(direct = import_flags) @@ -150,6 +151,7 @@ def _proto_gen_impl(ctx): outs.extend(_PyOuts([src.basename], use_grpc_plugin = use_grpc_plugin)) elif lang == "ruby": outs.extend(_RubyOuts([src.basename])) + # Otherwise, rely on user-supplied outs. args += [("--%s_out=" + path_tpl) % (lang, gen_dir)] @@ -262,7 +264,7 @@ _proto_gen = rule( "langs": attr.string_list(), "outs": attr.string_list(), "out_type": attr.string( - default = "all" + default = "all", ), }, output_to_genfiles = True, @@ -642,7 +644,7 @@ def _source_proto_library( native.filegroup( name = name, - srcs = [":%s_genproto"%name], + srcs = [":%s_genproto" % name], testonly = testonly, visibility = visibility, **kwargs diff --git a/python/BUILD.bazel b/python/BUILD.bazel index ffaf988be1..56d8c8abe6 100644 --- a/python/BUILD.bazel +++ b/python/BUILD.bazel @@ -275,6 +275,13 @@ py_test( deps = [":python_test_lib"], ) +py_test( + name = "field_mask_test", + srcs = ["google/protobuf/internal/field_mask_test.py"], + imports = ["."], + deps = [":python_test_lib"], +) + py_test( name = "generator_test", srcs = ["google/protobuf/internal/generator_test.py"], @@ -453,12 +460,10 @@ pkg_files( "google/protobuf/pyext/README", "google/protobuf/python_protobuf.h", "internal.bzl", - "mox.py", "python_version.py", "release.sh", "setup.cfg", "setup.py", - "stubout.py", "tox.ini", ], strip_prefix = strip_prefix.from_root(""), diff --git a/python/google/protobuf/internal/field_mask.py b/python/google/protobuf/internal/field_mask.py new file mode 100644 index 0000000000..489769901e --- /dev/null +++ b/python/google/protobuf/internal/field_mask.py @@ -0,0 +1,333 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# https://developers.google.com/protocol-buffers/ +# +# 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. + +"""Contains FieldMask class.""" + +from google.protobuf.descriptor import FieldDescriptor + + +class FieldMask(object): + """Class for FieldMask message type.""" + + __slots__ = () + + def ToJsonString(self): + """Converts FieldMask to string according to proto3 JSON spec.""" + camelcase_paths = [] + for path in self.paths: + camelcase_paths.append(_SnakeCaseToCamelCase(path)) + return ','.join(camelcase_paths) + + def FromJsonString(self, value): + """Converts string to FieldMask according to proto3 JSON spec.""" + if not isinstance(value, str): + raise ValueError('FieldMask JSON value not a string: {!r}'.format(value)) + self.Clear() + if value: + for path in value.split(','): + self.paths.append(_CamelCaseToSnakeCase(path)) + + def IsValidForDescriptor(self, message_descriptor): + """Checks whether the FieldMask is valid for Message Descriptor.""" + for path in self.paths: + if not _IsValidPath(message_descriptor, path): + return False + return True + + def AllFieldsFromDescriptor(self, message_descriptor): + """Gets all direct fields of Message Descriptor to FieldMask.""" + self.Clear() + for field in message_descriptor.fields: + self.paths.append(field.name) + + def CanonicalFormFromMask(self, mask): + """Converts a FieldMask to the canonical form. + + Removes paths that are covered by another path. For example, + "foo.bar" is covered by "foo" and will be removed if "foo" + is also in the FieldMask. Then sorts all paths in alphabetical order. + + Args: + mask: The original FieldMask to be converted. + """ + tree = _FieldMaskTree(mask) + tree.ToFieldMask(self) + + def Union(self, mask1, mask2): + """Merges mask1 and mask2 into this FieldMask.""" + _CheckFieldMaskMessage(mask1) + _CheckFieldMaskMessage(mask2) + tree = _FieldMaskTree(mask1) + tree.MergeFromFieldMask(mask2) + tree.ToFieldMask(self) + + def Intersect(self, mask1, mask2): + """Intersects mask1 and mask2 into this FieldMask.""" + _CheckFieldMaskMessage(mask1) + _CheckFieldMaskMessage(mask2) + tree = _FieldMaskTree(mask1) + intersection = _FieldMaskTree() + for path in mask2.paths: + tree.IntersectPath(path, intersection) + intersection.ToFieldMask(self) + + def MergeMessage( + self, source, destination, + replace_message_field=False, replace_repeated_field=False): + """Merges fields specified in FieldMask from source to destination. + + Args: + source: Source message. + destination: The destination message to be merged into. + replace_message_field: Replace message field if True. Merge message + field if False. + replace_repeated_field: Replace repeated field if True. Append + elements of repeated field if False. + """ + tree = _FieldMaskTree(self) + tree.MergeMessage( + source, destination, replace_message_field, replace_repeated_field) + + +def _IsValidPath(message_descriptor, path): + """Checks whether the path is valid for Message Descriptor.""" + parts = path.split('.') + last = parts.pop() + for name in parts: + field = message_descriptor.fields_by_name.get(name) + if (field is None or + field.label == FieldDescriptor.LABEL_REPEATED or + field.type != FieldDescriptor.TYPE_MESSAGE): + return False + message_descriptor = field.message_type + return last in message_descriptor.fields_by_name + + +def _CheckFieldMaskMessage(message): + """Raises ValueError if message is not a FieldMask.""" + message_descriptor = message.DESCRIPTOR + if (message_descriptor.name != 'FieldMask' or + message_descriptor.file.name != 'google/protobuf/field_mask.proto'): + raise ValueError('Message {0} is not a FieldMask.'.format( + message_descriptor.full_name)) + + +def _SnakeCaseToCamelCase(path_name): + """Converts a path name from snake_case to camelCase.""" + result = [] + after_underscore = False + for c in path_name: + if c.isupper(): + raise ValueError( + 'Fail to print FieldMask to Json string: Path name ' + '{0} must not contain uppercase letters.'.format(path_name)) + if after_underscore: + if c.islower(): + result.append(c.upper()) + after_underscore = False + else: + raise ValueError( + 'Fail to print FieldMask to Json string: The ' + 'character after a "_" must be a lowercase letter ' + 'in path name {0}.'.format(path_name)) + elif c == '_': + after_underscore = True + else: + result += c + + if after_underscore: + raise ValueError('Fail to print FieldMask to Json string: Trailing "_" ' + 'in path name {0}.'.format(path_name)) + return ''.join(result) + + +def _CamelCaseToSnakeCase(path_name): + """Converts a field name from camelCase to snake_case.""" + result = [] + for c in path_name: + if c == '_': + raise ValueError('Fail to parse FieldMask: Path name ' + '{0} must not contain "_"s.'.format(path_name)) + if c.isupper(): + result += '_' + result += c.lower() + else: + result += c + return ''.join(result) + + +class _FieldMaskTree(object): + """Represents a FieldMask in a tree structure. + + For example, given a FieldMask "foo.bar,foo.baz,bar.baz", + the FieldMaskTree will be: + [_root] -+- foo -+- bar + | | + | +- baz + | + +- bar --- baz + In the tree, each leaf node represents a field path. + """ + + __slots__ = ('_root',) + + def __init__(self, field_mask=None): + """Initializes the tree by FieldMask.""" + self._root = {} + if field_mask: + self.MergeFromFieldMask(field_mask) + + def MergeFromFieldMask(self, field_mask): + """Merges a FieldMask to the tree.""" + for path in field_mask.paths: + self.AddPath(path) + + def AddPath(self, path): + """Adds a field path into the tree. + + If the field path to add is a sub-path of an existing field path + in the tree (i.e., a leaf node), it means the tree already matches + the given path so nothing will be added to the tree. If the path + matches an existing non-leaf node in the tree, that non-leaf node + will be turned into a leaf node with all its children removed because + the path matches all the node's children. Otherwise, a new path will + be added. + + Args: + path: The field path to add. + """ + node = self._root + for name in path.split('.'): + if name not in node: + node[name] = {} + elif not node[name]: + # Pre-existing empty node implies we already have this entire tree. + return + node = node[name] + # Remove any sub-trees we might have had. + node.clear() + + def ToFieldMask(self, field_mask): + """Converts the tree to a FieldMask.""" + field_mask.Clear() + _AddFieldPaths(self._root, '', field_mask) + + def IntersectPath(self, path, intersection): + """Calculates the intersection part of a field path with this tree. + + Args: + path: The field path to calculates. + intersection: The out tree to record the intersection part. + """ + node = self._root + for name in path.split('.'): + if name not in node: + return + elif not node[name]: + intersection.AddPath(path) + return + node = node[name] + intersection.AddLeafNodes(path, node) + + def AddLeafNodes(self, prefix, node): + """Adds leaf nodes begin with prefix to this tree.""" + if not node: + self.AddPath(prefix) + for name in node: + child_path = prefix + '.' + name + self.AddLeafNodes(child_path, node[name]) + + def MergeMessage( + self, source, destination, + replace_message, replace_repeated): + """Merge all fields specified by this tree from source to destination.""" + _MergeMessage( + self._root, source, destination, replace_message, replace_repeated) + + +def _StrConvert(value): + """Converts value to str if it is not.""" + # This file is imported by c extension and some methods like ClearField + # requires string for the field name. py2/py3 has different text + # type and may use unicode. + if not isinstance(value, str): + return value.encode('utf-8') + return value + + +def _MergeMessage( + node, source, destination, replace_message, replace_repeated): + """Merge all fields specified by a sub-tree from source to destination.""" + source_descriptor = source.DESCRIPTOR + for name in node: + child = node[name] + field = source_descriptor.fields_by_name[name] + if field is None: + raise ValueError('Error: Can\'t find field {0} in message {1}.'.format( + name, source_descriptor.full_name)) + if child: + # Sub-paths are only allowed for singular message fields. + if (field.label == FieldDescriptor.LABEL_REPEATED or + field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE): + raise ValueError('Error: Field {0} in message {1} is not a singular ' + 'message field and cannot have sub-fields.'.format( + name, source_descriptor.full_name)) + if source.HasField(name): + _MergeMessage( + child, getattr(source, name), getattr(destination, name), + replace_message, replace_repeated) + continue + if field.label == FieldDescriptor.LABEL_REPEATED: + if replace_repeated: + destination.ClearField(_StrConvert(name)) + repeated_source = getattr(source, name) + repeated_destination = getattr(destination, name) + repeated_destination.MergeFrom(repeated_source) + else: + if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: + if replace_message: + destination.ClearField(_StrConvert(name)) + if source.HasField(name): + getattr(destination, name).MergeFrom(getattr(source, name)) + else: + setattr(destination, name, getattr(source, name)) + + +def _AddFieldPaths(node, prefix, field_mask): + """Adds the field paths descended from node to field_mask.""" + if not node and prefix: + field_mask.paths.append(prefix) + return + for name in sorted(node): + if prefix: + child_path = prefix + '.' + name + else: + child_path = name + _AddFieldPaths(node[name], child_path, field_mask) diff --git a/python/google/protobuf/internal/field_mask_test.py b/python/google/protobuf/internal/field_mask_test.py new file mode 100644 index 0000000000..82664185f6 --- /dev/null +++ b/python/google/protobuf/internal/field_mask_test.py @@ -0,0 +1,400 @@ +# Protocol Buffers - Google's data interchange format +# Copyright 2008 Google Inc. All rights reserved. +# https://developers.google.com/protocol-buffers/ +# +# 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. + +"""Test for google.protobuf.internal.well_known_types.""" + +import unittest + +from google.protobuf import field_mask_pb2 +from google.protobuf import map_unittest_pb2 +from google.protobuf import unittest_pb2 +from google.protobuf.internal import field_mask +from google.protobuf.internal import test_util +from google.protobuf import descriptor + + +class FieldMaskTest(unittest.TestCase): + + def testStringFormat(self): + mask = field_mask_pb2.FieldMask() + self.assertEqual('', mask.ToJsonString()) + mask.paths.append('foo') + self.assertEqual('foo', mask.ToJsonString()) + mask.paths.append('bar') + self.assertEqual('foo,bar', mask.ToJsonString()) + + mask.FromJsonString('') + self.assertEqual('', mask.ToJsonString()) + mask.FromJsonString('foo') + self.assertEqual(['foo'], mask.paths) + mask.FromJsonString('foo,bar') + self.assertEqual(['foo', 'bar'], mask.paths) + + # Test camel case + mask.Clear() + mask.paths.append('foo_bar') + self.assertEqual('fooBar', mask.ToJsonString()) + mask.paths.append('bar_quz') + self.assertEqual('fooBar,barQuz', mask.ToJsonString()) + + mask.FromJsonString('') + self.assertEqual('', mask.ToJsonString()) + self.assertEqual([], mask.paths) + mask.FromJsonString('fooBar') + self.assertEqual(['foo_bar'], mask.paths) + mask.FromJsonString('fooBar,barQuz') + self.assertEqual(['foo_bar', 'bar_quz'], mask.paths) + + def testDescriptorToFieldMask(self): + mask = field_mask_pb2.FieldMask() + msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR + mask.AllFieldsFromDescriptor(msg_descriptor) + self.assertEqual(76, len(mask.paths)) + self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) + for field in msg_descriptor.fields: + self.assertTrue(field.name in mask.paths) + + def testIsValidForDescriptor(self): + msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR + # Empty mask + mask = field_mask_pb2.FieldMask() + self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) + # All fields from descriptor + mask.AllFieldsFromDescriptor(msg_descriptor) + self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) + # Child under optional message + mask.paths.append('optional_nested_message.bb') + self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) + # Repeated field is only allowed in the last position of path + mask.paths.append('repeated_nested_message.bb') + self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) + # Invalid top level field + mask = field_mask_pb2.FieldMask() + mask.paths.append('xxx') + self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) + # Invalid field in root + mask = field_mask_pb2.FieldMask() + mask.paths.append('xxx.zzz') + self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) + # Invalid field in internal node + mask = field_mask_pb2.FieldMask() + mask.paths.append('optional_nested_message.xxx.zzz') + self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) + # Invalid field in leaf + mask = field_mask_pb2.FieldMask() + mask.paths.append('optional_nested_message.xxx') + self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) + + def testCanonicalFrom(self): + mask = field_mask_pb2.FieldMask() + out_mask = field_mask_pb2.FieldMask() + # Paths will be sorted. + mask.FromJsonString('baz.quz,bar,foo') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString()) + # Duplicated paths will be removed. + mask.FromJsonString('foo,bar,foo') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('bar,foo', out_mask.ToJsonString()) + # Sub-paths of other paths will be removed. + mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString()) + + # Test more deeply nested cases. + mask.FromJsonString( + 'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('foo.bar.baz1,foo.bar.baz2', + out_mask.ToJsonString()) + mask.FromJsonString( + 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('foo.bar.baz1,foo.bar.baz2', + out_mask.ToJsonString()) + mask.FromJsonString( + 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('foo.bar', out_mask.ToJsonString()) + mask.FromJsonString( + 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo') + out_mask.CanonicalFormFromMask(mask) + self.assertEqual('foo', out_mask.ToJsonString()) + + def testUnion(self): + mask1 = field_mask_pb2.FieldMask() + mask2 = field_mask_pb2.FieldMask() + out_mask = field_mask_pb2.FieldMask() + mask1.FromJsonString('foo,baz') + mask2.FromJsonString('bar,quz') + out_mask.Union(mask1, mask2) + self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString()) + # Overlap with duplicated paths. + mask1.FromJsonString('foo,baz.bb') + mask2.FromJsonString('baz.bb,quz') + out_mask.Union(mask1, mask2) + self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString()) + # Overlap with paths covering some other paths. + mask1.FromJsonString('foo.bar.baz,quz') + mask2.FromJsonString('foo.bar,bar') + out_mask.Union(mask1, mask2) + self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString()) + src = unittest_pb2.TestAllTypes() + with self.assertRaises(ValueError): + out_mask.Union(src, mask2) + + def testIntersect(self): + mask1 = field_mask_pb2.FieldMask() + mask2 = field_mask_pb2.FieldMask() + out_mask = field_mask_pb2.FieldMask() + # Test cases without overlapping. + mask1.FromJsonString('foo,baz') + mask2.FromJsonString('bar,quz') + out_mask.Intersect(mask1, mask2) + self.assertEqual('', out_mask.ToJsonString()) + self.assertEqual(len(out_mask.paths), 0) + self.assertEqual(out_mask.paths, []) + # Overlap with duplicated paths. + mask1.FromJsonString('foo,baz.bb') + mask2.FromJsonString('baz.bb,quz') + out_mask.Intersect(mask1, mask2) + self.assertEqual('baz.bb', out_mask.ToJsonString()) + # Overlap with paths covering some other paths. + mask1.FromJsonString('foo.bar.baz,quz') + mask2.FromJsonString('foo.bar,bar') + out_mask.Intersect(mask1, mask2) + self.assertEqual('foo.bar.baz', out_mask.ToJsonString()) + mask1.FromJsonString('foo.bar,bar') + mask2.FromJsonString('foo.bar.baz,quz') + out_mask.Intersect(mask1, mask2) + self.assertEqual('foo.bar.baz', out_mask.ToJsonString()) + # Intersect '' with '' + mask1.Clear() + mask2.Clear() + mask1.paths.append('') + mask2.paths.append('') + self.assertEqual(mask1.paths, ['']) + self.assertEqual('', mask1.ToJsonString()) + out_mask.Intersect(mask1, mask2) + self.assertEqual(out_mask.paths, []) + + def testMergeMessageWithoutMapFields(self): + # Test merge one field. + src = unittest_pb2.TestAllTypes() + test_util.SetAllFields(src) + for field in src.DESCRIPTOR.fields: + if field.containing_oneof: + continue + field_name = field.name + dst = unittest_pb2.TestAllTypes() + # Only set one path to mask. + mask = field_mask_pb2.FieldMask() + mask.paths.append(field_name) + mask.MergeMessage(src, dst) + # The expected result message. + msg = unittest_pb2.TestAllTypes() + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + repeated_src = getattr(src, field_name) + repeated_msg = getattr(msg, field_name) + if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + for item in repeated_src: + repeated_msg.add().CopyFrom(item) + else: + repeated_msg.extend(repeated_src) + elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + getattr(msg, field_name).CopyFrom(getattr(src, field_name)) + else: + setattr(msg, field_name, getattr(src, field_name)) + # Only field specified in mask is merged. + self.assertEqual(msg, dst) + + # Test merge nested fields. + nested_src = unittest_pb2.NestedTestAllTypes() + nested_dst = unittest_pb2.NestedTestAllTypes() + nested_src.child.payload.optional_int32 = 1234 + nested_src.child.child.payload.optional_int32 = 5678 + mask = field_mask_pb2.FieldMask() + mask.FromJsonString('child.payload') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(1234, nested_dst.child.payload.optional_int32) + self.assertEqual(0, nested_dst.child.child.payload.optional_int32) + + mask.FromJsonString('child.child.payload') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(1234, nested_dst.child.payload.optional_int32) + self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) + + nested_dst.Clear() + mask.FromJsonString('child.child.payload') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(0, nested_dst.child.payload.optional_int32) + self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) + + nested_dst.Clear() + mask.FromJsonString('child') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(1234, nested_dst.child.payload.optional_int32) + self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) + + # Test MergeOptions. + nested_dst.Clear() + nested_dst.child.payload.optional_int64 = 4321 + # Message fields will be merged by default. + mask.FromJsonString('child.payload') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(1234, nested_dst.child.payload.optional_int32) + self.assertEqual(4321, nested_dst.child.payload.optional_int64) + # Change the behavior to replace message fields. + mask.FromJsonString('child.payload') + mask.MergeMessage(nested_src, nested_dst, True, False) + self.assertEqual(1234, nested_dst.child.payload.optional_int32) + self.assertEqual(0, nested_dst.child.payload.optional_int64) + + # By default, fields missing in source are not cleared in destination. + nested_dst.payload.optional_int32 = 1234 + self.assertTrue(nested_dst.HasField('payload')) + mask.FromJsonString('payload') + mask.MergeMessage(nested_src, nested_dst) + self.assertTrue(nested_dst.HasField('payload')) + # But they are cleared when replacing message fields. + nested_dst.Clear() + nested_dst.payload.optional_int32 = 1234 + mask.FromJsonString('payload') + mask.MergeMessage(nested_src, nested_dst, True, False) + self.assertFalse(nested_dst.HasField('payload')) + + nested_src.payload.repeated_int32.append(1234) + nested_dst.payload.repeated_int32.append(5678) + # Repeated fields will be appended by default. + mask.FromJsonString('payload.repeatedInt32') + mask.MergeMessage(nested_src, nested_dst) + self.assertEqual(2, len(nested_dst.payload.repeated_int32)) + self.assertEqual(5678, nested_dst.payload.repeated_int32[0]) + self.assertEqual(1234, nested_dst.payload.repeated_int32[1]) + # Change the behavior to replace repeated fields. + mask.FromJsonString('payload.repeatedInt32') + mask.MergeMessage(nested_src, nested_dst, False, True) + self.assertEqual(1, len(nested_dst.payload.repeated_int32)) + self.assertEqual(1234, nested_dst.payload.repeated_int32[0]) + + # Test Merge oneof field. + new_msg = unittest_pb2.TestOneof2() + dst = unittest_pb2.TestOneof2() + dst.foo_message.moo_int = 1 + mask = field_mask_pb2.FieldMask() + mask.FromJsonString('fooMessage,fooLazyMessage.mooInt') + mask.MergeMessage(new_msg, dst) + self.assertTrue(dst.HasField('foo_message')) + self.assertFalse(dst.HasField('foo_lazy_message')) + + def testMergeMessageWithMapField(self): + empty_map = map_unittest_pb2.TestRecursiveMapMessage() + src_level_2 = map_unittest_pb2.TestRecursiveMapMessage() + src_level_2.a['src level 2'].CopyFrom(empty_map) + src = map_unittest_pb2.TestRecursiveMapMessage() + src.a['common key'].CopyFrom(src_level_2) + src.a['src level 1'].CopyFrom(src_level_2) + + dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage() + dst_level_2.a['dst level 2'].CopyFrom(empty_map) + dst = map_unittest_pb2.TestRecursiveMapMessage() + dst.a['common key'].CopyFrom(dst_level_2) + dst.a['dst level 1'].CopyFrom(empty_map) + + mask = field_mask_pb2.FieldMask() + mask.FromJsonString('a') + mask.MergeMessage(src, dst) + + # map from dst is replaced with map from src. + self.assertEqual(dst.a['common key'], src_level_2) + self.assertEqual(dst.a['src level 1'], src_level_2) + self.assertEqual(dst.a['dst level 1'], empty_map) + + def testMergeErrors(self): + src = unittest_pb2.TestAllTypes() + dst = unittest_pb2.TestAllTypes() + mask = field_mask_pb2.FieldMask() + test_util.SetAllFields(src) + mask.FromJsonString('optionalInt32.field') + with self.assertRaises(ValueError) as e: + mask.MergeMessage(src, dst) + self.assertEqual('Error: Field optional_int32 in message ' + 'protobuf_unittest.TestAllTypes is not a singular ' + 'message field and cannot have sub-fields.', + str(e.exception)) + + def testSnakeCaseToCamelCase(self): + self.assertEqual('fooBar', + field_mask._SnakeCaseToCamelCase('foo_bar')) + self.assertEqual('FooBar', + field_mask._SnakeCaseToCamelCase('_foo_bar')) + self.assertEqual('foo3Bar', + field_mask._SnakeCaseToCamelCase('foo3_bar')) + + # No uppercase letter is allowed. + self.assertRaisesRegex( + ValueError, + 'Fail to print FieldMask to Json string: Path name Foo must ' + 'not contain uppercase letters.', + field_mask._SnakeCaseToCamelCase, 'Foo') + # Any character after a "_" must be a lowercase letter. + # 1. "_" cannot be followed by another "_". + # 2. "_" cannot be followed by a digit. + # 3. "_" cannot appear as the last character. + self.assertRaisesRegex( + ValueError, + 'Fail to print FieldMask to Json string: The character after a ' + '"_" must be a lowercase letter in path name foo__bar.', + field_mask._SnakeCaseToCamelCase, 'foo__bar') + self.assertRaisesRegex( + ValueError, + 'Fail to print FieldMask to Json string: The character after a ' + '"_" must be a lowercase letter in path name foo_3bar.', + field_mask._SnakeCaseToCamelCase, 'foo_3bar') + self.assertRaisesRegex( + ValueError, + 'Fail to print FieldMask to Json string: Trailing "_" in path ' + 'name foo_bar_.', field_mask._SnakeCaseToCamelCase, 'foo_bar_') + + def testCamelCaseToSnakeCase(self): + self.assertEqual('foo_bar', + field_mask._CamelCaseToSnakeCase('fooBar')) + self.assertEqual('_foo_bar', + field_mask._CamelCaseToSnakeCase('FooBar')) + self.assertEqual('foo3_bar', + field_mask._CamelCaseToSnakeCase('foo3Bar')) + self.assertRaisesRegex( + ValueError, + 'Fail to parse FieldMask: Path name foo_bar must not contain "_"s.', + field_mask._CamelCaseToSnakeCase, 'foo_bar') + + +if __name__ == '__main__': + unittest.main() diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto index 37baca7e53..96de1e4312 100644 --- a/python/google/protobuf/internal/missing_enum_values.proto +++ b/python/google/protobuf/internal/missing_enum_values.proto @@ -30,7 +30,6 @@ syntax = "proto2"; - package google.protobuf.python.internal; message TestEnumValues { @@ -53,4 +52,3 @@ message TestMissingEnumValues { message JustString { required string dummy = 1; } - diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py index 8881d758a5..e340f90870 100644 --- a/python/google/protobuf/internal/well_known_types.py +++ b/python/google/protobuf/internal/well_known_types.py @@ -44,7 +44,9 @@ import calendar import collections.abc import datetime -from google.protobuf.descriptor import FieldDescriptor +from google.protobuf.internal import field_mask + +FieldMask = field_mask.FieldMask _TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S' _NANOS_PER_SECOND = 1000000000 @@ -430,306 +432,6 @@ def _RoundTowardZero(value, divider): return result -class FieldMask(object): - """Class for FieldMask message type.""" - - __slots__ = () - - def ToJsonString(self): - """Converts FieldMask to string according to proto3 JSON spec.""" - camelcase_paths = [] - for path in self.paths: - camelcase_paths.append(_SnakeCaseToCamelCase(path)) - return ','.join(camelcase_paths) - - def FromJsonString(self, value): - """Converts string to FieldMask according to proto3 JSON spec.""" - if not isinstance(value, str): - raise ValueError('FieldMask JSON value not a string: {!r}'.format(value)) - self.Clear() - if value: - for path in value.split(','): - self.paths.append(_CamelCaseToSnakeCase(path)) - - def IsValidForDescriptor(self, message_descriptor): - """Checks whether the FieldMask is valid for Message Descriptor.""" - for path in self.paths: - if not _IsValidPath(message_descriptor, path): - return False - return True - - def AllFieldsFromDescriptor(self, message_descriptor): - """Gets all direct fields of Message Descriptor to FieldMask.""" - self.Clear() - for field in message_descriptor.fields: - self.paths.append(field.name) - - def CanonicalFormFromMask(self, mask): - """Converts a FieldMask to the canonical form. - - Removes paths that are covered by another path. For example, - "foo.bar" is covered by "foo" and will be removed if "foo" - is also in the FieldMask. Then sorts all paths in alphabetical order. - - Args: - mask: The original FieldMask to be converted. - """ - tree = _FieldMaskTree(mask) - tree.ToFieldMask(self) - - def Union(self, mask1, mask2): - """Merges mask1 and mask2 into this FieldMask.""" - _CheckFieldMaskMessage(mask1) - _CheckFieldMaskMessage(mask2) - tree = _FieldMaskTree(mask1) - tree.MergeFromFieldMask(mask2) - tree.ToFieldMask(self) - - def Intersect(self, mask1, mask2): - """Intersects mask1 and mask2 into this FieldMask.""" - _CheckFieldMaskMessage(mask1) - _CheckFieldMaskMessage(mask2) - tree = _FieldMaskTree(mask1) - intersection = _FieldMaskTree() - for path in mask2.paths: - tree.IntersectPath(path, intersection) - intersection.ToFieldMask(self) - - def MergeMessage( - self, source, destination, - replace_message_field=False, replace_repeated_field=False): - """Merges fields specified in FieldMask from source to destination. - - Args: - source: Source message. - destination: The destination message to be merged into. - replace_message_field: Replace message field if True. Merge message - field if False. - replace_repeated_field: Replace repeated field if True. Append - elements of repeated field if False. - """ - tree = _FieldMaskTree(self) - tree.MergeMessage( - source, destination, replace_message_field, replace_repeated_field) - - -def _IsValidPath(message_descriptor, path): - """Checks whether the path is valid for Message Descriptor.""" - parts = path.split('.') - last = parts.pop() - for name in parts: - field = message_descriptor.fields_by_name.get(name) - if (field is None or - field.label == FieldDescriptor.LABEL_REPEATED or - field.type != FieldDescriptor.TYPE_MESSAGE): - return False - message_descriptor = field.message_type - return last in message_descriptor.fields_by_name - - -def _CheckFieldMaskMessage(message): - """Raises ValueError if message is not a FieldMask.""" - message_descriptor = message.DESCRIPTOR - if (message_descriptor.name != 'FieldMask' or - message_descriptor.file.name != 'google/protobuf/field_mask.proto'): - raise ValueError('Message {0} is not a FieldMask.'.format( - message_descriptor.full_name)) - - -def _SnakeCaseToCamelCase(path_name): - """Converts a path name from snake_case to camelCase.""" - result = [] - after_underscore = False - for c in path_name: - if c.isupper(): - raise ValueError( - 'Fail to print FieldMask to Json string: Path name ' - '{0} must not contain uppercase letters.'.format(path_name)) - if after_underscore: - if c.islower(): - result.append(c.upper()) - after_underscore = False - else: - raise ValueError( - 'Fail to print FieldMask to Json string: The ' - 'character after a "_" must be a lowercase letter ' - 'in path name {0}.'.format(path_name)) - elif c == '_': - after_underscore = True - else: - result += c - - if after_underscore: - raise ValueError('Fail to print FieldMask to Json string: Trailing "_" ' - 'in path name {0}.'.format(path_name)) - return ''.join(result) - - -def _CamelCaseToSnakeCase(path_name): - """Converts a field name from camelCase to snake_case.""" - result = [] - for c in path_name: - if c == '_': - raise ValueError('Fail to parse FieldMask: Path name ' - '{0} must not contain "_"s.'.format(path_name)) - if c.isupper(): - result += '_' - result += c.lower() - else: - result += c - return ''.join(result) - - -class _FieldMaskTree(object): - """Represents a FieldMask in a tree structure. - - For example, given a FieldMask "foo.bar,foo.baz,bar.baz", - the FieldMaskTree will be: - [_root] -+- foo -+- bar - | | - | +- baz - | - +- bar --- baz - In the tree, each leaf node represents a field path. - """ - - __slots__ = ('_root',) - - def __init__(self, field_mask=None): - """Initializes the tree by FieldMask.""" - self._root = {} - if field_mask: - self.MergeFromFieldMask(field_mask) - - def MergeFromFieldMask(self, field_mask): - """Merges a FieldMask to the tree.""" - for path in field_mask.paths: - self.AddPath(path) - - def AddPath(self, path): - """Adds a field path into the tree. - - If the field path to add is a sub-path of an existing field path - in the tree (i.e., a leaf node), it means the tree already matches - the given path so nothing will be added to the tree. If the path - matches an existing non-leaf node in the tree, that non-leaf node - will be turned into a leaf node with all its children removed because - the path matches all the node's children. Otherwise, a new path will - be added. - - Args: - path: The field path to add. - """ - node = self._root - for name in path.split('.'): - if name not in node: - node[name] = {} - elif not node[name]: - # Pre-existing empty node implies we already have this entire tree. - return - node = node[name] - # Remove any sub-trees we might have had. - node.clear() - - def ToFieldMask(self, field_mask): - """Converts the tree to a FieldMask.""" - field_mask.Clear() - _AddFieldPaths(self._root, '', field_mask) - - def IntersectPath(self, path, intersection): - """Calculates the intersection part of a field path with this tree. - - Args: - path: The field path to calculates. - intersection: The out tree to record the intersection part. - """ - node = self._root - for name in path.split('.'): - if name not in node: - return - elif not node[name]: - intersection.AddPath(path) - return - node = node[name] - intersection.AddLeafNodes(path, node) - - def AddLeafNodes(self, prefix, node): - """Adds leaf nodes begin with prefix to this tree.""" - if not node: - self.AddPath(prefix) - for name in node: - child_path = prefix + '.' + name - self.AddLeafNodes(child_path, node[name]) - - def MergeMessage( - self, source, destination, - replace_message, replace_repeated): - """Merge all fields specified by this tree from source to destination.""" - _MergeMessage( - self._root, source, destination, replace_message, replace_repeated) - - -def _StrConvert(value): - """Converts value to str if it is not.""" - # This file is imported by c extension and some methods like ClearField - # requires string for the field name. py2/py3 has different text - # type and may use unicode. - if not isinstance(value, str): - return value.encode('utf-8') - return value - - -def _MergeMessage( - node, source, destination, replace_message, replace_repeated): - """Merge all fields specified by a sub-tree from source to destination.""" - source_descriptor = source.DESCRIPTOR - for name in node: - child = node[name] - field = source_descriptor.fields_by_name[name] - if field is None: - raise ValueError('Error: Can\'t find field {0} in message {1}.'.format( - name, source_descriptor.full_name)) - if child: - # Sub-paths are only allowed for singular message fields. - if (field.label == FieldDescriptor.LABEL_REPEATED or - field.cpp_type != FieldDescriptor.CPPTYPE_MESSAGE): - raise ValueError('Error: Field {0} in message {1} is not a singular ' - 'message field and cannot have sub-fields.'.format( - name, source_descriptor.full_name)) - if source.HasField(name): - _MergeMessage( - child, getattr(source, name), getattr(destination, name), - replace_message, replace_repeated) - continue - if field.label == FieldDescriptor.LABEL_REPEATED: - if replace_repeated: - destination.ClearField(_StrConvert(name)) - repeated_source = getattr(source, name) - repeated_destination = getattr(destination, name) - repeated_destination.MergeFrom(repeated_source) - else: - if field.cpp_type == FieldDescriptor.CPPTYPE_MESSAGE: - if replace_message: - destination.ClearField(_StrConvert(name)) - if source.HasField(name): - getattr(destination, name).MergeFrom(getattr(source, name)) - else: - setattr(destination, name, getattr(source, name)) - - -def _AddFieldPaths(node, prefix, field_mask): - """Adds the field paths descended from node to field_mask.""" - if not node and prefix: - field_mask.paths.append(prefix) - return - for name in sorted(node): - if prefix: - child_path = prefix + '.' + name - else: - child_path = name - _AddFieldPaths(node[name], child_path, field_mask) - - def _SetStructValue(struct_value, value): if value is None: struct_value.null_value = 0 diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py index a32459a9e6..601ae4119b 100644 --- a/python/google/protobuf/internal/well_known_types_test.py +++ b/python/google/protobuf/internal/well_known_types_test.py @@ -38,15 +38,11 @@ import unittest from google.protobuf import any_pb2 from google.protobuf import duration_pb2 -from google.protobuf import field_mask_pb2 from google.protobuf import struct_pb2 from google.protobuf import timestamp_pb2 -from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_pb2 from google.protobuf.internal import any_test_pb2 -from google.protobuf.internal import test_util from google.protobuf.internal import well_known_types -from google.protobuf import descriptor from google.protobuf import text_format from google.protobuf.internal import _parameterized @@ -390,362 +386,6 @@ class TimeUtilTest(TimeUtilTestBase): message.ToJsonString) -class FieldMaskTest(unittest.TestCase): - - def testStringFormat(self): - mask = field_mask_pb2.FieldMask() - self.assertEqual('', mask.ToJsonString()) - mask.paths.append('foo') - self.assertEqual('foo', mask.ToJsonString()) - mask.paths.append('bar') - self.assertEqual('foo,bar', mask.ToJsonString()) - - mask.FromJsonString('') - self.assertEqual('', mask.ToJsonString()) - mask.FromJsonString('foo') - self.assertEqual(['foo'], mask.paths) - mask.FromJsonString('foo,bar') - self.assertEqual(['foo', 'bar'], mask.paths) - - # Test camel case - mask.Clear() - mask.paths.append('foo_bar') - self.assertEqual('fooBar', mask.ToJsonString()) - mask.paths.append('bar_quz') - self.assertEqual('fooBar,barQuz', mask.ToJsonString()) - - mask.FromJsonString('') - self.assertEqual('', mask.ToJsonString()) - self.assertEqual([], mask.paths) - mask.FromJsonString('fooBar') - self.assertEqual(['foo_bar'], mask.paths) - mask.FromJsonString('fooBar,barQuz') - self.assertEqual(['foo_bar', 'bar_quz'], mask.paths) - - def testDescriptorToFieldMask(self): - mask = field_mask_pb2.FieldMask() - msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR - mask.AllFieldsFromDescriptor(msg_descriptor) - self.assertEqual(76, len(mask.paths)) - self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) - for field in msg_descriptor.fields: - self.assertTrue(field.name in mask.paths) - - def testIsValidForDescriptor(self): - msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR - # Empty mask - mask = field_mask_pb2.FieldMask() - self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) - # All fields from descriptor - mask.AllFieldsFromDescriptor(msg_descriptor) - self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) - # Child under optional message - mask.paths.append('optional_nested_message.bb') - self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) - # Repeated field is only allowed in the last position of path - mask.paths.append('repeated_nested_message.bb') - self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) - # Invalid top level field - mask = field_mask_pb2.FieldMask() - mask.paths.append('xxx') - self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) - # Invalid field in root - mask = field_mask_pb2.FieldMask() - mask.paths.append('xxx.zzz') - self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) - # Invalid field in internal node - mask = field_mask_pb2.FieldMask() - mask.paths.append('optional_nested_message.xxx.zzz') - self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) - # Invalid field in leaf - mask = field_mask_pb2.FieldMask() - mask.paths.append('optional_nested_message.xxx') - self.assertFalse(mask.IsValidForDescriptor(msg_descriptor)) - - def testCanonicalFrom(self): - mask = field_mask_pb2.FieldMask() - out_mask = field_mask_pb2.FieldMask() - # Paths will be sorted. - mask.FromJsonString('baz.quz,bar,foo') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('bar,baz.quz,foo', out_mask.ToJsonString()) - # Duplicated paths will be removed. - mask.FromJsonString('foo,bar,foo') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('bar,foo', out_mask.ToJsonString()) - # Sub-paths of other paths will be removed. - mask.FromJsonString('foo.b1,bar.b1,foo.b2,bar') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('bar,foo.b1,foo.b2', out_mask.ToJsonString()) - - # Test more deeply nested cases. - mask.FromJsonString( - 'foo.bar.baz1,foo.bar.baz2.quz,foo.bar.baz2') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('foo.bar.baz1,foo.bar.baz2', - out_mask.ToJsonString()) - mask.FromJsonString( - 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('foo.bar.baz1,foo.bar.baz2', - out_mask.ToJsonString()) - mask.FromJsonString( - 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo.bar') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('foo.bar', out_mask.ToJsonString()) - mask.FromJsonString( - 'foo.bar.baz1,foo.bar.baz2,foo.bar.baz2.quz,foo') - out_mask.CanonicalFormFromMask(mask) - self.assertEqual('foo', out_mask.ToJsonString()) - - def testUnion(self): - mask1 = field_mask_pb2.FieldMask() - mask2 = field_mask_pb2.FieldMask() - out_mask = field_mask_pb2.FieldMask() - mask1.FromJsonString('foo,baz') - mask2.FromJsonString('bar,quz') - out_mask.Union(mask1, mask2) - self.assertEqual('bar,baz,foo,quz', out_mask.ToJsonString()) - # Overlap with duplicated paths. - mask1.FromJsonString('foo,baz.bb') - mask2.FromJsonString('baz.bb,quz') - out_mask.Union(mask1, mask2) - self.assertEqual('baz.bb,foo,quz', out_mask.ToJsonString()) - # Overlap with paths covering some other paths. - mask1.FromJsonString('foo.bar.baz,quz') - mask2.FromJsonString('foo.bar,bar') - out_mask.Union(mask1, mask2) - self.assertEqual('bar,foo.bar,quz', out_mask.ToJsonString()) - src = unittest_pb2.TestAllTypes() - with self.assertRaises(ValueError): - out_mask.Union(src, mask2) - - def testIntersect(self): - mask1 = field_mask_pb2.FieldMask() - mask2 = field_mask_pb2.FieldMask() - out_mask = field_mask_pb2.FieldMask() - # Test cases without overlapping. - mask1.FromJsonString('foo,baz') - mask2.FromJsonString('bar,quz') - out_mask.Intersect(mask1, mask2) - self.assertEqual('', out_mask.ToJsonString()) - self.assertEqual(len(out_mask.paths), 0) - self.assertEqual(out_mask.paths, []) - # Overlap with duplicated paths. - mask1.FromJsonString('foo,baz.bb') - mask2.FromJsonString('baz.bb,quz') - out_mask.Intersect(mask1, mask2) - self.assertEqual('baz.bb', out_mask.ToJsonString()) - # Overlap with paths covering some other paths. - mask1.FromJsonString('foo.bar.baz,quz') - mask2.FromJsonString('foo.bar,bar') - out_mask.Intersect(mask1, mask2) - self.assertEqual('foo.bar.baz', out_mask.ToJsonString()) - mask1.FromJsonString('foo.bar,bar') - mask2.FromJsonString('foo.bar.baz,quz') - out_mask.Intersect(mask1, mask2) - self.assertEqual('foo.bar.baz', out_mask.ToJsonString()) - # Intersect '' with '' - mask1.Clear() - mask2.Clear() - mask1.paths.append('') - mask2.paths.append('') - self.assertEqual(mask1.paths, ['']) - self.assertEqual('', mask1.ToJsonString()) - out_mask.Intersect(mask1, mask2) - self.assertEqual(out_mask.paths, []) - - def testMergeMessageWithoutMapFields(self): - # Test merge one field. - src = unittest_pb2.TestAllTypes() - test_util.SetAllFields(src) - for field in src.DESCRIPTOR.fields: - if field.containing_oneof: - continue - field_name = field.name - dst = unittest_pb2.TestAllTypes() - # Only set one path to mask. - mask = field_mask_pb2.FieldMask() - mask.paths.append(field_name) - mask.MergeMessage(src, dst) - # The expected result message. - msg = unittest_pb2.TestAllTypes() - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - repeated_src = getattr(src, field_name) - repeated_msg = getattr(msg, field_name) - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - for item in repeated_src: - repeated_msg.add().CopyFrom(item) - else: - repeated_msg.extend(repeated_src) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - getattr(msg, field_name).CopyFrom(getattr(src, field_name)) - else: - setattr(msg, field_name, getattr(src, field_name)) - # Only field specified in mask is merged. - self.assertEqual(msg, dst) - - # Test merge nested fields. - nested_src = unittest_pb2.NestedTestAllTypes() - nested_dst = unittest_pb2.NestedTestAllTypes() - nested_src.child.payload.optional_int32 = 1234 - nested_src.child.child.payload.optional_int32 = 5678 - mask = field_mask_pb2.FieldMask() - mask.FromJsonString('child.payload') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(1234, nested_dst.child.payload.optional_int32) - self.assertEqual(0, nested_dst.child.child.payload.optional_int32) - - mask.FromJsonString('child.child.payload') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(1234, nested_dst.child.payload.optional_int32) - self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) - - nested_dst.Clear() - mask.FromJsonString('child.child.payload') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(0, nested_dst.child.payload.optional_int32) - self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) - - nested_dst.Clear() - mask.FromJsonString('child') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(1234, nested_dst.child.payload.optional_int32) - self.assertEqual(5678, nested_dst.child.child.payload.optional_int32) - - # Test MergeOptions. - nested_dst.Clear() - nested_dst.child.payload.optional_int64 = 4321 - # Message fields will be merged by default. - mask.FromJsonString('child.payload') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(1234, nested_dst.child.payload.optional_int32) - self.assertEqual(4321, nested_dst.child.payload.optional_int64) - # Change the behavior to replace message fields. - mask.FromJsonString('child.payload') - mask.MergeMessage(nested_src, nested_dst, True, False) - self.assertEqual(1234, nested_dst.child.payload.optional_int32) - self.assertEqual(0, nested_dst.child.payload.optional_int64) - - # By default, fields missing in source are not cleared in destination. - nested_dst.payload.optional_int32 = 1234 - self.assertTrue(nested_dst.HasField('payload')) - mask.FromJsonString('payload') - mask.MergeMessage(nested_src, nested_dst) - self.assertTrue(nested_dst.HasField('payload')) - # But they are cleared when replacing message fields. - nested_dst.Clear() - nested_dst.payload.optional_int32 = 1234 - mask.FromJsonString('payload') - mask.MergeMessage(nested_src, nested_dst, True, False) - self.assertFalse(nested_dst.HasField('payload')) - - nested_src.payload.repeated_int32.append(1234) - nested_dst.payload.repeated_int32.append(5678) - # Repeated fields will be appended by default. - mask.FromJsonString('payload.repeatedInt32') - mask.MergeMessage(nested_src, nested_dst) - self.assertEqual(2, len(nested_dst.payload.repeated_int32)) - self.assertEqual(5678, nested_dst.payload.repeated_int32[0]) - self.assertEqual(1234, nested_dst.payload.repeated_int32[1]) - # Change the behavior to replace repeated fields. - mask.FromJsonString('payload.repeatedInt32') - mask.MergeMessage(nested_src, nested_dst, False, True) - self.assertEqual(1, len(nested_dst.payload.repeated_int32)) - self.assertEqual(1234, nested_dst.payload.repeated_int32[0]) - - # Test Merge oneof field. - new_msg = unittest_pb2.TestOneof2() - dst = unittest_pb2.TestOneof2() - dst.foo_message.moo_int = 1 - mask = field_mask_pb2.FieldMask() - mask.FromJsonString('fooMessage,fooLazyMessage.mooInt') - mask.MergeMessage(new_msg, dst) - self.assertTrue(dst.HasField('foo_message')) - self.assertFalse(dst.HasField('foo_lazy_message')) - - def testMergeMessageWithMapField(self): - empty_map = map_unittest_pb2.TestRecursiveMapMessage() - src_level_2 = map_unittest_pb2.TestRecursiveMapMessage() - src_level_2.a['src level 2'].CopyFrom(empty_map) - src = map_unittest_pb2.TestRecursiveMapMessage() - src.a['common key'].CopyFrom(src_level_2) - src.a['src level 1'].CopyFrom(src_level_2) - - dst_level_2 = map_unittest_pb2.TestRecursiveMapMessage() - dst_level_2.a['dst level 2'].CopyFrom(empty_map) - dst = map_unittest_pb2.TestRecursiveMapMessage() - dst.a['common key'].CopyFrom(dst_level_2) - dst.a['dst level 1'].CopyFrom(empty_map) - - mask = field_mask_pb2.FieldMask() - mask.FromJsonString('a') - mask.MergeMessage(src, dst) - - # map from dst is replaced with map from src. - self.assertEqual(dst.a['common key'], src_level_2) - self.assertEqual(dst.a['src level 1'], src_level_2) - self.assertEqual(dst.a['dst level 1'], empty_map) - - def testMergeErrors(self): - src = unittest_pb2.TestAllTypes() - dst = unittest_pb2.TestAllTypes() - mask = field_mask_pb2.FieldMask() - test_util.SetAllFields(src) - mask.FromJsonString('optionalInt32.field') - with self.assertRaises(ValueError) as e: - mask.MergeMessage(src, dst) - self.assertEqual('Error: Field optional_int32 in message ' - 'protobuf_unittest.TestAllTypes is not a singular ' - 'message field and cannot have sub-fields.', - str(e.exception)) - - def testSnakeCaseToCamelCase(self): - self.assertEqual('fooBar', - well_known_types._SnakeCaseToCamelCase('foo_bar')) - self.assertEqual('FooBar', - well_known_types._SnakeCaseToCamelCase('_foo_bar')) - self.assertEqual('foo3Bar', - well_known_types._SnakeCaseToCamelCase('foo3_bar')) - - # No uppercase letter is allowed. - self.assertRaisesRegex( - ValueError, - 'Fail to print FieldMask to Json string: Path name Foo must ' - 'not contain uppercase letters.', - well_known_types._SnakeCaseToCamelCase, 'Foo') - # Any character after a "_" must be a lowercase letter. - # 1. "_" cannot be followed by another "_". - # 2. "_" cannot be followed by a digit. - # 3. "_" cannot appear as the last character. - self.assertRaisesRegex( - ValueError, - 'Fail to print FieldMask to Json string: The character after a ' - '"_" must be a lowercase letter in path name foo__bar.', - well_known_types._SnakeCaseToCamelCase, 'foo__bar') - self.assertRaisesRegex( - ValueError, - 'Fail to print FieldMask to Json string: The character after a ' - '"_" must be a lowercase letter in path name foo_3bar.', - well_known_types._SnakeCaseToCamelCase, 'foo_3bar') - self.assertRaisesRegex( - ValueError, - 'Fail to print FieldMask to Json string: Trailing "_" in path ' - 'name foo_bar_.', well_known_types._SnakeCaseToCamelCase, 'foo_bar_') - - def testCamelCaseToSnakeCase(self): - self.assertEqual('foo_bar', - well_known_types._CamelCaseToSnakeCase('fooBar')) - self.assertEqual('_foo_bar', - well_known_types._CamelCaseToSnakeCase('FooBar')) - self.assertEqual('foo3_bar', - well_known_types._CamelCaseToSnakeCase('foo3Bar')) - self.assertRaisesRegex( - ValueError, - 'Fail to parse FieldMask: Path name foo_bar must not contain "_"s.', - well_known_types._CamelCaseToSnakeCase, 'foo_bar') - - class StructTest(unittest.TestCase): def testStruct(self): diff --git a/python/mox.py b/python/mox.py deleted file mode 100755 index 9dd8ac7eb4..0000000000 --- a/python/mox.py +++ /dev/null @@ -1,1401 +0,0 @@ -#!/usr/bin/python2.4 -# -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This file is used for testing. The original is at: -# http://code.google.com/p/pymox/ - -"""Mox, an object-mocking framework for Python. - -Mox works in the record-replay-verify paradigm. When you first create -a mock object, it is in record mode. You then programmatically set -the expected behavior of the mock object (what methods are to be -called on it, with what parameters, what they should return, and in -what order). - -Once you have set up the expected mock behavior, you put it in replay -mode. Now the mock responds to method calls just as you told it to. -If an unexpected method (or an expected method with unexpected -parameters) is called, then an exception will be raised. - -Once you are done interacting with the mock, you need to verify that -all the expected interactions occurred. (Maybe your code exited -prematurely without calling some cleanup method!) The verify phase -ensures that every expected method was called; otherwise, an exception -will be raised. - -Suggested usage / workflow: - - # Create Mox factory - my_mox = Mox() - - # Create a mock data access object - mock_dao = my_mox.CreateMock(DAOClass) - - # Set up expected behavior - mock_dao.RetrievePersonWithIdentifier('1').AndReturn(person) - mock_dao.DeletePerson(person) - - # Put mocks in replay mode - my_mox.ReplayAll() - - # Inject mock object and run test - controller.SetDao(mock_dao) - controller.DeletePersonById('1') - - # Verify all methods were called as expected - my_mox.VerifyAll() -""" - -from collections import deque -import re -import types -import unittest - -import stubout - -class Error(AssertionError): - """Base exception for this module.""" - - pass - - -class ExpectedMethodCallsError(Error): - """Raised when Verify() is called before all expected methods have been called - """ - - def __init__(self, expected_methods): - """Init exception. - - Args: - # expected_methods: A sequence of MockMethod objects that should have been - # called. - expected_methods: [MockMethod] - - Raises: - ValueError: if expected_methods contains no methods. - """ - - if not expected_methods: - raise ValueError("There must be at least one expected method") - Error.__init__(self) - self._expected_methods = expected_methods - - def __str__(self): - calls = "\n".join(["%3d. %s" % (i, m) - for i, m in enumerate(self._expected_methods)]) - return "Verify: Expected methods never called:\n%s" % (calls,) - - -class UnexpectedMethodCallError(Error): - """Raised when an unexpected method is called. - - This can occur if a method is called with incorrect parameters, or out of the - specified order. - """ - - def __init__(self, unexpected_method, expected): - """Init exception. - - Args: - # unexpected_method: MockMethod that was called but was not at the head of - # the expected_method queue. - # expected: MockMethod or UnorderedGroup the method should have - # been in. - unexpected_method: MockMethod - expected: MockMethod or UnorderedGroup - """ - - Error.__init__(self) - self._unexpected_method = unexpected_method - self._expected = expected - - def __str__(self): - return "Unexpected method call: %s. Expecting: %s" % \ - (self._unexpected_method, self._expected) - - -class UnknownMethodCallError(Error): - """Raised if an unknown method is requested of the mock object.""" - - def __init__(self, unknown_method_name): - """Init exception. - - Args: - # unknown_method_name: Method call that is not part of the mocked class's - # public interface. - unknown_method_name: str - """ - - Error.__init__(self) - self._unknown_method_name = unknown_method_name - - def __str__(self): - return "Method called is not a member of the object: %s" % \ - self._unknown_method_name - - -class Mox(object): - """Mox: a factory for creating mock objects.""" - - # A list of types that should be stubbed out with MockObjects (as - # opposed to MockAnythings). - _USE_MOCK_OBJECT = [types.ClassType, types.InstanceType, types.ModuleType, - types.ObjectType, types.TypeType] - - def __init__(self): - """Initialize a new Mox.""" - - self._mock_objects = [] - self.stubs = stubout.StubOutForTesting() - - def CreateMock(self, class_to_mock): - """Create a new mock object. - - Args: - # class_to_mock: the class to be mocked - class_to_mock: class - - Returns: - MockObject that can be used as the class_to_mock would be. - """ - - new_mock = MockObject(class_to_mock) - self._mock_objects.append(new_mock) - return new_mock - - def CreateMockAnything(self): - """Create a mock that will accept any method calls. - - This does not enforce an interface. - """ - - new_mock = MockAnything() - self._mock_objects.append(new_mock) - return new_mock - - def ReplayAll(self): - """Set all mock objects to replay mode.""" - - for mock_obj in self._mock_objects: - mock_obj._Replay() - - - def VerifyAll(self): - """Call verify on all mock objects created.""" - - for mock_obj in self._mock_objects: - mock_obj._Verify() - - def ResetAll(self): - """Call reset on all mock objects. This does not unset stubs.""" - - for mock_obj in self._mock_objects: - mock_obj._Reset() - - def StubOutWithMock(self, obj, attr_name, use_mock_anything=False): - """Replace a method, attribute, etc. with a Mock. - - This will replace a class or module with a MockObject, and everything else - (method, function, etc) with a MockAnything. This can be overridden to - always use a MockAnything by setting use_mock_anything to True. - - Args: - obj: A Python object (class, module, instance, callable). - attr_name: str. The name of the attribute to replace with a mock. - use_mock_anything: bool. True if a MockAnything should be used regardless - of the type of attribute. - """ - - attr_to_replace = getattr(obj, attr_name) - if type(attr_to_replace) in self._USE_MOCK_OBJECT and not use_mock_anything: - stub = self.CreateMock(attr_to_replace) - else: - stub = self.CreateMockAnything() - - self.stubs.Set(obj, attr_name, stub) - - def UnsetStubs(self): - """Restore stubs to their original state.""" - - self.stubs.UnsetAll() - -def Replay(*args): - """Put mocks into Replay mode. - - Args: - # args is any number of mocks to put into replay mode. - """ - - for mock in args: - mock._Replay() - - -def Verify(*args): - """Verify mocks. - - Args: - # args is any number of mocks to be verified. - """ - - for mock in args: - mock._Verify() - - -def Reset(*args): - """Reset mocks. - - Args: - # args is any number of mocks to be reset. - """ - - for mock in args: - mock._Reset() - - -class MockAnything: - """A mock that can be used to mock anything. - - This is helpful for mocking classes that do not provide a public interface. - """ - - def __init__(self): - """ """ - self._Reset() - - def __getattr__(self, method_name): - """Intercept method calls on this object. - - A new MockMethod is returned that is aware of the MockAnything's - state (record or replay). The call will be recorded or replayed - by the MockMethod's __call__. - - Args: - # method name: the name of the method being called. - method_name: str - - Returns: - A new MockMethod aware of MockAnything's state (record or replay). - """ - - return self._CreateMockMethod(method_name) - - def _CreateMockMethod(self, method_name): - """Create a new mock method call and return it. - - Args: - # method name: the name of the method being called. - method_name: str - - Returns: - A new MockMethod aware of MockAnything's state (record or replay). - """ - - return MockMethod(method_name, self._expected_calls_queue, - self._replay_mode) - - def __nonzero__(self): - """Return 1 for nonzero so the mock can be used as a conditional.""" - - return 1 - - def __eq__(self, rhs): - """Provide custom logic to compare objects.""" - - return (isinstance(rhs, MockAnything) and - self._replay_mode == rhs._replay_mode and - self._expected_calls_queue == rhs._expected_calls_queue) - - def __ne__(self, rhs): - """Provide custom logic to compare objects.""" - - return not self == rhs - - def _Replay(self): - """Start replaying expected method calls.""" - - self._replay_mode = True - - def _Verify(self): - """Verify that all of the expected calls have been made. - - Raises: - ExpectedMethodCallsError: if there are still more method calls in the - expected queue. - """ - - # If the list of expected calls is not empty, raise an exception - if self._expected_calls_queue: - # The last MultipleTimesGroup is not popped from the queue. - if (len(self._expected_calls_queue) == 1 and - isinstance(self._expected_calls_queue[0], MultipleTimesGroup) and - self._expected_calls_queue[0].IsSatisfied()): - pass - else: - raise ExpectedMethodCallsError(self._expected_calls_queue) - - def _Reset(self): - """Reset the state of this mock to record mode with an empty queue.""" - - # Maintain a list of method calls we are expecting - self._expected_calls_queue = deque() - - # Make sure we are in setup mode, not replay mode - self._replay_mode = False - - -class MockObject(MockAnything, object): - """A mock object that simulates the public/protected interface of a class.""" - - def __init__(self, class_to_mock): - """Initialize a mock object. - - This determines the methods and properties of the class and stores them. - - Args: - # class_to_mock: class to be mocked - class_to_mock: class - """ - - # This is used to hack around the mixin/inheritance of MockAnything, which - # is not a proper object (it can be anything. :-) - MockAnything.__dict__['__init__'](self) - - # Get a list of all the public and special methods we should mock. - self._known_methods = set() - self._known_vars = set() - self._class_to_mock = class_to_mock - for method in dir(class_to_mock): - if callable(getattr(class_to_mock, method)): - self._known_methods.add(method) - else: - self._known_vars.add(method) - - def __getattr__(self, name): - """Intercept attribute request on this object. - - If the attribute is a public class variable, it will be returned and not - recorded as a call. - - If the attribute is not a variable, it is handled like a method - call. The method name is checked against the set of mockable - methods, and a new MockMethod is returned that is aware of the - MockObject's state (record or replay). The call will be recorded - or replayed by the MockMethod's __call__. - - Args: - # name: the name of the attribute being requested. - name: str - - Returns: - Either a class variable or a new MockMethod that is aware of the state - of the mock (record or replay). - - Raises: - UnknownMethodCallError if the MockObject does not mock the requested - method. - """ - - if name in self._known_vars: - return getattr(self._class_to_mock, name) - - if name in self._known_methods: - return self._CreateMockMethod(name) - - raise UnknownMethodCallError(name) - - def __eq__(self, rhs): - """Provide custom logic to compare objects.""" - - return (isinstance(rhs, MockObject) and - self._class_to_mock == rhs._class_to_mock and - self._replay_mode == rhs._replay_mode and - self._expected_calls_queue == rhs._expected_calls_queue) - - def __setitem__(self, key, value): - """Provide custom logic for mocking classes that support item assignment. - - Args: - key: Key to set the value for. - value: Value to set. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __setitem__ method that has already been called if not in replay mode. - - Raises: - TypeError if the underlying class does not support item assignment. - UnexpectedMethodCallError if the object does not expect the call to - __setitem__. - - """ - setitem = self._class_to_mock.__dict__.get('__setitem__', None) - - # Verify the class supports item assignment. - if setitem is None: - raise TypeError('object does not support item assignment') - - # If we are in replay mode then simply call the mock __setitem__ method. - if self._replay_mode: - return MockMethod('__setitem__', self._expected_calls_queue, - self._replay_mode)(key, value) - - - # Otherwise, create a mock method __setitem__. - return self._CreateMockMethod('__setitem__')(key, value) - - def __getitem__(self, key): - """Provide custom logic for mocking classes that are subscriptable. - - Args: - key: Key to return the value for. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __getitem__ method that has already been called if not in replay mode. - - Raises: - TypeError if the underlying class is not subscriptable. - UnexpectedMethodCallError if the object does not expect the call to - __setitem__. - - """ - getitem = self._class_to_mock.__dict__.get('__getitem__', None) - - # Verify the class supports item assignment. - if getitem is None: - raise TypeError('unsubscriptable object') - - # If we are in replay mode then simply call the mock __getitem__ method. - if self._replay_mode: - return MockMethod('__getitem__', self._expected_calls_queue, - self._replay_mode)(key) - - - # Otherwise, create a mock method __getitem__. - return self._CreateMockMethod('__getitem__')(key) - - def __call__(self, *params, **named_params): - """Provide custom logic for mocking classes that are callable.""" - - # Verify the class we are mocking is callable - callable = self._class_to_mock.__dict__.get('__call__', None) - if callable is None: - raise TypeError('Not callable') - - # Because the call is happening directly on this object instead of a method, - # the call on the mock method is made right here - mock_method = self._CreateMockMethod('__call__') - return mock_method(*params, **named_params) - - @property - def __class__(self): - """Return the class that is being mocked.""" - - return self._class_to_mock - - -class MockMethod(object): - """Callable mock method. - - A MockMethod should act exactly like the method it mocks, accepting parameters - and returning a value, or throwing an exception (as specified). When this - method is called, it can optionally verify whether the called method (name and - signature) matches the expected method. - """ - - def __init__(self, method_name, call_queue, replay_mode): - """Construct a new mock method. - - Args: - # method_name: the name of the method - # call_queue: deque of calls, verify this call against the head, or add - # this call to the queue. - # replay_mode: False if we are recording, True if we are verifying calls - # against the call queue. - method_name: str - call_queue: list or deque - replay_mode: bool - """ - - self._name = method_name - self._call_queue = call_queue - if not isinstance(call_queue, deque): - self._call_queue = deque(self._call_queue) - self._replay_mode = replay_mode - - self._params = None - self._named_params = None - self._return_value = None - self._exception = None - self._side_effects = None - - def __call__(self, *params, **named_params): - """Log parameters and return the specified return value. - - If the Mock(Anything/Object) associated with this call is in record mode, - this MockMethod will be pushed onto the expected call queue. If the mock - is in replay mode, this will pop a MockMethod off the top of the queue and - verify this call is equal to the expected call. - - Raises: - UnexpectedMethodCall if this call is supposed to match an expected method - call and it does not. - """ - - self._params = params - self._named_params = named_params - - if not self._replay_mode: - self._call_queue.append(self) - return self - - expected_method = self._VerifyMethodCall() - - if expected_method._side_effects: - expected_method._side_effects(*params, **named_params) - - if expected_method._exception: - raise expected_method._exception - - return expected_method._return_value - - def __getattr__(self, name): - """Raise an AttributeError with a helpful message.""" - - raise AttributeError('MockMethod has no attribute "%s". ' - 'Did you remember to put your mocks in replay mode?' % name) - - def _PopNextMethod(self): - """Pop the next method from our call queue.""" - try: - return self._call_queue.popleft() - except IndexError: - raise UnexpectedMethodCallError(self, None) - - def _VerifyMethodCall(self): - """Verify the called method is expected. - - This can be an ordered method, or part of an unordered set. - - Returns: - The expected mock method. - - Raises: - UnexpectedMethodCall if the method called was not expected. - """ - - expected = self._PopNextMethod() - - # Loop here, because we might have a MethodGroup followed by another - # group. - while isinstance(expected, MethodGroup): - expected, method = expected.MethodCalled(self) - if method is not None: - return method - - # This is a mock method, so just check equality. - if expected != self: - raise UnexpectedMethodCallError(self, expected) - - return expected - - def __str__(self): - params = ', '.join( - [repr(p) for p in self._params or []] + - ['%s=%r' % x for x in sorted((self._named_params or {}).items())]) - desc = "%s(%s) -> %r" % (self._name, params, self._return_value) - return desc - - def __eq__(self, rhs): - """Test whether this MockMethod is equivalent to another MockMethod. - - Args: - # rhs: the right hand side of the test - rhs: MockMethod - """ - - return (isinstance(rhs, MockMethod) and - self._name == rhs._name and - self._params == rhs._params and - self._named_params == rhs._named_params) - - def __ne__(self, rhs): - """Test whether this MockMethod is not equivalent to another MockMethod. - - Args: - # rhs: the right hand side of the test - rhs: MockMethod - """ - - return not self == rhs - - def GetPossibleGroup(self): - """Returns a possible group from the end of the call queue or None if no - other methods are on the stack. - """ - - # Remove this method from the tail of the queue so we can add it to a group. - this_method = self._call_queue.pop() - assert this_method == self - - # Determine if the tail of the queue is a group, or just a regular ordered - # mock method. - group = None - try: - group = self._call_queue[-1] - except IndexError: - pass - - return group - - def _CheckAndCreateNewGroup(self, group_name, group_class): - """Checks if the last method (a possible group) is an instance of our - group_class. Adds the current method to this group or creates a new one. - - Args: - - group_name: the name of the group. - group_class: the class used to create instance of this new group - """ - group = self.GetPossibleGroup() - - # If this is a group, and it is the correct group, add the method. - if isinstance(group, group_class) and group.group_name() == group_name: - group.AddMethod(self) - return self - - # Create a new group and add the method. - new_group = group_class(group_name) - new_group.AddMethod(self) - self._call_queue.append(new_group) - return self - - def InAnyOrder(self, group_name="default"): - """Move this method into a group of unordered calls. - - A group of unordered calls must be defined together, and must be executed - in full before the next expected method can be called. There can be - multiple groups that are expected serially, if they are given - different group names. The same group name can be reused if there is a - standard method call, or a group with a different name, spliced between - usages. - - Args: - group_name: the name of the unordered group. - - Returns: - self - """ - return self._CheckAndCreateNewGroup(group_name, UnorderedGroup) - - def MultipleTimes(self, group_name="default"): - """Move this method into group of calls which may be called multiple times. - - A group of repeating calls must be defined together, and must be executed in - full before the next expected method can be called. - - Args: - group_name: the name of the unordered group. - - Returns: - self - """ - return self._CheckAndCreateNewGroup(group_name, MultipleTimesGroup) - - def AndReturn(self, return_value): - """Set the value to return when this method is called. - - Args: - # return_value can be anything. - """ - - self._return_value = return_value - return return_value - - def AndRaise(self, exception): - """Set the exception to raise when this method is called. - - Args: - # exception: the exception to raise when this method is called. - exception: Exception - """ - - self._exception = exception - - def WithSideEffects(self, side_effects): - """Set the side effects that are simulated when this method is called. - - Args: - side_effects: A callable which modifies the parameters or other relevant - state which a given test case depends on. - - Returns: - Self for chaining with AndReturn and AndRaise. - """ - self._side_effects = side_effects - return self - -class Comparator: - """Base class for all Mox comparators. - - A Comparator can be used as a parameter to a mocked method when the exact - value is not known. For example, the code you are testing might build up a - long SQL string that is passed to your mock DAO. You're only interested that - the IN clause contains the proper primary keys, so you can set your mock - up as follows: - - mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) - - Now whatever query is passed in must contain the string 'IN (1, 2, 4, 5)'. - - A Comparator may replace one or more parameters, for example: - # return at most 10 rows - mock_dao.RunQuery(StrContains('SELECT'), 10) - - or - - # Return some non-deterministic number of rows - mock_dao.RunQuery(StrContains('SELECT'), IsA(int)) - """ - - def equals(self, rhs): - """Special equals method that all comparators must implement. - - Args: - rhs: any python object - """ - - raise NotImplementedError('method must be implemented by a subclass.') - - def __eq__(self, rhs): - return self.equals(rhs) - - def __ne__(self, rhs): - return not self.equals(rhs) - - -class IsA(Comparator): - """This class wraps a basic Python type or class. It is used to verify - that a parameter is of the given type or class. - - Example: - mock_dao.Connect(IsA(DbConnectInfo)) - """ - - def __init__(self, class_name): - """Initialize IsA - - Args: - class_name: basic python type or a class - """ - - self._class_name = class_name - - def equals(self, rhs): - """Check to see if the RHS is an instance of class_name. - - Args: - # rhs: the right hand side of the test - rhs: object - - Returns: - bool - """ - - try: - return isinstance(rhs, self._class_name) - except TypeError: - # Check raw types if there was a type error. This is helpful for - # things like cStringIO.StringIO. - return type(rhs) == type(self._class_name) - - def __repr__(self): - return str(self._class_name) - -class IsAlmost(Comparator): - """Comparison class used to check whether a parameter is nearly equal - to a given value. Generally useful for floating point numbers. - - Example mock_dao.SetTimeout((IsAlmost(3.9))) - """ - - def __init__(self, float_value, places=7): - """Initialize IsAlmost. - - Args: - float_value: The value for making the comparison. - places: The number of decimal places to round to. - """ - - self._float_value = float_value - self._places = places - - def equals(self, rhs): - """Check to see if RHS is almost equal to float_value - - Args: - rhs: the value to compare to float_value - - Returns: - bool - """ - - try: - return round(rhs-self._float_value, self._places) == 0 - except TypeError: - # This is probably because either float_value or rhs is not a number. - return False - - def __repr__(self): - return str(self._float_value) - -class StrContains(Comparator): - """Comparison class used to check whether a substring exists in a - string parameter. This can be useful in mocking a database with SQL - passed in as a string parameter, for example. - - Example: - mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) - """ - - def __init__(self, search_string): - """Initialize. - - Args: - # search_string: the string you are searching for - search_string: str - """ - - self._search_string = search_string - - def equals(self, rhs): - """Check to see if the search_string is contained in the rhs string. - - Args: - # rhs: the right hand side of the test - rhs: object - - Returns: - bool - """ - - try: - return rhs.find(self._search_string) > -1 - except Exception: - return False - - def __repr__(self): - return '' % self._search_string - - -class Regex(Comparator): - """Checks if a string matches a regular expression. - - This uses a given regular expression to determine equality. - """ - - def __init__(self, pattern, flags=0): - """Initialize. - - Args: - # pattern is the regular expression to search for - pattern: str - # flags passed to re.compile function as the second argument - flags: int - """ - - self.regex = re.compile(pattern, flags=flags) - - def equals(self, rhs): - """Check to see if rhs matches regular expression pattern. - - Returns: - bool - """ - - return self.regex.search(rhs) is not None - - def __repr__(self): - s = '' % self._key - - -class ContainsKeyValue(Comparator): - """Checks whether a key/value pair is in a dict parameter. - - Example: - mock_dao.UpdateUsers(ContainsKeyValue('stevepm', stevepm_user_info)) - """ - - def __init__(self, key, value): - """Initialize. - - Args: - # key: a key in a dict - # value: the corresponding value - """ - - self._key = key - self._value = value - - def equals(self, rhs): - """Check whether the given key/value pair is in the rhs dict. - - Returns: - bool - """ - - try: - return rhs[self._key] == self._value - except Exception: - return False - - def __repr__(self): - return '' % (self._key, self._value) - - -class SameElementsAs(Comparator): - """Checks whether iterables contain the same elements (ignoring order). - - Example: - mock_dao.ProcessUsers(SameElementsAs('stevepm', 'salomaki')) - """ - - def __init__(self, expected_seq): - """Initialize. - - Args: - expected_seq: a sequence - """ - - self._expected_seq = expected_seq - - def equals(self, actual_seq): - """Check to see whether actual_seq has same elements as expected_seq. - - Args: - actual_seq: sequence - - Returns: - bool - """ - - try: - expected = dict([(element, None) for element in self._expected_seq]) - actual = dict([(element, None) for element in actual_seq]) - except TypeError: - # Fall back to slower list-compare if any of the objects are unhashable. - expected = list(self._expected_seq) - actual = list(actual_seq) - expected.sort() - actual.sort() - return expected == actual - - def __repr__(self): - return '' % self._expected_seq - - -class And(Comparator): - """Evaluates one or more Comparators on RHS and returns an AND of the results. - """ - - def __init__(self, *args): - """Initialize. - - Args: - *args: One or more Comparator - """ - - self._comparators = args - - def equals(self, rhs): - """Checks whether all Comparators are equal to rhs. - - Args: - # rhs: can be anything - - Returns: - bool - """ - - for comparator in self._comparators: - if not comparator.equals(rhs): - return False - - return True - - def __repr__(self): - return '' % str(self._comparators) - - -class Or(Comparator): - """Evaluates one or more Comparators on RHS and returns an OR of the results. - """ - - def __init__(self, *args): - """Initialize. - - Args: - *args: One or more Mox comparators - """ - - self._comparators = args - - def equals(self, rhs): - """Checks whether any Comparator is equal to rhs. - - Args: - # rhs: can be anything - - Returns: - bool - """ - - for comparator in self._comparators: - if comparator.equals(rhs): - return True - - return False - - def __repr__(self): - return '' % str(self._comparators) - - -class Func(Comparator): - """Call a function that should verify the parameter passed in is correct. - - You may need the ability to perform more advanced operations on the parameter - in order to validate it. You can use this to have a callable validate any - parameter. The callable should return either True or False. - - - Example: - - def myParamValidator(param): - # Advanced logic here - return True - - mock_dao.DoSomething(Func(myParamValidator), true) - """ - - def __init__(self, func): - """Initialize. - - Args: - func: callable that takes one parameter and returns a bool - """ - - self._func = func - - def equals(self, rhs): - """Test whether rhs passes the function test. - - rhs is passed into func. - - Args: - rhs: any python object - - Returns: - the result of func(rhs) - """ - - return self._func(rhs) - - def __repr__(self): - return str(self._func) - - -class IgnoreArg(Comparator): - """Ignore an argument. - - This can be used when we don't care about an argument of a method call. - - Example: - # Check if CastMagic is called with 3 as first arg and 'disappear' as third. - mymock.CastMagic(3, IgnoreArg(), 'disappear') - """ - - def equals(self, unused_rhs): - """Ignores arguments and returns True. - - Args: - unused_rhs: any python object - - Returns: - always returns True - """ - - return True - - def __repr__(self): - return '' - - -class MethodGroup(object): - """Base class containing common behaviour for MethodGroups.""" - - def __init__(self, group_name): - self._group_name = group_name - - def group_name(self): - return self._group_name - - def __str__(self): - return '<%s "%s">' % (self.__class__.__name__, self._group_name) - - def AddMethod(self, mock_method): - raise NotImplementedError - - def MethodCalled(self, mock_method): - raise NotImplementedError - - def IsSatisfied(self): - raise NotImplementedError - -class UnorderedGroup(MethodGroup): - """UnorderedGroup holds a set of method calls that may occur in any order. - - This construct is helpful for non-deterministic events, such as iterating - over the keys of a dict. - """ - - def __init__(self, group_name): - super(UnorderedGroup, self).__init__(group_name) - self._methods = [] - - def AddMethod(self, mock_method): - """Add a method to this group. - - Args: - mock_method: A mock method to be added to this group. - """ - - self._methods.append(mock_method) - - def MethodCalled(self, mock_method): - """Remove a method call from the group. - - If the method is not in the set, an UnexpectedMethodCallError will be - raised. - - Args: - mock_method: a mock method that should be equal to a method in the group. - - Returns: - The mock method from the group - - Raises: - UnexpectedMethodCallError if the mock_method was not in the group. - """ - - # Check to see if this method exists, and if so, remove it from the set - # and return it. - for method in self._methods: - if method == mock_method: - # Remove the called mock_method instead of the method in the group. - # The called method will match any comparators when equality is checked - # during removal. The method in the group could pass a comparator to - # another comparator during the equality check. - self._methods.remove(mock_method) - - # If this group is not empty, put it back at the head of the queue. - if not self.IsSatisfied(): - mock_method._call_queue.appendleft(self) - - return self, method - - raise UnexpectedMethodCallError(mock_method, self) - - def IsSatisfied(self): - """Return True if there are not any methods in this group.""" - - return len(self._methods) == 0 - - -class MultipleTimesGroup(MethodGroup): - """MultipleTimesGroup holds methods that may be called any number of times. - - Note: Each method must be called at least once. - - This is helpful, if you don't know or care how many times a method is called. - """ - - def __init__(self, group_name): - super(MultipleTimesGroup, self).__init__(group_name) - self._methods = set() - self._methods_called = set() - - def AddMethod(self, mock_method): - """Add a method to this group. - - Args: - mock_method: A mock method to be added to this group. - """ - - self._methods.add(mock_method) - - def MethodCalled(self, mock_method): - """Remove a method call from the group. - - If the method is not in the set, an UnexpectedMethodCallError will be - raised. - - Args: - mock_method: a mock method that should be equal to a method in the group. - - Returns: - The mock method from the group - - Raises: - UnexpectedMethodCallError if the mock_method was not in the group. - """ - - # Check to see if this method exists, and if so add it to the set of - # called methods. - - for method in self._methods: - if method == mock_method: - self._methods_called.add(mock_method) - # Always put this group back on top of the queue, because we don't know - # when we are done. - mock_method._call_queue.appendleft(self) - return self, method - - if self.IsSatisfied(): - next_method = mock_method._PopNextMethod(); - return next_method, None - else: - raise UnexpectedMethodCallError(mock_method, self) - - def IsSatisfied(self): - """Return True if all methods in this group are called at least once.""" - # NOTE(psycho): We can't use the simple set difference here because we want - # to match different parameters which are considered the same e.g. IsA(str) - # and some string. This solution is O(n^2) but n should be small. - tmp = self._methods.copy() - for called in self._methods_called: - for expected in tmp: - if called == expected: - tmp.remove(expected) - if not tmp: - return True - break - return False - - -class MoxMetaTestBase(type): - """Metaclass to add mox cleanup and verification to every test. - - As the mox unit testing class is being constructed (MoxTestBase or a - subclass), this metaclass will modify all test functions to call the - CleanUpMox method of the test class after they finish. This means that - unstubbing and verifying will happen for every test with no additional code, - and any failures will result in test failures as opposed to errors. - """ - - def __init__(cls, name, bases, d): - type.__init__(cls, name, bases, d) - - # also get all the attributes from the base classes to account - # for a case when test class is not the immediate child of MoxTestBase - for base in bases: - for attr_name in dir(base): - d[attr_name] = getattr(base, attr_name) - - for func_name, func in d.items(): - if func_name.startswith('test') and callable(func): - setattr(cls, func_name, MoxMetaTestBase.CleanUpTest(cls, func)) - - @staticmethod - def CleanUpTest(cls, func): - """Adds Mox cleanup code to any MoxTestBase method. - - Always unsets stubs after a test. Will verify all mocks for tests that - otherwise pass. - - Args: - cls: MoxTestBase or subclass; the class whose test method we are altering. - func: method; the method of the MoxTestBase test class we wish to alter. - - Returns: - The modified method. - """ - def new_method(self, *args, **kwargs): - mox_obj = getattr(self, 'mox', None) - cleanup_mox = False - if mox_obj and isinstance(mox_obj, Mox): - cleanup_mox = True - try: - func(self, *args, **kwargs) - finally: - if cleanup_mox: - mox_obj.UnsetStubs() - if cleanup_mox: - mox_obj.VerifyAll() - new_method.__name__ = func.__name__ - new_method.__doc__ = func.__doc__ - new_method.__module__ = func.__module__ - return new_method - - -class MoxTestBase(unittest.TestCase): - """Convenience test class to make stubbing easier. - - Sets up a "mox" attribute which is an instance of Mox - any mox tests will - want this. Also automatically unsets any stubs and verifies that all mock - methods have been called at the end of each test, eliminating boilerplate - code. - """ - - __metaclass__ = MoxMetaTestBase - - def setUp(self): - self.mox = Mox() diff --git a/python/stubout.py b/python/stubout.py deleted file mode 100755 index ba391045b6..0000000000 --- a/python/stubout.py +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/python2.4 -# -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This file is used for testing. The original is at: -# http://code.google.com/p/pymox/ - -import inspect - - -class StubOutForTesting: - """Sample Usage: - You want os.path.exists() to always return true during testing. - - stubs = StubOutForTesting() - stubs.Set(os.path, 'exists', lambda x: 1) - ... - stubs.UnsetAll() - - The above changes os.path.exists into a lambda that returns 1. Once - the ... part of the code finishes, the UnsetAll() looks up the old value - of os.path.exists and restores it. - - """ - def __init__(self): - self.cache = [] - self.stubs = [] - - def __del__(self): - self.SmartUnsetAll() - self.UnsetAll() - - def SmartSet(self, obj, attr_name, new_attr): - """Replace obj.attr_name with new_attr. This method is smart and works - at the module, class, and instance level while preserving proper - inheritance. It will not stub out C types however unless that has been - explicitly allowed by the type. - - This method supports the case where attr_name is a staticmethod or a - classmethod of obj. - - Notes: - - If obj is an instance, then it is its class that will actually be - stubbed. Note that the method Set() does not do that: if obj is - an instance, it (and not its class) will be stubbed. - - The stubbing is using the builtin getattr and setattr. So, the __get__ - and __set__ will be called when stubbing (TODO: A better idea would - probably be to manipulate obj.__dict__ instead of getattr() and - setattr()). - - Raises AttributeError if the attribute cannot be found. - """ - if (inspect.ismodule(obj) or - (not inspect.isclass(obj) and obj.__dict__.has_key(attr_name))): - orig_obj = obj - orig_attr = getattr(obj, attr_name) - - else: - if not inspect.isclass(obj): - mro = list(inspect.getmro(obj.__class__)) - else: - mro = list(inspect.getmro(obj)) - - mro.reverse() - - orig_attr = None - - for cls in mro: - try: - orig_obj = cls - orig_attr = getattr(obj, attr_name) - except AttributeError: - continue - - if orig_attr is None: - raise AttributeError("Attribute not found.") - - # Calling getattr() on a staticmethod transforms it to a 'normal' function. - # We need to ensure that we put it back as a staticmethod. - old_attribute = obj.__dict__.get(attr_name) - if old_attribute is not None and isinstance(old_attribute, staticmethod): - orig_attr = staticmethod(orig_attr) - - self.stubs.append((orig_obj, attr_name, orig_attr)) - setattr(orig_obj, attr_name, new_attr) - - def SmartUnsetAll(self): - """Reverses all the SmartSet() calls, restoring things to their original - definition. Its okay to call SmartUnsetAll() repeatedly, as later calls - have no effect if no SmartSet() calls have been made. - - """ - self.stubs.reverse() - - for args in self.stubs: - setattr(*args) - - self.stubs = [] - - def Set(self, parent, child_name, new_child): - """Replace child_name's old definition with new_child, in the context - of the given parent. The parent could be a module when the child is a - function at module scope. Or the parent could be a class when a class' - method is being replaced. The named child is set to new_child, while - the prior definition is saved away for later, when UnsetAll() is called. - - This method supports the case where child_name is a staticmethod or a - classmethod of parent. - """ - old_child = getattr(parent, child_name) - - old_attribute = parent.__dict__.get(child_name) - if old_attribute is not None and isinstance(old_attribute, staticmethod): - old_child = staticmethod(old_child) - - self.cache.append((parent, old_child, child_name)) - setattr(parent, child_name, new_child) - - def UnsetAll(self): - """Reverses all the Set() calls, restoring things to their original - definition. Its okay to call UnsetAll() repeatedly, as later calls have - no effect if no Set() calls have been made. - - """ - # Undo calls to Set() in reverse order, in case Set() was called on the - # same arguments repeatedly (want the original call to be last one undone) - self.cache.reverse() - - for (parent, old_child, child_name) in self.cache: - setattr(parent, child_name, old_child) - self.cache = [] diff --git a/src/file_lists.cmake b/src/file_lists.cmake index eb9a19a048..1626c92ced 100644 --- a/src/file_lists.cmake +++ b/src/file_lists.cmake @@ -24,6 +24,8 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/importer.cc @@ -53,6 +55,13 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/lexer.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/message_path.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/untyped_message.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/writer.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/zero_copy_buffered_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_field.cc @@ -93,6 +102,9 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/wrappers.pb.h ${protobuf_SOURCE_DIR}/src/google/protobuf/any.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_allocation_policy.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_cleanup.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_impl.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.h @@ -129,6 +141,16 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/descriptor_traits.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/lexer.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/message_path.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/parser_traits.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/unparser_traits.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/untyped_message.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/writer.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/json/internal/zero_copy_buffered_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/json/json.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map.h ${protobuf_SOURCE_DIR}/src/google/protobuf/map_entry.h @@ -159,7 +181,6 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/platform_macros.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/port.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/status_macros.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/stl_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.h ${protobuf_SOURCE_DIR}/src/google/protobuf/text_format.h ${protobuf_SOURCE_DIR}/src/google/protobuf/unknown_field_set.h @@ -179,6 +200,8 @@ set(libprotobuf_hdrs set(libprotobuf_lite_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/any_lite.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/arenaz_sampler.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/extension_set.cc @@ -208,6 +231,9 @@ set(libprotobuf_lite_srcs set(libprotobuf_lite_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/any.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_align.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_allocation_policy.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_cleanup.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_config.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arena_impl.h ${protobuf_SOURCE_DIR}/src/google/protobuf/arenastring.h @@ -246,7 +272,6 @@ set(libprotobuf_lite_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/platform_macros.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/port.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/status_macros.h - ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/stl_util.h ${protobuf_SOURCE_DIR}/src/google/protobuf/stubs/strutil.h ${protobuf_SOURCE_DIR}/src/google/protobuf/wire_format_lite.h ) diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index 49632c6295..fedc0f426d 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -604,6 +604,7 @@ proto_library( visibility = [ "//:__pkg__", "//conformance:__pkg__", + "@upb//:__subpackages__", ], ) @@ -614,6 +615,7 @@ proto_library( visibility = [ "//:__pkg__", "//conformance:__pkg__", + "@upb//:__subpackages__", ], deps = [ ":any_proto", diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index e2c2042fdc..8bd980118a 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -93,7 +93,6 @@ option objc_class_prefix = "GPB"; // in the type URL, for example "foo.bar.com/x/y.z" will yield type // name "y.z". // -// // JSON // // The JSON representation of an `Any` value uses the regular diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto index 3d598fc859..426c2409a2 100644 --- a/src/google/protobuf/api.proto +++ b/src/google/protobuf/api.proto @@ -82,7 +82,6 @@ message Api { // be omitted. Zero major versions must only be used for // experimental, non-GA interfaces. // - // string version = 4; // Source context for the protocol buffer service represented by this diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc index 2a183d3d9d..f033d6728a 100644 --- a/src/google/protobuf/arenastring.cc +++ b/src/google/protobuf/arenastring.cc @@ -39,7 +39,6 @@ #include "absl/synchronization/mutex.h" #include "google/protobuf/message_lite.h" #include "google/protobuf/parse_context.h" -#include "google/protobuf/stubs/stl_util.h" // clang-format off #include "google/protobuf/port_def.inc" diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index cc8098783a..84e096a447 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -89,7 +89,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/text_format.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. @@ -872,7 +871,7 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { // Now copy in the data. std::string::size_type data_pos = 0; - char* target_ptr = ::google::protobuf::string_as_array(target) + pos; + char* target_ptr = &(*target)[pos]; while (data_pos < data_.size()) { // Copy indent. memcpy(target_ptr, indent_.data(), indent_.size()); @@ -889,8 +888,7 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { } UpdateMetadata(data_, pos, data_.size() + indent_size, indent_.size()); - GOOGLE_CHECK_EQ(target_ptr, - ::google::protobuf::string_as_array(target) + pos + data_.size() + indent_size); + GOOGLE_CHECK_EQ(target_ptr, &(*target)[pos] + data_.size() + indent_size); } } } diff --git a/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc index 4685c0ae25..3ea5d733dc 100644 --- a/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/bootstrap_unittest.cc @@ -56,7 +56,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/cpp/helpers.h" -#include "google/protobuf/stubs/stl_util.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.h b/src/google/protobuf/compiler/cpp/cpp_generator.h index b3364533df..599b4abf5a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.h +++ b/src/google/protobuf/compiler/cpp/cpp_generator.h @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_ #define GOOGLE_PROTOBUF_COMPILER_CPP_CPP_GENERATOR_H_ diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index 70ff98f40f..64edf64d43 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -271,6 +271,12 @@ struct NumToEntryTable { static NumToEntryTable MakeNumToEntryTable( const std::vector& field_descriptors); +static int FieldNameDataSize(const std::vector& data) { + // We add a +1 here to allow for a NUL termination character. It makes the + // codegen nicer. + return data.empty() ? 0 : data.size() + 1; +} + void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { if (!should_generate_tctable()) { return; @@ -288,9 +294,7 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { "TcParseTable<$1$, $2$, $3$, $4$, $5$> _table_;\n", tc_table_info_->table_size_log2, ordered_fields_.size(), tc_table_info_->aux_entries.size(), - // We add a +1 here to allow for a NUL termination character. It makes the - // codegen nicer. - tc_table_info_->field_name_data.size() + 1, + FieldNameDataSize(tc_table_info_->field_name_data), field_num_to_entry_table.size16()); if (should_generate_guarded_tctable()) { format.Outdent(); @@ -450,7 +454,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { "{\n", tc_table_info_->table_size_log2, ordered_fields_.size(), tc_table_info_->aux_entries.size(), - tc_table_info_->field_name_data.size() + 1, // See above for why +1 + FieldNameDataSize(tc_table_info_->field_name_data), field_num_to_entry_table.size16()); { auto table_scope = format.ScopedIndent(); @@ -608,12 +612,12 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { format("}}, {{\n"); } } // ordered_fields_.empty() - { - // field_names[] - auto field_name_scope = format.ScopedIndent(); - GenerateFieldNames(format); - } - format("}},\n"); + { + // field_names[] + auto field_name_scope = format.ScopedIndent(); + GenerateFieldNames(format); + } + format("}},\n"); } format("};\n\n"); // _table_ } @@ -832,6 +836,11 @@ void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) { } void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) { + if (tc_table_info_->field_name_data.empty()) { + // No names to output. + return; + } + // We could just output the bytes directly, but we want it to look better than // that in the source code. Also, it is more efficient for compilation time to // have a literal string than an initializer list of chars. @@ -854,8 +863,8 @@ void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) { format("\"\n"); // Then print each name in a line of its own - for (; sizes < sizes_end && sizes[0] != 0; p += *sizes++) { - format("\"$1$\"\n", std::string(p, p + *sizes)); + for (; sizes < sizes_end; p += *sizes++) { + if (*sizes != 0) format("\"$1$\"\n", std::string(p, p + *sizes)); } } diff --git a/src/google/protobuf/compiler/cpp/unittest.inc b/src/google/protobuf/compiler/cpp/unittest.inc index f1c498638f..1f65a905b5 100644 --- a/src/google/protobuf/compiler/cpp/unittest.inc +++ b/src/google/protobuf/compiler/cpp/unittest.inc @@ -76,7 +76,6 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/test_util2.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. #include "google/protobuf/port_def.inc" @@ -664,7 +663,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToArray) { TestUtil::SetAllFields(&message1); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -678,8 +677,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToArray) { TestUtil::SetPackedFields(&packed_message1); int packed_size = packed_message1.ByteSizeLong(); packed_data.resize(packed_size); - uint8_t* start = - reinterpret_cast(::google::protobuf::string_as_array(&packed_data)); + uint8_t* start = reinterpret_cast(&packed_data[0]); uint8_t* end = packed_message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(packed_size, end - start); EXPECT_TRUE(packed_message2.ParseFromString(packed_data)); @@ -696,7 +694,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SerializationToStream) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -715,7 +713,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, PackedFieldsSerializationToStream) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -1841,7 +1839,7 @@ std::string data; message1.set_foo_int(123); int size = message1.ByteSizeLong(); data.resize(size); -uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); +uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1855,7 +1853,7 @@ EXPECT_EQ(message2.foo_int(), 123); message1.set_foo_string("foo"); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1870,7 +1868,7 @@ EXPECT_EQ(message2.foo_int(), 123); message1.set_foo_bytes("moo"); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1884,7 +1882,7 @@ EXPECT_EQ(message2.foo_int(), 123); message1.set_foo_enum(UNITTEST::TestOneof2::FOO); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1898,7 +1896,7 @@ EXPECT_EQ(message2.foo_int(), 123); message1.mutable_foo_message()->set_moo_int(234); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1912,7 +1910,7 @@ EXPECT_EQ(message2.foo_int(), 123); message1.mutable_foogroup()->set_a(345); int size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -1937,11 +1935,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); @@ -1958,11 +1956,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); @@ -1980,11 +1978,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); @@ -2001,11 +1999,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); @@ -2022,11 +2020,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); @@ -2043,11 +2041,11 @@ data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); - io::CodedOutputStream output_stream(&array_stream); - message1.SerializeWithCachedSizes(&output_stream); - EXPECT_FALSE(output_stream.HadError()); - EXPECT_EQ(size, output_stream.ByteCount()); + io::ArrayOutputStream array_stream(&data[0], size, 1); + io::CodedOutputStream output_stream(&array_stream); + message1.SerializeWithCachedSizes(&output_stream); + EXPECT_FALSE(output_stream.HadError()); + EXPECT_EQ(size, output_stream.ByteCount()); } EXPECT_TRUE(message2.ParseFromString(data)); diff --git a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc index 798cab5c47..a477a8112a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc @@ -51,7 +51,6 @@ #include "google/protobuf/compiler/importer.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/stubs/stl_util.h" namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_generator.h b/src/google/protobuf/compiler/java/java_generator.h index 205837172c..45d30a59b3 100644 --- a/src/google/protobuf/compiler/java/java_generator.h +++ b/src/google/protobuf/compiler/java/java_generator.h @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + #ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_JAVA_GENERATOR_H_ #define GOOGLE_PROTOBUF_COMPILER_JAVA_JAVA_GENERATOR_H_ diff --git a/src/google/protobuf/compiler/objectivec/enum.cc b/src/google/protobuf/compiler/objectivec/enum.cc index fcd7706d17..af3e3353cd 100644 --- a/src/google/protobuf/compiler/objectivec/enum.cc +++ b/src/google/protobuf/compiler/objectivec/enum.cc @@ -36,8 +36,8 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/text_format_decode_data.h" #include "google/protobuf/io/printer.h" @@ -58,8 +58,7 @@ std::string SafelyPrintIntToCode(int v) { } // namespace EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) - : descriptor_(descriptor), - name_(EnumName(descriptor_)) { + : descriptor_(descriptor), name_(EnumName(descriptor_)) { // Track the names for the enum values, and if an alias overlaps a base // value, skip making a name for it. Likewise if two alias overlap, the // first one wins. @@ -121,25 +120,29 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { // doesn't have to bother with the `enum_extensibility` attribute, as the // default will be what is needed. - printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", - "comments", enum_comments, - "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()), - "name", name_); + printer->Print( + "$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", + "comments", enum_comments, "deprecated_attribute", + GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()), "name", + name_); printer->Indent(); if (HasPreservingUnknownEnumSemantics(descriptor_->file())) { // Include the unknown value. printer->Print( - "/**\n" - " * Value used if any message's field encounters a value that is not defined\n" - " * by this enum. The message will also have C functions to get/set the rawValue\n" - " * of the field.\n" - " **/\n" - "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", - "name", name_); + // clang-format off + "/**\n" + " * Value used if any message's field encounters a value that is not defined\n" + " * by this enum. The message will also have C functions to get/set the rawValue\n" + " * of the field.\n" + " **/\n" + "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n", + // clang-format on + "name", name_); } for (int i = 0; i < all_values_.size(); i++) { - if (alias_values_to_skip_.find(all_values_[i]) != alias_values_to_skip_.end()) { + if (alias_values_to_skip_.find(all_values_[i]) != + alias_values_to_skip_.end()) { continue; } if (all_values_[i]->GetSourceLocation(&location)) { @@ -152,14 +155,14 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { } } - printer->Print( - "$name$$deprecated_attribute$ = $value$,\n", - "name", EnumValueName(all_values_[i]), - "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]), - "value", SafelyPrintIntToCode(all_values_[i]->number())); + printer->Print("$name$$deprecated_attribute$ = $value$,\n", "name", + EnumValueName(all_values_[i]), "deprecated_attribute", + GetOptionalDeprecatedAttribute(all_values_[i]), "value", + SafelyPrintIntToCode(all_values_[i]->number())); } printer->Outdent(); printer->Print( + // clang-format off "};\n" "\n" "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n" @@ -169,6 +172,7 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { " * the time this source was generated.\n" " **/\n" "BOOL $name$_IsValidValue(int32_t value);\n" + // clang-format on "\n", "name", name_); } @@ -199,38 +203,42 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { } printer->Print( + // clang-format off "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" " static _Atomic(GPBEnumDescriptor*) descriptor = nil;\n" " if (!descriptor) {\n", + // clang-format on "name", name_); static const int kBytesPerLine = 40; // allow for escaping - printer->Print( - " static const char *valueNames ="); + printer->Print(" static const char *valueNames ="); for (int i = 0; i < text_blob.size(); i += kBytesPerLine) { printer->Print( - "\n \"$data$\"", - "data", EscapeTrigraphs(absl::CEscape(text_blob.substr(i, kBytesPerLine)))); + "\n \"$data$\"", "data", + EscapeTrigraphs(absl::CEscape(text_blob.substr(i, kBytesPerLine)))); } printer->Print( ";\n" " static const int32_t values[] = {\n"); for (int i = 0; i < all_values_.size(); i++) { - printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); + printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); } printer->Print(" };\n"); if (text_format_decode_data.num_entries() == 0) { printer->Print( + // clang-format off " GPBEnumDescriptor *worker =\n" " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" " valueNames:valueNames\n" " values:values\n" " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" " enumVerifier:$name$_IsValidValue];\n", + // clang-format on "name", name_); - } else { - printer->Print( + } else { + printer->Print( + // clang-format off " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" " GPBEnumDescriptor *worker =\n" " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" @@ -239,35 +247,41 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" " enumVerifier:$name$_IsValidValue\n" " extraTextFormatInfo:extraTextFormatInfo];\n", - "name", name_, - "extraTextFormatInfo", absl::CEscape(text_format_decode_data.Data())); - } - printer->Print( - " GPBEnumDescriptor *expected = nil;\n" - " if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n" - " [worker release];\n" - " }\n" - " }\n" - " return descriptor;\n" - "}\n\n"); + // clang-format on + "name", name_, "extraTextFormatInfo", + absl::CEscape(text_format_decode_data.Data())); + } + // clang-format off + printer->Print( + " GPBEnumDescriptor *expected = nil;\n" + " if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) {\n" + " [worker release];\n" + " }\n" + " }\n" + " return descriptor;\n" + "}\n\n"); + // clang-format on printer->Print( + // clang-format off "BOOL $name$_IsValidValue(int32_t value__) {\n" " switch (value__) {\n", + // clang-format on "name", name_); for (int i = 0; i < base_values_.size(); i++) { - printer->Print( - " case $name$:\n", - "name", EnumValueName(base_values_[i])); + printer->Print(" case $name$:\n", "name", + EnumValueName(base_values_[i])); } + // clang-format off printer->Print( " return YES;\n" " default:\n" " return NO;\n" " }\n" "}\n\n"); + // clang-format on } } // namespace objectivec } // namespace compiler diff --git a/src/google/protobuf/compiler/objectivec/enum.h b/src/google/protobuf/compiler/objectivec/enum.h index 0759ae5dc2..65f741196e 100644 --- a/src/google/protobuf/compiler/objectivec/enum.h +++ b/src/google/protobuf/compiler/objectivec/enum.h @@ -31,9 +31,10 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__ -#include #include +#include #include + #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" diff --git a/src/google/protobuf/compiler/objectivec/enum_field.cc b/src/google/protobuf/compiler/objectivec/enum_field.cc index 72d0b581f0..c08cbde970 100644 --- a/src/google/protobuf/compiler/objectivec/enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/enum_field.cc @@ -28,12 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/enum_field.h" + #include #include -#include "google/protobuf/compiler/objectivec/enum_field.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" namespace google { @@ -78,6 +79,7 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations( return; } + // clang-format off printer->Print( variables_, "/**\n" @@ -92,12 +94,14 @@ void EnumFieldGenerator::GenerateCFunctionDeclarations( " **/\n" "void Set$owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message, int32_t value);\n" "\n"); + // clang-format on } void EnumFieldGenerator::GenerateCFunctionImplementations( io::Printer* printer) const { if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) return; + // clang-format off printer->Print( variables_, "int32_t $owning_message_class$_$capitalized_name$_RawValue($owning_message_class$ *message) {\n" @@ -112,13 +116,13 @@ void EnumFieldGenerator::GenerateCFunctionImplementations( " GPBSetMessageRawEnumField(message, field, value);\n" "}\n" "\n"); + // clang-format on } void EnumFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const { - SingleFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + std::set* fwd_decls, bool include_external_types) const { + SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // If it is an enum defined in a different file (and not a WKT), then we'll // need a forward declaration for it. When it is in our file, all the enums // are output before the message, so it will be declared before it is needed. @@ -142,8 +146,8 @@ RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} void RepeatedEnumFieldGenerator::FinishInitialization(void) { RepeatedFieldGenerator::FinishInitialization(); - variables_["array_comment"] = - "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; + variables_["array_comment"] = "// |" + variables_["name"] + "| contains |" + + variables_["storage_type"] + "|\n"; } } // namespace objectivec diff --git a/src/google/protobuf/compiler/objectivec/enum_field.h b/src/google/protobuf/compiler/objectivec/enum_field.h index 1cbd6cffad..ac4e70f78a 100644 --- a/src/google/protobuf/compiler/objectivec/enum_field.h +++ b/src/google/protobuf/compiler/objectivec/enum_field.h @@ -33,6 +33,7 @@ #include #include + #include "google/protobuf/compiler/objectivec/field.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/extension.cc b/src/google/protobuf/compiler/objectivec/extension.cc index f13bff0755..d23cf5c126 100644 --- a/src/google/protobuf/compiler/objectivec/extension.cc +++ b/src/google/protobuf/compiler/objectivec/extension.cc @@ -33,8 +33,8 @@ #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" @@ -52,7 +52,7 @@ ExtensionGenerator::ExtensionGenerator(const std::string& root_class_name, // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some // error cases, so it seems to be ok to use as a back door for errors. std::cerr << "error: Extension is a map<>!" - << " That used to be blocked by the compiler." << std::endl; + << " That used to be blocked by the compiler." << std::endl; std::cerr.flush(); abort(); } @@ -76,10 +76,14 @@ void ExtensionGenerator::GenerateMembersHeader(io::Printer* printer) { } // Unlike normal message fields, check if the file for the extension was // deprecated. - vars["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()); - printer->Print(vars, - "$comments$" - "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n"); + vars["deprecated_attribute"] = + GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()); + // clang-format off + printer->Print( + vars, + "$comments$" + "+ (GPBExtensionDescriptor *)$method_name$$storage_attribute$$deprecated_attribute$;\n"); + // clang-format on } void ExtensionGenerator::GenerateStaticVariablesInitialization( @@ -117,22 +121,25 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( if (objc_type == OBJECTIVECTYPE_ENUM) { vars["enum_desc_func_name"] = - EnumName(descriptor_->enum_type()) + "_EnumDescriptor"; + EnumName(descriptor_->enum_type()) + "_EnumDescriptor"; } else { vars["enum_desc_func_name"] = "NULL"; } - printer->Print(vars, - "{\n" - " .defaultValue.$default_name$ = $default$,\n" - " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" - " .extendedClass.clazz = $extended_type$,\n" - " .messageOrGroupClass.clazz = $type$,\n" - " .enumDescriptorFunc = $enum_desc_func_name$,\n" - " .fieldNumber = $number$,\n" - " .dataType = $extension_type$,\n" - " .options = $options$,\n" - "},\n"); + // clang-format off + printer->Print( + vars, + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" + " .extendedClass.clazz = $extended_type$,\n" + " .messageOrGroupClass.clazz = $type$,\n" + " .enumDescriptorFunc = $enum_desc_func_name$,\n" + " .fieldNumber = $number$,\n" + " .dataType = $extension_type$,\n" + " .options = $options$,\n" + "},\n"); + // clang-format on } void ExtensionGenerator::DetermineObjectiveCClassDefinitions( @@ -147,9 +154,11 @@ void ExtensionGenerator::DetermineObjectiveCClassDefinitions( } void ExtensionGenerator::GenerateRegistrationSource(io::Printer* printer) { + // clang-format off printer->Print( "[registry addExtension:$root_class_and_method_name$];\n", "root_class_and_method_name", root_class_and_method_name_); + // clang-format on } } // namespace objectivec diff --git a/src/google/protobuf/compiler/objectivec/field.cc b/src/google/protobuf/compiler/objectivec/field.cc index ca3c43a28f..94663be507 100644 --- a/src/google/protobuf/compiler/objectivec/field.cc +++ b/src/google/protobuf/compiler/objectivec/field.cc @@ -34,10 +34,10 @@ #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/objectivec/enum_field.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/compiler/objectivec/map_field.h" #include "google/protobuf/compiler/objectivec/message_field.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/primitive_field.h" #include "google/protobuf/io/printer.h" @@ -78,7 +78,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, classname + "_FieldNumber_" + capitalized_name; (*variables)["field_number"] = absl::StrCat(descriptor->number()); (*variables)["field_type"] = GetCapitalizedType(descriptor); - (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); + (*variables)["deprecated_attribute"] = + GetOptionalDeprecatedAttribute(descriptor); std::vector field_flags; if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); @@ -109,8 +110,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["dataTypeSpecific_name"] = "clazz"; (*variables)["dataTypeSpecific_value"] = "Nil"; - (*variables)["storage_offset_value"] = - "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; + (*variables)["storage_offset_value"] = "(uint32_t)offsetof(" + classname + + "__storage_, " + camel_case_name + ")"; (*variables)["storage_offset_comment"] = ""; // Clear some common things so they can be set just when needed. @@ -162,29 +163,6 @@ bool HasNonZeroDefaultValue(const FieldDescriptor* field) { return false; } -bool IsPrimitiveType(const FieldDescriptor* field) { - ObjectiveCType type = GetObjectiveCType(field); - switch (type) { - case OBJECTIVECTYPE_INT32: - case OBJECTIVECTYPE_UINT32: - case OBJECTIVECTYPE_INT64: - case OBJECTIVECTYPE_UINT64: - case OBJECTIVECTYPE_FLOAT: - case OBJECTIVECTYPE_DOUBLE: - case OBJECTIVECTYPE_BOOLEAN: - case OBJECTIVECTYPE_ENUM: - return true; - break; - default: - return false; - } -} - -bool IsReferenceType(const FieldDescriptor* field) { - return !IsPrimitiveType(field); -} - - } // namespace FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field) { @@ -236,13 +214,10 @@ FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor) FieldGenerator::~FieldGenerator() {} void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const { - printer->Print( - variables_, - "$field_number_name$ = $field_number$,\n"); + printer->Print(variables_, "$field_number_name$ = $field_number$,\n"); } -void FieldGenerator::GenerateCFunctionDeclarations( - io::Printer* printer) const { +void FieldGenerator::GenerateCFunctionDeclarations(io::Printer* printer) const { // Nothing } @@ -252,8 +227,7 @@ void FieldGenerator::GenerateCFunctionImplementations( } void FieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const { + std::set* fwd_decls, bool include_external_types) const { // Nothing } @@ -262,10 +236,11 @@ void FieldGenerator::DetermineObjectiveCClassDefinitions( // Nothing } -void FieldGenerator::GenerateFieldDescription( - io::Printer* printer, bool include_default) const { +void FieldGenerator::GenerateFieldDescription(io::Printer* printer, + bool include_default) const { // Printed in the same order as the structure decl. if (include_default) { + // clang-format off printer->Print( variables_, "{\n" @@ -278,7 +253,9 @@ void FieldGenerator::GenerateFieldDescription( " .core.flags = $fieldflags$,\n" " .core.dataType = GPBDataType$field_type$,\n" "},\n"); + // clang-format on } else { + // clang-format off printer->Print( variables_, "{\n" @@ -290,6 +267,7 @@ void FieldGenerator::GenerateFieldDescription( " .flags = $fieldflags$,\n" " .dataType = GPBDataType$field_type$,\n" "},\n"); + // clang-format on } } @@ -301,14 +279,13 @@ void FieldGenerator::SetNoHasBit(void) { variables_["has_index"] = "GPBNoHasBit"; } -int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { - return 0; -} +int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { return 0; } void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some // error cases, so it seems to be ok to use as a back door for errors. - std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl; + std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." + << std::endl; std::cerr.flush(); abort(); } @@ -349,14 +326,18 @@ void SingleFieldGenerator::GenerateFieldStorageDeclaration( void SingleFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { printer->Print(variables_, "$comments$"); + // clang-format off printer->Print( variables_, "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" "\n"); + // clang-format on if (WantsHasProperty()) { + // clang-format off printer->Print( variables_, "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + // clang-format on } } @@ -394,26 +375,30 @@ void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration( void ObjCObjFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { - // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that // it uses pointers and deals with Objective C's rules around storage name // conventions (init*, new*, etc.) printer->Print(variables_, "$comments$"); + // clang-format off printer->Print( variables_, "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); + // clang-format on if (WantsHasProperty()) { + // clang-format off printer->Print( variables_, "/** Test to see if @c $name$ has been set. */\n" "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); + // clang-format on } if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + "- ($property_type$ *)$name$ " + "GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -446,13 +431,13 @@ void RepeatedFieldGenerator::GeneratePropertyImplementation( void RepeatedFieldGenerator::GeneratePropertyDeclaration( io::Printer* printer) const { - // Repeated fields don't need the has* properties, but they do expose a // *Count (to check without autocreation). So for the field property we need // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for // dealing with needing Objective C's rules around storage name conventions // (init*, new*, etc.) + // clang-format off printer->Print( variables_, "$comments$" @@ -460,11 +445,14 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" "/** The number of items in @c $name$ without causing the container to be created. */\n" "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); + // clang-format on if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 + // clang-format off printer->Print(variables_, "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); + // clang-format on } printer->Print("\n"); } @@ -479,8 +467,7 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) extension_generators_(descriptor->extension_count()) { // Construct all the FieldGenerators. for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset( - FieldGenerator::Make(descriptor->field(i))); + field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i))); } for (int i = 0; i < descriptor->extension_count(); i++) { extension_generators_[i].reset( diff --git a/src/google/protobuf/compiler/objectivec/field.h b/src/google/protobuf/compiler/objectivec/field.h index 6750b513cd..aae11883d0 100644 --- a/src/google/protobuf/compiler/objectivec/field.h +++ b/src/google/protobuf/compiler/objectivec/field.h @@ -33,6 +33,7 @@ #include #include + #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" @@ -63,15 +64,14 @@ class FieldGenerator { virtual void GenerateCFunctionImplementations(io::Printer* printer) const; // Exposed for subclasses, should always call it on the parent class also. - virtual void DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const; + virtual void DetermineForwardDeclarations(std::set* fwd_decls, + bool include_external_types) const; virtual void DetermineObjectiveCClassDefinitions( std::set* fwd_decls) const; // Used during generation, not intended to be extended by subclasses. - void GenerateFieldDescription( - io::Printer* printer, bool include_default) const; + void GenerateFieldDescription(io::Printer* printer, + bool include_default) const; void GenerateFieldNumberConstant(io::Printer* printer) const; // Exposed to get and set the has bits information. @@ -111,10 +111,12 @@ class SingleFieldGenerator : public FieldGenerator { SingleFieldGenerator(const SingleFieldGenerator&) = delete; SingleFieldGenerator& operator=(const SingleFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GenerateFieldStorageDeclaration( + io::Printer* printer) const override; virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + virtual void GeneratePropertyImplementation( + io::Printer* printer) const override; virtual bool RuntimeUsesHasBit(void) const override; @@ -130,7 +132,8 @@ class ObjCObjFieldGenerator : public SingleFieldGenerator { ObjCObjFieldGenerator(const ObjCObjFieldGenerator&) = delete; ObjCObjFieldGenerator& operator=(const ObjCObjFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GenerateFieldStorageDeclaration( + io::Printer* printer) const override; virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; protected: @@ -144,10 +147,12 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { RepeatedFieldGenerator(const RepeatedFieldGenerator&) = delete; RepeatedFieldGenerator& operator=(const RepeatedFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GenerateFieldStorageDeclaration( + io::Printer* printer) const override; virtual void GeneratePropertyDeclaration(io::Printer* printer) const override; - virtual void GeneratePropertyImplementation(io::Printer* printer) const override; + virtual void GeneratePropertyImplementation( + io::Printer* printer) const override; virtual bool RuntimeUsesHasBit(void) const override; diff --git a/src/google/protobuf/compiler/objectivec/file.cc b/src/google/protobuf/compiler/objectivec/file.cc index ff74517963..2fe4ccd04e 100644 --- a/src/google/protobuf/compiler/objectivec/file.cc +++ b/src/google/protobuf/compiler/objectivec/file.cc @@ -34,14 +34,14 @@ #include #include -#include "google/protobuf/compiler/code_generator.h" #include "absl/strings/str_cat.h" +#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/objectivec/enum.h" #include "google/protobuf/compiler/objectivec/extension.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" #include "google/protobuf/compiler/objectivec/import_writer.h" #include "google/protobuf/compiler/objectivec/message.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some @@ -137,7 +137,7 @@ struct FileDescriptorsOrderedByName { } // namespace -FileGenerator::CommonState::CommonState() { } +FileGenerator::CommonState::CommonState() {} const FileGenerator::CommonState::MinDepsEntry& FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal( @@ -156,20 +156,24 @@ FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal( CollectMinimalFileDepsContainingExtensionsInternal(dep); // Everything the dep covered, this file will also cover. - covered_deps_collector.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end()); + covered_deps_collector.insert(dep_info.covered_deps.begin(), + dep_info.covered_deps.end()); // Prune everything from the dep's covered list in case another dep lists it // as a min dep. to_prune.insert(dep_info.covered_deps.begin(), dep_info.covered_deps.end()); // Does the dep have any extensions... if (dep_info.has_extensions) { - // Yes -> Add this file, prune its min_deps and add them to the covered deps. + // Yes -> Add this file, prune its min_deps and add them to the covered + // deps. min_deps_collector.insert(dep); to_prune.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); - covered_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); + covered_deps_collector.insert(dep_info.min_deps.begin(), + dep_info.min_deps.end()); } else { // No -> Just use its min_deps. - min_deps_collector.insert(dep_info.min_deps.begin(), dep_info.min_deps.end()); + min_deps_collector.insert(dep_info.min_deps.begin(), + dep_info.min_deps.end()); } } @@ -178,22 +182,25 @@ FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal( // Fast path: if nothing to prune or there was only one dep, the prune work is // a waste, skip it. if (to_prune.empty() || file->dependency_count() == 1) { - return deps_info_cache_.insert( - {file, {file_has_exts, min_deps_collector, covered_deps_collector}}).first->second; + return deps_info_cache_ + .insert( + {file, {file_has_exts, min_deps_collector, covered_deps_collector}}) + .first->second; } std::unordered_set min_deps; std::copy_if(min_deps_collector.begin(), min_deps_collector.end(), std::inserter(min_deps, min_deps.end()), - [&](const FileDescriptor* value){ - return to_prune.find(value) == to_prune.end(); - }); - return deps_info_cache_.insert( - {file, {file_has_exts, min_deps, covered_deps_collector}}).first->second; + [&](const FileDescriptor* value) { + return to_prune.find(value) == to_prune.end(); + }); + return deps_info_cache_ + .insert({file, {file_has_exts, min_deps, covered_deps_collector}}) + .first->second; } -// Collect the deps of the given file that contain extensions. This can be used to -// create the chain of roots that need to be wired together. +// Collect the deps of the given file that contain extensions. This can be used +// to create the chain of roots that need to be wired together. // // NOTE: If any changes are made to this and the supporting functions, you will // need to manually validate what the generated code is for the test files: @@ -205,7 +212,7 @@ const std::vector FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensions( const FileDescriptor* file) { std::unordered_set min_deps = - CollectMinimalFileDepsContainingExtensionsInternal(file).min_deps; + CollectMinimalFileDepsContainingExtensionsInternal(file).min_deps; // Sort the list since pointer order isn't stable across runs. std::vector result(min_deps.begin(), min_deps.end()); std::sort(result.begin(), result.end(), FileDescriptorsOrderedByName()); @@ -261,6 +268,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // compiled, since that will be the versions for the ObjC runtime at that // time. The constants in the generated code will then get their values at // at compile time (so checking against the headers being used to compile). + // clang-format off printer->Print( "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n" @@ -270,10 +278,12 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "#endif\n" "\n", "google_protobuf_objc_version", absl::StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); + // clang-format on // The bundled protos (WKTs) don't use of forward declarations. bool headers_use_forward_declarations = - generation_options_.headers_use_forward_declarations && !is_bundled_proto_; + generation_options_.headers_use_forward_declarations && + !is_bundled_proto_; { ImportWriter import_writer( @@ -299,6 +309,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // deprecated-declarations suppression is only needed if some place in this // proto file is something deprecated or if it references something from // another file that is deprecated. + // clang-format off printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" @@ -307,6 +318,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "\n" "CF_EXTERN_C_BEGIN\n" "\n"); + // clang-format on std::set fwd_decls; for (const auto& generator : message_generators_) { @@ -338,6 +350,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // For extensions to chain together, the Root gets created even if there // are no extensions. printer->Print( + // clang-format off "#pragma mark - $root_class_name$\n" "\n" "/**\n" @@ -353,6 +366,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n" "@end\n" "\n", + // clang-format off "root_class_name", root_class_name_); if (!extension_generators_.empty()) { @@ -372,6 +386,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { generator->GenerateMessageHeader(printer); } + // clang-format off printer->Print( "NS_ASSUME_NONNULL_END\n" "\n" @@ -382,6 +397,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n" "\n" "// clange-format on\n"); + // clang-format on } void FileGenerator::GenerateSource(io::Printer* printer) { @@ -401,11 +417,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } std::vector deps_with_extensions = - common_state_.CollectMinimalFileDepsContainingExtensions(file_); + common_state_.CollectMinimalFileDepsContainingExtensions(file_); // The bundled protos (WKTs) don't use of forward declarations. bool headers_use_forward_declarations = - generation_options_.headers_use_forward_declarations && !is_bundled_proto_; + generation_options_.headers_use_forward_declarations && + !is_bundled_proto_; { ImportWriter import_writer( @@ -426,7 +443,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { public_import_names.insert(file_->public_dependency(i)->name()); } for (int i = 0; i < file_->dependency_count(); i++) { - const FileDescriptor *dep = file_->dependency(i); + const FileDescriptor* dep = file_->dependency(i); bool public_import = (public_import_names.count(dep->name()) != 0); if (!public_import) { import_writer.AddFile(dep, header_extension); @@ -471,11 +488,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // another file that is deprecated. // dollar-in-identifier-extension is needed because we use references to // objc class names that have $ in identifiers. + // clang-format off printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" "#pragma clang diagnostic push\n" "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); + // clang-format on if (includes_oneof) { // The generated code for oneof's uses direct ivar access, suppress the // warning in case developer turn that on in the context they compile the @@ -484,17 +503,20 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); } if (!fwd_decls.empty()) { + // clang-format off printer->Print( - "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); + "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); + // clang-format on } - printer->Print( - "\n"); + printer->Print("\n"); if (!fwd_decls.empty()) { + // clang-format off printer->Print( "#pragma mark - Objective C Class declarations\n" "// Forward declarations of Objective C classes that we can use as\n" "// static values in struct initializers.\n" "// We don't use [Foo class] because it is not a static value.\n"); + // clang-format on } for (const auto& i : fwd_decls) { printer->Print("$value$\n", "value", i); @@ -503,9 +525,11 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print("\n"); } printer->Print( + // clang-format off "#pragma mark - $root_class_name$\n" "\n" "@implementation $root_class_name$\n\n", + // clang-format on "root_class_name", root_class_name_); const bool file_contains_extensions = FileContainsExtensions(file_); @@ -513,6 +537,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // If there were any extensions or this file has any dependencies, output // a registry to override to create the file specific registry. if (file_contains_extensions || !deps_with_extensions.empty()) { + // clang-format off printer->Print( "+ (GPBExtensionRegistry*)extensionRegistry {\n" " // This is called by +initialize so there is no need to worry\n" @@ -521,13 +546,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { " if (!registry) {\n" " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" " registry = [[GPBExtensionRegistry alloc] init];\n"); + // clang-format on printer->Indent(); printer->Indent(); if (file_contains_extensions) { - printer->Print( - "static GPBExtensionDescription descriptions[] = {\n"); + printer->Print("static GPBExtensionDescription descriptions[] = {\n"); printer->Indent(); for (const auto& generator : extension_generators_) { generator->GenerateStaticVariablesInitialization(printer); @@ -536,6 +561,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { generator->GenerateStaticVariablesInitialization(printer); } printer->Outdent(); + // clang-format off printer->Print( "};\n" "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" @@ -546,15 +572,20 @@ void FileGenerator::GenerateSource(io::Printer* printer) { " [self globallyRegisterExtension:extension];\n" " [extension release];\n" "}\n"); + // clang-format on } if (deps_with_extensions.empty()) { + // clang-format off printer->Print( "// None of the imports (direct or indirect) defined extensions, so no need to add\n" "// them to this registry.\n"); + // clang-format on } else { + // clang-format off printer->Print( "// Merge in the imports (direct or indirect) that defined extensions.\n"); + // clang-format on for (std::vector::iterator iter = deps_with_extensions.begin(); iter != deps_with_extensions.end(); ++iter) { @@ -568,19 +599,25 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Outdent(); printer->Outdent(); + // clang-format off printer->Print( " }\n" " return registry;\n" "}\n"); + // clang-format on } else { if (file_->dependency_count() > 0) { + // clang-format off printer->Print( "// No extensions in the file and none of the imports (direct or indirect)\n" "// defined extensions, so no need to generate +extensionRegistry.\n"); + // clang-format on } else { + // clang-format off printer->Print( "// No extensions in the file and no imports, so no need to generate\n" "// +extensionRegistry.\n"); + // clang-format on } } @@ -603,7 +640,9 @@ void FileGenerator::GenerateSource(io::Printer* printer) { vars["syntax"] = "GPBFileSyntaxProto3"; break; } - printer->Print(vars, + // clang-format off + printer->Print( + vars, "#pragma mark - $root_class_name$_FileDescriptor\n" "\n" "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" @@ -612,23 +651,30 @@ void FileGenerator::GenerateSource(io::Printer* printer) { " static GPBFileDescriptor *descriptor = NULL;\n" " if (!descriptor) {\n" " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); + // clang-format on if (!vars["objc_prefix"].empty()) { + // clang-format off printer->Print( vars, " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" " objcPrefix:@\"$objc_prefix$\"\n" " syntax:$syntax$];\n"); + // clang-format on } else { + // clang-format off printer->Print( vars, " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" " syntax:$syntax$];\n"); + // clang-format on } + // clang-format off printer->Print( " }\n" " return descriptor;\n" "}\n" "\n"); + // clang-format on } for (const auto& generator : enum_generators_) { @@ -638,13 +684,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) { generator->GenerateSource(printer); } + // clang-format off printer->Print( - "\n" - "#pragma clang diagnostic pop\n" - "\n" - "// @@protoc_insertion_point(global_scope)\n" - "\n" - "// clange-format on\n"); + "\n" + "#pragma clang diagnostic pop\n" + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n" + "// clang-format on\n"); + // clang-format on } // Helper to print the import of the runtime support at the top of generated @@ -655,9 +703,8 @@ void FileGenerator::PrintFileRuntimePreamble( const std::vector& headers_to_import) const { printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" "// clang-format off\n" + "// source: $filename$\n" "\n", "filename", file_->name()); @@ -670,14 +717,13 @@ void FileGenerator::PrintFileRuntimePreamble( import_prefix += "/"; } for (const auto& header : headers_to_import) { - printer->Print( - "#import \"$import_prefix$$header$\"\n", - "import_prefix", import_prefix, - "header", header); + printer->Print("#import \"$import_prefix$$header$\"\n", "import_prefix", + import_prefix, "header", header); } } else { - ImportWriter::PrintRuntimeImports( - printer, headers_to_import, generation_options_.runtime_import_prefix, true); + ImportWriter::PrintRuntimeImports(printer, headers_to_import, + generation_options_.runtime_import_prefix, + true); } printer->Print("\n"); diff --git a/src/google/protobuf/compiler/objectivec/file.h b/src/google/protobuf/compiler/objectivec/file.h index 1af0f54906..21404baca1 100644 --- a/src/google/protobuf/compiler/objectivec/file.h +++ b/src/google/protobuf/compiler/objectivec/file.h @@ -35,6 +35,7 @@ #include #include #include + #include "google/protobuf/compiler/objectivec/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" @@ -66,7 +67,8 @@ class FileGenerator { // have extensions. std::unordered_set covered_deps; }; - const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal(const FileDescriptor* file); + const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal( + const FileDescriptor* file); std::unordered_map deps_info_cache_; }; diff --git a/src/google/protobuf/compiler/objectivec/generator.cc b/src/google/protobuf/compiler/objectivec/generator.cc index 8267d2c827..1b963683ae 100644 --- a/src/google/protobuf/compiler/objectivec/generator.cc +++ b/src/google/protobuf/compiler/objectivec/generator.cc @@ -39,8 +39,8 @@ #include "absl/strings/str_split.h" #include "absl/strings/strip.h" #include "google/protobuf/compiler/objectivec/file.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" #include "google/protobuf/io/zero_copy_stream.h" @@ -75,9 +75,7 @@ ObjectiveCGenerator::ObjectiveCGenerator() {} ObjectiveCGenerator::~ObjectiveCGenerator() {} -bool ObjectiveCGenerator::HasGenerateAll() const { - return true; -} +bool ObjectiveCGenerator::HasGenerateAll() const { return true; } bool ObjectiveCGenerator::Generate(const FileDescriptor* file, const std::string& parameter, @@ -97,7 +95,8 @@ bool ObjectiveCGenerator::GenerateAll( // options along with their values. If the option appears multiple times, only // the last value will be considered. // - // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework + // e.g. protoc ... + // --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework Options validation_options; GenerationOptions generation_options; @@ -127,8 +126,8 @@ bool ObjectiveCGenerator::GenerateAll( // A semicolon delimited string that lists the paths of .proto files to // exclude from the package prefix validations (expected_prefixes_path). // This is provided as an "out", to skip some files being checked. - for (absl::string_view split_piece : absl::StrSplit( - options[i].second, ";", absl::SkipEmpty())) { + for (absl::string_view split_piece : + absl::StrSplit(options[i].second, ";", absl::SkipEmpty())) { validation_options.expected_prefixes_suppressions.push_back( std::string(split_piece)); } @@ -142,7 +141,8 @@ bool ObjectiveCGenerator::GenerateAll( // Default is "no". if (!StringToBool(options[i].second, &validation_options.prefixes_must_be_registered)) { - *error = "error: Unknown value for prefixes_must_be_registered: " + options[i].second; + *error = "error: Unknown value for prefixes_must_be_registered: " + + options[i].second; return false; } } else if (options[i].first == "require_prefixes") { @@ -154,7 +154,8 @@ bool ObjectiveCGenerator::GenerateAll( // Default is "no". if (!StringToBool(options[i].second, &validation_options.require_prefixes)) { - *error = "error: Unknown value for require_prefixes: " + options[i].second; + *error = + "error: Unknown value for require_prefixes: " + options[i].second; return false; } } else if (options[i].first == "generate_for_named_framework") { @@ -167,7 +168,8 @@ bool ObjectiveCGenerator::GenerateAll( // the "default" framework name used for everything that wasn't mapped by // the mapping file. generation_options.generate_for_named_framework = options[i].second; - } else if (options[i].first == "named_framework_to_proto_path_mappings_path") { + } else if (options[i].first == + "named_framework_to_proto_path_mappings_path") { // Path to find a file containing the list of framework names and proto // files. The generator uses this to decide if a proto file // referenced should use a framework style import vs. a user level import @@ -188,7 +190,8 @@ bool ObjectiveCGenerator::GenerateAll( // mappings file, it will use the default framework name if one was passed // with generate_for_named_framework, or the relative path to it's include // path otherwise. - generation_options.named_framework_to_proto_path_mappings_path = options[i].second; + generation_options.named_framework_to_proto_path_mappings_path = + options[i].second; } else if (options[i].first == "runtime_import_prefix") { // Path to use as a prefix on #imports of runtime provided headers in the // generated files. When integrating ObjC protos into a build system, @@ -198,8 +201,9 @@ bool ObjectiveCGenerator::GenerateAll( std::string(absl::StripSuffix(options[i].second, "/")); } else if (options[i].first == "package_to_prefix_mappings_path") { // Path to use for when loading the objc class prefix mappings to use. - // The `objc_class_prefix` file option is always honored first if one is present. - // This option also has precedent over the use_package_as_prefix option. + // The `objc_class_prefix` file option is always honored first if one is + // present. This option also has precedent over the use_package_as_prefix + // option. // // The format of the file is: // - An entry is a line of "package=prefix". @@ -243,7 +247,8 @@ bool ObjectiveCGenerator::GenerateAll( } else if (options[i].first == "headers_use_forward_declarations") { if (!StringToBool(options[i].second, &generation_options.headers_use_forward_declarations)) { - *error = "error: Unknown value for headers_use_forward_declarations: " + options[i].second; + *error = "error: Unknown value for headers_use_forward_declarations: " + + options[i].second; return false; } } else { diff --git a/src/google/protobuf/compiler/objectivec/generator.h b/src/google/protobuf/compiler/objectivec/generator.h index 8b4e1292e7..7de5b410a8 100644 --- a/src/google/protobuf/compiler/objectivec/generator.h +++ b/src/google/protobuf/compiler/objectivec/generator.h @@ -34,6 +34,7 @@ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__ #include + #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/descriptor.h" diff --git a/src/google/protobuf/compiler/objectivec/helpers.cc b/src/google/protobuf/compiler/objectivec/helpers.cc index e5604efe48..da5739db4a 100644 --- a/src/google/protobuf/compiler/objectivec/helpers.cc +++ b/src/google/protobuf/compiler/objectivec/helpers.cc @@ -28,16 +28,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/helpers.h" + #include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/compiler/objectivec/names.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/stubs/strutil.h" #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "absl/strings/str_split.h" #include "absl/strings/str_replace.h" -#include "google/protobuf/compiler/objectivec/helpers.h" -#include "google/protobuf/compiler/objectivec/names.h" -#include "google/protobuf/io/printer.h" -#include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/stubs/common.h" // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some @@ -55,7 +56,7 @@ std::string EscapeTrigraphs(absl::string_view to_escape) { namespace { std::string GetZeroEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { + switch (flag_type) { case FLAGTYPE_DESCRIPTOR_INITIALIZATION: return "GPBDescriptorInitializationFlag_None"; case FLAGTYPE_EXTENSION: @@ -69,7 +70,7 @@ std::string GetZeroEnumNameForFlagType(const FlagType flag_type) { } std::string GetEnumNameForFlagType(const FlagType flag_type) { - switch(flag_type) { + switch (flag_type) { case FLAGTYPE_DESCRIPTOR_INITIALIZATION: return "GPBDescriptorInitializationFlags"; case FLAGTYPE_EXTENSION: @@ -82,8 +83,7 @@ std::string GetEnumNameForFlagType(const FlagType flag_type) { } } -std::string HandleExtremeFloatingPoint(std::string val, - bool add_float_suffix) { +std::string HandleExtremeFloatingPoint(std::string val, bool add_float_suffix) { if (val == "nan") { return "NAN"; } else if (val == "inf") { @@ -202,7 +202,7 @@ std::string GPBGenericValueFieldName(const FieldDescriptor* field) { // Returns the field within the GPBGenericValue union to use for the given // field. if (field->is_repeated()) { - return "valueMessage"; + return "valueMessage"; } switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -237,7 +237,6 @@ std::string GPBGenericValueFieldName(const FieldDescriptor* field) { return std::string(); } - std::string DefaultValue(const FieldDescriptor* field) { // Repeated fields don't have defaults. if (field->is_repeated()) { @@ -336,10 +335,10 @@ std::string ObjCClassDeclaration(const std::string& class_name) { } std::string BuildCommentsString(const SourceLocation& location, - bool prefer_single_line) { + bool prefer_single_line) { const std::string& comments = location.leading_comments.empty() - ? location.trailing_comments - : location.leading_comments; + ? location.trailing_comments + : location.leading_comments; std::vector lines; lines = absl::StrSplit(comments, "\n", absl::AllowEmpty()); while (!lines.empty() && lines.back().empty()) { @@ -388,7 +387,6 @@ std::string BuildCommentsString(const SourceLocation& location, return final_comments; } - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/helpers.h b/src/google/protobuf/compiler/objectivec/helpers.h index ce7cc9aae3..c37c0366b0 100644 --- a/src/google/protobuf/compiler/objectivec/helpers.h +++ b/src/google/protobuf/compiler/objectivec/helpers.h @@ -79,10 +79,33 @@ inline ObjectiveCType GetObjectiveCType(const FieldDescriptor* field) { return GetObjectiveCType(field->type()); } +inline bool IsPrimitiveType(const FieldDescriptor* field) { + ObjectiveCType type = GetObjectiveCType(field); + switch (type) { + case OBJECTIVECTYPE_INT32: + case OBJECTIVECTYPE_UINT32: + case OBJECTIVECTYPE_INT64: + case OBJECTIVECTYPE_UINT64: + case OBJECTIVECTYPE_FLOAT: + case OBJECTIVECTYPE_DOUBLE: + case OBJECTIVECTYPE_BOOLEAN: + case OBJECTIVECTYPE_ENUM: + return true; + break; + default: + return false; + } +} + +inline bool IsReferenceType(const FieldDescriptor* field) { + return !IsPrimitiveType(field); +} + std::string GPBGenericValueFieldName(const FieldDescriptor* field); std::string DefaultValue(const FieldDescriptor* field); -std::string BuildFlagsString(const FlagType type, const std::vector& strings); +std::string BuildFlagsString(const FlagType type, + const std::vector& strings); // Returns a symbol that can be used in C code to refer to an Objective C // class without initializing the class. @@ -134,7 +157,6 @@ std::string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, } } - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/import_writer.cc b/src/google/protobuf/compiler/objectivec/import_writer.cc index 3a058a916f..a0291b05a9 100644 --- a/src/google/protobuf/compiler/objectivec/import_writer.cc +++ b/src/google/protobuf/compiler/objectivec/import_writer.cc @@ -29,10 +29,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "google/protobuf/compiler/objectivec/import_writer.h" + +#include "absl/strings/ascii.h" #include "google/protobuf/compiler/objectivec/line_consumer.h" #include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" -#include "absl/strings/ascii.h" // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some // error cases, so it seems to be ok to use as a back door for errors. @@ -46,17 +47,19 @@ namespace { class ProtoFrameworkCollector : public LineConsumer { public: - ProtoFrameworkCollector(std::map* inout_proto_file_to_framework_name) + ProtoFrameworkCollector( + std::map* inout_proto_file_to_framework_name) : map_(inout_proto_file_to_framework_name) {} - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override; + virtual bool ConsumeLine(const absl::string_view& line, + std::string* out_error) override; private: std::map* map_; }; -bool ProtoFrameworkCollector::ConsumeLine( - const absl::string_view& line, std::string* out_error) { +bool ProtoFrameworkCollector::ConsumeLine(const absl::string_view& line, + std::string* out_error) { int offset = line.find(':'); if (offset == absl::string_view::npos) { *out_error = @@ -64,8 +67,10 @@ bool ProtoFrameworkCollector::ConsumeLine( std::string(line) + "'."; return false; } - absl::string_view framework_name = absl::StripAsciiWhitespace(line.substr(0, offset)); - absl::string_view proto_file_list = absl::StripAsciiWhitespace(line.substr(offset + 1)); + absl::string_view framework_name = + absl::StripAsciiWhitespace(line.substr(0, offset)); + absl::string_view proto_file_list = + absl::StripAsciiWhitespace(line.substr(offset + 1)); int start = 0; while (start < proto_file_list.length()) { @@ -74,16 +79,17 @@ bool ProtoFrameworkCollector::ConsumeLine( offset = proto_file_list.length(); } - absl::string_view proto_file = - absl::StripAsciiWhitespace(proto_file_list.substr(start, offset - start)); + absl::string_view proto_file = absl::StripAsciiWhitespace( + proto_file_list.substr(start, offset - start)); if (!proto_file.empty()) { std::map::iterator existing_entry = map_->find(std::string(proto_file)); if (existing_entry != map_->end()) { std::cerr << "warning: duplicate proto file reference, replacing " "framework entry for '" - << std::string(proto_file) << "' with '" << std::string(framework_name) - << "' (was '" << existing_entry->second << "')." << std::endl; + << std::string(proto_file) << "' with '" + << std::string(framework_name) << "' (was '" + << existing_entry->second << "')." << std::endl; std::cerr.flush(); } @@ -141,15 +147,14 @@ void ImportWriter::AddFile(const FileDescriptor* file, proto_file_to_framework_name_.find(file->name()); if (proto_lookup != proto_file_to_framework_name_.end()) { other_framework_imports_.push_back( - proto_lookup->second + "/" + - FilePathBasename(file) + header_extension); + proto_lookup->second + "/" + FilePathBasename(file) + header_extension); return; } if (!generate_for_named_framework_.empty()) { - other_framework_imports_.push_back( - generate_for_named_framework_ + "/" + - FilePathBasename(file) + header_extension); + other_framework_imports_.push_back(generate_for_named_framework_ + "/" + + FilePathBasename(file) + + header_extension); return; } @@ -172,9 +177,7 @@ void ImportWriter::Print(io::Printer* printer) const { for (std::vector::const_iterator iter = other_framework_imports_.begin(); iter != other_framework_imports_.end(); ++iter) { - printer->Print( - "#import <$header$>\n", - "header", *iter); + printer->Print("#import <$header$>\n", "header", *iter); } add_blank_line = true; @@ -187,9 +190,7 @@ void ImportWriter::Print(io::Printer* printer) const { for (std::vector::const_iterator iter = other_imports_.begin(); iter != other_imports_.end(); ++iter) { - printer->Print( - "#import \"$header$\"\n", - "header", *iter); + printer->Print("#import \"$header$\"\n", "header", *iter); } } } @@ -200,10 +201,8 @@ void ImportWriter::PrintRuntimeImports( // Given an override, use that. if (!runtime_import_prefix.empty()) { for (const auto& header : header_to_import) { - printer->Print( - " #import \"$import_prefix$/$header$\"\n", - "import_prefix", runtime_import_prefix, - "header", header); + printer->Print(" #import \"$import_prefix$/$header$\"\n", "import_prefix", + runtime_import_prefix, "header", header); } return; } @@ -213,33 +212,27 @@ void ImportWriter::PrintRuntimeImports( if (default_cpp_symbol) { printer->Print( + // clang-format off "// This CPP symbol can be defined to use imports that match up to the framework\n" "// imports needed when using CocoaPods.\n" "#if !defined($cpp_symbol$)\n" " #define $cpp_symbol$ 0\n" "#endif\n" "\n", + // clang-format on "cpp_symbol", cpp_symbol); } - printer->Print( - "#if $cpp_symbol$\n", - "cpp_symbol", cpp_symbol); + printer->Print("#if $cpp_symbol$\n", "cpp_symbol", cpp_symbol); for (const auto& header : header_to_import) { - printer->Print( - " #import <$framework_name$/$header$>\n", - "framework_name", framework_name, - "header", header); + printer->Print(" #import <$framework_name$/$header$>\n", "framework_name", + framework_name, "header", header); } - printer->Print( - "#else\n"); + printer->Print("#else\n"); for (const auto& header : header_to_import) { - printer->Print( - " #import \"$header$\"\n", - "header", header); + printer->Print(" #import \"$header$\"\n", "header", header); } - printer->Print( - "#endif\n"); + printer->Print("#endif\n"); } void ImportWriter::ParseFrameworkMappings() { @@ -250,10 +243,11 @@ void ImportWriter::ParseFrameworkMappings() { ProtoFrameworkCollector collector(&proto_file_to_framework_name_); std::string parse_error; - if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, - &collector, &parse_error)) { - std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_ - << " : " << parse_error << std::endl; + if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_, &collector, + &parse_error)) { + std::cerr << "error parsing " + << named_framework_to_proto_path_mappings_path_ << " : " + << parse_error << std::endl; std::cerr.flush(); } } diff --git a/src/google/protobuf/compiler/objectivec/import_writer.h b/src/google/protobuf/compiler/objectivec/import_writer.h index 7c8b29729e..e6fc628901 100644 --- a/src/google/protobuf/compiler/objectivec/import_writer.h +++ b/src/google/protobuf/compiler/objectivec/import_writer.h @@ -55,10 +55,10 @@ class ImportWriter { void AddFile(const FileDescriptor* file, const std::string& header_extension); void Print(io::Printer* printer) const; - static void PrintRuntimeImports(io::Printer* printer, - const std::vector& header_to_import, - const std::string& runtime_import_prefix, - bool default_cpp_symbol = false); + static void PrintRuntimeImports( + io::Printer* printer, const std::vector& header_to_import, + const std::string& runtime_import_prefix, + bool default_cpp_symbol = false); private: void ParseFrameworkMappings(); @@ -75,7 +75,6 @@ class ImportWriter { std::vector other_imports_; }; - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/line_consumer.cc b/src/google/protobuf/compiler/objectivec/line_consumer.cc index 2026c2826d..b668875a42 100644 --- a/src/google/protobuf/compiler/objectivec/line_consumer.cc +++ b/src/google/protobuf/compiler/objectivec/line_consumer.cc @@ -61,16 +61,14 @@ namespace objectivec { namespace posix { #ifdef _WIN32 using google::protobuf::io::win32::open; -#else // !_WIN32 +#else // !_WIN32 using ::open; #endif // _WIN32 } // namespace posix namespace { -bool ascii_isnewline(char c) { - return c == '\n' || c == '\r'; -} +bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; } bool ReadLine(absl::string_view* input, absl::string_view* line) { for (int len = 0; len < input->size(); ++len) { @@ -149,7 +147,8 @@ bool Parser::Finish(std::string* out_error) { if (!leftover_.empty() && !ParseChunk("\n", out_error)) { return false; } - // This really should never fail if ParseChunk succeeded, but check to be sure. + // This really should never fail if ParseChunk succeeded, but check to be + // sure. if (!leftover_.empty()) { *out_error = "ParseSimple Internal error: finished with pending data."; return false; @@ -157,8 +156,10 @@ bool Parser::Finish(std::string* out_error) { return true; } -std::string FullErrorString(const std::string& name, int line_num, const std::string& msg) { - return std::string("error: ") + name + " Line " + absl::StrCat(line_num) + ", " + msg; +std::string FullErrorString(const std::string& name, int line_num, + const std::string& msg) { + return std::string("error: ") + name + " Line " + absl::StrCat(line_num) + + ", " + msg; } } // namespace @@ -186,8 +187,7 @@ bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer, bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, const std::string& stream_name, - LineConsumer* line_consumer, - std::string* out_error) { + LineConsumer* line_consumer, std::string* out_error) { std::string local_error; Parser parser(line_consumer); const void* buf; @@ -197,9 +197,11 @@ bool ParseSimpleStream(io::ZeroCopyInputStream& input_stream, continue; } - if (!parser.ParseChunk(absl::string_view(static_cast(buf), buf_len), - &local_error)) { - *out_error = FullErrorString(stream_name, parser.last_line(), local_error); + if (!parser.ParseChunk( + absl::string_view(static_cast(buf), buf_len), + &local_error)) { + *out_error = + FullErrorString(stream_name, parser.last_line(), local_error); return false; } } diff --git a/src/google/protobuf/compiler/objectivec/line_consumer.h b/src/google/protobuf/compiler/objectivec/line_consumer.h index 15a935b6b0..bdddf08242 100644 --- a/src/google/protobuf/compiler/objectivec/line_consumer.h +++ b/src/google/protobuf/compiler/objectivec/line_consumer.h @@ -52,7 +52,8 @@ class PROTOC_EXPORT LineConsumer { public: LineConsumer(); virtual ~LineConsumer(); - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) = 0; + virtual bool ConsumeLine(const absl::string_view& line, + std::string* out_error) = 0; }; bool PROTOC_EXPORT ParseSimpleFile(const std::string& path, diff --git a/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc b/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc index 2513b6f4fe..ff8ff87d2d 100644 --- a/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc +++ b/src/google/protobuf/compiler/objectivec/line_consumer_unittest.cc @@ -29,11 +29,12 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "google/protobuf/compiler/objectivec/line_consumer.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" -#include "absl/strings/str_cat.h" #include +#include "absl/strings/str_cat.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" + namespace google { namespace protobuf { namespace compiler { @@ -43,11 +44,12 @@ namespace { class TestLineCollector : public LineConsumer { public: explicit TestLineCollector(std::vector* inout_lines, - const std::string* reject_line = nullptr, - bool skip_msg = false) - : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {} + const std::string* reject_line = nullptr, + bool skip_msg = false) + : lines_(inout_lines), reject_(reject_line), skip_msg_(skip_msg) {} - bool ConsumeLine(const absl::string_view& line, std::string* out_error) override { + bool ConsumeLine(const absl::string_view& line, + std::string* out_error) override { if (reject_ && *reject_ == line) { if (!skip_msg_) { *out_error = std::string("Rejected '") + *reject_ + "'"; @@ -71,19 +73,20 @@ const int kBlockSizeCount = ABSL_ARRAYSIZE(kBlockSizes); TEST(ObjCHelper, ParseSimple_BasicsSuccess) { const std::vector>> tests = { - {"", {}}, - {"a", {"a"}}, - {"a c", {"a c"}}, - {" a c ", {"a c"}}, - {"\ta c ", {"a c"}}, - {"abc\n", {"abc"}}, - {"abc\nd f", {"abc", "d f"}}, - {"\n abc \n def \n\n", {"abc", "def"}}, + {"", {}}, + {"a", {"a"}}, + {"a c", {"a c"}}, + {" a c ", {"a c"}}, + {"\ta c ", {"a c"}}, + {"abc\n", {"abc"}}, + {"abc\nd f", {"abc", "d f"}}, + {"\n abc \n def \n\n", {"abc", "def"}}, }; for (const auto& test : tests) { for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + io::ArrayInputStream input(test.first.data(), test.first.size(), + kBlockSizes[i]); std::string err_str; std::vector lines; TestLineCollector collector(&lines); @@ -96,22 +99,23 @@ TEST(ObjCHelper, ParseSimple_BasicsSuccess) { TEST(ObjCHelper, ParseSimple_DropsComments) { const std::vector>> tests = { - {"# nothing", {}}, - {"#", {}}, - {"##", {}}, - {"\n# nothing\n", {}}, - {"a # same line", {"a"}}, - {"a # same line\n", {"a"}}, - {"a\n# line\nc", {"a", "c"}}, - {"# n o t # h i n g #", {}}, - {"## n o # t h i n g #", {}}, - {"a# n o t # h i n g #", {"a"}}, - {"a\n## n o # t h i n g #", {"a"}}, + {"# nothing", {}}, + {"#", {}}, + {"##", {}}, + {"\n# nothing\n", {}}, + {"a # same line", {"a"}}, + {"a # same line\n", {"a"}}, + {"a\n# line\nc", {"a", "c"}}, + {"# n o t # h i n g #", {}}, + {"## n o # t h i n g #", {}}, + {"a# n o t # h i n g #", {"a"}}, + {"a\n## n o # t h i n g #", {"a"}}, }; for (const auto& test : tests) { for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(test.first.data(), test.first.size(), kBlockSizes[i]); + io::ArrayInputStream input(test.first.data(), test.first.size(), + kBlockSizes[i]); std::string err_str; std::vector lines; TestLineCollector collector(&lines); @@ -124,21 +128,22 @@ TEST(ObjCHelper, ParseSimple_DropsComments) { TEST(ObjCHelper, ParseSimple_RejectLines) { const std::vector> tests = { - std::make_tuple("a\nb\nc", "a", 1), - std::make_tuple("a\nb\nc", "b", 2), - std::make_tuple("a\nb\nc", "c", 3), - std::make_tuple("a\nb\nc\n", "c", 3), + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), }; for (const auto& test : tests) { for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), - kBlockSizes[i]); + io::ArrayInputStream input(std::get<0>(test).data(), + std::get<0>(test).size(), kBlockSizes[i]); std::string err_str; TestLineCollector collector(nullptr, &std::get<1>(test)); EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); std::string expected_err = - absl::StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", std::get<1>(test), "'"); + absl::StrCat("error: dummy Line ", std::get<2>(test), ", Rejected '", + std::get<1>(test), "'"); EXPECT_EQ(err_str, expected_err); } } @@ -146,22 +151,23 @@ TEST(ObjCHelper, ParseSimple_RejectLines) { TEST(ObjCHelper, ParseSimple_RejectLinesNoMessage) { const std::vector> tests = { - std::make_tuple("a\nb\nc", "a", 1), - std::make_tuple("a\nb\nc", "b", 2), - std::make_tuple("a\nb\nc", "c", 3), - std::make_tuple("a\nb\nc\n", "c", 3), + std::make_tuple("a\nb\nc", "a", 1), + std::make_tuple("a\nb\nc", "b", 2), + std::make_tuple("a\nb\nc", "c", 3), + std::make_tuple("a\nb\nc\n", "c", 3), }; for (const auto& test : tests) { for (int i = 0; i < kBlockSizeCount; i++) { - io::ArrayInputStream input(std::get<0>(test).data(), std::get<0>(test).size(), - kBlockSizes[i]); + io::ArrayInputStream input(std::get<0>(test).data(), + std::get<0>(test).size(), kBlockSizes[i]); std::string err_str; - TestLineCollector collector(nullptr, &std::get<1>(test), true /* skip msg */); + TestLineCollector collector(nullptr, &std::get<1>(test), + true /* skip msg */); EXPECT_FALSE(ParseSimpleStream(input, "dummy", &collector, &err_str)); std::string expected_err = - absl::StrCat("error: dummy Line ", std::get<2>(test), - ", ConsumeLine failed without setting an error."); + absl::StrCat("error: dummy Line ", std::get<2>(test), + ", ConsumeLine failed without setting an error."); EXPECT_EQ(err_str, expected_err); } } diff --git a/src/google/protobuf/compiler/objectivec/map_field.cc b/src/google/protobuf/compiler/objectivec/map_field.cc index e11794a77e..0c6acb3929 100644 --- a/src/google/protobuf/compiler/objectivec/map_field.cc +++ b/src/google/protobuf/compiler/objectivec/map_field.cc @@ -28,12 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/map_field.h" + #include #include -#include "google/protobuf/compiler/objectivec/map_field.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" namespace google { @@ -84,8 +85,7 @@ const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) { MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) : RepeatedFieldGenerator(descriptor) { - const FieldDescriptor* key_descriptor = - descriptor->message_type()->map_key(); + const FieldDescriptor* key_descriptor = descriptor->message_type()->map_key(); const FieldDescriptor* value_descriptor = descriptor->message_type()->map_value(); value_field_generator_.reset(FieldGenerator::Make(value_descriptor)); @@ -135,8 +135,8 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor) variables_["array_storage_type"] = class_name; if (value_is_object_type) { variables_["array_property_type"] = - class_name + "<" + - value_field_generator_->variable("storage_type") + "*>"; + class_name + "<" + value_field_generator_->variable("storage_type") + + "*>"; } } @@ -156,15 +156,15 @@ void MapFieldGenerator::FinishInitialization(void) { descriptor_->message_type()->map_value(); if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) { variables_["array_comment"] = - "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n"; + "// |" + variables_["name"] + "| values are |" + + value_field_generator_->variable("storage_type") + "|\n"; } } void MapFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const { - RepeatedFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + std::set* fwd_decls, bool include_external_types) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); // Within a file there is no requirement on the order of the messages, so @@ -186,8 +186,8 @@ void MapFieldGenerator::DetermineObjectiveCClassDefinitions( const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { - fwd_decls->insert(ObjCClassDeclaration( - value_field_generator_->variable("storage_type"))); + fwd_decls->insert( + ObjCClassDeclaration(value_field_generator_->variable("storage_type"))); } } diff --git a/src/google/protobuf/compiler/objectivec/message.cc b/src/google/protobuf/compiler/objectivec/message.cc index 9169ecddfc..a68aa60a28 100644 --- a/src/google/protobuf/compiler/objectivec/message.cc +++ b/src/google/protobuf/compiler/objectivec/message.cc @@ -38,8 +38,8 @@ #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/objectivec/enum.h" #include "google/protobuf/compiler/objectivec/extension.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/text_format_decode_data.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" @@ -152,11 +152,12 @@ struct ExtensionRangeOrdering { // and return it. const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { const FieldDescriptor** fields = - new const FieldDescriptor* [descriptor->field_count()]; + new const FieldDescriptor*[descriptor->field_count()]; for (int i = 0; i < descriptor->field_count(); i++) { fields[i] = descriptor->field(i); } - std::sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber()); + std::sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); return fields; } @@ -164,12 +165,12 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { // array and return it. const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { const FieldDescriptor** fields = - new const FieldDescriptor* [descriptor->field_count()]; + new const FieldDescriptor*[descriptor->field_count()]; for (int i = 0; i < descriptor->field_count(); i++) { fields[i] = descriptor->field(i); } std::sort(fields, fields + descriptor->field_count(), - FieldOrderingByStorageSize()); + FieldOrderingByStorageSize()); return fields; } @@ -200,8 +201,7 @@ MessageGenerator::MessageGenerator(const std::string& root_classname, for (int i = 0; i < descriptor_->nested_type_count(); i++) { MessageGenerator* generator = - new MessageGenerator(root_classname_, - descriptor_->nested_type(i)); + new MessageGenerator(root_classname_, descriptor_->nested_type(i)); nested_message_generators_.emplace_back(generator); } } @@ -220,8 +220,7 @@ void MessageGenerator::GenerateStaticVariablesInitialization( } void MessageGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) { + std::set* fwd_decls, bool include_external_types) { if (!IsMapEntryMessage(descriptor_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* fieldDescriptor = descriptor_->field(i); @@ -305,16 +304,18 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { } printer->Print( + // clang-format off "#pragma mark - $classname$\n" "\n", + // clang-format on "classname", class_name_); if (descriptor_->field_count()) { std::unique_ptr sorted_fields( SortFieldsByNumber(descriptor_)); - printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", - "classname", class_name_); + printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", "classname", + class_name_); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -339,9 +340,10 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { } printer->Print( + // clang-format off "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n", - "classname", class_name_, - "deprecated_attribute", deprecated_attribute_, + // clang-format on + "classname", class_name_, "deprecated_attribute", deprecated_attribute_, "comments", message_comments); std::vector seen_oneofs(oneof_generators_.size(), 0); @@ -374,8 +376,8 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { } if (descriptor_->extension_count() > 0) { - printer->Print("@interface $classname$ (DynamicMethods)\n\n", - "classname", class_name_); + printer->Print("@interface $classname$ (DynamicMethods)\n\n", "classname", + class_name_); for (const auto& generator : extension_generators_) { generator->GenerateMembersHeader(printer); } @@ -390,20 +392,23 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { void MessageGenerator::GenerateSource(io::Printer* printer) { if (!IsMapEntryMessage(descriptor_)) { printer->Print( + // clang-format off "#pragma mark - $classname$\n" "\n", + // clang-format on "classname", class_name_); if (!deprecated_attribute_.empty()) { // No warnings when compiling the impl of this deprecated class. + // clang-format off printer->Print( "#pragma clang diagnostic push\n" "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n" "\n"); + // clang-format on } - printer->Print("@implementation $classname$\n\n", - "classname", class_name_); + printer->Print("@implementation $classname$\n\n", "classname", class_name_); for (const auto& generator : oneof_generators_) { generator->GeneratePropertyImplementation(printer); @@ -426,7 +431,7 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { } std::sort(sorted_extensions.begin(), sorted_extensions.end(), - ExtensionRangeOrdering()); + ExtensionRangeOrdering()); // Assign has bits: // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing @@ -452,11 +457,13 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { sizeof_has_storage += oneof_generators_.size(); printer->Print( + // clang-format off "\n" "typedef struct $classname$__storage_ {\n" " uint32_t _has_storage_[$sizeof_has_storage$];\n", - "classname", class_name_, - "sizeof_has_storage", absl::StrCat(sizeof_has_storage)); + // clang-format on + "classname", class_name_, "sizeof_has_storage", + absl::StrCat(sizeof_has_storage)); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -467,13 +474,14 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { printer->Print("} $classname$__storage_;\n\n", "classname", class_name_); - + // clang-format off printer->Print( "// This method is threadsafe because it is initially called\n" "// in +initialize for each subclass.\n" "+ (GPBDescriptor *)descriptor {\n" " static GPBDescriptor *descriptor = nil;\n" " if (!descriptor) {\n"); + // clang-format on TextFormatDecodeData text_format_decode_data; bool has_fields = descriptor_->field_count() > 0; @@ -487,23 +495,21 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { if (has_fields) { printer->Indent(); printer->Indent(); - printer->Print( - "static $field_description_type$ fields[] = {\n", - "field_description_type", field_description_type); + printer->Print("static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); ++i) { const FieldGenerator& field_generator = field_generators_.get(sorted_fields[i]); field_generator.GenerateFieldDescription(printer, need_defaults); if (field_generator.needs_textformat_name_support()) { - text_format_decode_data.AddString(sorted_fields[i]->number(), - field_generator.generated_objc_name(), - field_generator.raw_field_name()); + text_format_decode_data.AddString( + sorted_fields[i]->number(), field_generator.generated_objc_name(), + field_generator.raw_field_name()); } } printer->Outdent(); - printer->Print( - "};\n"); + printer->Print("};\n"); printer->Outdent(); printer->Outdent(); } @@ -528,9 +534,10 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); } - vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, - init_flags); + vars["init_flags"] = + BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION, init_flags); + // clang-format off printer->Print( vars, " GPBDescriptor *localDescriptor =\n" @@ -541,55 +548,63 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " fieldCount:$fields_count$\n" " storageSize:sizeof($classname$__storage_)\n" " flags:$init_flags$];\n"); + // clang-format on if (!oneof_generators_.empty()) { - printer->Print( - " static const char *oneofs[] = {\n"); + printer->Print(" static const char *oneofs[] = {\n"); for (const auto& generator : oneof_generators_) { printer->Print(" \"$name$\",\n", "name", generator->DescriptorName()); } printer->Print( + // clang-format off " };\n" " [localDescriptor setupOneofs:oneofs\n" " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n" " firstHasIndex:$first_has_index$];\n", + // clang-format on "first_has_index", oneof_generators_[0]->HasIndexAsString()); } if (text_format_decode_data.num_entries() != 0) { const std::string text_format_data_str(text_format_decode_data.Data()); + // clang-format off printer->Print( "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" " static const char *extraTextFormatInfo ="); + // clang-format on static const int kBytesPerLine = 40; // allow for escaping for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { - printer->Print( - "\n \"$data$\"", - "data", EscapeTrigraphs( - absl::CEscape(text_format_data_str.substr(i, kBytesPerLine)))); + printer->Print("\n \"$data$\"", "data", + EscapeTrigraphs(absl::CEscape( + text_format_data_str.substr(i, kBytesPerLine)))); } + // clang-format off printer->Print( ";\n" " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); + // clang-format on } if (!sorted_extensions.empty()) { - printer->Print( - " static const GPBExtensionRange ranges[] = {\n"); + printer->Print(" static const GPBExtensionRange ranges[] = {\n"); for (int i = 0; i < sorted_extensions.size(); i++) { - printer->Print(" { .start = $start$, .end = $end$ },\n", - "start", absl::StrCat(sorted_extensions[i]->start), - "end", absl::StrCat(sorted_extensions[i]->end)); + printer->Print(" { .start = $start$, .end = $end$ },\n", "start", + absl::StrCat(sorted_extensions[i]->start), "end", + absl::StrCat(sorted_extensions[i]->end)); } + // clang-format off printer->Print( " };\n" " [localDescriptor setupExtensionRanges:ranges\n" " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); + // clang-format on } if (descriptor_->containing_type() != NULL) { std::string containing_class = ClassName(descriptor_->containing_type()); std::string parent_class_ref = ObjCClass(containing_class); printer->Print( + // clang-format off " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n", + // clang-format on "parent_class_ref", parent_class_ref); } std::string suffix_added; @@ -599,6 +614,7 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n", "suffix", suffix_added); } + // clang-format off printer->Print( " #if defined(DEBUG) && DEBUG\n" " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" @@ -608,11 +624,14 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " return descriptor;\n" "}\n\n" "@end\n\n"); + // clang-format on if (!deprecated_attribute_.empty()) { + // clang-format off printer->Print( "#pragma clang diagnostic pop\n" "\n"); + // clang-format on } for (int i = 0; i < descriptor_->field_count(); i++) { diff --git a/src/google/protobuf/compiler/objectivec/message.h b/src/google/protobuf/compiler/objectivec/message.h index 7eb8c2df98..137f35a109 100644 --- a/src/google/protobuf/compiler/objectivec/message.h +++ b/src/google/protobuf/compiler/objectivec/message.h @@ -31,9 +31,10 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ #define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__ -#include #include +#include #include + #include "google/protobuf/compiler/objectivec/field.h" #include "google/protobuf/compiler/objectivec/oneof.h" #include "google/protobuf/descriptor.h" diff --git a/src/google/protobuf/compiler/objectivec/message_field.cc b/src/google/protobuf/compiler/objectivec/message_field.cc index b9dd6c02fb..62e6281547 100644 --- a/src/google/protobuf/compiler/objectivec/message_field.cc +++ b/src/google/protobuf/compiler/objectivec/message_field.cc @@ -28,12 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/message_field.h" + #include #include -#include "google/protobuf/compiler/objectivec/message_field.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" namespace google { @@ -66,15 +67,14 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const { - ObjCObjFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + std::set* fwd_decls, bool include_external_types) const { + ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // Within a file there is no requirement on the order of the messages, so // local references need a forward declaration. External files (not WKTs), // need one when requested. - if ((include_external_types && - !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + if ((include_external_types && !IsProtobufLibraryBundledProtoFile( + descriptor_->message_type()->file())) || descriptor_->file() == descriptor_->message_type()->file()) { // Class name is already in "storage_type". fwd_decls->insert("@class " + variable("storage_type")); @@ -98,15 +98,14 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls, - bool include_external_types) const { - RepeatedFieldGenerator::DetermineForwardDeclarations( - fwd_decls, include_external_types); + std::set* fwd_decls, bool include_external_types) const { + RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls, + include_external_types); // Within a file there is no requirement on the order of the messages, so // local references need a forward declaration. External files (not WKTs), // need one when requested. - if ((include_external_types && - !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + if ((include_external_types && !IsProtobufLibraryBundledProtoFile( + descriptor_->message_type()->file())) || descriptor_->file() == descriptor_->message_type()->file()) { // Class name is already in "storage_type". fwd_decls->insert("@class " + variable("storage_type")); diff --git a/src/google/protobuf/compiler/objectivec/message_field.h b/src/google/protobuf/compiler/objectivec/message_field.h index 7ed1cf24ff..90ff3ab211 100644 --- a/src/google/protobuf/compiler/objectivec/message_field.h +++ b/src/google/protobuf/compiler/objectivec/message_field.h @@ -68,7 +68,8 @@ class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { virtual ~RepeatedMessageFieldGenerator(); RepeatedMessageFieldGenerator(const RepeatedMessageFieldGenerator&) = delete; - RepeatedMessageFieldGenerator operator=(const RepeatedMessageFieldGenerator&) = delete; + RepeatedMessageFieldGenerator operator=( + const RepeatedMessageFieldGenerator&) = delete; public: virtual void DetermineForwardDeclarations( diff --git a/src/google/protobuf/compiler/objectivec/names.cc b/src/google/protobuf/compiler/objectivec/names.cc index 84fb4dd17d..e9cd9a338f 100644 --- a/src/google/protobuf/compiler/objectivec/names.cc +++ b/src/google/protobuf/compiler/objectivec/names.cc @@ -28,6 +28,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "google/protobuf/compiler/objectivec/names.h" + #include #include #include @@ -35,11 +37,10 @@ #include #include -#include "google/protobuf/compiler/code_generator.h" #include "absl/strings/ascii.h" #include "absl/strings/str_split.h" +#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/objectivec/line_consumer.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/nsobject_methods.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/zero_copy_stream_impl.h" @@ -67,7 +68,8 @@ class SimpleLineCollector : public LineConsumer { explicit SimpleLineCollector(std::unordered_set* inout_set) : set_(inout_set) {} - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override { + virtual bool ConsumeLine(const absl::string_view& line, + std::string* out_error) override { set_->insert(std::string(line)); return true; } @@ -78,11 +80,13 @@ class SimpleLineCollector : public LineConsumer { class PackageToPrefixesCollector : public LineConsumer { public: - PackageToPrefixesCollector(const std::string &usage, - std::map* inout_package_to_prefix_map) + PackageToPrefixesCollector( + const std::string& usage, + std::map* inout_package_to_prefix_map) : usage_(usage), prefix_map_(inout_package_to_prefix_map) {} - virtual bool ConsumeLine(const absl::string_view& line, std::string* out_error) override; + virtual bool ConsumeLine(const absl::string_view& line, + std::string* out_error) override; private: const std::string usage_; @@ -93,7 +97,9 @@ class PrefixModeStorage { public: PrefixModeStorage(); - std::string package_to_prefix_mappings_path() const { return package_to_prefix_mappings_path_; } + std::string package_to_prefix_mappings_path() const { + return package_to_prefix_mappings_path_; + } void set_package_to_prefix_mappings_path(const std::string& path) { package_to_prefix_mappings_path_ = path; package_to_prefix_map_.clear(); @@ -115,7 +121,9 @@ class PrefixModeStorage { // When using a proto package as the prefix, this should be added as the // prefix in front of it. const std::string& forced_package_prefix() const { return forced_prefix_; } - void set_forced_package_prefix(const std::string& prefix) { forced_prefix_ = prefix; } + void set_forced_package_prefix(const std::string& prefix) { + forced_prefix_ = prefix; + } private: bool use_package_name_; @@ -132,7 +140,8 @@ PrefixModeStorage::PrefixModeStorage() { use_package_name_ = BoolFromEnvVar("GPB_OBJC_USE_PACKAGE_AS_PREFIX", false); - const char* exception_path = getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH"); + const char* exception_path = + getenv("GPB_OBJC_PACKAGE_PREFIX_EXCEPTIONS_PATH"); if (exception_path) { exception_path_ = exception_path; } @@ -143,21 +152,25 @@ PrefixModeStorage::PrefixModeStorage() { } } -std::string PrefixModeStorage::prefix_from_proto_package_mappings(const FileDescriptor* file) { +std::string PrefixModeStorage::prefix_from_proto_package_mappings( + const FileDescriptor* file) { if (!file) { return ""; } - if (package_to_prefix_map_.empty() && !package_to_prefix_mappings_path_.empty()) { + if (package_to_prefix_map_.empty() && + !package_to_prefix_mappings_path_.empty()) { std::string error_str; - // Re use the same collector as we use for expected_prefixes_path since the file - // format is the same. - PackageToPrefixesCollector collector("Package to prefixes", &package_to_prefix_map_); - if (!ParseSimpleFile(package_to_prefix_mappings_path_, &collector, &error_str)) { + // Re use the same collector as we use for expected_prefixes_path since the + // file format is the same. + PackageToPrefixesCollector collector("Package to prefixes", + &package_to_prefix_map_); + if (!ParseSimpleFile(package_to_prefix_mappings_path_, &collector, + &error_str)) { if (error_str.empty()) { - error_str = std::string("protoc:0: warning: Failed to parse") - + std::string(" prefix to proto package mappings file: ") - + package_to_prefix_mappings_path_; + error_str = std::string("protoc:0: warning: Failed to parse") + + std::string(" prefix to proto package mappings file: ") + + package_to_prefix_mappings_path_; } std::cerr << error_str << std::endl; std::cerr.flush(); @@ -169,7 +182,8 @@ std::string PrefixModeStorage::prefix_from_proto_package_mappings(const FileDesc // For files without packages, the can be registered as "no_package:PATH", // allowing the expected prefixes file. static const std::string no_package_prefix("no_package:"); - const std::string lookup_key = package.empty() ? no_package_prefix + file->name() : package; + const std::string lookup_key = + package.empty() ? no_package_prefix + file->name() : package; std::map::const_iterator prefix_lookup = package_to_prefix_map_.find(lookup_key); @@ -187,9 +201,9 @@ bool PrefixModeStorage::is_package_exempted(const std::string& package) { SimpleLineCollector collector(&exceptions_); if (!ParseSimpleFile(exception_path_, &collector, &error_str)) { if (error_str.empty()) { - error_str = std::string("protoc:0: warning: Failed to parse") - + std::string(" package prefix exceptions file: ") - + exception_path_; + error_str = std::string("protoc:0: warning: Failed to parse") + + std::string(" package prefix exceptions file: ") + + exception_path_; } std::cerr << error_str << std::endl; std::cerr.flush(); @@ -320,8 +334,7 @@ std::string UnderscoresToCamelCase(const std::string& input, } result += value; } - if ((result.length() != 0) && - !first_capitalized && + if ((result.length() != 0) && !first_capitalized && !first_segment_forces_upper) { result[0] = absl::ascii_tolower(result[0]); } @@ -329,72 +342,193 @@ std::string UnderscoresToCamelCase(const std::string& input, } const char* const kReservedWordList[] = { - // Note NSObject Methods: - // These are brought in from nsobject_methods.h that is generated - // using method_dump.sh. See kNSObjectMethods below. - - // Objective C "keywords" that aren't in C - // From - // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c - // with some others added on. - "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway", - "self", "instancetype", "nullable", "nonnull", "nil", "Nil", - "YES", "NO", "weak", - - // C/C++ keywords (Incl C++ 0x11) - // From http://en.cppreference.com/w/cpp/keywords - "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor", - "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", - "compl", "const", "constexpr", "const_cast", "continue", "decltype", - "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit", - "export", "extern ", "false", "float", "for", "friend", "goto", "if", - "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", - "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", - "public", "register", "reinterpret_cast", "return", "short", "signed", - "sizeof", "static", "static_assert", "static_cast", "struct", "switch", - "template", "this", "thread_local", "throw", "true", "try", "typedef", - "typeid", "typename", "union", "unsigned", "using", "virtual", "void", - "volatile", "wchar_t", "while", "xor", "xor_eq", - - // C99 keywords - // From - // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm - "restrict", - - // GCC/Clang extension - "typeof", - - // Not a keyword, but will break you - "NULL", - - // C88+ specs call for these to be macros, so depending on what they are - // defined to be it can lead to odd errors for some Xcode/SDK versions. - "stdin", "stdout", "stderr", - - // Objective-C Runtime typedefs - // From - "Category", "Ivar", "Method", "Protocol", - - // GPBMessage Methods - // Only need to add instance methods that may conflict with - // method declared in protos. The main cases are methods - // that take no arguments, or setFoo:/hasFoo: type methods. - "clear", "data", "delimitedData", "descriptor", "extensionRegistry", - "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize", - "sortedExtensionsInUse", "unknownFields", - - // MacTypes.h names - "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount", - "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount", - "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType", - "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style", - "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord", + // Note NSObject Methods: + // These are brought in from nsobject_methods.h that is generated + // using method_dump.sh. See kNSObjectMethods below. + + // Objective C "keywords" that aren't in C + // From + // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c + // with some others added on. + "id", + "_cmd", + "super", + "in", + "out", + "inout", + "bycopy", + "byref", + "oneway", + "self", + "instancetype", + "nullable", + "nonnull", + "nil", + "Nil", + "YES", + "NO", + "weak", + + // C/C++ keywords (Incl C++ 0x11) + // From http://en.cppreference.com/w/cpp/keywords + "and", + "and_eq", + "alignas", + "alignof", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "const", + "constexpr", + "const_cast", + "continue", + "decltype", + "default", + "delete", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern ", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + + // C99 keywords + // From + // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm + "restrict", + + // GCC/Clang extension + "typeof", + + // Not a keyword, but will break you + "NULL", + + // C88+ specs call for these to be macros, so depending on what they are + // defined to be it can lead to odd errors for some Xcode/SDK versions. + "stdin", + "stdout", + "stderr", + + // Objective-C Runtime typedefs + // From + "Category", + "Ivar", + "Method", + "Protocol", + + // GPBMessage Methods + // Only need to add instance methods that may conflict with + // method declared in protos. The main cases are methods + // that take no arguments, or setFoo:/hasFoo: type methods. + "clear", + "data", + "delimitedData", + "descriptor", + "extensionRegistry", + "extensionsCurrentlySet", + "initialized", + "isInitialized", + "serializedSize", + "sortedExtensionsInUse", + "unknownFields", + + // MacTypes.h names + "Fixed", + "Fract", + "Size", + "LogicalAddress", + "PhysicalAddress", + "ByteCount", + "ByteOffset", + "Duration", + "AbsoluteTime", + "OptionBits", + "ItemCount", + "PBVersion", + "ScriptCode", + "LangCode", + "RegionCode", + "OSType", + "ProcessSerialNumber", + "Point", + "Rect", + "FixedPoint", + "FixedRect", + "Style", + "StyleParameter", + "StyleField", + "TimeScale", + "TimeBase", + "TimeRecord", }; // returns true is input starts with __ or _[A-Z] which are reserved identifiers -// in C/ C++. All calls should go through UnderscoresToCamelCase before getting here -// but this verifies and allows for future expansion if we decide to redefine what a -// reserved C identifier is (for example the GNU list +// in C/ C++. All calls should go through UnderscoresToCamelCase before getting +// here but this verifies and allows for future expansion if we decide to +// redefine what a reserved C identifier is (for example the GNU list // https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html ) bool IsReservedCIdentifier(const std::string& input) { if (input.length() > 2) { @@ -422,7 +556,8 @@ std::string SanitizeNameForObjC(const std::string& prefix, // b) Isn't equivalent to the prefix or // c) Has the prefix, but the letter after the prefix is lowercase if (absl::StartsWith(input, prefix)) { - if (input.length() == prefix.length() || !absl::ascii_isupper(input[prefix.length()])) { + if (input.length() == prefix.length() || + !absl::ascii_isupper(input[prefix.length()])) { sanitized = prefix + input; } else { sanitized = input; @@ -469,8 +604,7 @@ void PathSplit(const std::string& path, std::string* directory, } bool IsSpecialNamePrefix(const std::string& name, - const std::string* special_names, - size_t count) { + const std::string* special_names, size_t count) { for (size_t i = 0; i < count; ++i) { const size_t length = special_names[i].length(); if (name.compare(0, length, special_names[i]) == 0) { @@ -503,8 +637,8 @@ bool IsRetainedName(const std::string& name) { // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html static const std::string retained_names[] = {"new", "alloc", "copy", "mutableCopy"}; - return IsSpecialNamePrefix(name, retained_names, - sizeof(retained_names) / sizeof(retained_names[0])); + return IsSpecialNamePrefix( + name, retained_names, sizeof(retained_names) / sizeof(retained_names[0])); } bool IsInitName(const std::string& name) { @@ -557,8 +691,10 @@ std::string FileClassPrefix(const FileDescriptor* file) { return file->options().objc_class_prefix(); } - // If package prefix is specified in an prefix to proto mappings file then use that. - std::string objc_class_prefix = g_prefix_mode.prefix_from_proto_package_mappings(file); + // If package prefix is specified in an prefix to proto mappings file then use + // that. + std::string objc_class_prefix = + g_prefix_mode.prefix_from_proto_package_mappings(file); if (!objc_class_prefix.empty()) { return objc_class_prefix; } @@ -577,7 +713,8 @@ std::string FileClassPrefix(const FileDescriptor* file) { // camelcase each one and then join them with underscores, and add an // underscore at the end. std::string result; - const std::vector segments = absl::StrSplit(file->package(), ".", absl::SkipEmpty()); + const std::vector segments = + absl::StrSplit(file->package(), ".", absl::SkipEmpty()); for (const auto& segment : segments) { const std::string part = UnderscoresToCamelCase(segment, true); if (part.empty()) { @@ -780,7 +917,8 @@ std::string OneofNameCapitalized(const OneofDescriptor* descriptor) { return result; } -std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field) { +std::string UnCamelCaseFieldName(const std::string& name, + const FieldDescriptor* field) { absl::string_view worker(name); if (absl::EndsWith(worker, "_p")) { worker = absl::StripSuffix(worker, "_p"); @@ -850,15 +988,18 @@ bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) { namespace { -bool PackageToPrefixesCollector::ConsumeLine( - const absl::string_view& line, std::string* out_error) { +bool PackageToPrefixesCollector::ConsumeLine(const absl::string_view& line, + std::string* out_error) { int offset = line.find('='); if (offset == absl::string_view::npos) { - *out_error = usage_ + " file line without equal sign: '" + absl::StrCat(line) + "'."; + *out_error = + usage_ + " file line without equal sign: '" + absl::StrCat(line) + "'."; return false; } - absl::string_view package = absl::StripAsciiWhitespace(line.substr(0, offset)); - absl::string_view prefix = absl::StripAsciiWhitespace(line.substr(offset + 1)); + absl::string_view package = + absl::StripAsciiWhitespace(line.substr(0, offset)); + absl::string_view prefix = + absl::StripAsciiWhitespace(line.substr(offset + 1)); MaybeUnQuote(&prefix); // Don't really worry about error checking the package/prefix for // being valid. Assume the file is validated when it is created/edited. @@ -874,8 +1015,7 @@ bool LoadExpectedPackagePrefixes(const std::string& expected_prefixes_path, } PackageToPrefixesCollector collector("Expected prefixes", prefix_map); - return ParseSimpleFile( - expected_prefixes_path, &collector, out_error); + return ParseSimpleFile(expected_prefixes_path, &collector, out_error); } bool ValidateObjCClassPrefix( @@ -929,9 +1069,9 @@ bool ValidateObjCClassPrefix( // If there was no prefix option, we're done at this point. if (!has_prefix) { if (require_prefixes) { - *out_error = - "error: '" + file->name() + "' does not have a required 'option" + - " objc_class_prefix'."; + *out_error = "error: '" + file->name() + + "' does not have a required 'option" + + " objc_class_prefix'."; return false; } return true; @@ -958,9 +1098,9 @@ bool ValidateObjCClassPrefix( // package (overlap is allowed, but it has to be listed as an expected // overlap). if (!other_package_for_prefix.empty()) { - *out_error = - "error: Found 'option objc_class_prefix = \"" + prefix + - "\";' in '" + file->name() + "'; that prefix is already used for "; + *out_error = "error: Found 'option objc_class_prefix = \"" + prefix + + "\";' in '" + file->name() + + "'; that prefix is already used for "; if (absl::StartsWith(other_package_for_prefix, no_package_prefix)) { absl::StrAppend( out_error, "file '", @@ -976,26 +1116,24 @@ bool ValidateObjCClassPrefix( expected_prefixes_path, ")."); return false; // Only report first usage of the prefix. } - } // !prefix.empty() && have_expected_prefix_file + } // !prefix.empty() && have_expected_prefix_file // Check: Warning - Make sure the prefix is is a reasonable value according // to Apple's rules (the checks above implicitly whitelist anything that // doesn't meet these rules). if (!prefix.empty() && !absl::ascii_isupper(prefix[0])) { - std::cerr - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " it should start with a capital letter." << std::endl; + std::cerr << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " it should start with a capital letter." << std::endl; std::cerr.flush(); } if (!prefix.empty() && prefix.length() < 3) { // Apple reserves 2 character prefixes for themselves. They do use some // 3 character prefixes, but they haven't updated the rules/docs. - std::cerr - << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "';" - << " Apple recommends they should be at least 3 characters long." - << std::endl; + std::cerr << "protoc:0: warning: Invalid 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "';" + << " Apple recommends they should be at least 3 characters long." + << std::endl; std::cerr.flush(); } @@ -1004,19 +1142,19 @@ bool ValidateObjCClassPrefix( if (have_expected_prefix_file) { if (prefixes_must_be_registered) { *out_error = - "error: '" + file->name() + "' has 'option objc_class_prefix = \"" + - prefix + "\";', but it is not registered. Add '" + lookup_key + " = " + - (prefix.empty() ? "\"\"" : prefix) + - "' to the expected prefixes file (" + expected_prefixes_path + ")."; + "error: '" + file->name() + "' has 'option objc_class_prefix = \"" + + prefix + "\";', but it is not registered. Add '" + lookup_key + + " = " + (prefix.empty() ? "\"\"" : prefix) + + "' to the expected prefixes file (" + expected_prefixes_path + ")."; return false; } std::cerr - << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" - << prefix << "\";' in '" << file->name() << "'; consider adding '" - << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix) - << "' to the expected prefixes file (" << expected_prefixes_path - << ")." << std::endl; + << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \"" + << prefix << "\";' in '" << file->name() << "'; consider adding '" + << lookup_key << " = " << (prefix.empty() ? "\"\"" : prefix) + << "' to the expected prefixes file (" << expected_prefixes_path << ")." + << std::endl; std::cerr.flush(); } @@ -1033,7 +1171,8 @@ Options::Options() { if (file_path) { expected_prefixes_path = file_path; } - const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); + const char* suppressions = + getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS"); if (suppressions) { expected_prefixes_suppressions = absl::StrSplit(suppressions, ";", absl::SkipEmpty()); @@ -1045,9 +1184,9 @@ Options::Options() { bool ValidateObjCClassPrefixes(const std::vector& files, std::string* out_error) { - // Options's ctor load from the environment. - Options options; - return ValidateObjCClassPrefixes(files, options, out_error); + // Options's ctor load from the environment. + Options options; + return ValidateObjCClassPrefixes(files, options, out_error); } bool ValidateObjCClassPrefixes(const std::vector& files, @@ -1062,28 +1201,25 @@ bool ValidateObjCClassPrefixes(const std::vector& files, // Load the expected package prefixes, if available, to validate against. std::map expected_package_prefixes; if (!LoadExpectedPackagePrefixes(generation_options.expected_prefixes_path, - &expected_package_prefixes, - out_error)) { + &expected_package_prefixes, out_error)) { return false; } for (int i = 0; i < files.size(); i++) { bool should_skip = - (std::find(generation_options.expected_prefixes_suppressions.begin(), - generation_options.expected_prefixes_suppressions.end(), - files[i]->name()) - != generation_options.expected_prefixes_suppressions.end()); + (std::find(generation_options.expected_prefixes_suppressions.begin(), + generation_options.expected_prefixes_suppressions.end(), + files[i]->name()) != + generation_options.expected_prefixes_suppressions.end()); if (should_skip) { continue; } - bool is_valid = - ValidateObjCClassPrefix(files[i], - generation_options.expected_prefixes_path, - expected_package_prefixes, - generation_options.prefixes_must_be_registered, - generation_options.require_prefixes, - out_error); + bool is_valid = ValidateObjCClassPrefix( + files[i], generation_options.expected_prefixes_path, + expected_package_prefixes, + generation_options.prefixes_must_be_registered, + generation_options.require_prefixes, out_error); if (!is_valid) { return false; } diff --git a/src/google/protobuf/compiler/objectivec/names.h b/src/google/protobuf/compiler/objectivec/names.h index e1b703c7bc..f1c67d081e 100644 --- a/src/google/protobuf/compiler/objectivec/names.h +++ b/src/google/protobuf/compiler/objectivec/names.h @@ -49,8 +49,7 @@ namespace objectivec { // Get/Set the path to a file to load for objc class prefix lookups. std::string PROTOC_EXPORT GetPackageToPrefixMappingsPath(); -void PROTOC_EXPORT SetPackageToPrefixMappingsPath( - const std::string& file_path); +void PROTOC_EXPORT SetPackageToPrefixMappingsPath(const std::string& file_path); // Get/Set if the proto package should be used to make the default prefix for // symbols. This will then impact most of the type naming apis below. It is done // as a global to not break any other generator reusing the methods since they @@ -61,8 +60,8 @@ void PROTOC_EXPORT SetUseProtoPackageAsDefaultPrefix(bool on_or_off); // `UseProtoPackageAsDefaultPrefix()` is `true`. An empty string means there // should be no exceptions. std::string PROTOC_EXPORT GetProtoPackagePrefixExceptionList(); -void PROTOC_EXPORT SetProtoPackagePrefixExceptionList( - const std::string& file_path); +void PROTOC_EXPORT +SetProtoPackagePrefixExceptionList(const std::string& file_path); // Get/Set a prefix to add before the prefix generated from the package name. // This is only used when UseProtoPackageAsDefaultPrefix() is True. std::string PROTOC_EXPORT GetForcedPackagePrefix(); @@ -108,14 +107,16 @@ std::string PROTOC_EXPORT EnumName(const EnumDescriptor* descriptor); std::string PROTOC_EXPORT EnumValueName(const EnumValueDescriptor* descriptor); // Returns the name of the enum value corresponding to the descriptor. -std::string PROTOC_EXPORT EnumValueShortName(const EnumValueDescriptor* descriptor); +std::string PROTOC_EXPORT +EnumValueShortName(const EnumValueDescriptor* descriptor); // Reverse what an enum does. std::string PROTOC_EXPORT UnCamelCaseEnumShortName(const std::string& name); // Returns the name to use for the extension (used as the method off the file's // Root class). -std::string PROTOC_EXPORT ExtensionMethodName(const FieldDescriptor* descriptor); +std::string PROTOC_EXPORT +ExtensionMethodName(const FieldDescriptor* descriptor); // Returns the transformed field name. std::string PROTOC_EXPORT FieldName(const FieldDescriptor* field); @@ -124,7 +125,8 @@ std::string PROTOC_EXPORT FieldNameCapitalized(const FieldDescriptor* field); // Returns the transformed oneof name. std::string PROTOC_EXPORT OneofEnumName(const OneofDescriptor* descriptor); std::string PROTOC_EXPORT OneofName(const OneofDescriptor* descriptor); -std::string PROTOC_EXPORT OneofNameCapitalized(const OneofDescriptor* descriptor); +std::string PROTOC_EXPORT +OneofNameCapitalized(const OneofDescriptor* descriptor); // Reverse of the above. std::string PROTOC_EXPORT UnCamelCaseFieldName(const std::string& name, diff --git a/src/google/protobuf/compiler/objectivec/names_unittest.cc b/src/google/protobuf/compiler/objectivec/names_unittest.cc index 0aac79497c..8063049913 100644 --- a/src/google/protobuf/compiler/objectivec/names_unittest.cc +++ b/src/google/protobuf/compiler/objectivec/names_unittest.cc @@ -29,10 +29,11 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "google/protobuf/compiler/objectivec/names.h" -#include "google/protobuf/io/zero_copy_stream_impl_lite.h" #include +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" + namespace google { namespace protobuf { namespace compiler { diff --git a/src/google/protobuf/compiler/objectivec/nsobject_methods.h b/src/google/protobuf/compiler/objectivec/nsobject_methods.h index 9c451b19a8..7a1b9ef2cd 100644 --- a/src/google/protobuf/compiler/objectivec/nsobject_methods.h +++ b/src/google/protobuf/compiler/objectivec/nsobject_methods.h @@ -35,193 +35,193 @@ // iOS: iPhoneSimulator12.1.sdk const char* const kNSObjectMethodsList[] = { - "CAMLType", - "CA_copyRenderValue", - "CA_prepareRenderValue", - "NS_copyCGImage", - "NS_tiledLayerVisibleRect", - "___tryRetain_OA", - "__autorelease_OA", - "__dealloc_zombie", - "__release_OA", - "__retain_OA", - "_accessibilityFinalize", - "_accessibilityIsTableViewDescendant", - "_accessibilityUIElementSpecifier", - "_accessibilityUseConvenienceAPI", - "_allowsDirectEncoding", - "_asScriptTerminologyNameArray", - "_asScriptTerminologyNameString", - "_bindingAdaptor", - "_cfTypeID", - "_copyDescription", - "_destroyObserverList", - "_didEndKeyValueObserving", - "_implicitObservationInfo", - "_internalAccessibilityAttributedHint", - "_internalAccessibilityAttributedLabel", - "_internalAccessibilityAttributedValue", - "_isAXConnector", - "_isAccessibilityContainerSectionCandidate", - "_isAccessibilityContentNavigatorSectionCandidate", - "_isAccessibilityContentSectionCandidate", - "_isAccessibilityTopLevelNavigatorSectionCandidate", - "_isDeallocating", - "_isKVOA", - "_isToManyChangeInformation", - "_ivarDescription", - "_localClassNameForClass", - "_methodDescription", - "_observerStorage", - "_overrideUseFastBlockObservers", - "_propertyDescription", - "_releaseBindingAdaptor", - "_scriptingCount", - "_scriptingCountNonrecursively", - "_scriptingDebugDescription", - "_scriptingExists", - "_scriptingShouldCheckObjectIndexes", - "_shortMethodDescription", - "_shouldSearchChildrenForSection", - "_traitStorageList", - "_tryRetain", - "_ui_descriptionBuilder", - "_uikit_variesByTraitCollections", - "_web_description", - "_webkit_invokeOnMainThread", - "_willBeginKeyValueObserving", - "accessibilityActivate", - "accessibilityActivationPoint", - "accessibilityAllowsOverriddenAttributesWhenIgnored", - "accessibilityAssistiveTechnologyFocusedIdentifiers", - "accessibilityAttributedHint", - "accessibilityAttributedLabel", - "accessibilityAttributedValue", - "accessibilityContainer", - "accessibilityContainerType", - "accessibilityCustomActions", - "accessibilityCustomRotors", - "accessibilityDecrement", - "accessibilityDragSourceDescriptors", - "accessibilityDropPointDescriptors", - "accessibilityElementCount", - "accessibilityElementDidBecomeFocused", - "accessibilityElementDidLoseFocus", - "accessibilityElementIsFocused", - "accessibilityElements", - "accessibilityElementsHidden", - "accessibilityFrame", - "accessibilityHeaderElements", - "accessibilityHint", - "accessibilityIdentification", - "accessibilityIdentifier", - "accessibilityIncrement", - "accessibilityLabel", - "accessibilityLanguage", - "accessibilityLocalizedStringKey", - "accessibilityNavigationStyle", - "accessibilityOverriddenAttributes", - "accessibilityParameterizedAttributeNames", - "accessibilityPath", - "accessibilityPerformEscape", - "accessibilityPerformMagicTap", - "accessibilityPresenterProcessIdentifier", - "accessibilityShouldUseUniqueId", - "accessibilitySupportsNotifications", - "accessibilitySupportsOverriddenAttributes", - "accessibilityTemporaryChildren", - "accessibilityTraits", - "accessibilityValue", - "accessibilityViewIsModal", - "accessibilityVisibleArea", - "allPropertyKeys", - "allowsWeakReference", - "attributeKeys", - "autoContentAccessingProxy", - "autorelease", - "awakeFromNib", - "boolValueSafe", - "bs_encoded", - "bs_isPlistableType", - "bs_secureEncoded", - "cl_json_serializeKey", - "class", - "classCode", - "classDescription", - "classForArchiver", - "classForCoder", - "classForKeyedArchiver", - "classForPortCoder", - "className", - "clearProperties", - "copy", - "dealloc", - "debugDescription", - "defaultAccessibilityTraits", - "description", - "doubleValueSafe", - "entityName", - "exposedBindings", - "finalize", - "finishObserving", - "flushKeyBindings", - "hash", - "init", - "int64ValueSafe", - "isAccessibilityElement", - "isAccessibilityElementByDefault", - "isElementAccessibilityExposedToInterfaceBuilder", - "isFault", - "isNSArray__", - "isNSCFConstantString__", - "isNSData__", - "isNSDate__", - "isNSDictionary__", - "isNSNumber__", - "isNSObject__", - "isNSOrderedSet__", - "isNSSet__", - "isNSString__", - "isNSTimeZone__", - "isNSValue__", - "isProxy", - "mutableCopy", - "nilValueForKey", - "objectSpecifier", - "observationInfo", - "pep_onDetachedThread", - "pep_onMainThread", - "pep_onMainThreadIfNecessary", - "prepareForInterfaceBuilder", - "release", - "releaseOnMainThread", - "retain", - "retainCount", - "retainWeakReference", - "scriptingProperties", - "self", - "shouldGroupAccessibilityChildren", - "storedAccessibilityActivationPoint", - "storedAccessibilityContainerType", - "storedAccessibilityElementsHidden", - "storedAccessibilityFrame", - "storedAccessibilityNavigationStyle", - "storedAccessibilityTraits", - "storedAccessibilityViewIsModal", - "storedIsAccessibilityElement", - "storedShouldGroupAccessibilityChildren", - "stringValueSafe", - "superclass", - "toManyRelationshipKeys", - "toOneRelationshipKeys", - "traitStorageList", - "un_safeBoolValue", - "userInterfaceItemIdentifier", - "utf8ValueSafe", - "valuesForKeysWithDictionary", - "zone", -// Protocol: CAAnimatableValue -// Protocol: CARenderValue -// Protocol: NSObject -// Protocol: ROCKRemoteInvocationInterface + "CAMLType", + "CA_copyRenderValue", + "CA_prepareRenderValue", + "NS_copyCGImage", + "NS_tiledLayerVisibleRect", + "___tryRetain_OA", + "__autorelease_OA", + "__dealloc_zombie", + "__release_OA", + "__retain_OA", + "_accessibilityFinalize", + "_accessibilityIsTableViewDescendant", + "_accessibilityUIElementSpecifier", + "_accessibilityUseConvenienceAPI", + "_allowsDirectEncoding", + "_asScriptTerminologyNameArray", + "_asScriptTerminologyNameString", + "_bindingAdaptor", + "_cfTypeID", + "_copyDescription", + "_destroyObserverList", + "_didEndKeyValueObserving", + "_implicitObservationInfo", + "_internalAccessibilityAttributedHint", + "_internalAccessibilityAttributedLabel", + "_internalAccessibilityAttributedValue", + "_isAXConnector", + "_isAccessibilityContainerSectionCandidate", + "_isAccessibilityContentNavigatorSectionCandidate", + "_isAccessibilityContentSectionCandidate", + "_isAccessibilityTopLevelNavigatorSectionCandidate", + "_isDeallocating", + "_isKVOA", + "_isToManyChangeInformation", + "_ivarDescription", + "_localClassNameForClass", + "_methodDescription", + "_observerStorage", + "_overrideUseFastBlockObservers", + "_propertyDescription", + "_releaseBindingAdaptor", + "_scriptingCount", + "_scriptingCountNonrecursively", + "_scriptingDebugDescription", + "_scriptingExists", + "_scriptingShouldCheckObjectIndexes", + "_shortMethodDescription", + "_shouldSearchChildrenForSection", + "_traitStorageList", + "_tryRetain", + "_ui_descriptionBuilder", + "_uikit_variesByTraitCollections", + "_web_description", + "_webkit_invokeOnMainThread", + "_willBeginKeyValueObserving", + "accessibilityActivate", + "accessibilityActivationPoint", + "accessibilityAllowsOverriddenAttributesWhenIgnored", + "accessibilityAssistiveTechnologyFocusedIdentifiers", + "accessibilityAttributedHint", + "accessibilityAttributedLabel", + "accessibilityAttributedValue", + "accessibilityContainer", + "accessibilityContainerType", + "accessibilityCustomActions", + "accessibilityCustomRotors", + "accessibilityDecrement", + "accessibilityDragSourceDescriptors", + "accessibilityDropPointDescriptors", + "accessibilityElementCount", + "accessibilityElementDidBecomeFocused", + "accessibilityElementDidLoseFocus", + "accessibilityElementIsFocused", + "accessibilityElements", + "accessibilityElementsHidden", + "accessibilityFrame", + "accessibilityHeaderElements", + "accessibilityHint", + "accessibilityIdentification", + "accessibilityIdentifier", + "accessibilityIncrement", + "accessibilityLabel", + "accessibilityLanguage", + "accessibilityLocalizedStringKey", + "accessibilityNavigationStyle", + "accessibilityOverriddenAttributes", + "accessibilityParameterizedAttributeNames", + "accessibilityPath", + "accessibilityPerformEscape", + "accessibilityPerformMagicTap", + "accessibilityPresenterProcessIdentifier", + "accessibilityShouldUseUniqueId", + "accessibilitySupportsNotifications", + "accessibilitySupportsOverriddenAttributes", + "accessibilityTemporaryChildren", + "accessibilityTraits", + "accessibilityValue", + "accessibilityViewIsModal", + "accessibilityVisibleArea", + "allPropertyKeys", + "allowsWeakReference", + "attributeKeys", + "autoContentAccessingProxy", + "autorelease", + "awakeFromNib", + "boolValueSafe", + "bs_encoded", + "bs_isPlistableType", + "bs_secureEncoded", + "cl_json_serializeKey", + "class", + "classCode", + "classDescription", + "classForArchiver", + "classForCoder", + "classForKeyedArchiver", + "classForPortCoder", + "className", + "clearProperties", + "copy", + "dealloc", + "debugDescription", + "defaultAccessibilityTraits", + "description", + "doubleValueSafe", + "entityName", + "exposedBindings", + "finalize", + "finishObserving", + "flushKeyBindings", + "hash", + "init", + "int64ValueSafe", + "isAccessibilityElement", + "isAccessibilityElementByDefault", + "isElementAccessibilityExposedToInterfaceBuilder", + "isFault", + "isNSArray__", + "isNSCFConstantString__", + "isNSData__", + "isNSDate__", + "isNSDictionary__", + "isNSNumber__", + "isNSObject__", + "isNSOrderedSet__", + "isNSSet__", + "isNSString__", + "isNSTimeZone__", + "isNSValue__", + "isProxy", + "mutableCopy", + "nilValueForKey", + "objectSpecifier", + "observationInfo", + "pep_onDetachedThread", + "pep_onMainThread", + "pep_onMainThreadIfNecessary", + "prepareForInterfaceBuilder", + "release", + "releaseOnMainThread", + "retain", + "retainCount", + "retainWeakReference", + "scriptingProperties", + "self", + "shouldGroupAccessibilityChildren", + "storedAccessibilityActivationPoint", + "storedAccessibilityContainerType", + "storedAccessibilityElementsHidden", + "storedAccessibilityFrame", + "storedAccessibilityNavigationStyle", + "storedAccessibilityTraits", + "storedAccessibilityViewIsModal", + "storedIsAccessibilityElement", + "storedShouldGroupAccessibilityChildren", + "stringValueSafe", + "superclass", + "toManyRelationshipKeys", + "toOneRelationshipKeys", + "traitStorageList", + "un_safeBoolValue", + "userInterfaceItemIdentifier", + "utf8ValueSafe", + "valuesForKeysWithDictionary", + "zone", + // Protocol: CAAnimatableValue + // Protocol: CARenderValue + // Protocol: NSObject + // Protocol: ROCKRemoteInvocationInterface }; diff --git a/src/google/protobuf/compiler/objectivec/oneof.cc b/src/google/protobuf/compiler/objectivec/oneof.cc index db4922f2d5..6fd934a83e 100644 --- a/src/google/protobuf/compiler/objectivec/oneof.cc +++ b/src/google/protobuf/compiler/objectivec/oneof.cc @@ -34,8 +34,8 @@ #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" namespace google { @@ -71,54 +71,53 @@ void OneofGenerator::SetOneofIndexBase(int index_base) { } void OneofGenerator::GenerateCaseEnum(io::Printer* printer) { - printer->Print( - variables_, - "typedef GPB_ENUM($enum_name$) {\n"); + printer->Print(variables_, "typedef GPB_ENUM($enum_name$) {\n"); printer->Indent(); - printer->Print( - variables_, - "$enum_name$_GPBUnsetOneOfCase = 0,\n"); + printer->Print(variables_, "$enum_name$_GPBUnsetOneOfCase = 0,\n"); std::string enum_name = variables_["enum_name"]; for (int j = 0; j < descriptor_->field_count(); j++) { const FieldDescriptor* field = descriptor_->field(j); std::string field_name = FieldNameCapitalized(field); - printer->Print( - "$enum_name$_$field_name$ = $field_number$,\n", - "enum_name", enum_name, - "field_name", field_name, - "field_number", absl::StrCat(field->number())); + printer->Print("$enum_name$_$field_name$ = $field_number$,\n", "enum_name", + enum_name, "field_name", field_name, "field_number", + absl::StrCat(field->number())); } printer->Outdent(); + // clang-format off printer->Print( "};\n" "\n"); + // clang-format on } void OneofGenerator::GeneratePublicCasePropertyDeclaration( io::Printer* printer) { + // clang-format off printer->Print( variables_, "$comments$" "@property(nonatomic, readonly) $enum_name$ $name$OneOfCase;\n" "\n"); + // clang-format on } void OneofGenerator::GenerateClearFunctionDeclaration(io::Printer* printer) { + // clang-format off printer->Print( variables_, "/**\n" " * Clears whatever value was set for the oneof '$name$'.\n" " **/\n" "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message);\n"); + // clang-format on } void OneofGenerator::GeneratePropertyImplementation(io::Printer* printer) { - printer->Print( - variables_, - "@dynamic $name$OneOfCase;\n"); + printer->Print(variables_, "@dynamic $name$OneOfCase;\n"); } void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { + // clang-format off printer->Print( variables_, "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" @@ -126,6 +125,7 @@ void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { " GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:$raw_index$];\n" " GPBClearOneof(message, oneof);\n" "}\n"); + // clang-format on } std::string OneofGenerator::DescriptorName(void) const { diff --git a/src/google/protobuf/compiler/objectivec/primitive_field.cc b/src/google/protobuf/compiler/objectivec/primitive_field.cc index 739d1ce334..b6a44d2dea 100644 --- a/src/google/protobuf/compiler/objectivec/primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/primitive_field.cc @@ -34,8 +34,8 @@ #include #include "absl/strings/str_cat.h" -#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/helpers.h" +#include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/printer.h" namespace google { diff --git a/src/google/protobuf/compiler/objectivec/primitive_field.h b/src/google/protobuf/compiler/objectivec/primitive_field.h index 904cd65b4a..5d509d23b1 100644 --- a/src/google/protobuf/compiler/objectivec/primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/primitive_field.h @@ -48,7 +48,8 @@ class PrimitiveFieldGenerator : public SingleFieldGenerator { PrimitiveFieldGenerator(const PrimitiveFieldGenerator&) = delete; PrimitiveFieldGenerator& operator=(const PrimitiveFieldGenerator&) = delete; - virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const override; + virtual void GenerateFieldStorageDeclaration( + io::Printer* printer) const override; virtual int ExtraRuntimeHasBitsNeeded(void) const override; virtual void SetExtraRuntimeHasBitsBase(int index_base) override; diff --git a/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc b/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc index 9e5ef76af9..3bc4eef527 100644 --- a/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data.cc @@ -28,12 +28,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" + #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" -#include "absl/strings/str_split.h" #include "absl/strings/str_replace.h" -#include "google/protobuf/compiler/objectivec/text_format_decode_data.h" +#include "absl/strings/str_split.h" +#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/printer.h" @@ -166,9 +167,9 @@ std::string DirectDecodeString(const std::string& str) { } // namespace -TextFormatDecodeData::TextFormatDecodeData() { } +TextFormatDecodeData::TextFormatDecodeData() {} -TextFormatDecodeData::~TextFormatDecodeData() { } +TextFormatDecodeData::~TextFormatDecodeData() {} void TextFormatDecodeData::AddString(int32_t key, const std::string& input_for_decode, @@ -177,8 +178,8 @@ void TextFormatDecodeData::AddString(int32_t key, i != entries_.end(); ++i) { if (i->first == key) { std::cerr << "error: duplicate key (" << key - << ") making TextFormat data, input: \"" << input_for_decode - << "\", desired: \"" << desired_output << "\"." << std::endl; + << ") making TextFormat data, input: \"" << input_for_decode + << "\", desired: \"" << desired_output << "\"." << std::endl; std::cerr.flush(); abort(); } @@ -213,16 +214,17 @@ std::string TextFormatDecodeData::DecodeDataForString( const std::string& input_for_decode, const std::string& desired_output) { if (input_for_decode.empty() || desired_output.empty()) { std::cerr << "error: got empty string for making TextFormat data, input: \"" - << input_for_decode << "\", desired: \"" << desired_output << "\"." - << std::endl; + << input_for_decode << "\", desired: \"" << desired_output + << "\"." << std::endl; std::cerr.flush(); abort(); } if ((input_for_decode.find('\0') != std::string::npos) || (desired_output.find('\0') != std::string::npos)) { - std::cerr << "error: got a null char in a string for making TextFormat data," - << " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \"" - << absl::CEscape(desired_output) << "\"." << std::endl; + std::cerr + << "error: got a null char in a string for making TextFormat data," + << " input: \"" << absl::CEscape(input_for_decode) << "\", desired: \"" + << absl::CEscape(desired_output) << "\"." << std::endl; std::cerr.flush(); abort(); } @@ -259,7 +261,6 @@ std::string TextFormatDecodeData::DecodeDataForString( return builder.Finish() + (char)'\0'; } - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/text_format_decode_data.h b/src/google/protobuf/compiler/objectivec/text_format_decode_data.h index e7b63f65ff..280d65a190 100644 --- a/src/google/protobuf/compiler/objectivec/text_format_decode_data.h +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data.h @@ -68,7 +68,6 @@ class PROTOC_EXPORT TextFormatDecodeData { std::vector entries_; }; - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc b/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc index ad1308ad9d..6cec537d4b 100644 --- a/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc +++ b/src/google/protobuf/compiler/objectivec/text_format_decode_data_unittest.cc @@ -212,7 +212,6 @@ TEST(ObjCHelper, TextFormatDecodeData_ByteCodes) { EXPECT_EQ(expected, decode_data.Data()); } - // Death tests do not work on Windows as of yet. #ifdef PROTOBUF_HAS_DEATH_TEST TEST(ObjCHelperDeathTest, TextFormatDecodeData_Failures) { diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto index 0f46a45485..b233bcebbb 100644 --- a/src/google/protobuf/compiler/plugin.proto +++ b/src/google/protobuf/compiler/plugin.proto @@ -89,7 +89,6 @@ message CodeGeneratorRequest { // The version number of protocol compiler. optional Version compiler_version = 3; - } // The plugin writes an encoded CodeGeneratorResponse to stdout. diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index bb31797a68..a46cf5ea44 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + #ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_PYTHON_GENERATOR_H_ #define GOOGLE_PROTOBUF_COMPILER_PYTHON_PYTHON_GENERATOR_H_ diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index f264b13abd..0636a87ab1 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -36,7 +36,6 @@ // A valid .proto file can be translated directly to a FileDescriptorProto // without any other information (e.g. without reading its imports). - syntax = "proto2"; package google.protobuf; @@ -134,7 +133,6 @@ message ExtensionRangeOptions { // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; - // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; } @@ -310,7 +308,6 @@ message MethodDescriptorProto { optional bool server_streaming = 6 [default = false]; } - // =================================================================== // Options @@ -351,7 +348,6 @@ message FileOptions { // domain names. optional string java_package = 1; - // Controls the name of the wrapper Java class generated for the .proto file. // That class will always contain the .proto file's getDescriptor() method as // well as any top-level extensions defined in the .proto file. @@ -378,7 +374,6 @@ message FileOptions { // This option has no effect on when used with the lite runtime. optional bool java_string_check_utf8 = 27 [default = false]; - // Generated classes can be optimized for speed or code size. enum OptimizeMode { SPEED = 1; // Generate complete code for parsing, serialization, @@ -395,9 +390,6 @@ message FileOptions { // - Otherwise, the basename of the .proto file, without extension. optional string go_package = 11; - - - // Should generic services be generated in each language? "Generic" services // are not specific to any particular RPC system. They are generated by the // main code generators in each language (without additional plugins). @@ -423,7 +415,6 @@ message FileOptions { // only to generated classes for C++. optional bool cc_enable_arenas = 31 [default = true]; - // Sets the objective c class prefix which is prepended to all objective c // generated classes from this .proto. There is no default. optional string objc_class_prefix = 36; @@ -456,7 +447,6 @@ message FileOptions { // determining the ruby package. optional string ruby_package = 45; - // The parser stores options it doesn't recognize here. // See the documentation for the "Options" section above. repeated UninterpretedOption uninterpreted_option = 999; @@ -528,7 +518,6 @@ message MessageOptions { reserved 8; // javalite_serializable reserved 9; // javanano_as_lite - // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -597,7 +586,6 @@ message FieldOptions { // call from multiple threads concurrently, while non-const methods continue // to require exclusive access. // - // // Note that implementations may choose not to check required fields within // a lazy sub-message. That is, calling IsInitialized() on the outer message // may return true even if the inner message has missing required fields. @@ -627,7 +615,6 @@ message FieldOptions { // For Google-internal migration only. Do not use. optional bool weak = 10 [default = false]; - // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -731,7 +718,6 @@ message MethodOptions { extensions 1000 to max; } - // A message representing a option the parser does not recognize. This only // appears in options protos created by the compiler::Parser class. // DescriptorPool resolves these when building Descriptor objects. Therefore, diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc index c024a7778c..5e0d6c33b4 100644 --- a/src/google/protobuf/descriptor_database.cc +++ b/src/google/protobuf/descriptor_database.cc @@ -42,7 +42,6 @@ #include "absl/strings/match.h" #include "absl/strings/str_replace.h" #include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/stubs/stl_util.h" namespace google { diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 81c3e369fd..a0d91df016 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -99,7 +99,6 @@ option objc_class_prefix = "GPB"; // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 // microsecond should be expressed in JSON format as "3.000001s". // -// message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 8ef2d2b9a4..5d07a9857d 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -53,7 +53,6 @@ #include "absl/strings/match.h" #include "google/protobuf/test_util.h" #include "google/protobuf/test_util2.h" -#include "google/protobuf/stubs/stl_util.h" #include "google/protobuf/stubs/strutil.h" @@ -552,7 +551,7 @@ TEST(ExtensionSetTest, SerializationToArray) { size_t size = source.ByteSizeLong(); std::string data; data.resize(size); - uint8_t* target = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* target = reinterpret_cast(&data[0]); uint8_t* end = source.SerializeWithCachedSizesToArray(target); EXPECT_EQ(size, end - target); EXPECT_TRUE(destination.ParseFromString(data)); @@ -574,7 +573,7 @@ TEST(ExtensionSetTest, SerializationToStream) { std::string data; data.resize(size); { - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); source.SerializeWithCachedSizes(&output_stream); ASSERT_FALSE(output_stream.HadError()); @@ -596,7 +595,7 @@ TEST(ExtensionSetTest, PackedSerializationToArray) { size_t size = source.ByteSizeLong(); std::string data; data.resize(size); - uint8_t* target = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* target = reinterpret_cast(&data[0]); uint8_t* end = source.SerializeWithCachedSizesToArray(target); EXPECT_EQ(size, end - target); EXPECT_TRUE(destination.ParseFromString(data)); @@ -618,7 +617,7 @@ TEST(ExtensionSetTest, PackedSerializationToStream) { std::string data; data.resize(size); { - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); source.SerializeWithCachedSizes(&output_stream); ASSERT_FALSE(output_stream.HadError()); diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index bacb9b845a..5008b82d0d 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -3095,7 +3095,7 @@ const internal::TcParseTableBase* Reflection::CreateTcParseTableForMessageSet() // Create a dummy table that only exists to make TcParser::ParseLoop jump // into the reflective parse loop. - using Table = internal::TcParseTable<0, 0, 0, 1, 1>; + using Table = internal::TcParseTable<0, 0, 0, 0, 1>; // We use `operator new` here because the destruction will be done with // `operator delete` unconditionally. void* p = ::operator new(sizeof(Table)); diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h index 58bf2777e6..dd4845ba88 100644 --- a/src/google/protobuf/generated_message_tctable_decl.h +++ b/src/google/protobuf/generated_message_tctable_decl.h @@ -347,7 +347,7 @@ struct TcParseTable { // Entries for all fields: std::array field_entries; std::array aux_entries; - std::array field_names; + std::array field_names; }; // Partial specialization: if there are no aux entries, there will be no array. @@ -363,7 +363,7 @@ struct TcParseTable field_lookup_table; std::array field_entries; - std::array field_names; + std::array field_names; }; // Partial specialization: if there are no fields at all, then we can save space @@ -375,7 +375,7 @@ struct TcParseTable<0, 0, 0, kNameTableSize, kFieldLookupSize> { // The fast parsing loop will always use this entry, so it must be present. std::array fast_entries; std::array field_lookup_table; - std::array field_names; + std::array field_names; }; static_assert(std::is_standard_layout>::value, diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc index 418918077f..e31d19116a 100644 --- a/src/google/protobuf/generated_message_tctable_gen.cc +++ b/src/google/protobuf/generated_message_tctable_gen.cc @@ -420,10 +420,9 @@ absl::string_view FieldNameForTable( case field_layout::kTvUtf8: case field_layout::kTvUtf8Debug: return field->name(); - break; } } - return "?"; + return ""; } std::vector GenerateFieldNames( @@ -431,6 +430,20 @@ std::vector GenerateFieldNames( const std::vector& entries) { static constexpr int kMaxNameLength = 255; std::vector out; + + bool found_needed_name = false; + for (const auto& entry : entries) { + if (!FieldNameForTable(entry).empty()) { + found_needed_name = true; + break; + } + } + + // No names needed. Omit the whole table. + if (!found_needed_name) { + return out; + } + // First, we output the size of each string, as an unsigned byte. The first // string is the message name. int count = 1; diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 25263d5b8d..f51be945e0 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -610,6 +610,7 @@ class PROTOBUF_EXPORT TcParser final { // For FindFieldEntry tests: friend class FindFieldEntryTest; + friend struct ParseFunctionGeneratorTestPeer; static constexpr const uint32_t kMtSmallScanSize = 4; // Mini parsing: diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 4d7f56cc55..4d9ec27d3f 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -96,7 +96,6 @@ #include "absl/strings/str_format.h" #include "google/protobuf/io/strtod.h" #include "google/protobuf/io/zero_copy_stream.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. #include "google/protobuf/port_def.inc" diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc index 2955c7bea0..041930e0b5 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl.cc @@ -47,7 +47,6 @@ #include "google/protobuf/stubs/logging.h" #include "google/protobuf/io/io_win32.h" #include "google/protobuf/io/zero_copy_stream_impl.h" -#include "google/protobuf/stubs/stl_util.h" namespace google { diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index 28ad9d667b..a23713c622 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -53,7 +53,6 @@ #include "google/protobuf/stubs/common.h" #include "google/protobuf/io/zero_copy_stream.h" #include "google/protobuf/port.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. @@ -387,24 +386,10 @@ class PROTOBUF_EXPORT LimitingInputStream PROTOBUF_FUTURE_FINAL // =================================================================== -// mutable_string_data() and as_string_data() are workarounds to improve -// the performance of writing new data to an existing string. Unfortunately -// the methods provided by the string class are suboptimal, and using memcpy() -// is mildly annoying because it requires its pointer args to be non-NULL even -// if we ask it to copy 0 bytes. Furthermore, string_as_array() has the -// property that it always returns NULL if its arg is the empty string, exactly -// what we want to avoid if we're using it in conjunction with memcpy()! -// With C++11, the desired memcpy() boils down to memcpy(..., &(*s)[0], size), -// where s is a string*. Without C++11, &(*s)[0] is not guaranteed to be safe, -// so we use string_as_array(), and live with the extra logic that tests whether -// *s is empty. - // Return a pointer to mutable characters underlying the given string. The // return value is valid until the next time the string is resized. We // trust the caller to treat the return value as an array of length s->size(). inline char* mutable_string_data(std::string* s) { - // This should be simpler & faster than string_as_array() because the latter - // is guaranteed to return NULL when *s is empty, so it has to check for that. return &(*s)[0]; } diff --git a/src/google/protobuf/json/BUILD.bazel b/src/google/protobuf/json/BUILD.bazel index 1339c7a973..15e90c4bf6 100644 --- a/src/google/protobuf/json/BUILD.bazel +++ b/src/google/protobuf/json/BUILD.bazel @@ -2,7 +2,8 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load("//build_defs:cpp_opts.bzl", "COPTS") package(default_visibility = [ - "//src/google/protobuf/util:__subpackages__", + "//src/google/protobuf/json:__pkg__", + "//pkg:__pkg__", ]) licenses(["notice"]) @@ -70,7 +71,6 @@ cc_library( hdrs = ["internal/zero_copy_buffered_stream.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ "//src/google/protobuf:port_def", "//src/google/protobuf/io", @@ -101,7 +101,6 @@ cc_library( hdrs = ["internal/untyped_message.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ "//src/google/protobuf", "//src/google/protobuf:port_def", @@ -124,7 +123,6 @@ cc_library( hdrs = ["internal/lexer.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ ":message_path", ":zero_copy_buffered_stream", @@ -164,7 +162,6 @@ cc_library( hdrs = ["internal/writer.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ "//src/google/protobuf:port_def", "//src/google/protobuf/io", @@ -180,7 +177,6 @@ cc_library( hdrs = ["internal/descriptor_traits.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ ":lexer", ":untyped_message", @@ -207,7 +203,6 @@ cc_library( ], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ ":descriptor_traits", ":lexer", @@ -242,7 +237,6 @@ cc_library( ], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ ":descriptor_traits", ":untyped_message", @@ -266,7 +260,6 @@ cc_library( hdrs = ["internal/message_path.h"], copts = COPTS, strip_include_prefix = "/src", - visibility = ["//visibility:private"], deps = [ "//src/google/protobuf", "@com_google_absl//absl/cleanup", diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index 3b615b7c5c..1a031717a2 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -675,8 +675,7 @@ TEST(Lite, AllLite28) { MapLiteTestUtil::SetMapFields(&message1); size_t size = message1.ByteSizeLong(); data.resize(size); - ::uint8_t* start = - reinterpret_cast<::uint8_t*>(::google::protobuf::string_as_array(&data)); + ::uint8_t* start = reinterpret_cast<::uint8_t*>(&data[0]); ::uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -696,7 +695,7 @@ TEST(Lite, AllLite29) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc index baf3c82c99..9b839ae45f 100644 --- a/src/google/protobuf/map_test.inc +++ b/src/google/protobuf/map_test.inc @@ -2692,7 +2692,7 @@ TEST(GeneratedMapFieldTest, SerializationToArray) { MapTestUtil::SetMapFields(&message1); size_t size = message1.ByteSizeLong(); data.resize(size); - uint8_t* start = reinterpret_cast(::google::protobuf::string_as_array(&data)); + uint8_t* start = reinterpret_cast(&data[0]); uint8_t* end = message1.SerializeWithCachedSizesToArray(start); EXPECT_EQ(size, end - start); EXPECT_TRUE(message2.ParseFromString(data)); @@ -2708,7 +2708,7 @@ TEST(GeneratedMapFieldTest, SerializationToStream) { data.resize(size); { // Allow the output stream to buffer only one byte at a time. - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&data), size, 1); + io::ArrayOutputStream array_stream(&data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); message1.SerializeWithCachedSizes(&output_stream); EXPECT_FALSE(output_stream.HadError()); @@ -3739,7 +3739,7 @@ static std::string DeterministicSerializationWithSerializePartialToCodedStream( const T& t) { const size_t size = t.ByteSizeLong(); std::string result(size, '\0'); - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size); + io::ArrayOutputStream array_stream(&result[0], size); io::CodedOutputStream output_stream(&array_stream); output_stream.SetSerializationDeterministic(true); t.SerializePartialToCodedStream(&output_stream); @@ -3753,7 +3753,7 @@ static std::string DeterministicSerializationWithSerializeToCodedStream( const T& t) { const size_t size = t.ByteSizeLong(); std::string result(size, '\0'); - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size); + io::ArrayOutputStream array_stream(&result[0], size); io::CodedOutputStream output_stream(&array_stream); output_stream.SetSerializationDeterministic(true); t.SerializeToCodedStream(&output_stream); @@ -3766,7 +3766,7 @@ template static std::string DeterministicSerialization(const T& t) { const size_t size = t.ByteSizeLong(); std::string result(size, '\0'); - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&result), size); + io::ArrayOutputStream array_stream(&result[0], size); { io::CodedOutputStream output_stream(&array_stream); output_stream.SetSerializationDeterministic(true); diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index 263ef61f80..7c88c5525e 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -76,7 +76,6 @@ message TestSameTypeMap { map map2 = 2; } - enum MapEnum { MAP_ENUM_FOO = 0; MAP_ENUM_BAR = 1; diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 4cad7af324..e43d93ab46 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -61,7 +61,6 @@ #include "google/protobuf/unknown_field_set.h" #include "google/protobuf/wire_format.h" #include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index eeecf078b0..6f91b16cc2 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -56,7 +56,6 @@ #include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "google/protobuf/stubs/strutil.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. #include "google/protobuf/port_def.inc" diff --git a/src/google/protobuf/stubs/BUILD.bazel b/src/google/protobuf/stubs/BUILD.bazel index 98f497e518..9cc3e757eb 100644 --- a/src/google/protobuf/stubs/BUILD.bazel +++ b/src/google/protobuf/stubs/BUILD.bazel @@ -26,7 +26,6 @@ cc_library( "platform_macros.h", "port.h", "status_macros.h", - "stl_util.h", "strutil.h", ], copts = COPTS, @@ -56,7 +55,6 @@ cc_library( "platform_macros.h", "port.h", "status_macros.h", - "stl_util.h", "strutil.h", ], deps = [ diff --git a/src/google/protobuf/stubs/callback.h b/src/google/protobuf/stubs/callback.h index 691eda4a95..ed4b9f78a9 100644 --- a/src/google/protobuf/stubs/callback.h +++ b/src/google/protobuf/stubs/callback.h @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// 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. + #ifndef GOOGLE_PROTOBUF_STUBS_CALLBACK_H_ #define GOOGLE_PROTOBUF_STUBS_CALLBACK_H_ diff --git a/src/google/protobuf/stubs/stl_util.h b/src/google/protobuf/stubs/stl_util.h deleted file mode 100644 index cd10c4b2ef..0000000000 --- a/src/google/protobuf/stubs/stl_util.h +++ /dev/null @@ -1,68 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. - -// from google3/util/gtl/stl_util.h - -#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ -#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ - -#include - -#include "google/protobuf/stubs/common.h" - -// Must be last. -#include "google/protobuf/port_def.inc" // NOLINT - -namespace google { -namespace protobuf { - -// Return a mutable char* pointing to a string's internal buffer, -// which may not be null-terminated. Writing through this pointer will -// modify the string. -// -// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the -// next call to a string method that invalidates iterators. -// -// As of 2006-04, there is no standard-blessed way of getting a -// mutable reference to a string's internal buffer. However, issue 530 -// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530) -// proposes this as the method. According to Matt Austern, this should -// already work on all current implementations. -inline char* string_as_array(std::string* str) { - // DO NOT USE const_cast(str->data())! See the unittest for why. - return str->empty() ? nullptr : &*str->begin(); -} - -} // namespace protobuf -} // namespace google - -#include "google/protobuf/port_undef.inc" // NOLINT - -#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__ diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index 720c6fcee3..7d088a80c1 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -44,7 +44,6 @@ #include "absl/strings/ascii.h" #include "absl/strings/string_view.h" #include "google/protobuf/stubs/logging.h" -#include "google/protobuf/stubs/stl_util.h" #ifdef _WIN32 // MSVC has only _snprintf, not snprintf. @@ -671,9 +670,8 @@ void Base64EscapeInternal(const unsigned char *src, int szsrc, const absl::string_view base64_chars) { const int calc_escaped_size = CalculateBase64EscapedLen(szsrc, do_padding); dest->resize(calc_escaped_size); - const int escaped_len = - Base64EscapeInternal(src, szsrc, string_as_array(dest), dest->size(), - base64_chars, do_padding); + const int escaped_len = Base64EscapeInternal( + src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding); GOOGLE_DCHECK_EQ(calc_escaped_size, escaped_len); dest->erase(escaped_len); } diff --git a/src/google/protobuf/stubs/strutil_unittest.cc b/src/google/protobuf/stubs/strutil_unittest.cc index 71e60e6819..ea15b1d752 100644 --- a/src/google/protobuf/stubs/strutil_unittest.cc +++ b/src/google/protobuf/stubs/strutil_unittest.cc @@ -35,7 +35,6 @@ #include #include -#include "google/protobuf/stubs/stl_util.h" #include "google/protobuf/testing/googletest.h" #ifdef _WIN32 diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 560d4131e7..30132a15fd 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -67,7 +67,6 @@ #include "google/protobuf/repeated_field.h" #include "google/protobuf/unknown_field_set.h" #include "google/protobuf/wire_format_lite.h" -#include "google/protobuf/stubs/stl_util.h" // Must be included last. #include "google/protobuf/port_def.inc" diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index 3b2df6d911..184a18f8ce 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -90,7 +90,6 @@ option objc_class_prefix = "GPB"; // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) // .setNanos((int) ((millis % 1000) * 1000000)).build(); // -// // Example 5: Compute Timestamp from Java `Instant.now()`. // // Instant now = Instant.now(); @@ -99,7 +98,6 @@ option objc_class_prefix = "GPB"; // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) // .setNanos(now.getNano()).build(); // -// // Example 6: Compute Timestamp from current time in Python. // // timestamp = Timestamp() @@ -132,7 +130,6 @@ option objc_class_prefix = "GPB"; // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D // ) to obtain a formatter capable of generating timestamps in this format. // -// message Timestamp { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index a8078158ea..440a6f0fe5 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -889,7 +889,6 @@ message TestRequiredOneof { } } - // Test messages for packed fields message TestPackedTypes { @@ -1070,7 +1069,6 @@ message TestMessageSize { optional int64 m6 = 6; } - // Test that RPC services work. message FooRequest {} message FooResponse {} @@ -1083,7 +1081,6 @@ service TestService { rpc Bar(BarRequest) returns (BarResponse); } - message BarRequest {} message BarResponse {} @@ -1437,7 +1434,6 @@ message TestVerifyBigFieldNumberUint32 { optional Nested optional_nested = 1; } - // This message contains different kind of enums to exercise the different // parsers in table-driven. message EnumParseTester { @@ -1565,4 +1561,3 @@ message StringParseTester { repeated string repeated_string_midfield = 1002; repeated string repeated_string_hifield = 1000002; }; - diff --git a/src/google/protobuf/unittest_import.proto b/src/google/protobuf/unittest_import.proto index 8d03e3888b..4fc0ebb022 100644 --- a/src/google/protobuf/unittest_import.proto +++ b/src/google/protobuf/unittest_import.proto @@ -64,7 +64,6 @@ enum ImportEnum { IMPORT_BAZ = 9; } - // To use an enum in a map, it must has the first value as 0. enum ImportEnumForMap { UNKNOWN = 0; diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index 7093f3db88..38337a48a2 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -59,7 +59,6 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "google/protobuf/test_util.h" -#include "google/protobuf/stubs/stl_util.h" namespace google { @@ -207,15 +206,13 @@ TEST_F(UnknownFieldSetTest, SerializeFastAndSlowAreEquivalent) { slow_buffer.resize(size); fast_buffer.resize(size); - uint8_t* target = - reinterpret_cast(::google::protobuf::string_as_array(&fast_buffer)); + uint8_t* target = reinterpret_cast(&fast_buffer[0]); uint8_t* result = WireFormat::SerializeUnknownFieldsToArray( empty_message_.unknown_fields(), target); EXPECT_EQ(size, result - target); { - io::ArrayOutputStream raw_stream(::google::protobuf::string_as_array(&slow_buffer), size, - 1); + io::ArrayOutputStream raw_stream(&slow_buffer[0], size, 1); io::CodedOutputStream output_stream(&raw_stream); WireFormat::SerializeUnknownFields(empty_message_.unknown_fields(), &output_stream); diff --git a/src/google/protobuf/util/json_format.proto b/src/google/protobuf/util/json_format.proto index 6199f09e83..a2703ce029 100644 --- a/src/google/protobuf/util/json_format.proto +++ b/src/google/protobuf/util/json_format.proto @@ -41,7 +41,6 @@ package protobuf_unittest; import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; - message TestFlagsAndStrings { required int32 A = 1; repeated group RepeatedGroup = 2 { @@ -96,7 +95,6 @@ message TestNumbers { optional uint32 f = 6; } - message TestCamelCase { optional string normal_field = 1; optional int32 CAPITAL_FIELD = 2; diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index e87219300c..238f3aaf25 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -330,17 +330,6 @@ class PROTOBUF_EXPORT MessageDifferencer { MapKeyComparator& operator=(const MapKeyComparator&) = delete; virtual ~MapKeyComparator(); - // This method is DEPRECATED. It is never called directly by - // MessageDifferencer. New code should implement only the next form of - // IsMatch. - // - // TODO(b/248337479) Remove this method. - virtual bool IsMatch( - const Message& /* message1 */, const Message& /* message2 */, - const std::vector& /* parent_fields */) const { - GOOGLE_CHECK(false) << "IsMatch() is not implemented."; - return false; - } // This method should be overridden by every implementation. The arg // unmapped_any is nonzero the original messages provided by the user are of @@ -354,7 +343,8 @@ class PROTOBUF_EXPORT MessageDifferencer { virtual bool IsMatch(const Message& message1, const Message& message2, int /* unmapped_any */, const std::vector& fields) const { - return IsMatch(message1, message2, fields); + GOOGLE_CHECK(false) << "IsMatch() is not implemented."; + return false; } }; diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index 93a4553538..8dbe9479c5 100644 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -1907,6 +1907,7 @@ class ValueProductMapKeyComparator public: typedef util::MessageDifferencer::SpecificField SpecificField; bool IsMatch(const Message& message1, const Message& message2, + int unpacked_any, const std::vector& parent_fields) const override { const Reflection* reflection1 = message1.GetReflection(); const Reflection* reflection2 = message2.GetReflection(); @@ -1968,6 +1969,7 @@ class OffsetByOneMapKeyComparator public: typedef util::MessageDifferencer::SpecificField SpecificField; bool IsMatch(const Message& message1, const Message& message2, + int unpacked_any, const std::vector& parent_fields) const override { return parent_fields.back().index + 1 == parent_fields.back().new_index; } @@ -3402,6 +3404,7 @@ class LengthMapKeyComparator public: typedef util::MessageDifferencer::SpecificField SpecificField; bool IsMatch(const Message& message1, const Message& message2, + int unpacked_any, const std::vector& parent_fields) const override { const Reflection* reflection1 = message1.GetReflection(); const Reflection* reflection2 = message2.GetReflection(); diff --git a/src/google/protobuf/well_known_types_unittest.cc b/src/google/protobuf/well_known_types_unittest.cc index 2cc25b5b54..4d7a0ff6dc 100644 --- a/src/google/protobuf/well_known_types_unittest.cc +++ b/src/google/protobuf/well_known_types_unittest.cc @@ -30,7 +30,6 @@ #include #include "google/protobuf/stubs/common.h" -#include "google/protobuf/stubs/stl_util.h" #include "google/protobuf/testing/googletest.h" #include "google/protobuf/unittest_well_known_types.pb.h" diff --git a/src/google/protobuf/wire_format_unittest.inc b/src/google/protobuf/wire_format_unittest.inc index 6a3c5bbfc4..81a577e5d4 100644 --- a/src/google/protobuf/wire_format_unittest.inc +++ b/src/google/protobuf/wire_format_unittest.inc @@ -49,7 +49,6 @@ #include "absl/strings/match.h" #include "google/protobuf/dynamic_message.h" #include "google/protobuf/test_util2.h" -#include "google/protobuf/stubs/stl_util.h" // clang-format off #include "google/protobuf/port_def.inc" @@ -494,16 +493,14 @@ TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) { // Serialize to flat array { - uint8_t* target = - reinterpret_cast(::google::protobuf::string_as_array(&flat_data)); + uint8_t* target = reinterpret_cast(&flat_data[0]); uint8_t* end = message_set.SerializeWithCachedSizesToArray(target); EXPECT_EQ(size, end - target); } // Serialize to buffer { - io::ArrayOutputStream array_stream(::google::protobuf::string_as_array(&stream_data), size, - 1); + io::ArrayOutputStream array_stream(&stream_data[0], size, 1); io::CodedOutputStream output_stream(&array_stream); message_set.SerializeWithCachedSizes(&output_stream); ASSERT_FALSE(output_stream.HadError()); diff --git a/third_party/jsoncpp b/third_party/jsoncpp new file mode 160000 index 0000000000..9059f5cad0 --- /dev/null +++ b/third_party/jsoncpp @@ -0,0 +1 @@ +Subproject commit 9059f5cad030ba11d37818847443a53918c327b1 diff --git a/third_party/jsoncpp.BUILD b/third_party/jsoncpp.BUILD new file mode 100644 index 0000000000..6d7ac3da98 --- /dev/null +++ b/third_party/jsoncpp.BUILD @@ -0,0 +1,37 @@ +licenses(["unencumbered"]) # Public Domain or MIT + +exports_files(["LICENSE"]) + +cc_library( + name = "jsoncpp", + srcs = [ + "src/lib_json/json_reader.cpp", + "src/lib_json/json_tool.h", + "src/lib_json/json_value.cpp", + "src/lib_json/json_writer.cpp", + ], + hdrs = [ + "include/json/allocator.h", + "include/json/assertions.h", + "include/json/config.h", + "include/json/json_features.h", + "include/json/forwards.h", + "include/json/json.h", + "include/json/reader.h", + "include/json/value.h", + "include/json/version.h", + "include/json/writer.h", + ], + copts = [ + "-DJSON_USE_EXCEPTION=0", + "-DJSON_HAS_INT64", + ], + includes = ["include"], + visibility = ["//visibility:public"], + deps = [":private"], +) + +cc_library( + name = "private", + textual_hdrs = ["src/lib_json/json_valueiterator.inl"], +)