Merge branch 'master' into export-plugin
commit
b6ef14bafa
@ -0,0 +1,34 @@
|
||||
##############################
|
||||
# Generic dwarfmode bindings #
|
||||
##############################
|
||||
|
||||
keybinding add Ctrl-W twaterlvl
|
||||
|
||||
# with cursor:
|
||||
keybinding add Ctrl-V vdig
|
||||
keybinding add Ctrl-Shift-V "vdig x"
|
||||
keybinding add Ctrl-C spotclean
|
||||
keybinding add Ctrl-Shift-K autodump-destroy-here
|
||||
|
||||
# any item:
|
||||
keybinding add Ctrl-K autodump-destroy-item
|
||||
|
||||
#############################
|
||||
# Context-specific bindings #
|
||||
#############################
|
||||
|
||||
# q->stockpile; p
|
||||
keybinding add Alt-P copystock
|
||||
|
||||
# q->workshop
|
||||
keybinding add Ctrl-D job-duplicate
|
||||
|
||||
# materials: q->workshop; b->select items
|
||||
keybinding add Shift-A "job-material ALUNITE"
|
||||
keybinding add Shift-M "job-material MICROCLINE"
|
||||
keybinding add Shift-D "job-material DACITE"
|
||||
keybinding add Shift-R "job-material RHYOLITE"
|
||||
keybinding add Shift-I "job-material CINNABAR"
|
||||
keybinding add Shift-B "job-material COBALTITE"
|
||||
keybinding add Shift-O "job-material OBSIDIAN"
|
||||
keybinding add Shift-G "job-material GLASS_GREEN"
|
@ -0,0 +1,2 @@
|
||||
config.h
|
||||
testHashMap.cpp
|
@ -0,0 +1,208 @@
|
||||
PROJECT(protobuf)
|
||||
|
||||
#Protocol buffers use C++0x hash maps, so we need to look for those. This is a rewrite of stl_hash.m4 in CMake.
|
||||
IF(CMAKE_COMPILER_IS_GNUCC)
|
||||
EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION)
|
||||
STRING(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
|
||||
LIST(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
|
||||
LIST(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
|
||||
IF(GCC_MAJOR LESS 4 OR (GCC_MAJOR EQUAL 4 AND GCC_MINOR LESS 2))
|
||||
#GCC is too old
|
||||
SET(STL_HASH_OLD_GCC 1)
|
||||
ENDIF()
|
||||
|
||||
#SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
SET(HAVE_HASH_MAP 0)
|
||||
SET(HASH_MAP_CLASS unordered_map)
|
||||
|
||||
#Check for all of the possible combinations of unordered_map and hash_map
|
||||
|
||||
FOREACH(header tr1/unordered_map unordered_map)
|
||||
FOREACH(namespace std::tr1 std )
|
||||
IF(HAVE_HASH_MAP EQUAL 0 AND NOT STL_HASH_OLD_GCC)
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp")
|
||||
TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp")
|
||||
IF (HASH_MAP_COMPILE_RESULT AND HASH_MAP_RUN_RESULT EQUAL 1)
|
||||
SET(HASH_MAP_H <${header}>)
|
||||
STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H})
|
||||
SET(HASH_NAMESPACE ${namespace})
|
||||
SET(HASH_MAP_CLASS unordered_map)
|
||||
SET(HASH_SET_CLASS unordered_set)
|
||||
SET(HAVE_HASH_MAP 1)
|
||||
SET(HAVE_HASH_SET 1)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDFOREACH(namespace)
|
||||
ENDFOREACH(header)
|
||||
IF (HAVE_HASH_MAP EQUAL 0)
|
||||
SET(HASH_MAP_CLASS hash_map)
|
||||
FOREACH(header ext/hash_map hash_map)
|
||||
FOREACH(namespace __gnu_cxx "" std stdext)
|
||||
IF (HAVE_HASH_MAP EQUAL 0)
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp")
|
||||
TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp")
|
||||
IF (HASH_MAP_COMPILE_RESULT)
|
||||
SET(HASH_MAP_H <${header}>)
|
||||
STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H})
|
||||
SET(HASH_NAMESPACE ${namespace})
|
||||
SET(HASH_MAP_CLASS hash_map)
|
||||
SET(HASH_SET_CLASS hash_set)
|
||||
SET(HAVE_HASH_MAP 1)
|
||||
SET(HAVE_HASH_SET 1)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
ENDFOREACH()
|
||||
ENDIF()
|
||||
|
||||
IF (HAVE_HASH_MAP EQUAL 0)
|
||||
MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please update GCC.")
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE(Threads)
|
||||
|
||||
ELSE()
|
||||
SET(HASH_MAP_H <hash_map>)
|
||||
SET(HASH_NAMESPACE std)
|
||||
SET(HASH_SET_H <hash_set>)
|
||||
SET(HAVE_HASH_MAP 1)
|
||||
SET(HAVE_HASH_SET 1)
|
||||
SET(HASH_MAP_CLASS hash_map)
|
||||
SET(HASH_SET_CLASS hash_set)
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/config.h")
|
||||
|
||||
SET(LIBPROTOBUF_LITE_HDRS
|
||||
google/protobuf/io/coded_stream.h
|
||||
google/protobuf/io/coded_stream_inl.h
|
||||
google/protobuf/stubs/common.h
|
||||
config.h
|
||||
google/protobuf/extension_set.h
|
||||
google/protobuf/generated_message_util.h
|
||||
google/protobuf/stubs/hash.h
|
||||
google/protobuf/stubs/map-util.h
|
||||
google/protobuf/message_lite.h
|
||||
google/protobuf/stubs/once.h
|
||||
google/protobuf/repeated_field.h
|
||||
google/protobuf/stubs/stl_util-inl.h
|
||||
google/protobuf/wire_format_lite.h
|
||||
google/protobuf/wire_format_lite_inl.h
|
||||
google/protobuf/io/zero_copy_stream.h
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.h
|
||||
)
|
||||
|
||||
SET(LIBPROTOBUF_FULL_HDRS
|
||||
google/protobuf/descriptor.h
|
||||
google/protobuf/descriptor.pb.h
|
||||
google/protobuf/descriptor_database.h
|
||||
google/protobuf/dynamic_message.h
|
||||
google/protobuf/generated_message_reflection.h
|
||||
google/protobuf/io/gzip_stream.h
|
||||
google/protobuf/compiler/importer.h
|
||||
google/protobuf/message.h
|
||||
google/protobuf/compiler/parser.h
|
||||
google/protobuf/io/printer.h
|
||||
google/protobuf/reflection_ops.h
|
||||
google/protobuf/service.h
|
||||
google/protobuf/stubs/strutil.h
|
||||
google/protobuf/stubs/substitute.h
|
||||
google/protobuf/text_format.h
|
||||
google/protobuf/io/tokenizer.h
|
||||
google/protobuf/unknown_field_set.h
|
||||
google/protobuf/wire_format.h
|
||||
google/protobuf/io/zero_copy_stream_impl.h
|
||||
)
|
||||
|
||||
LIST(APPEND LIBPROTOBUF_FULL_HDRS ${LIBPROTOBUF_LITE_HDRS})
|
||||
|
||||
SET(LIBPROTOBUF_LITE_SRCS
|
||||
google/protobuf/io/coded_stream.cc
|
||||
google/protobuf/stubs/common.cc
|
||||
google/protobuf/extension_set.cc
|
||||
google/protobuf/generated_message_util.cc
|
||||
google/protobuf/message_lite.cc
|
||||
google/protobuf/stubs/once.cc
|
||||
google/protobuf/repeated_field.cc
|
||||
google/protobuf/wire_format_lite.cc
|
||||
google/protobuf/io/zero_copy_stream.cc
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.cc
|
||||
)
|
||||
|
||||
SET(LIBPROTOBUF_FULL_SRCS
|
||||
google/protobuf/descriptor.cc
|
||||
google/protobuf/descriptor.pb.cc
|
||||
google/protobuf/descriptor_database.cc
|
||||
google/protobuf/dynamic_message.cc
|
||||
google/protobuf/extension_set_heavy.cc
|
||||
google/protobuf/generated_message_reflection.cc
|
||||
google/protobuf/io/gzip_stream.cc
|
||||
google/protobuf/compiler/importer.cc
|
||||
google/protobuf/message.cc
|
||||
google/protobuf/compiler/parser.cc
|
||||
google/protobuf/io/printer.cc
|
||||
google/protobuf/reflection_ops.cc
|
||||
google/protobuf/service.cc
|
||||
google/protobuf/stubs/structurally_valid.cc
|
||||
google/protobuf/stubs/strutil.cc
|
||||
google/protobuf/stubs/substitute.cc
|
||||
google/protobuf/text_format.cc
|
||||
google/protobuf/io/tokenizer.cc
|
||||
google/protobuf/unknown_field_set.cc
|
||||
google/protobuf/wire_format.cc
|
||||
google/protobuf/io/zero_copy_stream_impl.cc
|
||||
)
|
||||
|
||||
SET(LIBPROTOC_HDRS
|
||||
google/protobuf/compiler/code_generator.h
|
||||
google/protobuf/compiler/command_line_interface.h
|
||||
google/protobuf/compiler/cpp/cpp_enum.h
|
||||
google/protobuf/compiler/cpp/cpp_enum_field.h
|
||||
google/protobuf/compiler/cpp/cpp_extension.h
|
||||
google/protobuf/compiler/cpp/cpp_field.h
|
||||
google/protobuf/compiler/cpp/cpp_file.h
|
||||
google/protobuf/compiler/cpp/cpp_generator.h
|
||||
google/protobuf/compiler/cpp/cpp_helpers.h
|
||||
google/protobuf/compiler/cpp/cpp_message.h
|
||||
google/protobuf/compiler/cpp/cpp_message_field.h
|
||||
google/protobuf/compiler/cpp/cpp_primitive_field.h
|
||||
google/protobuf/compiler/cpp/cpp_service.h
|
||||
google/protobuf/compiler/cpp/cpp_string_field.h
|
||||
google/protobuf/compiler/plugin.h
|
||||
google/protobuf/compiler/plugin.pb.h
|
||||
google/protobuf/compiler/subprocess.h
|
||||
google/protobuf/compiler/zip_writer.h
|
||||
)
|
||||
|
||||
SET(LIBPROTOC_SRCS
|
||||
google/protobuf/compiler/code_generator.cc
|
||||
google/protobuf/compiler/command_line_interface.cc
|
||||
google/protobuf/compiler/cpp/cpp_enum.cc
|
||||
google/protobuf/compiler/cpp/cpp_enum_field.cc
|
||||
google/protobuf/compiler/cpp/cpp_extension.cc
|
||||
google/protobuf/compiler/cpp/cpp_field.cc
|
||||
google/protobuf/compiler/cpp/cpp_file.cc
|
||||
google/protobuf/compiler/cpp/cpp_generator.cc
|
||||
google/protobuf/compiler/cpp/cpp_helpers.cc
|
||||
google/protobuf/compiler/cpp/cpp_message.cc
|
||||
google/protobuf/compiler/cpp/cpp_message_field.cc
|
||||
google/protobuf/compiler/cpp/cpp_primitive_field.cc
|
||||
google/protobuf/compiler/cpp/cpp_service.cc
|
||||
google/protobuf/compiler/cpp/cpp_string_field.cc
|
||||
google/protobuf/compiler/plugin.cc
|
||||
google/protobuf/compiler/plugin.pb.cc
|
||||
google/protobuf/compiler/subprocess.cc
|
||||
google/protobuf/compiler/zip_writer.cc
|
||||
)
|
||||
|
||||
LIST(APPEND LIBPROTOBUF_FULL_SRCS ${LIBPROTOBUF_LITE_SRCS})
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
ADD_LIBRARY(protobuf-lite ${LIBPROTOBUF_LITE_SRCS} ${LIBPROTOBUF_LITE_HDRS})
|
||||
ADD_LIBRARY(protobuf ${LIBPROTOBUF_FULL_SRCS} ${LIBPROTOBUF_FULL_HDRS})
|
||||
ADD_LIBRARY(protoc ${LIBPROTOC_SRCS} ${LIBPROTOC_HDRS})
|
||||
ADD_EXECUTABLE(protoc-bin google/protobuf/compiler/main.cc google/protobuf/compiler/command_line_interface.h google/protobuf/compiler/cpp/cpp_generator.h)
|
||||
SET_TARGET_PROPERTIES(protoc-bin PROPERTIES OUTPUT_NAME protoc)
|
||||
TARGET_LINK_LIBRARIES(protoc-bin protoc protobuf ${CMAKE_THREAD_LIBS_INIT})
|
@ -0,0 +1,33 @@
|
||||
Copyright 2008, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Code generated by the Protocol Buffer compiler is owned by the owner
|
||||
of the input file used when generating it. This code is not
|
||||
standalone and requires a support library to be linked with it. This
|
||||
support library is itself covered by the above license.
|
@ -0,0 +1,12 @@
|
||||
#define HASH_MAP_H @HASH_MAP_H@
|
||||
#define HASH_SET_H @HASH_SET_H@
|
||||
#define HASH_MAP_CLASS @HASH_MAP_CLASS@
|
||||
#define HASH_SET_CLASS @HASH_SET_CLASS@
|
||||
#define HASH_NAMESPACE @HASH_NAMESPACE@
|
||||
#define HAVE_HASH_MAP @HAVE_HASH_MAP@
|
||||
#define HAVE_HASH_SET @HAVE_HASH_SET@
|
||||
#define HAVE_PTHREAD @CMAKE_USE_PTHREADS_INIT@
|
||||
|
||||
/* define if you want to use zlib. See readme.txt for additional
|
||||
* requirements. */
|
||||
// #define HAVE_ZLIB 1
|
@ -0,0 +1,80 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
CodeGenerator::~CodeGenerator() {}
|
||||
GeneratorContext::~GeneratorContext() {}
|
||||
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert(
|
||||
const string& filename, const string& insertion_point) {
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion.";
|
||||
return NULL; // make compiler happy
|
||||
}
|
||||
|
||||
void GeneratorContext::ListParsedFiles(
|
||||
vector<const FileDescriptor*>* output) {
|
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles";
|
||||
}
|
||||
|
||||
// Parses a set of comma-delimited name/value pairs.
|
||||
void ParseGeneratorParameter(const string& text,
|
||||
vector<pair<string, string> >* output) {
|
||||
vector<string> parts;
|
||||
SplitStringUsing(text, ",", &parts);
|
||||
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
string::size_type equals_pos = parts[i].find_first_of('=');
|
||||
pair<string, string> value;
|
||||
if (equals_pos == string::npos) {
|
||||
value.first = parts[i];
|
||||
value.second = "";
|
||||
} else {
|
||||
value.first = parts[i].substr(0, equals_pos);
|
||||
value.second = parts[i].substr(equals_pos + 1);
|
||||
}
|
||||
output->push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,142 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines the abstract interface implemented by each of the language-specific
|
||||
// code generators.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io { class ZeroCopyOutputStream; }
|
||||
class FileDescriptor;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// Defined in this file.
|
||||
class CodeGenerator;
|
||||
class GeneratorContext;
|
||||
|
||||
// The abstract interface to a class which generates code implementing a
|
||||
// particular proto file in a particular language. A number of these may
|
||||
// be registered with CommandLineInterface to support various languages.
|
||||
class LIBPROTOC_EXPORT CodeGenerator {
|
||||
public:
|
||||
inline CodeGenerator() {}
|
||||
virtual ~CodeGenerator();
|
||||
|
||||
// Generates code for the given proto file, generating one or more files in
|
||||
// the given output directory.
|
||||
//
|
||||
// A parameter to be passed to the generator can be specified on the
|
||||
// command line. This is intended to be used by Java and similar languages
|
||||
// to specify which specific class from the proto file is to be generated,
|
||||
// though it could have other uses as well. It is empty if no parameter was
|
||||
// given.
|
||||
//
|
||||
// Returns true if successful. Otherwise, sets *error to a description of
|
||||
// the problem (e.g. "invalid parameter") and returns false.
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator);
|
||||
};
|
||||
|
||||
// CodeGenerators generate one or more files in a given directory. This
|
||||
// abstract interface represents the directory to which the CodeGenerator is
|
||||
// to write and other information about the context in which the Generator
|
||||
// runs.
|
||||
class LIBPROTOC_EXPORT GeneratorContext {
|
||||
public:
|
||||
inline GeneratorContext() {}
|
||||
virtual ~GeneratorContext();
|
||||
|
||||
// Opens the given file, truncating it if it exists, and returns a
|
||||
// ZeroCopyOutputStream that writes to the file. The caller takes ownership
|
||||
// of the returned object. This method never fails (a dummy stream will be
|
||||
// returned instead).
|
||||
//
|
||||
// The filename given should be relative to the root of the source tree.
|
||||
// E.g. the C++ generator, when generating code for "foo/bar.proto", will
|
||||
// generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that
|
||||
// "foo/" is included in these filenames. The filename is not allowed to
|
||||
// contain "." or ".." components.
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0;
|
||||
|
||||
// Creates a ZeroCopyOutputStream which will insert code into the given file
|
||||
// at the given insertion point. See plugin.proto (plugin.pb.h) for more
|
||||
// information on insertion points. The default implementation
|
||||
// assert-fails -- it exists only for backwards-compatibility.
|
||||
//
|
||||
// WARNING: This feature is currently EXPERIMENTAL and is subject to change.
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert(
|
||||
const string& filename, const string& insertion_point);
|
||||
|
||||
// Returns a vector of FileDescriptors for all the files being compiled
|
||||
// in this run. Useful for languages, such as Go, that treat files
|
||||
// differently when compiled as a set rather than individually.
|
||||
virtual void ListParsedFiles(vector<const FileDescriptor*>* output);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext);
|
||||
};
|
||||
|
||||
// The type GeneratorContext was once called OutputDirectory. This typedef
|
||||
// provides backward compatibility.
|
||||
typedef GeneratorContext OutputDirectory;
|
||||
|
||||
// Several code generators treat the parameter argument as holding a
|
||||
// list of options separated by commas. This helper function parses
|
||||
// a set of comma-delimited name/value pairs: e.g.,
|
||||
// "foo=bar,baz,qux=corge"
|
||||
// parses to the pairs:
|
||||
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
|
||||
extern void ParseGeneratorParameter(const string&,
|
||||
vector<pair<string, string> >*);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,318 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Implements the Protocol Compiler front-end such that it may be reused by
|
||||
// custom compilers written to support other languages.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class FileDescriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
class FileDescriptorProto; // descriptor.pb.h
|
||||
template<typename T> class RepeatedPtrField; // repeated_field.h
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
class GeneratorContext; // code_generator.h
|
||||
class DiskSourceTree; // importer.h
|
||||
|
||||
// This class implements the command-line interface to the protocol compiler.
|
||||
// It is designed to make it very easy to create a custom protocol compiler
|
||||
// supporting the languages of your choice. For example, if you wanted to
|
||||
// create a custom protocol compiler binary which includes both the regular
|
||||
// C++ support plus support for your own custom output "Foo", you would
|
||||
// write a class "FooGenerator" which implements the CodeGenerator interface,
|
||||
// then write a main() procedure like this:
|
||||
//
|
||||
// int main(int argc, char* argv[]) {
|
||||
// google::protobuf::compiler::CommandLineInterface cli;
|
||||
//
|
||||
// // Support generation of C++ source and headers.
|
||||
// google::protobuf::compiler::cpp::CppGenerator cpp_generator;
|
||||
// cli.RegisterGenerator("--cpp_out", &cpp_generator,
|
||||
// "Generate C++ source and header.");
|
||||
//
|
||||
// // Support generation of Foo code.
|
||||
// FooGenerator foo_generator;
|
||||
// cli.RegisterGenerator("--foo_out", &foo_generator,
|
||||
// "Generate Foo file.");
|
||||
//
|
||||
// return cli.Run(argc, argv);
|
||||
// }
|
||||
//
|
||||
// The compiler is invoked with syntax like:
|
||||
// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto
|
||||
//
|
||||
// For a full description of the command-line syntax, invoke it with --help.
|
||||
class LIBPROTOC_EXPORT CommandLineInterface {
|
||||
public:
|
||||
CommandLineInterface();
|
||||
~CommandLineInterface();
|
||||
|
||||
// Register a code generator for a language.
|
||||
//
|
||||
// Parameters:
|
||||
// * flag_name: The command-line flag used to specify an output file of
|
||||
// this type. The name must start with a '-'. If the name is longer
|
||||
// than one letter, it must start with two '-'s.
|
||||
// * generator: The CodeGenerator which will be called to generate files
|
||||
// of this type.
|
||||
// * help_text: Text describing this flag in the --help output.
|
||||
//
|
||||
// Some generators accept extra parameters. You can specify this parameter
|
||||
// on the command-line by placing it before the output directory, separated
|
||||
// by a colon:
|
||||
// protoc --foo_out=enable_bar:outdir
|
||||
// The text before the colon is passed to CodeGenerator::Generate() as the
|
||||
// "parameter".
|
||||
void RegisterGenerator(const string& flag_name,
|
||||
CodeGenerator* generator,
|
||||
const string& help_text);
|
||||
|
||||
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
|
||||
// but does not match any registered generator, the compiler will attempt to
|
||||
// find a "plugin" to implement the generator. Plugins are just executables.
|
||||
// They should live somewhere in the PATH.
|
||||
//
|
||||
// The compiler determines the executable name to search for by concatenating
|
||||
// exe_name_prefix with the unrecognized flag name, removing "_out". So, for
|
||||
// example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out,
|
||||
// the compiler will try to run the program "protoc-foo".
|
||||
//
|
||||
// The plugin program should implement the following usage:
|
||||
// plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
|
||||
// --out indicates the output directory (as passed to the --foo_out
|
||||
// parameter); if omitted, the current directory should be used. --parameter
|
||||
// gives the generator parameter, if any was provided. The PROTO_FILES list
|
||||
// the .proto files which were given on the compiler command-line; these are
|
||||
// the files for which the plugin is expected to generate output code.
|
||||
// Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in
|
||||
// descriptor.proto). This is piped to the plugin's stdin. The set will
|
||||
// include descriptors for all the files listed in PROTO_FILES as well as
|
||||
// all files that they import. The plugin MUST NOT attempt to read the
|
||||
// PROTO_FILES directly -- it must use the FileDescriptorSet.
|
||||
//
|
||||
// The plugin should generate whatever files are necessary, as code generators
|
||||
// normally do. It should write the names of all files it generates to
|
||||
// stdout. The names should be relative to the output directory, NOT absolute
|
||||
// names or relative to the current directory. If any errors occur, error
|
||||
// messages should be written to stderr. If an error is fatal, the plugin
|
||||
// should exit with a non-zero exit code.
|
||||
void AllowPlugins(const string& exe_name_prefix);
|
||||
|
||||
// Run the Protocol Compiler with the given command-line parameters.
|
||||
// Returns the error code which should be returned by main().
|
||||
//
|
||||
// It may not be safe to call Run() in a multi-threaded environment because
|
||||
// it calls strerror(). I'm not sure why you'd want to do this anyway.
|
||||
int Run(int argc, const char* const argv[]);
|
||||
|
||||
// Call SetInputsAreCwdRelative(true) if the input files given on the command
|
||||
// line should be interpreted relative to the proto import path specified
|
||||
// using --proto_path or -I flags. Otherwise, input file names will be
|
||||
// interpreted relative to the current working directory (or as absolute
|
||||
// paths if they start with '/'), though they must still reside inside
|
||||
// a directory given by --proto_path or the compiler will fail. The latter
|
||||
// mode is generally more intuitive and easier to use, especially e.g. when
|
||||
// defining implicit rules in Makefiles.
|
||||
void SetInputsAreProtoPathRelative(bool enable) {
|
||||
inputs_are_proto_path_relative_ = enable;
|
||||
}
|
||||
|
||||
// Provides some text which will be printed when the --version flag is
|
||||
// used. The version of libprotoc will also be printed on the next line
|
||||
// after this text.
|
||||
void SetVersionInfo(const string& text) {
|
||||
version_info_ = text;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
class ErrorPrinter;
|
||||
class GeneratorContextImpl;
|
||||
class MemoryOutputStream;
|
||||
|
||||
// Clear state from previous Run().
|
||||
void Clear();
|
||||
|
||||
// Remaps each file in input_files_ so that it is relative to one of the
|
||||
// directories in proto_path_. Returns false if an error occurred. This
|
||||
// is only used if inputs_are_proto_path_relative_ is false.
|
||||
bool MakeInputsBeProtoPathRelative(
|
||||
DiskSourceTree* source_tree);
|
||||
|
||||
// Parse all command-line arguments.
|
||||
bool ParseArguments(int argc, const char* const argv[]);
|
||||
|
||||
// Parses a command-line argument into a name/value pair. Returns
|
||||
// true if the next argument in the argv should be used as the value,
|
||||
// false otherwise.
|
||||
//
|
||||
// Exmaples:
|
||||
// "-Isrc/protos" ->
|
||||
// name = "-I", value = "src/protos"
|
||||
// "--cpp_out=src/foo.pb2.cc" ->
|
||||
// name = "--cpp_out", value = "src/foo.pb2.cc"
|
||||
// "foo.proto" ->
|
||||
// name = "", value = "foo.proto"
|
||||
bool ParseArgument(const char* arg, string* name, string* value);
|
||||
|
||||
// Interprets arguments parsed with ParseArgument.
|
||||
bool InterpretArgument(const string& name, const string& value);
|
||||
|
||||
// Print the --help text to stderr.
|
||||
void PrintHelpText();
|
||||
|
||||
// Generate the given output file from the given input.
|
||||
struct OutputDirective; // see below
|
||||
bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files,
|
||||
const OutputDirective& output_directive,
|
||||
GeneratorContext* generator_context);
|
||||
bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files,
|
||||
const string& plugin_name,
|
||||
const string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
string* error);
|
||||
|
||||
// Implements --encode and --decode.
|
||||
bool EncodeOrDecode(const DescriptorPool* pool);
|
||||
|
||||
// Implements the --descriptor_set_out option.
|
||||
bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files);
|
||||
|
||||
// Get all transitive dependencies of the given file (including the file
|
||||
// itself), adding them to the given list of FileDescriptorProtos. The
|
||||
// protos will be ordered such that every file is listed before any file that
|
||||
// depends on it, so that you can call DescriptorPool::BuildFile() on them
|
||||
// in order. Any files in *already_seen will not be added, and each file
|
||||
// added will be inserted into *already_seen.
|
||||
static void GetTransitiveDependencies(
|
||||
const FileDescriptor* file,
|
||||
set<const FileDescriptor*>* already_seen,
|
||||
RepeatedPtrField<FileDescriptorProto>* output);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// The name of the executable as invoked (i.e. argv[0]).
|
||||
string executable_name_;
|
||||
|
||||
// Version info set with SetVersionInfo().
|
||||
string version_info_;
|
||||
|
||||
// Map from flag names to registered generators.
|
||||
struct GeneratorInfo {
|
||||
CodeGenerator* generator;
|
||||
string help_text;
|
||||
};
|
||||
typedef map<string, GeneratorInfo> GeneratorMap;
|
||||
GeneratorMap generators_;
|
||||
|
||||
// See AllowPlugins(). If this is empty, plugins aren't allowed.
|
||||
string plugin_prefix_;
|
||||
|
||||
// Maps specific plugin names to files. When executing a plugin, this map
|
||||
// is searched first to find the plugin executable. If not found here, the
|
||||
// PATH (or other OS-specific search strategy) is searched.
|
||||
map<string, string> plugins_;
|
||||
|
||||
// Stuff parsed from command line.
|
||||
enum Mode {
|
||||
MODE_COMPILE, // Normal mode: parse .proto files and compile them.
|
||||
MODE_ENCODE, // --encode: read text from stdin, write binary to stdout.
|
||||
MODE_DECODE // --decode: read binary from stdin, write text to stdout.
|
||||
};
|
||||
|
||||
Mode mode_;
|
||||
|
||||
enum ErrorFormat {
|
||||
ERROR_FORMAT_GCC, // GCC error output format (default).
|
||||
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
|
||||
};
|
||||
|
||||
ErrorFormat error_format_;
|
||||
|
||||
vector<pair<string, string> > proto_path_; // Search path for proto files.
|
||||
vector<string> input_files_; // Names of the input proto files.
|
||||
|
||||
// output_directives_ lists all the files we are supposed to output and what
|
||||
// generator to use for each.
|
||||
struct OutputDirective {
|
||||
string name; // E.g. "--foo_out"
|
||||
CodeGenerator* generator; // NULL for plugins
|
||||
string parameter;
|
||||
string output_location;
|
||||
};
|
||||
vector<OutputDirective> output_directives_;
|
||||
|
||||
// When using --encode or --decode, this names the type we are encoding or
|
||||
// decoding. (Empty string indicates --decode_raw.)
|
||||
string codec_type_;
|
||||
|
||||
// If --descriptor_set_out was given, this is the filename to which the
|
||||
// FileDescriptorSet should be written. Otherwise, empty.
|
||||
string descriptor_set_name_;
|
||||
|
||||
// True if --include_imports was given, meaning that we should
|
||||
// write all transitive dependencies to the DescriptorSet. Otherwise, only
|
||||
// the .proto files listed on the command-line are added.
|
||||
bool imports_in_descriptor_set_;
|
||||
|
||||
// Was the --disallow_services flag used?
|
||||
bool disallow_services_;
|
||||
|
||||
// See SetInputsAreProtoPathRelative().
|
||||
bool inputs_are_proto_path_relative_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
@ -0,0 +1,258 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
: descriptor_(descriptor),
|
||||
classname_(ClassName(descriptor, false)),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
}
|
||||
|
||||
EnumGenerator::~EnumGenerator() {}
|
||||
|
||||
void EnumGenerator::GenerateDefinition(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["classname"] = classname_;
|
||||
vars["short_name"] = descriptor_->name();
|
||||
|
||||
printer->Print(vars, "enum $classname$ {\n");
|
||||
printer->Indent();
|
||||
|
||||
const EnumValueDescriptor* min_value = descriptor_->value(0);
|
||||
const EnumValueDescriptor* max_value = descriptor_->value(0);
|
||||
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
vars["name"] = descriptor_->value(i)->name();
|
||||
vars["number"] = SimpleItoa(descriptor_->value(i)->number());
|
||||
vars["prefix"] = (descriptor_->containing_type() == NULL) ?
|
||||
"" : classname_ + "_";
|
||||
|
||||
if (i > 0) printer->Print(",\n");
|
||||
printer->Print(vars, "$prefix$$name$ = $number$");
|
||||
|
||||
if (descriptor_->value(i)->number() < min_value->number()) {
|
||||
min_value = descriptor_->value(i);
|
||||
}
|
||||
if (descriptor_->value(i)->number() > max_value->number()) {
|
||||
max_value = descriptor_->value(i);
|
||||
}
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print("\n};\n");
|
||||
|
||||
vars["min_name"] = min_value->name();
|
||||
vars["max_name"] = max_value->name();
|
||||
|
||||
if (dllexport_decl_.empty()) {
|
||||
vars["dllexport"] = "";
|
||||
} else {
|
||||
vars["dllexport"] = dllexport_decl_ + " ";
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"$dllexport$bool $classname$_IsValid(int value);\n"
|
||||
"const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n"
|
||||
"const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n"
|
||||
"const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n"
|
||||
"\n");
|
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) {
|
||||
printer->Print(vars,
|
||||
"$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n");
|
||||
// The _Name and _Parse methods
|
||||
printer->Print(vars,
|
||||
"inline const ::std::string& $classname$_Name($classname$ value) {\n"
|
||||
" return ::google::protobuf::internal::NameOfEnum(\n"
|
||||
" $classname$_descriptor(), value);\n"
|
||||
"}\n");
|
||||
printer->Print(vars,
|
||||
"inline bool $classname$_Parse(\n"
|
||||
" const ::std::string& name, $classname$* value) {\n"
|
||||
" return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n"
|
||||
" $classname$_descriptor(), name, value);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void EnumGenerator::
|
||||
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) {
|
||||
if (HasDescriptorMethods(descriptor_->file())) {
|
||||
printer->Print(
|
||||
"template <>\n"
|
||||
"inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n"
|
||||
" return $classname$_descriptor();\n"
|
||||
"}\n",
|
||||
"classname", ClassName(descriptor_, true));
|
||||
}
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateSymbolImports(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["nested_name"] = descriptor_->name();
|
||||
vars["classname"] = classname_;
|
||||
printer->Print(vars, "typedef $classname$ $nested_name$;\n");
|
||||
|
||||
for (int j = 0; j < descriptor_->value_count(); j++) {
|
||||
vars["tag"] = descriptor_->value(j)->name();
|
||||
printer->Print(vars,
|
||||
"static const $nested_name$ $tag$ = $classname$_$tag$;\n");
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"static inline bool $nested_name$_IsValid(int value) {\n"
|
||||
" return $classname$_IsValid(value);\n"
|
||||
"}\n"
|
||||
"static const $nested_name$ $nested_name$_MIN =\n"
|
||||
" $classname$_$nested_name$_MIN;\n"
|
||||
"static const $nested_name$ $nested_name$_MAX =\n"
|
||||
" $classname$_$nested_name$_MAX;\n"
|
||||
"static const int $nested_name$_ARRAYSIZE =\n"
|
||||
" $classname$_$nested_name$_ARRAYSIZE;\n");
|
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) {
|
||||
printer->Print(vars,
|
||||
"static inline const ::google::protobuf::EnumDescriptor*\n"
|
||||
"$nested_name$_descriptor() {\n"
|
||||
" return $classname$_descriptor();\n"
|
||||
"}\n");
|
||||
printer->Print(vars,
|
||||
"static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n"
|
||||
" return $classname$_Name(value);\n"
|
||||
"}\n");
|
||||
printer->Print(vars,
|
||||
"static inline bool $nested_name$_Parse(const ::std::string& name,\n"
|
||||
" $nested_name$* value) {\n"
|
||||
" return $classname$_Parse(name, value);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateDescriptorInitializer(
|
||||
io::Printer* printer, int index) {
|
||||
map<string, string> vars;
|
||||
vars["classname"] = classname_;
|
||||
vars["index"] = SimpleItoa(index);
|
||||
|
||||
if (descriptor_->containing_type() == NULL) {
|
||||
printer->Print(vars,
|
||||
"$classname$_descriptor_ = file->enum_type($index$);\n");
|
||||
} else {
|
||||
vars["parent"] = ClassName(descriptor_->containing_type(), false);
|
||||
printer->Print(vars,
|
||||
"$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void EnumGenerator::GenerateMethods(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["classname"] = classname_;
|
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) {
|
||||
printer->Print(vars,
|
||||
"const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n"
|
||||
" protobuf_AssignDescriptorsOnce();\n"
|
||||
" return $classname$_descriptor_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"bool $classname$_IsValid(int value) {\n"
|
||||
" switch(value) {\n");
|
||||
|
||||
// Multiple values may have the same number. Make sure we only cover
|
||||
// each number once by first constructing a set containing all valid
|
||||
// numbers, then printing a case statement for each element.
|
||||
|
||||
set<int> numbers;
|
||||
for (int j = 0; j < descriptor_->value_count(); j++) {
|
||||
const EnumValueDescriptor* value = descriptor_->value(j);
|
||||
numbers.insert(value->number());
|
||||
}
|
||||
|
||||
for (set<int>::iterator iter = numbers.begin();
|
||||
iter != numbers.end(); ++iter) {
|
||||
printer->Print(
|
||||
" case $number$:\n",
|
||||
"number", SimpleItoa(*iter));
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
" return true;\n"
|
||||
" default:\n"
|
||||
" return false;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
|
||||
if (descriptor_->containing_type() != NULL) {
|
||||
// We need to "define" the static constants which were declared in the
|
||||
// header, to give the linker a place to put them. Or at least the C++
|
||||
// standard says we have to. MSVC actually insists tha we do _not_ define
|
||||
// them again in the .cc file.
|
||||
printer->Print("#ifndef _MSC_VER\n");
|
||||
|
||||
vars["parent"] = ClassName(descriptor_->containing_type(), false);
|
||||
vars["nested_name"] = descriptor_->name();
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) {
|
||||
vars["value"] = descriptor_->value(i)->name();
|
||||
printer->Print(vars,
|
||||
"const $classname$ $parent$::$value$;\n");
|
||||
}
|
||||
printer->Print(vars,
|
||||
"const $classname$ $parent$::$nested_name$_MIN;\n"
|
||||
"const $classname$ $parent$::$nested_name$_MAX;\n"
|
||||
"const int $parent$::$nested_name$_ARRAYSIZE;\n");
|
||||
|
||||
printer->Print("#endif // _MSC_VER\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,99 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class EnumGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit EnumGenerator(const EnumDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
~EnumGenerator();
|
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate header code defining the enum. This code should be placed
|
||||
// within the enum's package namespace, but NOT within any class, even for
|
||||
// nested enums.
|
||||
void GenerateDefinition(io::Printer* printer);
|
||||
|
||||
// Generate specialization of GetEnumDescriptor<MyEnum>().
|
||||
// Precondition: in ::google::protobuf namespace.
|
||||
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
|
||||
|
||||
// For enums nested within a message, generate code to import all the enum's
|
||||
// symbols (e.g. the enum type name, all its values, etc.) into the class's
|
||||
// namespace. This should be placed inside the class definition in the
|
||||
// header.
|
||||
void GenerateSymbolImports(io::Printer* printer);
|
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code that initializes the global variable storing the enum's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index);
|
||||
|
||||
// Generate non-inline methods related to the enum, such as IsValidValue().
|
||||
// Goes in the .cc file.
|
||||
void GenerateMethods(io::Printer* printer);
|
||||
|
||||
private:
|
||||
const EnumDescriptor* descriptor_;
|
||||
string classname_;
|
||||
string dllexport_decl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
@ -0,0 +1,361 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
const EnumValueDescriptor* default_value = descriptor->default_value_enum();
|
||||
(*variables)["type"] = ClassName(descriptor->enum_type(), true);
|
||||
(*variables)["default"] = SimpleItoa(default_value->number());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator::
|
||||
EnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "int $name$_;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $name$() const$deprecation$;\n"
|
||||
"inline void set_$name$($type$ value)$deprecation$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
" return static_cast< $type$ >($name$_);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" set_has_$name$();\n"
|
||||
" $name$_ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "set_$name$(from.$name$());\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"int value;\n"
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
|
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
|
||||
" input, &value)));\n"
|
||||
"if ($type$_IsValid(value)) {\n"
|
||||
" set_$name$(static_cast< $type$ >(value));\n");
|
||||
if (HasUnknownFields(descriptor_->file())) {
|
||||
printer->Print(variables_,
|
||||
"} else {\n"
|
||||
" mutable_unknown_fields()->AddVarint($number$, value);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
|
||||
" $number$, this->$name$(), output);\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
|
||||
" $number$, this->$name$(), target);\n");
|
||||
}
|
||||
|
||||
void EnumFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator::
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetEnumVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::RepeatedField<int> $name$_;\n");
|
||||
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
|
||||
printer->Print(variables_,
|
||||
"mutable int _$name$_cached_byte_size_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $name$(int index) const$deprecation$;\n"
|
||||
"inline void set_$name$(int index, $type$ value)$deprecation$;\n"
|
||||
"inline void add_$name$($type$ value)$deprecation$;\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n"
|
||||
"inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $classname$::$name$(int index) const {\n"
|
||||
" return static_cast< $type$ >($name$_.Get(index));\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" $name$_.Set(index, value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$($type$ value) {\n"
|
||||
" GOOGLE_DCHECK($type$_IsValid(value));\n"
|
||||
" $name$_.Add(value);\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedField<int>&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::google::protobuf::RepeatedField<int>*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
" return &$name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
// Don't use ReadRepeatedPrimitive here so that the enum can be validated.
|
||||
printer->Print(variables_,
|
||||
"int value;\n"
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
|
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
|
||||
" input, &value)));\n"
|
||||
"if ($type$_IsValid(value)) {\n"
|
||||
" add_$name$(static_cast< $type$ >(value));\n");
|
||||
if (HasUnknownFields(descriptor_->file())) {
|
||||
printer->Print(variables_,
|
||||
"} else {\n"
|
||||
" mutable_unknown_fields()->AddVarint($number$, value);\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
|
||||
if (!descriptor_->options().packed()) {
|
||||
// We use a non-inlined implementation in this case, since this path will
|
||||
// rarely be executed.
|
||||
printer->Print(variables_,
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
|
||||
" input,\n"
|
||||
" &$type$_IsValid,\n"
|
||||
" this->mutable_$name$())));\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::uint32 length;\n"
|
||||
"DO_(input->ReadVarint32(&length));\n"
|
||||
"::google::protobuf::io::CodedInputStream::Limit limit = "
|
||||
"input->PushLimit(length);\n"
|
||||
"while (input->BytesUntilLimit() > 0) {\n"
|
||||
" int value;\n"
|
||||
" DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
|
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
|
||||
" input, &value)));\n"
|
||||
" if ($type$_IsValid(value)) {\n"
|
||||
" add_$name$(static_cast< $type$ >(value));\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"input->PopLimit(limit);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
// Write the tag and the size.
|
||||
printer->Print(variables_,
|
||||
"if (this->$name$_size() > 0) {\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::WriteTag(\n"
|
||||
" $number$,\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
|
||||
" output);\n"
|
||||
" output->WriteVarint32(_$name$_cached_byte_size_);\n"
|
||||
"}\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n"
|
||||
" this->$name$(i), output);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormatLite::WriteEnum(\n"
|
||||
" $number$, this->$name$(i), output);\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
// Write the tag and the size.
|
||||
printer->Print(variables_,
|
||||
"if (this->$name$_size() > 0) {\n"
|
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
|
||||
" $number$,\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
|
||||
" target);\n"
|
||||
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray("
|
||||
" _$name$_cached_byte_size_, target);\n"
|
||||
"}\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n"
|
||||
" this->$name$(i), target);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n"
|
||||
" $number$, this->$name$(i), target);\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"{\n"
|
||||
" int data_size = 0;\n");
|
||||
printer->Indent();
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n"
|
||||
" this->$name$(i));\n"
|
||||
"}\n");
|
||||
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (data_size > 0) {\n"
|
||||
" total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
|
||||
"}\n"
|
||||
"_$name$_cached_byte_size_ = data_size;\n"
|
||||
"total_size += data_size;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ * this->$name$_size() + data_size;\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,103 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class EnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~EnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~RepeatedEnumFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
@ -0,0 +1,210 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_extension.h>
|
||||
#include <map>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the fully-qualified class name of the message that this field
|
||||
// extends. This function is used in the Google-internal code to handle some
|
||||
// legacy cases.
|
||||
string ExtendeeClassName(const FieldDescriptor* descriptor) {
|
||||
const Descriptor* extendee = descriptor->containing_type();
|
||||
return ClassName(extendee, true);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
: descriptor_(descriptor),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
// Construct type_traits_.
|
||||
if (descriptor_->is_repeated()) {
|
||||
type_traits_ = "Repeated";
|
||||
}
|
||||
|
||||
switch (descriptor_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
type_traits_.append("EnumTypeTraits< ");
|
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true));
|
||||
type_traits_.append(", ");
|
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true));
|
||||
type_traits_.append("_IsValid>");
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
type_traits_.append("StringTypeTraits");
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
type_traits_.append("MessageTypeTraits< ");
|
||||
type_traits_.append(ClassName(descriptor_->message_type(), true));
|
||||
type_traits_.append(" >");
|
||||
break;
|
||||
default:
|
||||
type_traits_.append("PrimitiveTypeTraits< ");
|
||||
type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type()));
|
||||
type_traits_.append(" >");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ExtensionGenerator::~ExtensionGenerator() {}
|
||||
|
||||
void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["extendee" ] = ExtendeeClassName(descriptor_);
|
||||
vars["number" ] = SimpleItoa(descriptor_->number());
|
||||
vars["type_traits" ] = type_traits_;
|
||||
vars["name" ] = descriptor_->name();
|
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
|
||||
vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
|
||||
vars["constant_name"] = FieldConstantName(descriptor_);
|
||||
|
||||
// If this is a class member, it needs to be declared "static". Otherwise,
|
||||
// it needs to be "extern". In the latter case, it also needs the DLL
|
||||
// export/import specifier.
|
||||
if (descriptor_->extension_scope() == NULL) {
|
||||
vars["qualifier"] = "extern";
|
||||
if (!dllexport_decl_.empty()) {
|
||||
vars["qualifier"] = dllexport_decl_ + " " + vars["qualifier"];
|
||||
}
|
||||
} else {
|
||||
vars["qualifier"] = "static";
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"static const int $constant_name$ = $number$;\n"
|
||||
"$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
|
||||
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
|
||||
" $name$;\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateDefinition(io::Printer* printer) {
|
||||
// If this is a class member, it needs to be declared in its class scope.
|
||||
string scope = (descriptor_->extension_scope() == NULL) ? "" :
|
||||
ClassName(descriptor_->extension_scope(), false) + "::";
|
||||
string name = scope + descriptor_->name();
|
||||
|
||||
map<string, string> vars;
|
||||
vars["extendee" ] = ExtendeeClassName(descriptor_);
|
||||
vars["type_traits" ] = type_traits_;
|
||||
vars["name" ] = name;
|
||||
vars["constant_name"] = FieldConstantName(descriptor_);
|
||||
vars["default" ] = DefaultValue(descriptor_);
|
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
|
||||
vars["packed" ] = descriptor_->options().packed() ? "true" : "false";
|
||||
vars["scope" ] = scope;
|
||||
|
||||
if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
// We need to declare a global string which will contain the default value.
|
||||
// We cannot declare it at class scope because that would require exposing
|
||||
// it in the header which would be annoying for other reasons. So we
|
||||
// replace :: with _ in the name and declare it as a global.
|
||||
string global_name = StringReplace(name, "::", "_", true);
|
||||
vars["global_name"] = global_name;
|
||||
printer->Print(vars,
|
||||
"const ::std::string $global_name$_default($default$);\n");
|
||||
|
||||
// Update the default to refer to the string global.
|
||||
vars["default"] = global_name + "_default";
|
||||
}
|
||||
|
||||
// Likewise, class members need to declare the field constant variable.
|
||||
if (descriptor_->extension_scope() != NULL) {
|
||||
printer->Print(vars,
|
||||
"#ifndef _MSC_VER\n"
|
||||
"const int $scope$$constant_name$;\n"
|
||||
"#endif\n");
|
||||
}
|
||||
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n"
|
||||
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n"
|
||||
" $name$($constant_name$, $default$);\n");
|
||||
}
|
||||
|
||||
void ExtensionGenerator::GenerateRegistration(io::Printer* printer) {
|
||||
map<string, string> vars;
|
||||
vars["extendee" ] = ExtendeeClassName(descriptor_);
|
||||
vars["number" ] = SimpleItoa(descriptor_->number());
|
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type()));
|
||||
vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false";
|
||||
vars["is_packed" ] = (descriptor_->is_repeated() &&
|
||||
descriptor_->options().packed())
|
||||
? "true" : "false";
|
||||
|
||||
switch (descriptor_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n"
|
||||
" &$extendee$::default_instance(),\n"
|
||||
" $number$, $field_type$, $is_repeated$, $is_packed$,\n");
|
||||
printer->Print(
|
||||
" &$type$_IsValid);\n",
|
||||
"type", ClassName(descriptor_->enum_type(), true));
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n"
|
||||
" &$extendee$::default_instance(),\n"
|
||||
" $number$, $field_type$, $is_repeated$, $is_packed$,\n");
|
||||
printer->Print(
|
||||
" &$type$::default_instance());\n",
|
||||
"type", ClassName(descriptor_->message_type(), true));
|
||||
break;
|
||||
default:
|
||||
printer->Print(vars,
|
||||
"::google::protobuf::internal::ExtensionSet::RegisterExtension(\n"
|
||||
" &$extendee$::default_instance(),\n"
|
||||
" $number$, $field_type$, $is_repeated$, $is_packed$);\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,85 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class FieldDescriptor; // descriptor.h
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Generates code for an extension, which may be within the scope of some
|
||||
// message or may be at file scope. This is much simpler than FieldGenerator
|
||||
// since extensions are just simple identifiers with interesting types.
|
||||
class ExtensionGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ExtensionGenerator(const FieldDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
~ExtensionGenerator();
|
||||
|
||||
// Header stuff.
|
||||
void GenerateDeclaration(io::Printer* printer);
|
||||
|
||||
// Source file stuff.
|
||||
void GenerateDefinition(io::Printer* printer);
|
||||
|
||||
// Generate code to register the extension.
|
||||
void GenerateRegistration(io::Printer* printer);
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
string type_traits_;
|
||||
string dllexport_decl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
@ -0,0 +1,139 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
using internal::WireFormat;
|
||||
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
(*variables)["name"] = FieldName(descriptor);
|
||||
(*variables)["index"] = SimpleItoa(descriptor->index());
|
||||
(*variables)["number"] = SimpleItoa(descriptor->number());
|
||||
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
|
||||
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
|
||||
|
||||
(*variables)["tag_size"] = SimpleItoa(
|
||||
WireFormat::TagSize(descriptor->number(), descriptor->type()));
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated()
|
||||
? " PROTOBUF_DEPRECATED" : "";
|
||||
|
||||
}
|
||||
|
||||
FieldGenerator::~FieldGenerator() {}
|
||||
|
||||
void FieldGenerator::
|
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
|
||||
// Reaching here indicates a bug. Cases are:
|
||||
// - This FieldGenerator should support packing, but this method should be
|
||||
// overridden.
|
||||
// - This FieldGenerator doesn't support packing, and this method should
|
||||
// never have been called.
|
||||
GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() "
|
||||
<< "called on field generator that does not support packing.";
|
||||
|
||||
}
|
||||
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
|
||||
: descriptor_(descriptor),
|
||||
field_generators_(
|
||||
new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
|
||||
// Construct all the FieldGenerators.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i)));
|
||||
}
|
||||
}
|
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) {
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new RepeatedMessageFieldGenerator(field);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // RepeatedStringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING:
|
||||
return new RepeatedStringFieldGenerator(field);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new RepeatedEnumFieldGenerator(field);
|
||||
default:
|
||||
return new RepeatedPrimitiveFieldGenerator(field);
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new MessageFieldGenerator(field);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // StringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING:
|
||||
return new StringFieldGenerator(field);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new EnumFieldGenerator(field);
|
||||
default:
|
||||
return new PrimitiveFieldGenerator(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldGeneratorMap::~FieldGeneratorMap() {}
|
||||
|
||||
const FieldGenerator& FieldGeneratorMap::get(
|
||||
const FieldDescriptor* field) const {
|
||||
GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
|
||||
return *field_generators_[field->index()];
|
||||
}
|
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,167 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Helper function: set variables in the map that are the same for all
|
||||
// field code generators.
|
||||
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
|
||||
// 'deprecation'].
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables);
|
||||
|
||||
class FieldGenerator {
|
||||
public:
|
||||
FieldGenerator() {}
|
||||
virtual ~FieldGenerator();
|
||||
|
||||
// Generate lines of code declaring members fields of the message class
|
||||
// needed to represent this field. These are placed inside the message
|
||||
// class.
|
||||
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate prototypes for all of the accessor functions related to this
|
||||
// field. These are placed inside the class definition.
|
||||
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate inline definitions of accessor functions for this field.
|
||||
// These are placed inside the header after all class definitions.
|
||||
virtual void GenerateInlineAccessorDefinitions(
|
||||
io::Printer* printer) const = 0;
|
||||
|
||||
// Generate definitions of accessors that aren't inlined. These are
|
||||
// placed somewhere in the .cc file.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateNonInlineAccessorDefinitions(
|
||||
io::Printer* printer) const {}
|
||||
|
||||
// Generate lines of code (statements, not declarations) which clear the
|
||||
// field. This is used to define the clear_$name$() method as well as
|
||||
// the Clear() method for the whole message.
|
||||
virtual void GenerateClearingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines of code (statements, not declarations) which merges the
|
||||
// contents of the field from the current message to the target message,
|
||||
// which is stored in the generated code variable "from".
|
||||
// This is used to fill in the MergeFrom method for the whole message.
|
||||
// Details of this usage can be found in message.cc under the
|
||||
// GenerateMergeFrom method.
|
||||
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines of code (statements, not declarations) which swaps
|
||||
// this field and the corresponding field of another message, which
|
||||
// is stored in the generated code variable "other". This is used to
|
||||
// define the Swap method. Details of usage can be found in
|
||||
// message.cc under the GenerateSwap method.
|
||||
virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the message class's SharedCtor()
|
||||
// method, invoked by each of the generated constructors.
|
||||
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate any code that needs to go in the class's SharedDtor() method,
|
||||
// invoked by the destructor.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateDestructorCode(io::Printer* printer) const {}
|
||||
|
||||
// Generate lines to decode this field, which will be placed inside the
|
||||
// message's MergeFromCodedStream() method.
|
||||
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines to decode this field from a packed value, which will be
|
||||
// placed inside the message's MergeFromCodedStream() method.
|
||||
virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer)
|
||||
const;
|
||||
|
||||
// Generate lines to serialize this field, which are placed within the
|
||||
// message's SerializeWithCachedSizes() method.
|
||||
virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines to serialize this field directly to the array "target",
|
||||
// which are placed within the message's SerializeWithCachedSizesToArray()
|
||||
// method. This must also advance "target" past the written bytes.
|
||||
virtual void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const = 0;
|
||||
|
||||
// Generate lines to compute the serialized size of this field, which
|
||||
// are placed in the message's ByteSize() method.
|
||||
virtual void GenerateByteSize(io::Printer* printer) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
|
||||
};
|
||||
|
||||
// Convenience class which constructs FieldGenerators for a Descriptor.
|
||||
class FieldGeneratorMap {
|
||||
public:
|
||||
explicit FieldGeneratorMap(const Descriptor* descriptor);
|
||||
~FieldGeneratorMap();
|
||||
|
||||
const FieldGenerator& get(const FieldDescriptor* field) const;
|
||||
|
||||
private:
|
||||
const Descriptor* descriptor_;
|
||||
scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
|
||||
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
|
||||
};
|
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
@ -0,0 +1,611 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_file.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_service.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_extension.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_message.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileGenerator::FileGenerator(const FileDescriptor* file,
|
||||
const string& dllexport_decl)
|
||||
: file_(file),
|
||||
message_generators_(
|
||||
new scoped_ptr<MessageGenerator>[file->message_type_count()]),
|
||||
enum_generators_(
|
||||
new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
|
||||
service_generators_(
|
||||
new scoped_ptr<ServiceGenerator>[file->service_count()]),
|
||||
extension_generators_(
|
||||
new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
|
||||
dllexport_decl_(dllexport_decl) {
|
||||
|
||||
for (int i = 0; i < file->message_type_count(); i++) {
|
||||
message_generators_[i].reset(
|
||||
new MessageGenerator(file->message_type(i), dllexport_decl));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->enum_type_count(); i++) {
|
||||
enum_generators_[i].reset(
|
||||
new EnumGenerator(file->enum_type(i), dllexport_decl));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->service_count(); i++) {
|
||||
service_generators_[i].reset(
|
||||
new ServiceGenerator(file->service(i), dllexport_decl));
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->extension_count(); i++) {
|
||||
extension_generators_[i].reset(
|
||||
new ExtensionGenerator(file->extension(i), dllexport_decl));
|
||||
}
|
||||
|
||||
SplitStringUsing(file_->package(), ".", &package_parts_);
|
||||
}
|
||||
|
||||
FileGenerator::~FileGenerator() {}
|
||||
|
||||
void FileGenerator::GenerateHeader(io::Printer* printer) {
|
||||
string filename_identifier = FilenameIdentifier(file_->name());
|
||||
|
||||
// Generate top of header.
|
||||
printer->Print(
|
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
|
||||
"// source: $filename$\n"
|
||||
"\n"
|
||||
"#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n"
|
||||
"#define PROTOBUF_$filename_identifier$__INCLUDED\n"
|
||||
"\n"
|
||||
"#include <string>\n"
|
||||
"\n",
|
||||
"filename", file_->name(),
|
||||
"filename_identifier", filename_identifier);
|
||||
|
||||
printer->Print(
|
||||
"#include <google/protobuf/stubs/common.h>\n"
|
||||
"\n");
|
||||
|
||||
// Verify the protobuf library header version is compatible with the protoc
|
||||
// version before going any further.
|
||||
printer->Print(
|
||||
"#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n"
|
||||
"#error This file was generated by a newer version of protoc which is\n"
|
||||
"#error incompatible with your Protocol Buffer headers. Please update\n"
|
||||
"#error your headers.\n"
|
||||
"#endif\n"
|
||||
"#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n"
|
||||
"#error This file was generated by an older version of protoc which is\n"
|
||||
"#error incompatible with your Protocol Buffer headers. Please\n"
|
||||
"#error regenerate this file with a newer version of protoc.\n"
|
||||
"#endif\n"
|
||||
"\n",
|
||||
"min_header_version",
|
||||
SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc),
|
||||
"protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION));
|
||||
|
||||
// OK, it's now safe to #include other files.
|
||||
printer->Print(
|
||||
"#include <google/protobuf/generated_message_util.h>\n"
|
||||
"#include <google/protobuf/repeated_field.h>\n"
|
||||
"#include <google/protobuf/extension_set.h>\n");
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/generated_message_reflection.h>\n");
|
||||
}
|
||||
|
||||
if (HasGenericServices(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/service.h>\n");
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < file_->dependency_count(); i++) {
|
||||
printer->Print(
|
||||
"#include \"$dependency$.pb.h\"\n",
|
||||
"dependency", StripProto(file_->dependency(i)->name()));
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"// @@protoc_insertion_point(includes)\n");
|
||||
|
||||
// Open namespace.
|
||||
GenerateNamespaceOpeners(printer);
|
||||
|
||||
// Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
|
||||
// functions, so that we can declare them to be friends of each class.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// Internal implementation detail -- do not call these.\n"
|
||||
"void $dllexport_decl$ $adddescriptorsname$();\n",
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
|
||||
"dllexport_decl", dllexport_decl_);
|
||||
|
||||
printer->Print(
|
||||
// Note that we don't put dllexport_decl on these because they are only
|
||||
// called by the .pb.cc file in which they are defined.
|
||||
"void $assigndescriptorsname$();\n"
|
||||
"void $shutdownfilename$();\n"
|
||||
"\n",
|
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()),
|
||||
"shutdownfilename", GlobalShutdownFileName(file_->name()));
|
||||
|
||||
// Generate forward declarations of classes.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateForwardDeclaration(printer);
|
||||
}
|
||||
|
||||
printer->Print("\n");
|
||||
|
||||
// Generate enum definitions.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateEnumDefinitions(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
enum_generators_[i]->GenerateDefinition(printer);
|
||||
}
|
||||
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
|
||||
// Generate class definitions.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
if (i > 0) {
|
||||
printer->Print("\n");
|
||||
printer->Print(kThinSeparator);
|
||||
printer->Print("\n");
|
||||
}
|
||||
message_generators_[i]->GenerateClassDefinition(printer);
|
||||
}
|
||||
|
||||
printer->Print("\n");
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
|
||||
if (HasGenericServices(file_)) {
|
||||
// Generate service definitions.
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
if (i > 0) {
|
||||
printer->Print("\n");
|
||||
printer->Print(kThinSeparator);
|
||||
printer->Print("\n");
|
||||
}
|
||||
service_generators_[i]->GenerateDeclarations(printer);
|
||||
}
|
||||
|
||||
printer->Print("\n");
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
}
|
||||
|
||||
// Declare extension identifiers.
|
||||
for (int i = 0; i < file_->extension_count(); i++) {
|
||||
extension_generators_[i]->GenerateDeclaration(printer);
|
||||
}
|
||||
|
||||
printer->Print("\n");
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
|
||||
// Generate class inline methods.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
if (i > 0) {
|
||||
printer->Print(kThinSeparator);
|
||||
printer->Print("\n");
|
||||
}
|
||||
message_generators_[i]->GenerateInlineMethods(printer);
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// @@protoc_insertion_point(namespace_scope)\n");
|
||||
|
||||
// Close up namespace.
|
||||
GenerateNamespaceClosers(printer);
|
||||
|
||||
// Emit GetEnumDescriptor specializations into google::protobuf namespace:
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
// The SWIG conditional is to avoid a null-pointer dereference
|
||||
// (bug 1984964) in swig-1.3.21 resulting from the following syntax:
|
||||
// namespace X { void Y<Z::W>(); }
|
||||
// which appears in GetEnumDescriptor() specializations.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"#ifndef SWIG\n"
|
||||
"namespace google {\nnamespace protobuf {\n"
|
||||
"\n");
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer);
|
||||
}
|
||||
printer->Print(
|
||||
"\n"
|
||||
"} // namespace google\n} // namespace protobuf\n"
|
||||
"#endif // SWIG\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// @@protoc_insertion_point(global_scope)\n"
|
||||
"\n");
|
||||
|
||||
printer->Print(
|
||||
"#endif // PROTOBUF_$filename_identifier$__INCLUDED\n",
|
||||
"filename_identifier", filename_identifier);
|
||||
}
|
||||
|
||||
void FileGenerator::GenerateSource(io::Printer* printer) {
|
||||
printer->Print(
|
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
|
||||
"\n"
|
||||
|
||||
// The generated code calls accessors that might be deprecated. We don't
|
||||
// want the compiler to warn in generated code.
|
||||
"#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n"
|
||||
"#include \"$basename$.pb.h\"\n"
|
||||
"\n"
|
||||
"#include <algorithm>\n" // for swap()
|
||||
"\n"
|
||||
"#include <google/protobuf/stubs/once.h>\n"
|
||||
"#include <google/protobuf/io/coded_stream.h>\n"
|
||||
"#include <google/protobuf/wire_format_lite_inl.h>\n",
|
||||
"basename", StripProto(file_->name()));
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"#include <google/protobuf/descriptor.h>\n"
|
||||
"#include <google/protobuf/reflection_ops.h>\n"
|
||||
"#include <google/protobuf/wire_format.h>\n");
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"// @@protoc_insertion_point(includes)\n");
|
||||
|
||||
GenerateNamespaceOpeners(printer);
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"\n"
|
||||
"namespace {\n"
|
||||
"\n");
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateDescriptorDeclarations(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
printer->Print(
|
||||
"const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n",
|
||||
"name", ClassName(file_->enum_type(i), false));
|
||||
}
|
||||
|
||||
if (HasGenericServices(file_)) {
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
printer->Print(
|
||||
"const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n",
|
||||
"name", file_->service(i)->name());
|
||||
}
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"} // namespace\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
// Define our externally-visible BuildDescriptors() function. (For the lite
|
||||
// library, all this does is initialize default instances.)
|
||||
GenerateBuildDescriptors(printer);
|
||||
|
||||
// Generate enums.
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
enum_generators_[i]->GenerateMethods(printer);
|
||||
}
|
||||
|
||||
// Generate classes.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
printer->Print("\n");
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
message_generators_[i]->GenerateClassMethods(printer);
|
||||
}
|
||||
|
||||
if (HasGenericServices(file_)) {
|
||||
// Generate services.
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
if (i == 0) printer->Print("\n");
|
||||
printer->Print(kThickSeparator);
|
||||
printer->Print("\n");
|
||||
service_generators_[i]->GenerateImplementation(printer);
|
||||
}
|
||||
}
|
||||
|
||||
// Define extensions.
|
||||
for (int i = 0; i < file_->extension_count(); i++) {
|
||||
extension_generators_[i]->GenerateDefinition(printer);
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// @@protoc_insertion_point(namespace_scope)\n");
|
||||
|
||||
GenerateNamespaceClosers(printer);
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// @@protoc_insertion_point(global_scope)\n");
|
||||
}
|
||||
|
||||
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
|
||||
// AddDescriptors() is a file-level procedure which adds the encoded
|
||||
// FileDescriptorProto for this .proto file to the global DescriptorPool
|
||||
// for generated files (DescriptorPool::generated_pool()). It always runs
|
||||
// at static initialization time, so all files will be registered before
|
||||
// main() starts. This procedure also constructs default instances and
|
||||
// registers extensions.
|
||||
//
|
||||
// Its sibling, AssignDescriptors(), actually pulls the compiled
|
||||
// FileDescriptor from the DescriptorPool and uses it to populate all of
|
||||
// the global variables which store pointers to the descriptor objects.
|
||||
// It also constructs the reflection objects. It is called the first time
|
||||
// anyone calls descriptor() or GetReflection() on one of the types defined
|
||||
// in the file.
|
||||
|
||||
// In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
|
||||
// and we only use AddDescriptors() to allocate default instances.
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
printer->Print(
|
||||
"\n"
|
||||
"void $assigndescriptorsname$() {\n",
|
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
|
||||
printer->Indent();
|
||||
|
||||
// Make sure the file has found its way into the pool. If a descriptor
|
||||
// is requested *during* static init then AddDescriptors() may not have
|
||||
// been called yet, so we call it manually. Note that it's fine if
|
||||
// AddDescriptors() is called multiple times.
|
||||
printer->Print(
|
||||
"$adddescriptorsname$();\n",
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
|
||||
|
||||
// Get the file's descriptor from the pool.
|
||||
printer->Print(
|
||||
"const ::google::protobuf::FileDescriptor* file =\n"
|
||||
" ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n"
|
||||
" \"$filename$\");\n"
|
||||
// Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
|
||||
// being unused when compiling an empty .proto file.
|
||||
"GOOGLE_CHECK(file != NULL);\n",
|
||||
"filename", file_->name());
|
||||
|
||||
// Go through all the stuff defined in this file and generated code to
|
||||
// assign the global descriptor pointers based on the file descriptor.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateDescriptorInitializer(printer, i);
|
||||
}
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) {
|
||||
enum_generators_[i]->GenerateDescriptorInitializer(printer, i);
|
||||
}
|
||||
if (HasGenericServices(file_)) {
|
||||
for (int i = 0; i < file_->service_count(); i++) {
|
||||
service_generators_[i]->GenerateDescriptorInitializer(printer, i);
|
||||
}
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n"
|
||||
"\n");
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// protobuf_AssignDescriptorsOnce(): The first time it is called, calls
|
||||
// AssignDescriptors(). All later times, waits for the first call to
|
||||
// complete and then returns.
|
||||
printer->Print(
|
||||
"namespace {\n"
|
||||
"\n"
|
||||
"GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n"
|
||||
"inline void protobuf_AssignDescriptorsOnce() {\n"
|
||||
" ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n"
|
||||
" &$assigndescriptorsname$);\n"
|
||||
"}\n"
|
||||
"\n",
|
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()));
|
||||
|
||||
// protobuf_RegisterTypes(): Calls
|
||||
// MessageFactory::InternalRegisterGeneratedType() for each message type.
|
||||
printer->Print(
|
||||
"void protobuf_RegisterTypes(const ::std::string&) {\n"
|
||||
" protobuf_AssignDescriptorsOnce();\n");
|
||||
printer->Indent();
|
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateTypeRegistrations(printer);
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n"
|
||||
"\n"
|
||||
"} // namespace\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"void $shutdownfilename$() {\n",
|
||||
"shutdownfilename", GlobalShutdownFileName(file_->name()));
|
||||
printer->Indent();
|
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateShutdownCode(printer);
|
||||
}
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"}\n");
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// Now generate the AddDescriptors() function.
|
||||
printer->Print(
|
||||
"\n"
|
||||
"void $adddescriptorsname$() {\n"
|
||||
// We don't need any special synchronization here because this code is
|
||||
// called at static init time before any threads exist.
|
||||
" static bool already_here = false;\n"
|
||||
" if (already_here) return;\n"
|
||||
" already_here = true;\n"
|
||||
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n"
|
||||
"\n",
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()));
|
||||
printer->Indent();
|
||||
|
||||
// Call the AddDescriptors() methods for all of our dependencies, to make
|
||||
// sure they get added first.
|
||||
for (int i = 0; i < file_->dependency_count(); i++) {
|
||||
const FileDescriptor* dependency = file_->dependency(i);
|
||||
// Print the namespace prefix for the dependency.
|
||||
vector<string> dependency_package_parts;
|
||||
SplitStringUsing(dependency->package(), ".", &dependency_package_parts);
|
||||
printer->Print("::");
|
||||
for (int i = 0; i < dependency_package_parts.size(); i++) {
|
||||
printer->Print("$name$::",
|
||||
"name", dependency_package_parts[i]);
|
||||
}
|
||||
// Call its AddDescriptors function.
|
||||
printer->Print(
|
||||
"$name$();\n",
|
||||
"name", GlobalAddDescriptorsName(dependency->name()));
|
||||
}
|
||||
|
||||
if (HasDescriptorMethods(file_)) {
|
||||
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
|
||||
// and embed it as a string literal, which is parsed and built into real
|
||||
// descriptors at initialization time.
|
||||
FileDescriptorProto file_proto;
|
||||
file_->CopyTo(&file_proto);
|
||||
string file_data;
|
||||
file_proto.SerializeToString(&file_data);
|
||||
|
||||
printer->Print(
|
||||
"::google::protobuf::DescriptorPool::InternalAddGeneratedFile(");
|
||||
|
||||
// Only write 40 bytes per line.
|
||||
static const int kBytesPerLine = 40;
|
||||
for (int i = 0; i < file_data.size(); i += kBytesPerLine) {
|
||||
printer->Print("\n \"$data$\"",
|
||||
"data", EscapeTrigraphs(CEscape(file_data.substr(i, kBytesPerLine))));
|
||||
}
|
||||
printer->Print(
|
||||
", $size$);\n",
|
||||
"size", SimpleItoa(file_data.size()));
|
||||
|
||||
// Call MessageFactory::InternalRegisterGeneratedFile().
|
||||
printer->Print(
|
||||
"::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n"
|
||||
" \"$filename$\", &protobuf_RegisterTypes);\n",
|
||||
"filename", file_->name());
|
||||
}
|
||||
|
||||
// Allocate and initialize default instances. This can't be done lazily
|
||||
// since default instances are returned by simple accessors and are used with
|
||||
// extensions. Speaking of which, we also register extensions at this time.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateDefaultInstanceAllocator(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->extension_count(); i++) {
|
||||
extension_generators_[i]->GenerateRegistration(printer);
|
||||
}
|
||||
for (int i = 0; i < file_->message_type_count(); i++) {
|
||||
message_generators_[i]->GenerateDefaultInstanceInitializer(printer);
|
||||
}
|
||||
|
||||
printer->Print(
|
||||
"::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n",
|
||||
"shutdownfilename", GlobalShutdownFileName(file_->name()));
|
||||
|
||||
printer->Outdent();
|
||||
|
||||
printer->Print(
|
||||
"}\n"
|
||||
"\n"
|
||||
"// Force AddDescriptors() to be called at static initialization time.\n"
|
||||
"struct StaticDescriptorInitializer_$filename$ {\n"
|
||||
" StaticDescriptorInitializer_$filename$() {\n"
|
||||
" $adddescriptorsname$();\n"
|
||||
" }\n"
|
||||
"} static_descriptor_initializer_$filename$_;\n"
|
||||
"\n",
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
|
||||
"filename", FilenameIdentifier(file_->name()));
|
||||
}
|
||||
|
||||
void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) {
|
||||
if (package_parts_.size() > 0) printer->Print("\n");
|
||||
|
||||
for (int i = 0; i < package_parts_.size(); i++) {
|
||||
printer->Print("namespace $part$ {\n",
|
||||
"part", package_parts_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) {
|
||||
if (package_parts_.size() > 0) printer->Print("\n");
|
||||
|
||||
for (int i = package_parts_.size() - 1; i >= 0; i--) {
|
||||
printer->Print("} // namespace $part$\n",
|
||||
"part", package_parts_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,98 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class FileDescriptor; // descriptor.h
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class EnumGenerator; // enum.h
|
||||
class MessageGenerator; // message.h
|
||||
class ServiceGenerator; // service.h
|
||||
class ExtensionGenerator; // extension.h
|
||||
|
||||
class FileGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit FileGenerator(const FileDescriptor* file,
|
||||
const string& dllexport_decl);
|
||||
~FileGenerator();
|
||||
|
||||
void GenerateHeader(io::Printer* printer);
|
||||
void GenerateSource(io::Printer* printer);
|
||||
|
||||
private:
|
||||
// Generate the BuildDescriptors() procedure, which builds all descriptors
|
||||
// for types defined in the file.
|
||||
void GenerateBuildDescriptors(io::Printer* printer);
|
||||
|
||||
void GenerateNamespaceOpeners(io::Printer* printer);
|
||||
void GenerateNamespaceClosers(io::Printer* printer);
|
||||
|
||||
const FileDescriptor* file_;
|
||||
|
||||
scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
|
||||
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
|
||||
scoped_array<scoped_ptr<ServiceGenerator> > service_generators_;
|
||||
scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
|
||||
|
||||
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
|
||||
vector<string> package_parts_;
|
||||
|
||||
string dllexport_decl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
@ -0,0 +1,122 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h>
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_file.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
CppGenerator::CppGenerator() {}
|
||||
CppGenerator::~CppGenerator() {}
|
||||
|
||||
bool CppGenerator::Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const {
|
||||
vector<pair<string, string> > options;
|
||||
ParseGeneratorParameter(parameter, &options);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// parse generator options
|
||||
|
||||
// TODO(kenton): If we ever have more options, we may want to create a
|
||||
// class that encapsulates them which we can pass down to all the
|
||||
// generator classes. Currently we pass dllexport_decl down to all of
|
||||
// them via the constructors, but we don't want to have to add another
|
||||
// constructor parameter for every option.
|
||||
|
||||
// If the dllexport_decl option is passed to the compiler, we need to write
|
||||
// it in front of every symbol that should be exported if this .proto is
|
||||
// compiled into a Windows DLL. E.g., if the user invokes the protocol
|
||||
// compiler as:
|
||||
// protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto
|
||||
// then we'll define classes like this:
|
||||
// class FOO_EXPORT Foo {
|
||||
// ...
|
||||
// }
|
||||
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
|
||||
// __declspec(dllimport) depending on what is being compiled.
|
||||
string dllexport_decl;
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
if (options[i].first == "dllexport_decl") {
|
||||
dllexport_decl = options[i].second;
|
||||
} else {
|
||||
*error = "Unknown generator option: " + options[i].first;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
string basename = StripProto(file->name());
|
||||
basename.append(".pb");
|
||||
|
||||
FileGenerator file_generator(file, dllexport_decl);
|
||||
|
||||
// Generate header.
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
generator_context->Open(basename + ".h"));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.GenerateHeader(&printer);
|
||||
}
|
||||
|
||||
// Generate cc file.
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
generator_context->Open(basename + ".cc"));
|
||||
io::Printer printer(output.get(), '$');
|
||||
file_generator.GenerateSource(&printer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,72 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Generates C++ code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// CodeGenerator implementation which generates a C++ source file and
|
||||
// header. If you create your own protocol compiler binary and you want
|
||||
// it to support C++ output, you can do so by registering an instance of this
|
||||
// CodeGenerator with the CommandLineInterface in your main() function.
|
||||
class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator {
|
||||
public:
|
||||
CppGenerator();
|
||||
~CppGenerator();
|
||||
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
GeneratorContext* generator_context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
@ -0,0 +1,347 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
string DotsToUnderscores(const string& name) {
|
||||
return StringReplace(name, ".", "_", true);
|
||||
}
|
||||
|
||||
string DotsToColons(const string& name) {
|
||||
return StringReplace(name, ".", "::", true);
|
||||
}
|
||||
|
||||
const char* const kKeywordList[] = {
|
||||
"and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
|
||||
"catch", "char", "class", "compl", "const", "const_cast", "continue",
|
||||
"default", "delete", "do", "double", "dynamic_cast", "else", "enum",
|
||||
"explicit", "extern", "false", "float", "for", "friend", "goto", "if",
|
||||
"inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
|
||||
"operator", "or", "or_eq", "private", "protected", "public", "register",
|
||||
"reinterpret_cast", "return", "short", "signed", "sizeof", "static",
|
||||
"static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
|
||||
"typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
|
||||
"void", "volatile", "wchar_t", "while", "xor", "xor_eq"
|
||||
};
|
||||
|
||||
hash_set<string> MakeKeywordsMap() {
|
||||
hash_set<string> result;
|
||||
for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
|
||||
result.insert(kKeywordList[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
hash_set<string> kKeywords = MakeKeywordsMap();
|
||||
|
||||
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
|
||||
string result;
|
||||
// Note: I distrust ctype.h due to locales.
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
if ('a' <= input[i] && input[i] <= 'z') {
|
||||
if (cap_next_letter) {
|
||||
result += input[i] + ('A' - 'a');
|
||||
} else {
|
||||
result += input[i];
|
||||
}
|
||||
cap_next_letter = false;
|
||||
} else if ('A' <= input[i] && input[i] <= 'Z') {
|
||||
// Capital letters are left as-is.
|
||||
result += input[i];
|
||||
cap_next_letter = false;
|
||||
} else if ('0' <= input[i] && input[i] <= '9') {
|
||||
result += input[i];
|
||||
cap_next_letter = true;
|
||||
} else {
|
||||
cap_next_letter = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const char kThickSeparator[] =
|
||||
"// ===================================================================\n";
|
||||
const char kThinSeparator[] =
|
||||
"// -------------------------------------------------------------------\n";
|
||||
|
||||
string ClassName(const Descriptor* descriptor, bool qualified) {
|
||||
|
||||
// Find "outer", the descriptor of the top-level message in which
|
||||
// "descriptor" is embedded.
|
||||
const Descriptor* outer = descriptor;
|
||||
while (outer->containing_type() != NULL) outer = outer->containing_type();
|
||||
|
||||
const string& outer_name = outer->full_name();
|
||||
string inner_name = descriptor->full_name().substr(outer_name.size());
|
||||
|
||||
if (qualified) {
|
||||
return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
|
||||
} else {
|
||||
return outer->name() + DotsToUnderscores(inner_name);
|
||||
}
|
||||
}
|
||||
|
||||
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
|
||||
if (enum_descriptor->containing_type() == NULL) {
|
||||
if (qualified) {
|
||||
return DotsToColons(enum_descriptor->full_name());
|
||||
} else {
|
||||
return enum_descriptor->name();
|
||||
}
|
||||
} else {
|
||||
string result = ClassName(enum_descriptor->containing_type(), qualified);
|
||||
result += '_';
|
||||
result += enum_descriptor->name();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string SuperClassName(const Descriptor* descriptor) {
|
||||
return HasDescriptorMethods(descriptor->file()) ?
|
||||
"::google::protobuf::Message" : "::google::protobuf::MessageLite";
|
||||
}
|
||||
|
||||
string FieldName(const FieldDescriptor* field) {
|
||||
string result = field->name();
|
||||
LowerString(&result);
|
||||
if (kKeywords.count(result) > 0) {
|
||||
result.append("_");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string FieldConstantName(const FieldDescriptor *field) {
|
||||
string field_name = UnderscoresToCamelCase(field->name(), true);
|
||||
string result = "k" + field_name + "FieldNumber";
|
||||
|
||||
if (!field->is_extension() &&
|
||||
field->containing_type()->FindFieldByCamelcaseName(
|
||||
field->camelcase_name()) != field) {
|
||||
// This field's camelcase name is not unique. As a hack, add the field
|
||||
// number to the constant name. This makes the constant rather useless,
|
||||
// but what can we do?
|
||||
result += "_" + SimpleItoa(field->number());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
string FieldMessageTypeName(const FieldDescriptor* field) {
|
||||
// Note: The Google-internal version of Protocol Buffers uses this function
|
||||
// as a hook point for hacks to support legacy code.
|
||||
return ClassName(field->message_type(), true);
|
||||
}
|
||||
|
||||
string StripProto(const string& filename) {
|
||||
if (HasSuffixString(filename, ".protodevel")) {
|
||||
return StripSuffixString(filename, ".protodevel");
|
||||
} else {
|
||||
return StripSuffixString(filename, ".proto");
|
||||
}
|
||||
}
|
||||
|
||||
const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
|
||||
switch (type) {
|
||||
case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
|
||||
case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
|
||||
case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
|
||||
case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
|
||||
case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
|
||||
case FieldDescriptor::CPPTYPE_FLOAT : return "float";
|
||||
case FieldDescriptor::CPPTYPE_BOOL : return "bool";
|
||||
case FieldDescriptor::CPPTYPE_ENUM : return "int";
|
||||
case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
|
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// CppTypes are added.
|
||||
}
|
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
|
||||
switch (type) {
|
||||
case FieldDescriptor::TYPE_INT32 : return "Int32";
|
||||
case FieldDescriptor::TYPE_INT64 : return "Int64";
|
||||
case FieldDescriptor::TYPE_UINT32 : return "UInt32";
|
||||
case FieldDescriptor::TYPE_UINT64 : return "UInt64";
|
||||
case FieldDescriptor::TYPE_SINT32 : return "SInt32";
|
||||
case FieldDescriptor::TYPE_SINT64 : return "SInt64";
|
||||
case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
|
||||
case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
|
||||
case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
|
||||
case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
|
||||
case FieldDescriptor::TYPE_FLOAT : return "Float";
|
||||
case FieldDescriptor::TYPE_DOUBLE : return "Double";
|
||||
|
||||
case FieldDescriptor::TYPE_BOOL : return "Bool";
|
||||
case FieldDescriptor::TYPE_ENUM : return "Enum";
|
||||
|
||||
case FieldDescriptor::TYPE_STRING : return "String";
|
||||
case FieldDescriptor::TYPE_BYTES : return "Bytes";
|
||||
case FieldDescriptor::TYPE_GROUP : return "Group";
|
||||
case FieldDescriptor::TYPE_MESSAGE : return "Message";
|
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
}
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
return "";
|
||||
}
|
||||
|
||||
string DefaultValue(const FieldDescriptor* field) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_INT32:
|
||||
return SimpleItoa(field->default_value_int32());
|
||||
case FieldDescriptor::CPPTYPE_UINT32:
|
||||
return SimpleItoa(field->default_value_uint32()) + "u";
|
||||
case FieldDescriptor::CPPTYPE_INT64:
|
||||
return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
|
||||
case FieldDescriptor::CPPTYPE_UINT64:
|
||||
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
|
||||
case FieldDescriptor::CPPTYPE_DOUBLE: {
|
||||
double value = field->default_value_double();
|
||||
if (value == numeric_limits<double>::infinity()) {
|
||||
return "::google::protobuf::internal::Infinity()";
|
||||
} else if (value == -numeric_limits<double>::infinity()) {
|
||||
return "-::google::protobuf::internal::Infinity()";
|
||||
} else if (value != value) {
|
||||
return "::google::protobuf::internal::NaN()";
|
||||
} else {
|
||||
return SimpleDtoa(value);
|
||||
}
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_FLOAT:
|
||||
{
|
||||
float value = field->default_value_float();
|
||||
if (value == numeric_limits<float>::infinity()) {
|
||||
return "static_cast<float>(::google::protobuf::internal::Infinity())";
|
||||
} else if (value == -numeric_limits<float>::infinity()) {
|
||||
return "static_cast<float>(-::google::protobuf::internal::Infinity())";
|
||||
} else if (value != value) {
|
||||
return "static_cast<float>(::google::protobuf::internal::NaN())";
|
||||
} else {
|
||||
string float_value = SimpleFtoa(value);
|
||||
// If floating point value contains a period (.) or an exponent
|
||||
// (either E or e), then append suffix 'f' to make it a float
|
||||
// literal.
|
||||
if (float_value.find_first_of(".eE") != string::npos) {
|
||||
float_value.push_back('f');
|
||||
}
|
||||
return float_value;
|
||||
}
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_BOOL:
|
||||
return field->default_value_bool() ? "true" : "false";
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
// Lazy: Generate a static_cast because we don't have a helper function
|
||||
// that constructs the full name of an enum value.
|
||||
return strings::Substitute(
|
||||
"static_cast< $0 >($1)",
|
||||
ClassName(field->enum_type(), true),
|
||||
field->default_value_enum()->number());
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return "\"" + EscapeTrigraphs(CEscape(field->default_value_string())) +
|
||||
"\"";
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return FieldMessageTypeName(field) + "::default_instance()";
|
||||
}
|
||||
// Can't actually get here; make compiler happy. (We could add a default
|
||||
// case above but then we wouldn't get the nice compiler warning when a
|
||||
// new type is added.)
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
return "";
|
||||
}
|
||||
|
||||
// Convert a file name into a valid identifier.
|
||||
string FilenameIdentifier(const string& filename) {
|
||||
string result;
|
||||
for (int i = 0; i < filename.size(); i++) {
|
||||
if (ascii_isalnum(filename[i])) {
|
||||
result.push_back(filename[i]);
|
||||
} else {
|
||||
// Not alphanumeric. To avoid any possibility of name conflicts we
|
||||
// use the hex code for the character.
|
||||
result.push_back('_');
|
||||
char buffer[kFastToBufferSize];
|
||||
result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return the name of the AddDescriptors() function for a given file.
|
||||
string GlobalAddDescriptorsName(const string& filename) {
|
||||
return "protobuf_AddDesc_" + FilenameIdentifier(filename);
|
||||
}
|
||||
|
||||
// Return the name of the AssignDescriptors() function for a given file.
|
||||
string GlobalAssignDescriptorsName(const string& filename) {
|
||||
return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
|
||||
}
|
||||
|
||||
// Return the name of the ShutdownFile() function for a given file.
|
||||
string GlobalShutdownFileName(const string& filename) {
|
||||
return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
|
||||
}
|
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape) {
|
||||
return StringReplace(to_escape, "?", "\\?", true);
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,159 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
// Commonly-used separator comments. Thick is a line of '=', thin is a line
|
||||
// of '-'.
|
||||
extern const char kThickSeparator[];
|
||||
extern const char kThinSeparator[];
|
||||
|
||||
// Returns the non-nested type name for the given type. If "qualified" is
|
||||
// true, prefix the type with the full namespace. For example, if you had:
|
||||
// package foo.bar;
|
||||
// message Baz { message Qux {} }
|
||||
// Then the qualified ClassName for Qux would be:
|
||||
// ::foo::bar::Baz_Qux
|
||||
// While the non-qualified version would be:
|
||||
// Baz_Qux
|
||||
string ClassName(const Descriptor* descriptor, bool qualified);
|
||||
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified);
|
||||
|
||||
string SuperClassName(const Descriptor* descriptor);
|
||||
|
||||
// Get the (unqualified) name that should be used for this field in C++ code.
|
||||
// The name is coerced to lower-case to emulate proto1 behavior. People
|
||||
// should be using lowercase-with-underscores style for proto field names
|
||||
// anyway, so normally this just returns field->name().
|
||||
string FieldName(const FieldDescriptor* field);
|
||||
|
||||
// Get the unqualified name that should be used for a field's field
|
||||
// number constant.
|
||||
string FieldConstantName(const FieldDescriptor *field);
|
||||
|
||||
// Returns the scope where the field was defined (for extensions, this is
|
||||
// different from the message type to which the field applies).
|
||||
inline const Descriptor* FieldScope(const FieldDescriptor* field) {
|
||||
return field->is_extension() ?
|
||||
field->extension_scope() : field->containing_type();
|
||||
}
|
||||
|
||||
// Returns the fully-qualified type name field->message_type(). Usually this
|
||||
// is just ClassName(field->message_type(), true);
|
||||
string FieldMessageTypeName(const FieldDescriptor* field);
|
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
string StripProto(const string& filename);
|
||||
|
||||
// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
|
||||
// Note: non-built-in type names will be qualified, meaning they will start
|
||||
// with a ::. If you are using the type as a template parameter, you will
|
||||
// need to insure there is a space between the < and the ::, because the
|
||||
// ridiculous C++ standard defines "<:" to be a synonym for "[".
|
||||
const char* PrimitiveTypeName(FieldDescriptor::CppType type);
|
||||
|
||||
// Get the declared type name in CamelCase format, as is used e.g. for the
|
||||
// methods of WireFormat. For example, TYPE_INT32 becomes "Int32".
|
||||
const char* DeclaredTypeMethodName(FieldDescriptor::Type type);
|
||||
|
||||
// Get code that evaluates to the field's default value.
|
||||
string DefaultValue(const FieldDescriptor* field);
|
||||
|
||||
// Convert a file name into a valid identifier.
|
||||
string FilenameIdentifier(const string& filename);
|
||||
|
||||
// Return the name of the AddDescriptors() function for a given file.
|
||||
string GlobalAddDescriptorsName(const string& filename);
|
||||
|
||||
// Return the name of the AssignDescriptors() function for a given file.
|
||||
string GlobalAssignDescriptorsName(const string& filename);
|
||||
|
||||
// Return the name of the ShutdownFile() function for a given file.
|
||||
string GlobalShutdownFileName(const string& filename);
|
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape);
|
||||
|
||||
// Do message classes in this file keep track of unknown fields?
|
||||
inline bool HasUnknownFields(const FileDescriptor *file) {
|
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
// Does this file have generated parsing, serialization, and other
|
||||
// standard methods for which reflection-based fallback implementations exist?
|
||||
inline bool HasGeneratedMethods(const FileDescriptor *file) {
|
||||
return file->options().optimize_for() != FileOptions::CODE_SIZE;
|
||||
}
|
||||
|
||||
// Do message classes in this file have descriptor and refelction methods?
|
||||
inline bool HasDescriptorMethods(const FileDescriptor *file) {
|
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
// Should we generate generic services for this file?
|
||||
inline bool HasGenericServices(const FileDescriptor *file) {
|
||||
return file->service_count() > 0 &&
|
||||
file->options().optimize_for() != FileOptions::LITE_RUNTIME &&
|
||||
file->options().cc_generic_services();
|
||||
}
|
||||
|
||||
// Should string fields in this file verify that their contents are UTF-8?
|
||||
inline bool HasUtf8Verification(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
|
||||
}
|
||||
|
||||
// Should we generate a separate, super-optimized code path for serializing to
|
||||
// flat arrays? We don't do this in Lite mode because we'd rather reduce code
|
||||
// size.
|
||||
inline bool HasFastArraySerialization(const FileDescriptor* file) {
|
||||
return file->options().optimize_for() == FileOptions::SPEED;
|
||||
}
|
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,170 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class EnumGenerator; // enum.h
|
||||
class ExtensionGenerator; // extension.h
|
||||
|
||||
class MessageGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit MessageGenerator(const Descriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
~MessageGenerator();
|
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate foward declarations for this class and all its nested types.
|
||||
void GenerateForwardDeclaration(io::Printer* printer);
|
||||
|
||||
// Generate definitions of all nested enums (must come before class
|
||||
// definitions because those classes use the enums definitions).
|
||||
void GenerateEnumDefinitions(io::Printer* printer);
|
||||
|
||||
// Generate specializations of GetEnumDescriptor<MyEnum>().
|
||||
// Precondition: in ::google::protobuf namespace.
|
||||
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer);
|
||||
|
||||
// Generate definitions for this class and all its nested types.
|
||||
void GenerateClassDefinition(io::Printer* printer);
|
||||
|
||||
// Generate definitions of inline methods (placed at the end of the header
|
||||
// file).
|
||||
void GenerateInlineMethods(io::Printer* printer);
|
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code which declares all the global descriptor pointers which
|
||||
// will be initialized by the methods below.
|
||||
void GenerateDescriptorDeclarations(io::Printer* printer);
|
||||
|
||||
// Generate code that initializes the global variable storing the message's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index);
|
||||
|
||||
// Generate code that calls MessageFactory::InternalRegisterGeneratedMessage()
|
||||
// for all types.
|
||||
void GenerateTypeRegistrations(io::Printer* printer);
|
||||
|
||||
// Generates code that allocates the message's default instance.
|
||||
void GenerateDefaultInstanceAllocator(io::Printer* printer);
|
||||
|
||||
// Generates code that initializes the message's default instance. This
|
||||
// is separate from allocating because all default instances must be
|
||||
// allocated before any can be initialized.
|
||||
void GenerateDefaultInstanceInitializer(io::Printer* printer);
|
||||
|
||||
// Generates code that should be run when ShutdownProtobufLibrary() is called,
|
||||
// to delete all dynamically-allocated objects.
|
||||
void GenerateShutdownCode(io::Printer* printer);
|
||||
|
||||
// Generate all non-inline methods for this class.
|
||||
void GenerateClassMethods(io::Printer* printer);
|
||||
|
||||
private:
|
||||
// Generate declarations and definitions of accessors for fields.
|
||||
void GenerateFieldAccessorDeclarations(io::Printer* printer);
|
||||
void GenerateFieldAccessorDefinitions(io::Printer* printer);
|
||||
|
||||
// Generate the field offsets array.
|
||||
void GenerateOffsets(io::Printer* printer);
|
||||
|
||||
// Generate constructors and destructor.
|
||||
void GenerateStructors(io::Printer* printer);
|
||||
|
||||
// The compiler typically generates multiple copies of each constructor and
|
||||
// destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
|
||||
// Placing common code in a separate method reduces the generated code size.
|
||||
//
|
||||
// Generate the shared constructor code.
|
||||
void GenerateSharedConstructorCode(io::Printer* printer);
|
||||
// Generate the shared destructor code.
|
||||
void GenerateSharedDestructorCode(io::Printer* printer);
|
||||
|
||||
// Generate standard Message methods.
|
||||
void GenerateClear(io::Printer* printer);
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer);
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer);
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer);
|
||||
void GenerateSerializeWithCachedSizesBody(io::Printer* printer,
|
||||
bool to_array);
|
||||
void GenerateByteSize(io::Printer* printer);
|
||||
void GenerateMergeFrom(io::Printer* printer);
|
||||
void GenerateCopyFrom(io::Printer* printer);
|
||||
void GenerateSwap(io::Printer* printer);
|
||||
void GenerateIsInitialized(io::Printer* printer);
|
||||
|
||||
// Helpers for GenerateSerializeWithCachedSizes().
|
||||
void GenerateSerializeOneField(io::Printer* printer,
|
||||
const FieldDescriptor* field,
|
||||
bool unbounded);
|
||||
void GenerateSerializeOneExtensionRange(
|
||||
io::Printer* printer, const Descriptor::ExtensionRange* range,
|
||||
bool unbounded);
|
||||
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
string classname_;
|
||||
string dllexport_decl_;
|
||||
FieldGeneratorMap field_generators_;
|
||||
scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
|
||||
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
|
||||
scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
@ -0,0 +1,277 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
(*variables)["type"] = FieldMessageTypeName(descriptor);
|
||||
(*variables)["stream_writer"] = (*variables)["declared_type"] +
|
||||
(HasFastArraySerialization(descriptor->message_type()->file()) ?
|
||||
"MaybeToArray" :
|
||||
"");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator::
|
||||
MessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$type$* $name$_;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $name$() const$deprecation$;\n"
|
||||
"inline $type$* mutable_$name$()$deprecation$;\n"
|
||||
"inline $type$* release_$name$()$deprecation$;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $classname$::$name$() const {\n"
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$() {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == NULL) $name$_ = new $type$;\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::release_$name$() {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" $type$* temp = $name$_;\n"
|
||||
" $name$_ = NULL;\n"
|
||||
" return temp;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != NULL) $name$_->$type$::Clear();\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"mutable_$name$()->$type$::MergeFrom(from.$name$());\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = NULL;\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
|
||||
" input, mutable_$name$()));\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
|
||||
" $number$, input, mutable_$name$()));\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
|
||||
" $number$, this->$name$(), output);\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"target = ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" Write$declared_type$NoVirtualToArray(\n"
|
||||
" $number$, this->$name$(), target);\n");
|
||||
}
|
||||
|
||||
void MessageFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
|
||||
" this->$name$());\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator::
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetMessageVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $name$(int index) const$deprecation$;\n"
|
||||
"inline $type$* mutable_$name$(int index)$deprecation$;\n"
|
||||
"inline $type$* add_$name$()$deprecation$;\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
|
||||
" $name$() const$deprecation$;\n"
|
||||
"inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
|
||||
" mutable_$name$()$deprecation$;\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const $type$& $classname$::$name$(int index) const {\n"
|
||||
" return $name$_.Get(index);\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$(int index) {\n"
|
||||
" return $name$_.Mutable(index);\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::add_$name$() {\n"
|
||||
" return $name$_.Add();\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::google::protobuf::RepeatedPtrField< $type$ >*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
" return &$name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
|
||||
" input, add_$name$()));\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n"
|
||||
" $number$, input, add_$name$()));\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
|
||||
" $number$, this->$name$(i), output);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" target = ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" Write$declared_type$NoVirtualToArray(\n"
|
||||
" $number$, this->$name$(i), target);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedMessageFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ * this->$name$_size();\n"
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" total_size +=\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
|
||||
" this->$name$(i));\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,102 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class MessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~MessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~RepeatedMessageFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
@ -0,0 +1,382 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
using internal::WireFormatLite;
|
||||
|
||||
namespace {
|
||||
|
||||
// For encodings with fixed sizes, returns that size in bytes. Otherwise
|
||||
// returns -1.
|
||||
int FixedSize(FieldDescriptor::Type type) {
|
||||
switch (type) {
|
||||
case FieldDescriptor::TYPE_INT32 : return -1;
|
||||
case FieldDescriptor::TYPE_INT64 : return -1;
|
||||
case FieldDescriptor::TYPE_UINT32 : return -1;
|
||||
case FieldDescriptor::TYPE_UINT64 : return -1;
|
||||
case FieldDescriptor::TYPE_SINT32 : return -1;
|
||||
case FieldDescriptor::TYPE_SINT64 : return -1;
|
||||
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
|
||||
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
|
||||
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
|
||||
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
|
||||
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize;
|
||||
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize;
|
||||
|
||||
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
|
||||
case FieldDescriptor::TYPE_ENUM : return -1;
|
||||
|
||||
case FieldDescriptor::TYPE_STRING : return -1;
|
||||
case FieldDescriptor::TYPE_BYTES : return -1;
|
||||
case FieldDescriptor::TYPE_GROUP : return -1;
|
||||
case FieldDescriptor::TYPE_MESSAGE : return -1;
|
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
}
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type());
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
|
||||
int fixed_size = FixedSize(descriptor->type());
|
||||
if (fixed_size != -1) {
|
||||
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
|
||||
}
|
||||
(*variables)["wire_format_field_type"] =
|
||||
"::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name(
|
||||
static_cast<FieldDescriptorProto_Type>(descriptor->type()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator::
|
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$type$ $name$_;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $name$() const$deprecation$;\n"
|
||||
"inline void set_$name$($type$ value)$deprecation$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $classname$::$name$() const {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" $name$_ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "set_$name$(from.$name$());\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_ = $default$;\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
|
||||
" $type$, $wire_format_field_type$>(\n"
|
||||
" input, &$name$_)));\n"
|
||||
"set_has_$name$();\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormatLite::Write$declared_type$("
|
||||
"$number$, this->$name$(), output);\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray("
|
||||
"$number$, this->$name$(), target);\n");
|
||||
}
|
||||
|
||||
void PrimitiveFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
int fixed_size = FixedSize(descriptor_->type());
|
||||
if (fixed_size == -1) {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" this->$name$());\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ + $fixed_size$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetPrimitiveVariables(descriptor, &variables_);
|
||||
|
||||
if (descriptor->options().packed()) {
|
||||
variables_["packed_reader"] = "ReadPackedPrimitive";
|
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline";
|
||||
} else {
|
||||
variables_["packed_reader"] = "ReadPackedPrimitiveNoInline";
|
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitive";
|
||||
}
|
||||
}
|
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
|
||||
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) {
|
||||
printer->Print(variables_,
|
||||
"mutable int _$name$_cached_byte_size_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $name$(int index) const$deprecation$;\n"
|
||||
"inline void set_$name$(int index, $type$ value)$deprecation$;\n"
|
||||
"inline void add_$name$($type$ value)$deprecation$;\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedField< $type$ >&\n"
|
||||
" $name$() const$deprecation$;\n"
|
||||
"inline ::google::protobuf::RepeatedField< $type$ >*\n"
|
||||
" mutable_$name$()$deprecation$;\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline $type$ $classname$::$name$(int index) const {\n"
|
||||
" return $name$_.Get(index);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n"
|
||||
" $name$_.Set(index, value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$($type$ value) {\n"
|
||||
" $name$_.Add(value);\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedField< $type$ >&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::google::protobuf::RepeatedField< $type$ >*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
" return &$name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n"
|
||||
" $type$, $wire_format_field_type$>(\n"
|
||||
" $tag_size$, $tag$, input, this->mutable_$name$())));\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n"
|
||||
" $type$, $wire_format_field_type$>(\n"
|
||||
" input, this->mutable_$name$())));\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
// Write the tag and the size.
|
||||
printer->Print(variables_,
|
||||
"if (this->$name$_size() > 0) {\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::WriteTag("
|
||||
"$number$, "
|
||||
"::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, "
|
||||
"output);\n"
|
||||
" output->WriteVarint32(_$name$_cached_byte_size_);\n"
|
||||
"}\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n"
|
||||
" this->$name$(i), output);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
|
||||
" $number$, this->$name$(i), output);\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
if (descriptor_->options().packed()) {
|
||||
// Write the tag and the size.
|
||||
printer->Print(variables_,
|
||||
"if (this->$name$_size() > 0) {\n"
|
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n"
|
||||
" $number$,\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n"
|
||||
" target);\n"
|
||||
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n"
|
||||
" _$name$_cached_byte_size_, target);\n"
|
||||
"}\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
" target = ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" Write$declared_type$NoTagToArray(this->$name$(i), target);\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" target = ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n");
|
||||
}
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"{\n"
|
||||
" int data_size = 0;\n");
|
||||
printer->Indent();
|
||||
int fixed_size = FixedSize(descriptor_->type());
|
||||
if (fixed_size == -1) {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" data_size += ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" $declared_type$Size(this->$name$(i));\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"data_size = $fixed_size$ * this->$name$_size();\n");
|
||||
}
|
||||
|
||||
if (descriptor_->options().packed()) {
|
||||
printer->Print(variables_,
|
||||
"if (data_size > 0) {\n"
|
||||
" total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n"
|
||||
"}\n"
|
||||
"_$name$_cached_byte_size_ = data_size;\n"
|
||||
"total_size += data_size;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ * this->$name$_size() + data_size;\n");
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,103 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~PrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~RepeatedPrimitiveFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
@ -0,0 +1,334 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_service.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
|
||||
const string& dllexport_decl)
|
||||
: descriptor_(descriptor) {
|
||||
vars_["classname"] = descriptor_->name();
|
||||
vars_["full_name"] = descriptor_->full_name();
|
||||
if (dllexport_decl.empty()) {
|
||||
vars_["dllexport"] = "";
|
||||
} else {
|
||||
vars_["dllexport"] = dllexport_decl + " ";
|
||||
}
|
||||
}
|
||||
|
||||
ServiceGenerator::~ServiceGenerator() {}
|
||||
|
||||
void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
|
||||
// Forward-declare the stub type.
|
||||
printer->Print(vars_,
|
||||
"class $classname$_Stub;\n"
|
||||
"\n");
|
||||
|
||||
GenerateInterface(printer);
|
||||
GenerateStubDefinition(printer);
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateInterface(io::Printer* printer) {
|
||||
printer->Print(vars_,
|
||||
"class $dllexport$$classname$ : public ::google::protobuf::Service {\n"
|
||||
" protected:\n"
|
||||
" // This class should be treated as an abstract interface.\n"
|
||||
" inline $classname$() {};\n"
|
||||
" public:\n"
|
||||
" virtual ~$classname$();\n");
|
||||
printer->Indent();
|
||||
|
||||
printer->Print(vars_,
|
||||
"\n"
|
||||
"typedef $classname$_Stub Stub;\n"
|
||||
"\n"
|
||||
"static const ::google::protobuf::ServiceDescriptor* descriptor();\n"
|
||||
"\n");
|
||||
|
||||
GenerateMethodSignatures(VIRTUAL, printer);
|
||||
|
||||
printer->Print(
|
||||
"\n"
|
||||
"// implements Service ----------------------------------------------\n"
|
||||
"\n"
|
||||
"const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n"
|
||||
"void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
|
||||
" ::google::protobuf::RpcController* controller,\n"
|
||||
" const ::google::protobuf::Message* request,\n"
|
||||
" ::google::protobuf::Message* response,\n"
|
||||
" ::google::protobuf::Closure* done);\n"
|
||||
"const ::google::protobuf::Message& GetRequestPrototype(\n"
|
||||
" const ::google::protobuf::MethodDescriptor* method) const;\n"
|
||||
"const ::google::protobuf::Message& GetResponsePrototype(\n"
|
||||
" const ::google::protobuf::MethodDescriptor* method) const;\n");
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(vars_,
|
||||
"\n"
|
||||
" private:\n"
|
||||
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
|
||||
"};\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
|
||||
printer->Print(vars_,
|
||||
"class $dllexport$$classname$_Stub : public $classname$ {\n"
|
||||
" public:\n");
|
||||
|
||||
printer->Indent();
|
||||
|
||||
printer->Print(vars_,
|
||||
"$classname$_Stub(::google::protobuf::RpcChannel* channel);\n"
|
||||
"$classname$_Stub(::google::protobuf::RpcChannel* channel,\n"
|
||||
" ::google::protobuf::Service::ChannelOwnership ownership);\n"
|
||||
"~$classname$_Stub();\n"
|
||||
"\n"
|
||||
"inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n"
|
||||
"\n"
|
||||
"// implements $classname$ ------------------------------------------\n"
|
||||
"\n");
|
||||
|
||||
GenerateMethodSignatures(NON_VIRTUAL, printer);
|
||||
|
||||
printer->Outdent();
|
||||
printer->Print(vars_,
|
||||
" private:\n"
|
||||
" ::google::protobuf::RpcChannel* channel_;\n"
|
||||
" bool owns_channel_;\n"
|
||||
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n"
|
||||
"};\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateMethodSignatures(
|
||||
VirtualOrNon virtual_or_non, io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
map<string, string> sub_vars;
|
||||
sub_vars["name"] = method->name();
|
||||
sub_vars["input_type"] = ClassName(method->input_type(), true);
|
||||
sub_vars["output_type"] = ClassName(method->output_type(), true);
|
||||
sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : "";
|
||||
|
||||
printer->Print(sub_vars,
|
||||
"$virtual$void $name$(::google::protobuf::RpcController* controller,\n"
|
||||
" const $input_type$* request,\n"
|
||||
" $output_type$* response,\n"
|
||||
" ::google::protobuf::Closure* done);\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
void ServiceGenerator::GenerateDescriptorInitializer(
|
||||
io::Printer* printer, int index) {
|
||||
map<string, string> vars;
|
||||
vars["classname"] = descriptor_->name();
|
||||
vars["index"] = SimpleItoa(index);
|
||||
|
||||
printer->Print(vars,
|
||||
"$classname$_descriptor_ = file->service($index$);\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
|
||||
printer->Print(vars_,
|
||||
"$classname$::~$classname$() {}\n"
|
||||
"\n"
|
||||
"const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n"
|
||||
" protobuf_AssignDescriptorsOnce();\n"
|
||||
" return $classname$_descriptor_;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n"
|
||||
" protobuf_AssignDescriptorsOnce();\n"
|
||||
" return $classname$_descriptor_;\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
|
||||
// Generate methods of the interface.
|
||||
GenerateNotImplementedMethods(printer);
|
||||
GenerateCallMethod(printer);
|
||||
GenerateGetPrototype(REQUEST, printer);
|
||||
GenerateGetPrototype(RESPONSE, printer);
|
||||
|
||||
// Generate stub implementation.
|
||||
printer->Print(vars_,
|
||||
"$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n"
|
||||
" : channel_(channel), owns_channel_(false) {}\n"
|
||||
"$classname$_Stub::$classname$_Stub(\n"
|
||||
" ::google::protobuf::RpcChannel* channel,\n"
|
||||
" ::google::protobuf::Service::ChannelOwnership ownership)\n"
|
||||
" : channel_(channel),\n"
|
||||
" owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n"
|
||||
"$classname$_Stub::~$classname$_Stub() {\n"
|
||||
" if (owns_channel_) delete channel_;\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
|
||||
GenerateStubMethods(printer);
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
map<string, string> sub_vars;
|
||||
sub_vars["classname"] = descriptor_->name();
|
||||
sub_vars["name"] = method->name();
|
||||
sub_vars["index"] = SimpleItoa(i);
|
||||
sub_vars["input_type"] = ClassName(method->input_type(), true);
|
||||
sub_vars["output_type"] = ClassName(method->output_type(), true);
|
||||
|
||||
printer->Print(sub_vars,
|
||||
"void $classname$::$name$(::google::protobuf::RpcController* controller,\n"
|
||||
" const $input_type$*,\n"
|
||||
" $output_type$*,\n"
|
||||
" ::google::protobuf::Closure* done) {\n"
|
||||
" controller->SetFailed(\"Method $name$() not implemented.\");\n"
|
||||
" done->Run();\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
|
||||
printer->Print(vars_,
|
||||
"void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
|
||||
" ::google::protobuf::RpcController* controller,\n"
|
||||
" const ::google::protobuf::Message* request,\n"
|
||||
" ::google::protobuf::Message* response,\n"
|
||||
" ::google::protobuf::Closure* done) {\n"
|
||||
" GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
|
||||
" switch(method->index()) {\n");
|
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
map<string, string> sub_vars;
|
||||
sub_vars["name"] = method->name();
|
||||
sub_vars["index"] = SimpleItoa(i);
|
||||
sub_vars["input_type"] = ClassName(method->input_type(), true);
|
||||
sub_vars["output_type"] = ClassName(method->output_type(), true);
|
||||
|
||||
// Note: down_cast does not work here because it only works on pointers,
|
||||
// not references.
|
||||
printer->Print(sub_vars,
|
||||
" case $index$:\n"
|
||||
" $name$(controller,\n"
|
||||
" ::google::protobuf::down_cast<const $input_type$*>(request),\n"
|
||||
" ::google::protobuf::down_cast< $output_type$*>(response),\n"
|
||||
" done);\n"
|
||||
" break;\n");
|
||||
}
|
||||
|
||||
printer->Print(vars_,
|
||||
" default:\n"
|
||||
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
|
||||
io::Printer* printer) {
|
||||
if (which == REQUEST) {
|
||||
printer->Print(vars_,
|
||||
"const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
|
||||
} else {
|
||||
printer->Print(vars_,
|
||||
"const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n");
|
||||
}
|
||||
|
||||
printer->Print(vars_,
|
||||
" const ::google::protobuf::MethodDescriptor* method) const {\n"
|
||||
" GOOGLE_DCHECK_EQ(method->service(), descriptor());\n"
|
||||
" switch(method->index()) {\n");
|
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
const Descriptor* type =
|
||||
(which == REQUEST) ? method->input_type() : method->output_type();
|
||||
|
||||
map<string, string> sub_vars;
|
||||
sub_vars["index"] = SimpleItoa(i);
|
||||
sub_vars["type"] = ClassName(type, true);
|
||||
|
||||
printer->Print(sub_vars,
|
||||
" case $index$:\n"
|
||||
" return $type$::default_instance();\n");
|
||||
}
|
||||
|
||||
printer->Print(vars_,
|
||||
" default:\n"
|
||||
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
|
||||
" return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
|
||||
" }\n"
|
||||
"}\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) {
|
||||
const MethodDescriptor* method = descriptor_->method(i);
|
||||
map<string, string> sub_vars;
|
||||
sub_vars["classname"] = descriptor_->name();
|
||||
sub_vars["name"] = method->name();
|
||||
sub_vars["index"] = SimpleItoa(i);
|
||||
sub_vars["input_type"] = ClassName(method->input_type(), true);
|
||||
sub_vars["output_type"] = ClassName(method->output_type(), true);
|
||||
|
||||
printer->Print(sub_vars,
|
||||
"void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n"
|
||||
" const $input_type$* request,\n"
|
||||
" $output_type$* response,\n"
|
||||
" ::google::protobuf::Closure* done) {\n"
|
||||
" channel_->CallMethod(descriptor()->method($index$),\n"
|
||||
" controller, request, response, done);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,118 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class Printer; // printer.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class ServiceGenerator {
|
||||
public:
|
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ServiceGenerator(const ServiceDescriptor* descriptor,
|
||||
const string& dllexport_decl);
|
||||
~ServiceGenerator();
|
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate the class definitions for the service's interface and the
|
||||
// stub implementation.
|
||||
void GenerateDeclarations(io::Printer* printer);
|
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code that initializes the global variable storing the service's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index);
|
||||
|
||||
// Generate implementations of everything declared by GenerateDeclarations().
|
||||
void GenerateImplementation(io::Printer* printer);
|
||||
|
||||
private:
|
||||
enum RequestOrResponse { REQUEST, RESPONSE };
|
||||
enum VirtualOrNon { VIRTUAL, NON_VIRTUAL };
|
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate the service abstract interface.
|
||||
void GenerateInterface(io::Printer* printer);
|
||||
|
||||
// Generate the stub class definition.
|
||||
void GenerateStubDefinition(io::Printer* printer);
|
||||
|
||||
// Prints signatures for all methods in the
|
||||
void GenerateMethodSignatures(VirtualOrNon virtual_or_non,
|
||||
io::Printer* printer);
|
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate the default implementations of the service methods, which
|
||||
// produce a "not implemented" error.
|
||||
void GenerateNotImplementedMethods(io::Printer* printer);
|
||||
|
||||
// Generate the CallMethod() method of the service.
|
||||
void GenerateCallMethod(io::Printer* printer);
|
||||
|
||||
// Generate the Get{Request,Response}Prototype() methods.
|
||||
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer);
|
||||
|
||||
// Generate the stub's implementations of the service methods.
|
||||
void GenerateStubMethods(io::Printer* printer);
|
||||
|
||||
const ServiceDescriptor* descriptor_;
|
||||
map<string, string> vars_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
@ -0,0 +1,453 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
namespace {
|
||||
|
||||
void SetStringVariables(const FieldDescriptor* descriptor,
|
||||
map<string, string>* variables) {
|
||||
SetCommonFieldVariables(descriptor, variables);
|
||||
(*variables)["default"] = DefaultValue(descriptor);
|
||||
(*variables)["default_variable"] = descriptor->default_value_string().empty()
|
||||
? "::google::protobuf::internal::kEmptyString"
|
||||
: "_default_" + FieldName(descriptor) + "_";
|
||||
(*variables)["pointer_type"] =
|
||||
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator::
|
||||
StringFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetStringVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_, "::std::string* $name$_;\n");
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_, "static const ::std::string $default_variable$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
// If we're using StringFieldGenerator for a field with a ctype, it's
|
||||
// because that ctype isn't actually implemented. In particular, this is
|
||||
// true of ctype=CORD and ctype=STRING_PIECE in the open source release.
|
||||
// We aren't releasing Cord because it has too many Google-specific
|
||||
// dependencies and we aren't releasing StringPiece because it's hardly
|
||||
// useful outside of Google and because it would get confusing to have
|
||||
// multiple instances of the StringPiece class in different libraries (PCRE
|
||||
// already includes it for their C++ bindings, which came from Google).
|
||||
//
|
||||
// In any case, we make all the accessors private while still actually
|
||||
// using a string to represent the field internally. This way, we can
|
||||
// guarantee that if we do ever implement the ctype, it won't break any
|
||||
// existing users who might be -- for whatever reason -- already using .proto
|
||||
// files that applied the ctype. The field can still be accessed via the
|
||||
// reflection interface since the reflection interface is independent of
|
||||
// the string's underlying representation.
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) {
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
" private:\n"
|
||||
" // Hidden due to unknown ctype option.\n");
|
||||
printer->Indent();
|
||||
}
|
||||
|
||||
printer->Print(variables_,
|
||||
"inline const ::std::string& $name$() const$deprecation$;\n"
|
||||
"inline void set_$name$(const ::std::string& value)$deprecation$;\n"
|
||||
"inline void set_$name$(const char* value)$deprecation$;\n"
|
||||
"inline void set_$name$(const $pointer_type$* value, size_t size)"
|
||||
"$deprecation$;\n"
|
||||
"inline ::std::string* mutable_$name$()$deprecation$;\n"
|
||||
"inline ::std::string* release_$name$()$deprecation$;\n");
|
||||
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) {
|
||||
printer->Outdent();
|
||||
printer->Print(" public:\n");
|
||||
printer->Indent();
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const ::std::string& $classname$::$name$() const {\n"
|
||||
" return *$name$_;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(const ::std::string& value) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == &$default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(const char* value) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == &$default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(value);\n"
|
||||
"}\n"
|
||||
"inline "
|
||||
"void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == &$default_variable$) {\n"
|
||||
" $name$_ = new ::std::string;\n"
|
||||
" }\n"
|
||||
" $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::mutable_$name$() {\n"
|
||||
" set_has_$name$();\n"
|
||||
" if ($name$_ == &$default_variable$) {\n");
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
" $name$_ = new ::std::string;\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
" $name$_ = new ::std::string($default_variable$);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" }\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::release_$name$() {\n"
|
||||
" clear_has_$name$();\n"
|
||||
" if ($name$_ == &$default_variable$) {\n"
|
||||
" return NULL;\n"
|
||||
" } else {\n"
|
||||
" ::std::string* temp = $name$_;\n"
|
||||
" $name$_ = const_cast< ::std::string*>(&$default_variable$);\n"
|
||||
" return temp;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
if (!descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
"const ::std::string $classname$::$default_variable$($default$);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
if (descriptor_->default_value_string().empty()) {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &$default_variable$) {\n"
|
||||
" $name$_->clear();\n"
|
||||
"}\n");
|
||||
} else {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &$default_variable$) {\n"
|
||||
" $name$_->assign($default_variable$);\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "set_$name$(from.$name$());\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"$name$_ = const_cast< ::std::string*>(&$default_variable$);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateDestructorCode(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"if ($name$_ != &$default_variable$) {\n"
|
||||
" delete $name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
|
||||
" input, this->mutable_$name$()));\n");
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$().data(), this->$name$().length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::PARSE);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$().data(), this->$name$().length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
|
||||
" $number$, this->$name$(), output);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$().data(), this->$name$().length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
"target =\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n"
|
||||
" $number$, this->$name$(), target);\n");
|
||||
}
|
||||
|
||||
void StringFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ +\n"
|
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" this->$name$());\n");
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator::
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor)
|
||||
: descriptor_(descriptor) {
|
||||
SetStringVariables(descriptor, &variables_);
|
||||
}
|
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GeneratePrivateMembers(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::RepeatedPtrField< ::std::string> $name$_;\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateAccessorDeclarations(io::Printer* printer) const {
|
||||
// See comment above about unknown ctypes.
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) {
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
" private:\n"
|
||||
" // Hidden due to unknown ctype option.\n");
|
||||
printer->Indent();
|
||||
}
|
||||
|
||||
printer->Print(variables_,
|
||||
"inline const ::std::string& $name$(int index) const$deprecation$;\n"
|
||||
"inline ::std::string* mutable_$name$(int index)$deprecation$;\n"
|
||||
"inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n"
|
||||
"inline void set_$name$(int index, const char* value)$deprecation$;\n"
|
||||
"inline "
|
||||
"void set_$name$(int index, const $pointer_type$* value, size_t size)"
|
||||
"$deprecation$;\n"
|
||||
"inline ::std::string* add_$name$()$deprecation$;\n"
|
||||
"inline void add_$name$(const ::std::string& value)$deprecation$;\n"
|
||||
"inline void add_$name$(const char* value)$deprecation$;\n"
|
||||
"inline void add_$name$(const $pointer_type$* value, size_t size)"
|
||||
"$deprecation$;\n");
|
||||
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const"
|
||||
"$deprecation$;\n"
|
||||
"inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()"
|
||||
"$deprecation$;\n");
|
||||
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) {
|
||||
printer->Outdent();
|
||||
printer->Print(" public:\n");
|
||||
printer->Indent();
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"inline const ::std::string& $classname$::$name$(int index) const {\n"
|
||||
" return $name$_.Get(index);\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::mutable_$name$(int index) {\n"
|
||||
" return $name$_.Mutable(index);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, const ::std::string& value) {\n"
|
||||
" $name$_.Mutable(index)->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$(int index, const char* value) {\n"
|
||||
" $name$_.Mutable(index)->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void "
|
||||
"$classname$::set_$name$"
|
||||
"(int index, const $pointer_type$* value, size_t size) {\n"
|
||||
" $name$_.Mutable(index)->assign(\n"
|
||||
" reinterpret_cast<const char*>(value), size);\n"
|
||||
"}\n"
|
||||
"inline ::std::string* $classname$::add_$name$() {\n"
|
||||
" return $name$_.Add();\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$(const ::std::string& value) {\n"
|
||||
" $name$_.Add()->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void $classname$::add_$name$(const char* value) {\n"
|
||||
" $name$_.Add()->assign(value);\n"
|
||||
"}\n"
|
||||
"inline void "
|
||||
"$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
|
||||
" $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
|
||||
"}\n");
|
||||
printer->Print(variables_,
|
||||
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n"
|
||||
"$classname$::$name$() const {\n"
|
||||
" return $name$_;\n"
|
||||
"}\n"
|
||||
"inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n"
|
||||
"$classname$::mutable_$name$() {\n"
|
||||
" return &$name$_;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateClearingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Clear();\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateMergingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateSwappingCode(io::Printer* printer) const {
|
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateConstructorCode(io::Printer* printer) const {
|
||||
// Not needed for repeated fields.
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateMergeFromCodedStream(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
|
||||
" input, this->add_$name$()));\n");
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$(0).data(), this->$name$(0).length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::PARSE);\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$(i).data(), this->$name$(i).length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
|
||||
" $number$, this->$name$(i), output);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n");
|
||||
if (HasUtf8Verification(descriptor_->file()) &&
|
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
|
||||
printer->Print(variables_,
|
||||
" ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n"
|
||||
" this->$name$(i).data(), this->$name$(i).length(),\n"
|
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n");
|
||||
}
|
||||
printer->Print(variables_,
|
||||
" target = ::google::protobuf::internal::WireFormatLite::\n"
|
||||
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void RepeatedStringFieldGenerator::
|
||||
GenerateByteSize(io::Printer* printer) const {
|
||||
printer->Print(variables_,
|
||||
"total_size += $tag_size$ * this->$name$_size();\n"
|
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"
|
||||
" total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n"
|
||||
" this->$name$(i));\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,104 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace cpp {
|
||||
|
||||
class StringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~StringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateDestructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator);
|
||||
};
|
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor);
|
||||
~RepeatedStringFieldGenerator();
|
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const;
|
||||
void GenerateAccessorDeclarations(io::Printer* printer) const;
|
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
|
||||
void GenerateClearingCode(io::Printer* printer) const;
|
||||
void GenerateMergingCode(io::Printer* printer) const;
|
||||
void GenerateSwappingCode(io::Printer* printer) const;
|
||||
void GenerateConstructorCode(io::Printer* printer) const;
|
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
|
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
|
||||
void GenerateByteSize(io::Printer* printer) const;
|
||||
|
||||
private:
|
||||
const FieldDescriptor* descriptor_;
|
||||
map<string, string> variables_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,459 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/compiler/importer.h>
|
||||
|
||||
#include <google/protobuf/compiler/parser.h>
|
||||
#include <google/protobuf/io/tokenizer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef F_OK
|
||||
#define F_OK 00 // not defined by MSVC for whatever reason
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
// Returns true if the text looks like a Windows-style absolute path, starting
|
||||
// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with
|
||||
// copy in command_line_interface.cc?
|
||||
static bool IsWindowsAbsolutePath(const string& text) {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
return text.size() >= 3 && text[1] == ':' &&
|
||||
isalpha(text[0]) &&
|
||||
(text[2] == '/' || text[2] == '\\') &&
|
||||
text.find_last_of(':') == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
MultiFileErrorCollector::~MultiFileErrorCollector() {}
|
||||
|
||||
// This class serves two purposes:
|
||||
// - It implements the ErrorCollector interface (used by Tokenizer and Parser)
|
||||
// in terms of MultiFileErrorCollector, using a particular filename.
|
||||
// - It lets us check if any errors have occurred.
|
||||
class SourceTreeDescriptorDatabase::SingleFileErrorCollector
|
||||
: public io::ErrorCollector {
|
||||
public:
|
||||
SingleFileErrorCollector(const string& filename,
|
||||
MultiFileErrorCollector* multi_file_error_collector)
|
||||
: filename_(filename),
|
||||
multi_file_error_collector_(multi_file_error_collector),
|
||||
had_errors_(false) {}
|
||||
~SingleFileErrorCollector() {}
|
||||
|
||||
bool had_errors() { return had_errors_; }
|
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(int line, int column, const string& message) {
|
||||
if (multi_file_error_collector_ != NULL) {
|
||||
multi_file_error_collector_->AddError(filename_, line, column, message);
|
||||
}
|
||||
had_errors_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
string filename_;
|
||||
MultiFileErrorCollector* multi_file_error_collector_;
|
||||
bool had_errors_;
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
|
||||
SourceTree* source_tree)
|
||||
: source_tree_(source_tree),
|
||||
error_collector_(NULL),
|
||||
using_validation_error_collector_(false),
|
||||
validation_error_collector_(this) {}
|
||||
|
||||
SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
|
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileByName(
|
||||
const string& filename, FileDescriptorProto* output) {
|
||||
scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
|
||||
if (input == NULL) {
|
||||
if (error_collector_ != NULL) {
|
||||
error_collector_->AddError(filename, -1, 0, "File not found.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up the tokenizer and parser.
|
||||
SingleFileErrorCollector file_error_collector(filename, error_collector_);
|
||||
io::Tokenizer tokenizer(input.get(), &file_error_collector);
|
||||
|
||||
Parser parser;
|
||||
if (error_collector_ != NULL) {
|
||||
parser.RecordErrorsTo(&file_error_collector);
|
||||
}
|
||||
if (using_validation_error_collector_) {
|
||||
parser.RecordSourceLocationsTo(&source_locations_);
|
||||
}
|
||||
|
||||
// Parse it.
|
||||
output->set_name(filename);
|
||||
return parser.Parse(&tokenizer, output) &&
|
||||
!file_error_collector.had_errors();
|
||||
}
|
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name, FileDescriptorProto* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type, int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SourceTreeDescriptorDatabase::ValidationErrorCollector::
|
||||
ValidationErrorCollector(SourceTreeDescriptorDatabase* owner)
|
||||
: owner_(owner) {}
|
||||
|
||||
SourceTreeDescriptorDatabase::ValidationErrorCollector::
|
||||
~ValidationErrorCollector() {}
|
||||
|
||||
void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError(
|
||||
const string& filename,
|
||||
const string& element_name,
|
||||
const Message* descriptor,
|
||||
ErrorLocation location,
|
||||
const string& message) {
|
||||
if (owner_->error_collector_ == NULL) return;
|
||||
|
||||
int line, column;
|
||||
owner_->source_locations_.Find(descriptor, location, &line, &column);
|
||||
owner_->error_collector_->AddError(filename, line, column, message);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
Importer::Importer(SourceTree* source_tree,
|
||||
MultiFileErrorCollector* error_collector)
|
||||
: database_(source_tree),
|
||||
pool_(&database_, database_.GetValidationErrorCollector()) {
|
||||
database_.RecordErrorsTo(error_collector);
|
||||
}
|
||||
|
||||
Importer::~Importer() {}
|
||||
|
||||
const FileDescriptor* Importer::Import(const string& filename) {
|
||||
return pool_.FindFileByName(filename);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
SourceTree::~SourceTree() {}
|
||||
|
||||
DiskSourceTree::DiskSourceTree() {}
|
||||
|
||||
DiskSourceTree::~DiskSourceTree() {}
|
||||
|
||||
static inline char LastChar(const string& str) {
|
||||
return str[str.size() - 1];
|
||||
}
|
||||
|
||||
// Given a path, returns an equivalent path with these changes:
|
||||
// - On Windows, any backslashes are replaced with forward slashes.
|
||||
// - Any instances of the directory "." are removed.
|
||||
// - Any consecutive '/'s are collapsed into a single slash.
|
||||
// Note that the resulting string may be empty.
|
||||
//
|
||||
// TODO(kenton): It would be nice to handle "..", e.g. so that we can figure
|
||||
// out that "foo/bar.proto" is inside "baz/../foo". However, if baz is a
|
||||
// symlink or doesn't exist, then things get complicated, and we can't
|
||||
// actually determine this without investigating the filesystem, probably
|
||||
// in non-portable ways. So, we punt.
|
||||
//
|
||||
// TODO(kenton): It would be nice to use realpath() here except that it
|
||||
// resolves symbolic links. This could cause problems if people place
|
||||
// symbolic links in their source tree. For example, if you executed:
|
||||
// protoc --proto_path=foo foo/bar/baz.proto
|
||||
// then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize
|
||||
// to a path which does not appear to be under foo, and thus the compiler
|
||||
// will complain that baz.proto is not inside the --proto_path.
|
||||
static string CanonicalizePath(string path) {
|
||||
#ifdef _WIN32
|
||||
// The Win32 API accepts forward slashes as a path delimiter even though
|
||||
// backslashes are standard. Let's avoid confusion and use only forward
|
||||
// slashes.
|
||||
if (HasPrefixString(path, "\\\\")) {
|
||||
// Avoid converting two leading backslashes.
|
||||
path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true);
|
||||
} else {
|
||||
path = StringReplace(path, "\\", "/", true);
|
||||
}
|
||||
#endif
|
||||
|
||||
vector<string> parts;
|
||||
vector<string> canonical_parts;
|
||||
SplitStringUsing(path, "/", &parts); // Note: Removes empty parts.
|
||||
for (int i = 0; i < parts.size(); i++) {
|
||||
if (parts[i] == ".") {
|
||||
// Ignore.
|
||||
} else {
|
||||
canonical_parts.push_back(parts[i]);
|
||||
}
|
||||
}
|
||||
string result = JoinStrings(canonical_parts, "/");
|
||||
if (!path.empty() && path[0] == '/') {
|
||||
// Restore leading slash.
|
||||
result = '/' + result;
|
||||
}
|
||||
if (!path.empty() && LastChar(path) == '/' &&
|
||||
!result.empty() && LastChar(result) != '/') {
|
||||
// Restore trailing slash.
|
||||
result += '/';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline bool ContainsParentReference(const string& path) {
|
||||
return path == ".." ||
|
||||
HasPrefixString(path, "../") ||
|
||||
HasSuffixString(path, "/..") ||
|
||||
path.find("/../") != string::npos;
|
||||
}
|
||||
|
||||
// Maps a file from an old location to a new one. Typically, old_prefix is
|
||||
// a virtual path and new_prefix is its corresponding disk path. Returns
|
||||
// false if the filename did not start with old_prefix, otherwise replaces
|
||||
// old_prefix with new_prefix and stores the result in *result. Examples:
|
||||
// string result;
|
||||
// assert(ApplyMapping("foo/bar", "", "baz", &result));
|
||||
// assert(result == "baz/foo/bar");
|
||||
//
|
||||
// assert(ApplyMapping("foo/bar", "foo", "baz", &result));
|
||||
// assert(result == "baz/bar");
|
||||
//
|
||||
// assert(ApplyMapping("foo", "foo", "bar", &result));
|
||||
// assert(result == "bar");
|
||||
//
|
||||
// assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
|
||||
// assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
|
||||
// assert(!ApplyMapping("foobar", "foo", "baz", &result));
|
||||
static bool ApplyMapping(const string& filename,
|
||||
const string& old_prefix,
|
||||
const string& new_prefix,
|
||||
string* result) {
|
||||
if (old_prefix.empty()) {
|
||||
// old_prefix matches any relative path.
|
||||
if (ContainsParentReference(filename)) {
|
||||
// We do not allow the file name to use "..".
|
||||
return false;
|
||||
}
|
||||
if (HasPrefixString(filename, "/") ||
|
||||
IsWindowsAbsolutePath(filename)) {
|
||||
// This is an absolute path, so it isn't matched by the empty string.
|
||||
return false;
|
||||
}
|
||||
result->assign(new_prefix);
|
||||
if (!result->empty()) result->push_back('/');
|
||||
result->append(filename);
|
||||
return true;
|
||||
} else if (HasPrefixString(filename, old_prefix)) {
|
||||
// old_prefix is a prefix of the filename. Is it the whole filename?
|
||||
if (filename.size() == old_prefix.size()) {
|
||||
// Yep, it's an exact match.
|
||||
*result = new_prefix;
|
||||
return true;
|
||||
} else {
|
||||
// Not an exact match. Is the next character a '/'? Otherwise,
|
||||
// this isn't actually a match at all. E.g. the prefix "foo/bar"
|
||||
// does not match the filename "foo/barbaz".
|
||||
int after_prefix_start = -1;
|
||||
if (filename[old_prefix.size()] == '/') {
|
||||
after_prefix_start = old_prefix.size() + 1;
|
||||
} else if (filename[old_prefix.size() - 1] == '/') {
|
||||
// old_prefix is never empty, and canonicalized paths never have
|
||||
// consecutive '/' characters.
|
||||
after_prefix_start = old_prefix.size();
|
||||
}
|
||||
if (after_prefix_start != -1) {
|
||||
// Yep. So the prefixes are directories and the filename is a file
|
||||
// inside them.
|
||||
string after_prefix = filename.substr(after_prefix_start);
|
||||
if (ContainsParentReference(after_prefix)) {
|
||||
// We do not allow the file name to use "..".
|
||||
return false;
|
||||
}
|
||||
result->assign(new_prefix);
|
||||
if (!result->empty()) result->push_back('/');
|
||||
result->append(after_prefix);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DiskSourceTree::MapPath(const string& virtual_path,
|
||||
const string& disk_path) {
|
||||
mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path)));
|
||||
}
|
||||
|
||||
DiskSourceTree::DiskFileToVirtualFileResult
|
||||
DiskSourceTree::DiskFileToVirtualFile(
|
||||
const string& disk_file,
|
||||
string* virtual_file,
|
||||
string* shadowing_disk_file) {
|
||||
int mapping_index = -1;
|
||||
string canonical_disk_file = CanonicalizePath(disk_file);
|
||||
|
||||
for (int i = 0; i < mappings_.size(); i++) {
|
||||
// Apply the mapping in reverse.
|
||||
if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path,
|
||||
mappings_[i].virtual_path, virtual_file)) {
|
||||
// Success.
|
||||
mapping_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapping_index == -1) {
|
||||
return NO_MAPPING;
|
||||
}
|
||||
|
||||
// Iterate through all mappings with higher precedence and verify that none
|
||||
// of them map this file to some other existing file.
|
||||
for (int i = 0; i < mapping_index; i++) {
|
||||
if (ApplyMapping(*virtual_file, mappings_[i].virtual_path,
|
||||
mappings_[i].disk_path, shadowing_disk_file)) {
|
||||
if (access(shadowing_disk_file->c_str(), F_OK) >= 0) {
|
||||
// File exists.
|
||||
return SHADOWED;
|
||||
}
|
||||
}
|
||||
}
|
||||
shadowing_disk_file->clear();
|
||||
|
||||
// Verify that we can open the file. Note that this also has the side-effect
|
||||
// of verifying that we are not canonicalizing away any non-existent
|
||||
// directories.
|
||||
scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
|
||||
if (stream == NULL) {
|
||||
return CANNOT_OPEN;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file,
|
||||
string* disk_file) {
|
||||
scoped_ptr<io::ZeroCopyInputStream> stream(OpenVirtualFile(virtual_file,
|
||||
disk_file));
|
||||
return stream != NULL;
|
||||
}
|
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) {
|
||||
return OpenVirtualFile(filename, NULL);
|
||||
}
|
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
|
||||
const string& virtual_file,
|
||||
string* disk_file) {
|
||||
if (virtual_file != CanonicalizePath(virtual_file) ||
|
||||
ContainsParentReference(virtual_file)) {
|
||||
// We do not allow importing of paths containing things like ".." or
|
||||
// consecutive slashes since the compiler expects files to be uniquely
|
||||
// identified by file name.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mappings_.size(); i++) {
|
||||
string temp_disk_file;
|
||||
if (ApplyMapping(virtual_file, mappings_[i].virtual_path,
|
||||
mappings_[i].disk_path, &temp_disk_file)) {
|
||||
io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
|
||||
if (stream != NULL) {
|
||||
if (disk_file != NULL) {
|
||||
*disk_file = temp_disk_file;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
if (errno == EACCES) {
|
||||
// The file exists but is not readable.
|
||||
// TODO(kenton): Find a way to report this more nicely.
|
||||
GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
|
||||
const string& filename) {
|
||||
int file_descriptor;
|
||||
do {
|
||||
file_descriptor = open(filename.c_str(), O_RDONLY);
|
||||
} while (file_descriptor < 0 && errno == EINTR);
|
||||
if (file_descriptor >= 0) {
|
||||
io::FileInputStream* result = new io::FileInputStream(file_descriptor);
|
||||
result->SetCloseOnDelete(true);
|
||||
return result;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,303 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file is the public interface to the .proto file parser.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor_database.h>
|
||||
#include <google/protobuf/compiler/parser.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io { class ZeroCopyInputStream; }
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// Defined in this file.
|
||||
class Importer;
|
||||
class MultiFileErrorCollector;
|
||||
class SourceTree;
|
||||
class DiskSourceTree;
|
||||
|
||||
// TODO(kenton): Move all SourceTree stuff to a separate file?
|
||||
|
||||
// An implementation of DescriptorDatabase which loads files from a SourceTree
|
||||
// and parses them.
|
||||
//
|
||||
// Note: This class is not thread-safe since it maintains a table of source
|
||||
// code locations for error reporting. However, when a DescriptorPool wraps
|
||||
// a DescriptorDatabase, it uses mutex locking to make sure only one method
|
||||
// of the database is called at a time, even if the DescriptorPool is used
|
||||
// from multiple threads. Therefore, there is only a problem if you create
|
||||
// multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase
|
||||
// and use them from multiple threads.
|
||||
//
|
||||
// Note: This class does not implement FindFileContainingSymbol() or
|
||||
// FindFileContainingExtension(); these will always return false.
|
||||
class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
SourceTreeDescriptorDatabase(SourceTree* source_tree);
|
||||
~SourceTreeDescriptorDatabase();
|
||||
|
||||
// Instructs the SourceTreeDescriptorDatabase to report any parse errors
|
||||
// to the given MultiFileErrorCollector. This should be called before
|
||||
// parsing. error_collector must remain valid until either this method
|
||||
// is called again or the SourceTreeDescriptorDatabase is destroyed.
|
||||
void RecordErrorsTo(MultiFileErrorCollector* error_collector) {
|
||||
error_collector_ = error_collector;
|
||||
}
|
||||
|
||||
// Gets a DescriptorPool::ErrorCollector which records errors to the
|
||||
// MultiFileErrorCollector specified with RecordErrorsTo(). This collector
|
||||
// has the ability to determine exact line and column numbers of errors
|
||||
// from the information given to it by the DescriptorPool.
|
||||
DescriptorPool::ErrorCollector* GetValidationErrorCollector() {
|
||||
using_validation_error_collector_ = true;
|
||||
return &validation_error_collector_;
|
||||
}
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename, FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
private:
|
||||
class SingleFileErrorCollector;
|
||||
|
||||
SourceTree* source_tree_;
|
||||
MultiFileErrorCollector* error_collector_;
|
||||
|
||||
class LIBPROTOBUF_EXPORT ValidationErrorCollector : public DescriptorPool::ErrorCollector {
|
||||
public:
|
||||
ValidationErrorCollector(SourceTreeDescriptorDatabase* owner);
|
||||
~ValidationErrorCollector();
|
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const string& filename,
|
||||
const string& element_name,
|
||||
const Message* descriptor,
|
||||
ErrorLocation location,
|
||||
const string& message);
|
||||
|
||||
private:
|
||||
SourceTreeDescriptorDatabase* owner_;
|
||||
};
|
||||
friend class ValidationErrorCollector;
|
||||
|
||||
bool using_validation_error_collector_;
|
||||
SourceLocationTable source_locations_;
|
||||
ValidationErrorCollector validation_error_collector_;
|
||||
};
|
||||
|
||||
// Simple interface for parsing .proto files. This wraps the process
|
||||
// of opening the file, parsing it with a Parser, recursively parsing all its
|
||||
// imports, and then cross-linking the results to produce a FileDescriptor.
|
||||
//
|
||||
// This is really just a thin wrapper around SourceTreeDescriptorDatabase.
|
||||
// You may find that SourceTreeDescriptorDatabase is more flexible.
|
||||
//
|
||||
// TODO(kenton): I feel like this class is not well-named.
|
||||
class LIBPROTOBUF_EXPORT Importer {
|
||||
public:
|
||||
Importer(SourceTree* source_tree,
|
||||
MultiFileErrorCollector* error_collector);
|
||||
~Importer();
|
||||
|
||||
// Import the given file and build a FileDescriptor representing it. If
|
||||
// the file is already in the DescriptorPool, the existing FileDescriptor
|
||||
// will be returned. The FileDescriptor is property of the DescriptorPool,
|
||||
// and will remain valid until it is destroyed. If any errors occur, they
|
||||
// will be reported using the error collector and Import() will return NULL.
|
||||
//
|
||||
// A particular Importer object will only report errors for a particular
|
||||
// file once. All future attempts to import the same file will return NULL
|
||||
// without reporting any errors. The idea is that you might want to import
|
||||
// a lot of files without seeing the same errors over and over again. If
|
||||
// you want to see errors for the same files repeatedly, you can use a
|
||||
// separate Importer object to import each one (but use the same
|
||||
// DescriptorPool so that they can be cross-linked).
|
||||
const FileDescriptor* Import(const string& filename);
|
||||
|
||||
// The DescriptorPool in which all imported FileDescriptors and their
|
||||
// contents are stored.
|
||||
inline const DescriptorPool* pool() const {
|
||||
return &pool_;
|
||||
}
|
||||
|
||||
private:
|
||||
SourceTreeDescriptorDatabase database_;
|
||||
DescriptorPool pool_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer);
|
||||
};
|
||||
|
||||
// If the importer encounters problems while trying to import the proto files,
|
||||
// it reports them to a MultiFileErrorCollector.
|
||||
class LIBPROTOBUF_EXPORT MultiFileErrorCollector {
|
||||
public:
|
||||
inline MultiFileErrorCollector() {}
|
||||
virtual ~MultiFileErrorCollector();
|
||||
|
||||
// Line and column numbers are zero-based. A line number of -1 indicates
|
||||
// an error with the entire file (e.g. "not found").
|
||||
virtual void AddError(const string& filename, int line, int column,
|
||||
const string& message) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector);
|
||||
};
|
||||
|
||||
// Abstract interface which represents a directory tree containing proto files.
|
||||
// Used by the default implementation of Importer to resolve import statements
|
||||
// Most users will probably want to use the DiskSourceTree implementation,
|
||||
// below.
|
||||
class LIBPROTOBUF_EXPORT SourceTree {
|
||||
public:
|
||||
inline SourceTree() {}
|
||||
virtual ~SourceTree();
|
||||
|
||||
// Open the given file and return a stream that reads it, or NULL if not
|
||||
// found. The caller takes ownership of the returned object. The filename
|
||||
// must be a path relative to the root of the source tree and must not
|
||||
// contain "." or ".." components.
|
||||
virtual io::ZeroCopyInputStream* Open(const string& filename) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree);
|
||||
};
|
||||
|
||||
// An implementation of SourceTree which loads files from locations on disk.
|
||||
// Multiple mappings can be set up to map locations in the DiskSourceTree to
|
||||
// locations in the physical filesystem.
|
||||
class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree {
|
||||
public:
|
||||
DiskSourceTree();
|
||||
~DiskSourceTree();
|
||||
|
||||
// Map a path on disk to a location in the SourceTree. The path may be
|
||||
// either a file or a directory. If it is a directory, the entire tree
|
||||
// under it will be mapped to the given virtual location. To map a directory
|
||||
// to the root of the source tree, pass an empty string for virtual_path.
|
||||
//
|
||||
// If multiple mapped paths apply when opening a file, they will be searched
|
||||
// in order. For example, if you do:
|
||||
// MapPath("bar", "foo/bar");
|
||||
// MapPath("", "baz");
|
||||
// and then you do:
|
||||
// Open("bar/qux");
|
||||
// the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux,
|
||||
// returning the first one that opens successfuly.
|
||||
//
|
||||
// disk_path may be an absolute path or relative to the current directory,
|
||||
// just like a path you'd pass to open().
|
||||
void MapPath(const string& virtual_path, const string& disk_path);
|
||||
|
||||
// Return type for DiskFileToVirtualFile().
|
||||
enum DiskFileToVirtualFileResult {
|
||||
SUCCESS,
|
||||
SHADOWED,
|
||||
CANNOT_OPEN,
|
||||
NO_MAPPING
|
||||
};
|
||||
|
||||
// Given a path to a file on disk, find a virtual path mapping to that
|
||||
// file. The first mapping created with MapPath() whose disk_path contains
|
||||
// the filename is used. However, that virtual path may not actually be
|
||||
// usable to open the given file. Possible return values are:
|
||||
// * SUCCESS: The mapping was found. *virtual_file is filled in so that
|
||||
// calling Open(*virtual_file) will open the file named by disk_file.
|
||||
// * SHADOWED: A mapping was found, but using Open() to open this virtual
|
||||
// path will end up returning some different file. This is because some
|
||||
// other mapping with a higher precedence also matches this virtual path
|
||||
// and maps it to a different file that exists on disk. *virtual_file
|
||||
// is filled in as it would be in the SUCCESS case. *shadowing_disk_file
|
||||
// is filled in with the disk path of the file which would be opened if
|
||||
// you were to call Open(*virtual_file).
|
||||
// * CANNOT_OPEN: The mapping was found and was not shadowed, but the
|
||||
// file specified cannot be opened. When this value is returned,
|
||||
// errno will indicate the reason the file cannot be opened. *virtual_file
|
||||
// will be set to the virtual path as in the SUCCESS case, even though
|
||||
// it is not useful.
|
||||
// * NO_MAPPING: Indicates that no mapping was found which contains this
|
||||
// file.
|
||||
DiskFileToVirtualFileResult
|
||||
DiskFileToVirtualFile(const string& disk_file,
|
||||
string* virtual_file,
|
||||
string* shadowing_disk_file);
|
||||
|
||||
// Given a virtual path, find the path to the file on disk.
|
||||
// Return true and update disk_file with the on-disk path if the file exists.
|
||||
// Return false and leave disk_file untouched if the file doesn't exist.
|
||||
bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file);
|
||||
|
||||
// implements SourceTree -------------------------------------------
|
||||
io::ZeroCopyInputStream* Open(const string& filename);
|
||||
|
||||
private:
|
||||
struct Mapping {
|
||||
string virtual_path;
|
||||
string disk_path;
|
||||
|
||||
inline Mapping(const string& virtual_path, const string& disk_path)
|
||||
: virtual_path(virtual_path), disk_path(disk_path) {}
|
||||
};
|
||||
vector<Mapping> mappings_;
|
||||
|
||||
// Like Open(), but returns the on-disk path in disk_file if disk_file is
|
||||
// non-NULL and the file could be successfully opened.
|
||||
io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file,
|
||||
string* disk_file);
|
||||
|
||||
// Like Open() but given the actual on-disk path.
|
||||
io::ZeroCopyInputStream* OpenDiskFile(const string& filename);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
|
@ -0,0 +1,61 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/command_line_interface.h>
|
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h>
|
||||
//#include <google/protobuf/compiler/python/python_generator.h>
|
||||
//#include <google/protobuf/compiler/java/java_generator.h>
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli;
|
||||
cli.AllowPlugins("protoc-");
|
||||
|
||||
// Proto2 C++
|
||||
google::protobuf::compiler::cpp::CppGenerator cpp_generator;
|
||||
cli.RegisterGenerator("--cpp_out", &cpp_generator,
|
||||
"Generate C++ header and source.");
|
||||
|
||||
// Proto2 Java
|
||||
//google::protobuf::compiler::java::JavaGenerator java_generator;
|
||||
//cli.RegisterGenerator("--java_out", &java_generator,
|
||||
// "Generate Java source file.");
|
||||
|
||||
|
||||
// Proto2 Python
|
||||
//google::protobuf::compiler::python::Generator py_generator;
|
||||
//cli.RegisterGenerator("--python_out", &py_generator,
|
||||
// "Generate Python source file.");
|
||||
|
||||
return cli.Run(argc, argv);
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/mock_code_generator.h>
|
||||
|
||||
#include <google/protobuf/testing/file.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
// Returns the list of the names of files in all_files in the form of a
|
||||
// comma-separated string.
|
||||
string CommaSeparatedList(const vector<const FileDescriptor*> all_files) {
|
||||
vector<string> names;
|
||||
for (int i = 0; i < all_files.size(); i++) {
|
||||
names.push_back(all_files[i]->name());
|
||||
}
|
||||
return JoinStrings(names, ",");
|
||||
}
|
||||
|
||||
static const char* kFirstInsertionPointName = "first_mock_insertion_point";
|
||||
static const char* kSecondInsertionPointName = "second_mock_insertion_point";
|
||||
static const char* kFirstInsertionPoint =
|
||||
"# @@protoc_insertion_point(first_mock_insertion_point) is here\n";
|
||||
static const char* kSecondInsertionPoint =
|
||||
" # @@protoc_insertion_point(second_mock_insertion_point) is here\n";
|
||||
|
||||
MockCodeGenerator::MockCodeGenerator(const string& name)
|
||||
: name_(name) {}
|
||||
|
||||
MockCodeGenerator::~MockCodeGenerator() {}
|
||||
|
||||
void MockCodeGenerator::ExpectGenerated(
|
||||
const string& name,
|
||||
const string& parameter,
|
||||
const string& insertions,
|
||||
const string& file,
|
||||
const string& first_message_name,
|
||||
const string& first_parsed_file_name,
|
||||
const string& output_directory) {
|
||||
string content;
|
||||
ASSERT_TRUE(File::ReadFileToString(
|
||||
output_directory + "/" + GetOutputFileName(name, file), &content));
|
||||
|
||||
vector<string> lines;
|
||||
SplitStringUsing(content, "\n", &lines);
|
||||
|
||||
while (!lines.empty() && lines.back().empty()) {
|
||||
lines.pop_back();
|
||||
}
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
lines[i] += "\n";
|
||||
}
|
||||
|
||||
vector<string> insertion_list;
|
||||
if (!insertions.empty()) {
|
||||
SplitStringUsing(insertions, ",", &insertion_list);
|
||||
}
|
||||
|
||||
ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2);
|
||||
EXPECT_EQ(GetOutputFileContent(name, parameter, file,
|
||||
first_parsed_file_name, first_message_name),
|
||||
lines[0]);
|
||||
|
||||
EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
|
||||
EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
|
||||
|
||||
for (int i = 0; i < insertion_list.size(); i++) {
|
||||
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
|
||||
file, file, first_message_name),
|
||||
lines[1 + i]);
|
||||
// Second insertion point is indented, so the inserted text should
|
||||
// automatically be indented too.
|
||||
EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert",
|
||||
file, file, first_message_name),
|
||||
lines[2 + insertion_list.size() + i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool MockCodeGenerator::Generate(
|
||||
const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
GeneratorContext* context,
|
||||
string* error) const {
|
||||
for (int i = 0; i < file->message_type_count(); i++) {
|
||||
if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) {
|
||||
string command = StripPrefixString(file->message_type(i)->name(),
|
||||
"MockCodeGenerator_");
|
||||
if (command == "Error") {
|
||||
*error = "Saw message type MockCodeGenerator_Error.";
|
||||
return false;
|
||||
} else if (command == "Exit") {
|
||||
cerr << "Saw message type MockCodeGenerator_Exit." << endl;
|
||||
exit(123);
|
||||
} else if (command == "Abort") {
|
||||
cerr << "Saw message type MockCodeGenerator_Abort." << endl;
|
||||
abort();
|
||||
} else {
|
||||
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasPrefixString(parameter, "insert=")) {
|
||||
vector<string> insert_into;
|
||||
SplitStringUsing(StripPrefixString(parameter, "insert="),
|
||||
",", &insert_into);
|
||||
|
||||
for (int i = 0; i < insert_into.size(); i++) {
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
context->OpenForInsert(
|
||||
GetOutputFileName(insert_into[i], file),
|
||||
kFirstInsertionPointName));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "first_insert",
|
||||
file, context));
|
||||
if (printer.failed()) {
|
||||
*error = "MockCodeGenerator detected write error.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
context->OpenForInsert(
|
||||
GetOutputFileName(insert_into[i], file),
|
||||
kSecondInsertionPointName));
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, "second_insert",
|
||||
file, context));
|
||||
if (printer.failed()) {
|
||||
*error = "MockCodeGenerator detected write error.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(
|
||||
context->Open(GetOutputFileName(name_, file)));
|
||||
|
||||
io::Printer printer(output.get(), '$');
|
||||
printer.PrintRaw(GetOutputFileContent(name_, parameter,
|
||||
file, context));
|
||||
printer.PrintRaw(kFirstInsertionPoint);
|
||||
printer.PrintRaw(kSecondInsertionPoint);
|
||||
|
||||
if (printer.failed()) {
|
||||
*error = "MockCodeGenerator detected write error.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string MockCodeGenerator::GetOutputFileName(const string& generator_name,
|
||||
const FileDescriptor* file) {
|
||||
return GetOutputFileName(generator_name, file->name());
|
||||
}
|
||||
|
||||
string MockCodeGenerator::GetOutputFileName(const string& generator_name,
|
||||
const string& file) {
|
||||
return file + ".MockCodeGenerator." + generator_name;
|
||||
}
|
||||
|
||||
string MockCodeGenerator::GetOutputFileContent(
|
||||
const string& generator_name,
|
||||
const string& parameter,
|
||||
const FileDescriptor* file,
|
||||
GeneratorContext *context) {
|
||||
vector<const FileDescriptor*> all_files;
|
||||
context->ListParsedFiles(&all_files);
|
||||
return GetOutputFileContent(
|
||||
generator_name, parameter, file->name(),
|
||||
CommaSeparatedList(all_files),
|
||||
file->message_type_count() > 0 ?
|
||||
file->message_type(0)->name() : "(none)");
|
||||
}
|
||||
|
||||
string MockCodeGenerator::GetOutputFileContent(
|
||||
const string& generator_name,
|
||||
const string& parameter,
|
||||
const string& file,
|
||||
const string& parsed_file_list,
|
||||
const string& first_message_name) {
|
||||
return strings::Substitute("$0: $1, $2, $3, $4\n",
|
||||
generator_name, parameter, file,
|
||||
first_message_name, parsed_file_list);
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,113 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
// A mock CodeGenerator, used by command_line_interface_unittest. This is in
|
||||
// its own file so that it can be used both directly and as a plugin.
|
||||
//
|
||||
// Generate() produces some output which can be checked by ExpectCalled(). The
|
||||
// generator can run in a different process (e.g. a plugin).
|
||||
//
|
||||
// If the parameter is "insert=NAMES", the MockCodeGenerator will insert lines
|
||||
// into the files generated by other MockCodeGenerators instead of creating
|
||||
// its own file. NAMES is a comma-separated list of the names of those other
|
||||
// MockCodeGenerators.
|
||||
//
|
||||
// MockCodeGenerator will also modify its behavior slightly if the input file
|
||||
// contains a message type with one of the following names:
|
||||
// MockCodeGenerator_Error: Causes Generate() to return false and set the
|
||||
// error message to "Saw message type MockCodeGenerator_Error."
|
||||
// MockCodeGenerator_Exit: Generate() prints "Saw message type
|
||||
// MockCodeGenerator_Exit." to stderr and then calls exit(123).
|
||||
// MockCodeGenerator_Abort: Generate() prints "Saw message type
|
||||
// MockCodeGenerator_Abort." to stderr and then calls abort().
|
||||
class MockCodeGenerator : public CodeGenerator {
|
||||
public:
|
||||
MockCodeGenerator(const string& name);
|
||||
virtual ~MockCodeGenerator();
|
||||
|
||||
// Expect (via gTest) that a MockCodeGenerator with the given name was called
|
||||
// with the given parameters by inspecting the output location.
|
||||
//
|
||||
// |insertions| is a comma-separated list of names of MockCodeGenerators which
|
||||
// should have inserted lines into this file.
|
||||
// |parsed_file_list| is a comma-separated list of names of the files
|
||||
// that are being compiled together in this run.
|
||||
static void ExpectGenerated(const string& name,
|
||||
const string& parameter,
|
||||
const string& insertions,
|
||||
const string& file,
|
||||
const string& first_message_name,
|
||||
const string& parsed_file_list,
|
||||
const string& output_directory);
|
||||
|
||||
// Get the name of the file which would be written by the given generator.
|
||||
static string GetOutputFileName(const string& generator_name,
|
||||
const FileDescriptor* file);
|
||||
static string GetOutputFileName(const string& generator_name,
|
||||
const string& file);
|
||||
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file,
|
||||
const string& parameter,
|
||||
GeneratorContext* context,
|
||||
string* error) const;
|
||||
|
||||
private:
|
||||
string name_;
|
||||
|
||||
static string GetOutputFileContent(const string& generator_name,
|
||||
const string& parameter,
|
||||
const FileDescriptor* file,
|
||||
GeneratorContext *context);
|
||||
static string GetOutputFileContent(const string& generator_name,
|
||||
const string& parameter,
|
||||
const string& file,
|
||||
const string& parsed_file_list,
|
||||
const string& first_message_name);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
|
@ -0,0 +1,64 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf::compiler namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
|
||||
// Implementation of the Protocol Buffer compiler.
|
||||
//
|
||||
// This package contains code for parsing .proto files and generating code
|
||||
// based on them. There are two reasons you might be interested in this
|
||||
// package:
|
||||
// - You want to parse .proto files at runtime. In this case, you should
|
||||
// look at importer.h. Since this functionality is widely useful, it is
|
||||
// included in the libprotobuf base library; you do not have to link against
|
||||
// libprotoc.
|
||||
// - You want to write a custom protocol compiler which generates different
|
||||
// kinds of code, e.g. code in a different language which is not supported
|
||||
// by the official compiler. For this purpose, command_line_interface.h
|
||||
// provides you with a complete compiler front-end, so all you need to do
|
||||
// is write a custom implementation of CodeGenerator and a trivial main()
|
||||
// function. You can even make your compiler support the official languages
|
||||
// in addition to your own. Since this functionality is only useful to those
|
||||
// writing custom compilers, it is in a separate library called "libprotoc"
|
||||
// which you will have to link against.
|
||||
namespace compiler {}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,434 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Implements parsing of .proto files to FileDescriptorProtos.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/io/tokenizer.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf { class Message; }
|
||||
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
// Defined in this file.
|
||||
class Parser;
|
||||
class SourceLocationTable;
|
||||
|
||||
// Implements parsing of protocol definitions (such as .proto files).
|
||||
//
|
||||
// Note that most users will be more interested in the Importer class.
|
||||
// Parser is a lower-level class which simply converts a single .proto file
|
||||
// to a FileDescriptorProto. It does not resolve import directives or perform
|
||||
// many other kinds of validation needed to construct a complete
|
||||
// FileDescriptor.
|
||||
class LIBPROTOBUF_EXPORT Parser {
|
||||
public:
|
||||
Parser();
|
||||
~Parser();
|
||||
|
||||
// Parse the entire input and construct a FileDescriptorProto representing
|
||||
// it. Returns true if no errors occurred, false otherwise.
|
||||
bool Parse(io::Tokenizer* input, FileDescriptorProto* file);
|
||||
|
||||
// Optional fetaures:
|
||||
|
||||
// DEPRECATED: New code should use the SourceCodeInfo embedded in the
|
||||
// FileDescriptorProto.
|
||||
//
|
||||
// Requests that locations of certain definitions be recorded to the given
|
||||
// SourceLocationTable while parsing. This can be used to look up exact line
|
||||
// and column numbers for errors reported by DescriptorPool during validation.
|
||||
// Set to NULL (the default) to discard source location information.
|
||||
void RecordSourceLocationsTo(SourceLocationTable* location_table) {
|
||||
source_location_table_ = location_table;
|
||||
}
|
||||
|
||||
// Requests that errors be recorded to the given ErrorCollector while
|
||||
// parsing. Set to NULL (the default) to discard error messages.
|
||||
void RecordErrorsTo(io::ErrorCollector* error_collector) {
|
||||
error_collector_ = error_collector;
|
||||
}
|
||||
|
||||
// Returns the identifier used in the "syntax = " declaration, if one was
|
||||
// seen during the last call to Parse(), or the empty string otherwise.
|
||||
const string& GetSyntaxIdentifier() { return syntax_identifier_; }
|
||||
|
||||
// If set true, input files will be required to begin with a syntax
|
||||
// identifier. Otherwise, files may omit this. If a syntax identifier
|
||||
// is provided, it must be 'syntax = "proto2";' and must appear at the
|
||||
// top of this file regardless of whether or not it was required.
|
||||
void SetRequireSyntaxIdentifier(bool value) {
|
||||
require_syntax_identifier_ = value;
|
||||
}
|
||||
|
||||
// Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop
|
||||
// parsing as soon as it has seen the syntax identifier, or lack thereof.
|
||||
// This is useful for quickly identifying the syntax of the file without
|
||||
// parsing the whole thing. If this is enabled, no error will be recorded
|
||||
// if the syntax identifier is something other than "proto2" (since
|
||||
// presumably the caller intends to deal with that), but other kinds of
|
||||
// errors (e.g. parse errors) will still be reported. When this is enabled,
|
||||
// you may pass a NULL FileDescriptorProto to Parse().
|
||||
void SetStopAfterSyntaxIdentifier(bool value) {
|
||||
stop_after_syntax_identifier_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
// =================================================================
|
||||
// Error recovery helpers
|
||||
|
||||
// Consume the rest of the current statement. This consumes tokens
|
||||
// until it sees one of:
|
||||
// ';' Consumes the token and returns.
|
||||
// '{' Consumes the brace then calls SkipRestOfBlock().
|
||||
// '}' Returns without consuming.
|
||||
// EOF Returns (can't consume).
|
||||
// The Parser often calls SkipStatement() after encountering a syntax
|
||||
// error. This allows it to go on parsing the following lines, allowing
|
||||
// it to report more than just one error in the file.
|
||||
void SkipStatement();
|
||||
|
||||
// Consume the rest of the current block, including nested blocks,
|
||||
// ending after the closing '}' is encountered and consumed, or at EOF.
|
||||
void SkipRestOfBlock();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Single-token consuming helpers
|
||||
//
|
||||
// These make parsing code more readable.
|
||||
|
||||
// True if the current token is TYPE_END.
|
||||
inline bool AtEnd();
|
||||
|
||||
// True if the next token matches the given text.
|
||||
inline bool LookingAt(const char* text);
|
||||
// True if the next token is of the given type.
|
||||
inline bool LookingAtType(io::Tokenizer::TokenType token_type);
|
||||
|
||||
// If the next token exactly matches the text given, consume it and return
|
||||
// true. Otherwise, return false without logging an error.
|
||||
bool TryConsume(const char* text);
|
||||
|
||||
// These attempt to read some kind of token from the input. If successful,
|
||||
// they return true. Otherwise they return false and add the given error
|
||||
// to the error list.
|
||||
|
||||
// Consume a token with the exact text given.
|
||||
bool Consume(const char* text, const char* error);
|
||||
// Same as above, but automatically generates the error "Expected \"text\".",
|
||||
// where "text" is the expected token text.
|
||||
bool Consume(const char* text);
|
||||
// Consume a token of type IDENTIFIER and store its text in "output".
|
||||
bool ConsumeIdentifier(string* output, const char* error);
|
||||
// Consume an integer and store its value in "output".
|
||||
bool ConsumeInteger(int* output, const char* error);
|
||||
// Consume a 64-bit integer and store its value in "output". If the value
|
||||
// is greater than max_value, an error will be reported.
|
||||
bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error);
|
||||
// Consume a number and store its value in "output". This will accept
|
||||
// tokens of either INTEGER or FLOAT type.
|
||||
bool ConsumeNumber(double* output, const char* error);
|
||||
// Consume a string literal and store its (unescaped) value in "output".
|
||||
bool ConsumeString(string* output, const char* error);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Error logging helpers
|
||||
|
||||
// Invokes error_collector_->AddError(), if error_collector_ is not NULL.
|
||||
void AddError(int line, int column, const string& error);
|
||||
|
||||
// Invokes error_collector_->AddError() with the line and column number
|
||||
// of the current token.
|
||||
void AddError(const string& error);
|
||||
|
||||
// Records a location in the SourceCodeInfo.location table (see
|
||||
// descriptor.proto). We use RAII to ensure that the start and end locations
|
||||
// are recorded -- the constructor records the start location and the
|
||||
// destructor records the end location. Since the parser is
|
||||
// recursive-descent, this works out beautifully.
|
||||
class LIBPROTOBUF_EXPORT LocationRecorder {
|
||||
public:
|
||||
// Construct the file's "root" location.
|
||||
LocationRecorder(Parser* parser);
|
||||
|
||||
// Construct a location that represents a declaration nested within the
|
||||
// given parent. E.g. a field's location is nested within the location
|
||||
// for a message type. The parent's path will be copied, so you should
|
||||
// call AddPath() only to add the path components leading from the parent
|
||||
// to the child (as opposed to leading from the root to the child).
|
||||
LocationRecorder(const LocationRecorder& parent);
|
||||
|
||||
// Convenience constructors that call AddPath() one or two times.
|
||||
LocationRecorder(const LocationRecorder& parent, int path1);
|
||||
LocationRecorder(const LocationRecorder& parent, int path1, int path2);
|
||||
|
||||
~LocationRecorder();
|
||||
|
||||
// Add a path component. See SourceCodeInfo.Location.path in
|
||||
// descriptor.proto.
|
||||
void AddPath(int path_component);
|
||||
|
||||
// By default the location is considered to start at the current token at
|
||||
// the time the LocationRecorder is created. StartAt() sets the start
|
||||
// location to the given token instead.
|
||||
void StartAt(const io::Tokenizer::Token& token);
|
||||
|
||||
// By default the location is considered to end at the previous token at
|
||||
// the time the LocationRecorder is destroyed. EndAt() sets the end
|
||||
// location to the given token instead.
|
||||
void EndAt(const io::Tokenizer::Token& token);
|
||||
|
||||
// Records the start point of this location to the SourceLocationTable that
|
||||
// was passed to RecordSourceLocationsTo(), if any. SourceLocationTable
|
||||
// is an older way of keeping track of source locations which is still
|
||||
// used in some places.
|
||||
void RecordLegacyLocation(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location);
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
SourceCodeInfo::Location* location_;
|
||||
|
||||
void Init(const LocationRecorder& parent);
|
||||
};
|
||||
|
||||
// =================================================================
|
||||
// Parsers for various language constructs
|
||||
|
||||
// Parses the "syntax = \"proto2\";" line at the top of the file. Returns
|
||||
// false if it failed to parse or if the syntax identifier was not
|
||||
// recognized.
|
||||
bool ParseSyntaxIdentifier();
|
||||
|
||||
// These methods parse various individual bits of code. They return
|
||||
// false if they completely fail to parse the construct. In this case,
|
||||
// it is probably necessary to skip the rest of the statement to recover.
|
||||
// However, if these methods return true, it does NOT mean that there
|
||||
// were no errors; only that there were no *syntax* errors. For instance,
|
||||
// if a service method is defined using proper syntax but uses a primitive
|
||||
// type as its input or output, ParseMethodField() still returns true
|
||||
// and only reports the error by calling AddError(). In practice, this
|
||||
// makes logic much simpler for the caller.
|
||||
|
||||
// Parse a top-level message, enum, service, etc.
|
||||
bool ParseTopLevelStatement(FileDescriptorProto* file,
|
||||
const LocationRecorder& root_location);
|
||||
|
||||
// Parse various language high-level language construrcts.
|
||||
bool ParseMessageDefinition(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumDefinition(EnumDescriptorProto* enum_type,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceDefinition(ServiceDescriptorProto* service,
|
||||
const LocationRecorder& service_location);
|
||||
bool ParsePackage(FileDescriptorProto* file,
|
||||
const LocationRecorder& root_location);
|
||||
bool ParseImport(string* import_filename,
|
||||
const LocationRecorder& root_location,
|
||||
int index);
|
||||
bool ParseOption(Message* options,
|
||||
const LocationRecorder& options_location);
|
||||
|
||||
// These methods parse the contents of a message, enum, or service type and
|
||||
// add them to the given object. They consume the entire block including
|
||||
// the beginning and ending brace.
|
||||
bool ParseMessageBlock(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumBlock(EnumDescriptorProto* enum_type,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceBlock(ServiceDescriptorProto* service,
|
||||
const LocationRecorder& service_location);
|
||||
|
||||
// Parse one statement within a message, enum, or service block, inclunding
|
||||
// final semicolon.
|
||||
bool ParseMessageStatement(DescriptorProto* message,
|
||||
const LocationRecorder& message_location);
|
||||
bool ParseEnumStatement(EnumDescriptorProto* message,
|
||||
const LocationRecorder& enum_location);
|
||||
bool ParseServiceStatement(ServiceDescriptorProto* message,
|
||||
const LocationRecorder& service_location);
|
||||
|
||||
// Parse a field of a message. If the field is a group, its type will be
|
||||
// added to "messages".
|
||||
//
|
||||
// parent_location and location_field_number_for_nested_type are needed when
|
||||
// parsing groups -- we need to generate a nested message type within the
|
||||
// parent and record its location accordingly. Since the parent could be
|
||||
// either a FileDescriptorProto or a DescriptorProto, we must pass in the
|
||||
// correct field number to use.
|
||||
bool ParseMessageField(FieldDescriptorProto* field,
|
||||
RepeatedPtrField<DescriptorProto>* messages,
|
||||
const LocationRecorder& parent_location,
|
||||
int location_field_number_for_nested_type,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
// Parse an "extensions" declaration.
|
||||
bool ParseExtensions(DescriptorProto* message,
|
||||
const LocationRecorder& extensions_location);
|
||||
|
||||
// Parse an "extend" declaration. (See also comments for
|
||||
// ParseMessageField().)
|
||||
bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions,
|
||||
RepeatedPtrField<DescriptorProto>* messages,
|
||||
const LocationRecorder& parent_location,
|
||||
int location_field_number_for_nested_type,
|
||||
const LocationRecorder& extend_location);
|
||||
|
||||
// Parse a single enum value within an enum block.
|
||||
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value,
|
||||
const LocationRecorder& enum_value_location);
|
||||
|
||||
// Parse enum constant options, i.e. the list in square brackets at the end
|
||||
// of the enum constant value definition.
|
||||
bool ParseEnumConstantOptions(EnumValueDescriptorProto* value,
|
||||
const LocationRecorder& enum_value_location);
|
||||
|
||||
// Parse a single method within a service definition.
|
||||
bool ParseServiceMethod(MethodDescriptorProto* method,
|
||||
const LocationRecorder& method_location);
|
||||
|
||||
// Parse "required", "optional", or "repeated" and fill in "label"
|
||||
// with the value.
|
||||
bool ParseLabel(FieldDescriptorProto::Label* label);
|
||||
|
||||
// Parse a type name and fill in "type" (if it is a primitive) or
|
||||
// "type_name" (if it is not) with the type parsed.
|
||||
bool ParseType(FieldDescriptorProto::Type* type,
|
||||
string* type_name);
|
||||
// Parse a user-defined type and fill in "type_name" with the name.
|
||||
// If a primitive type is named, it is treated as an error.
|
||||
bool ParseUserDefinedType(string* type_name);
|
||||
|
||||
// Parses field options, i.e. the stuff in square brackets at the end
|
||||
// of a field definition. Also parses default value.
|
||||
bool ParseFieldOptions(FieldDescriptorProto* field,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
// Parse the "default" option. This needs special handling because its
|
||||
// type is the field's type.
|
||||
bool ParseDefaultAssignment(FieldDescriptorProto* field,
|
||||
const LocationRecorder& field_location);
|
||||
|
||||
// Parse a single option name/value pair, e.g. "ctype = CORD". The name
|
||||
// identifies a field of the given Message, and the value of that field
|
||||
// is set to the parsed value.
|
||||
bool ParseOptionAssignment(Message* options,
|
||||
const LocationRecorder& options_location);
|
||||
|
||||
// Parses a single part of a multipart option name. A multipart name consists
|
||||
// of names separated by dots. Each name is either an identifier or a series
|
||||
// of identifiers separated by dots and enclosed in parentheses. E.g.,
|
||||
// "foo.(bar.baz).qux".
|
||||
bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
|
||||
const LocationRecorder& part_location);
|
||||
|
||||
// Parses a string surrounded by balanced braces. Strips off the outer
|
||||
// braces and stores the enclosed string in *value.
|
||||
// E.g.,
|
||||
// { foo } *value gets 'foo'
|
||||
// { foo { bar: box } } *value gets 'foo { bar: box }'
|
||||
// {} *value gets ''
|
||||
//
|
||||
// REQUIRES: LookingAt("{")
|
||||
// When finished successfully, we are looking at the first token past
|
||||
// the ending brace.
|
||||
bool ParseUninterpretedBlock(string* value);
|
||||
|
||||
// =================================================================
|
||||
|
||||
io::Tokenizer* input_;
|
||||
io::ErrorCollector* error_collector_;
|
||||
SourceCodeInfo* source_code_info_;
|
||||
SourceLocationTable* source_location_table_; // legacy
|
||||
bool had_errors_;
|
||||
bool require_syntax_identifier_;
|
||||
bool stop_after_syntax_identifier_;
|
||||
string syntax_identifier_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser);
|
||||
};
|
||||
|
||||
// A table mapping (descriptor, ErrorLocation) pairs -- as reported by
|
||||
// DescriptorPool when validating descriptors -- to line and column numbers
|
||||
// within the original source code.
|
||||
//
|
||||
// This is semi-obsolete: FileDescriptorProto.source_code_info now contains
|
||||
// far more complete information about source locations. However, as of this
|
||||
// writing you still need to use SourceLocationTable when integrating with
|
||||
// DescriptorPool.
|
||||
class LIBPROTOBUF_EXPORT SourceLocationTable {
|
||||
public:
|
||||
SourceLocationTable();
|
||||
~SourceLocationTable();
|
||||
|
||||
// Finds the precise location of the given error and fills in *line and
|
||||
// *column with the line and column numbers. If not found, sets *line to
|
||||
// -1 and *column to 0 (since line = -1 is used to mean "error has no exact
|
||||
// location" in the ErrorCollector interface). Returns true if found, false
|
||||
// otherwise.
|
||||
bool Find(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location,
|
||||
int* line, int* column) const;
|
||||
|
||||
// Adds a location to the table.
|
||||
void Add(const Message* descriptor,
|
||||
DescriptorPool::ErrorCollector::ErrorLocation location,
|
||||
int line, int column);
|
||||
|
||||
// Clears the contents of the table.
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
typedef map<
|
||||
pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>,
|
||||
pair<int, int> > LocationMap;
|
||||
LocationMap location_map_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__
|
@ -0,0 +1,163 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/plugin.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef STDIN_FILENO
|
||||
#define STDIN_FILENO 0
|
||||
#endif
|
||||
#ifndef STDOUT_FILENO
|
||||
#define STDOUT_FILENO 1
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/compiler/plugin.pb.h>
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
class GeneratorResponseContext : public GeneratorContext {
|
||||
public:
|
||||
GeneratorResponseContext(CodeGeneratorResponse* response,
|
||||
const vector<const FileDescriptor*>& parsed_files)
|
||||
: response_(response),
|
||||
parsed_files_(parsed_files) {}
|
||||
virtual ~GeneratorResponseContext() {}
|
||||
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) {
|
||||
CodeGeneratorResponse::File* file = response_->add_file();
|
||||
file->set_name(filename);
|
||||
return new io::StringOutputStream(file->mutable_content());
|
||||
}
|
||||
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert(
|
||||
const string& filename, const string& insertion_point) {
|
||||
CodeGeneratorResponse::File* file = response_->add_file();
|
||||
file->set_name(filename);
|
||||
file->set_insertion_point(insertion_point);
|
||||
return new io::StringOutputStream(file->mutable_content());
|
||||
}
|
||||
|
||||
void ListParsedFiles(vector<const FileDescriptor*>* output) {
|
||||
*output = parsed_files_;
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGeneratorResponse* response_;
|
||||
const vector<const FileDescriptor*>& parsed_files_;
|
||||
};
|
||||
|
||||
int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
|
||||
|
||||
if (argc > 1) {
|
||||
cerr << argv[0] << ": Unknown option: " << argv[1] << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
_setmode(STDIN_FILENO, _O_BINARY);
|
||||
_setmode(STDOUT_FILENO, _O_BINARY);
|
||||
#endif
|
||||
|
||||
CodeGeneratorRequest request;
|
||||
if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
|
||||
cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
DescriptorPool pool;
|
||||
for (int i = 0; i < request.proto_file_size(); i++) {
|
||||
const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
|
||||
if (file == NULL) {
|
||||
// BuildFile() already wrote an error message.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vector<const FileDescriptor*> parsed_files;
|
||||
for (int i = 0; i < request.file_to_generate_size(); i++) {
|
||||
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
|
||||
if (parsed_files.back() == NULL) {
|
||||
cerr << argv[0] << ": protoc asked plugin to generate a file but "
|
||||
"did not provide a descriptor for the file: "
|
||||
<< request.file_to_generate(i) << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
CodeGeneratorResponse response;
|
||||
GeneratorResponseContext context(&response, parsed_files);
|
||||
|
||||
for (int i = 0; i < parsed_files.size(); i++) {
|
||||
const FileDescriptor* file = parsed_files[i];
|
||||
|
||||
string error;
|
||||
bool succeeded = generator->Generate(
|
||||
file, request.parameter(), &context, &error);
|
||||
|
||||
if (!succeeded && error.empty()) {
|
||||
error = "Code generator returned false but provided no error "
|
||||
"description.";
|
||||
}
|
||||
if (!error.empty()) {
|
||||
response.set_error(file->name() + ": " + error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
|
||||
cerr << argv[0] << ": Error writing to stdout." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,73 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Front-end for protoc code generator plugins written in C++.
|
||||
//
|
||||
// To implement a protoc plugin in C++, simply write an implementation of
|
||||
// CodeGenerator, then create a main() function like:
|
||||
// int main(int argc, char* argv[]) {
|
||||
// MyCodeGenerator generator;
|
||||
// return google::protobuf::compiler::PluginMain(argc, argv, &generator);
|
||||
// }
|
||||
// You must link your plugin against libprotobuf and libprotoc.
|
||||
//
|
||||
// To get protoc to use the plugin, do one of the following:
|
||||
// * Place the plugin binary somewhere in the PATH and give it the name
|
||||
// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you
|
||||
// then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace
|
||||
// "NAME" with your plugin's name), protoc will invoke your plugin to generate
|
||||
// the output, which will be placed in OUT_DIR.
|
||||
// * Place the plugin binary anywhere, with any name, and pass the --plugin
|
||||
// parameter to protoc to direct it to your plugin like so:
|
||||
// protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR
|
||||
// On Windows, make sure to include the .exe suffix:
|
||||
// protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
|
||||
// Implements main() for a protoc plugin exposing the given code generator.
|
||||
int PluginMain(int argc, char* argv[], const CodeGenerator* generator);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,790 @@
|
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: google/protobuf/compiler/plugin.proto
|
||||
|
||||
#ifndef PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
|
||||
#define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION < 2004000
|
||||
#error This file was generated by a newer version of protoc which is
|
||||
#error incompatible with your Protocol Buffer headers. Please update
|
||||
#error your headers.
|
||||
#endif
|
||||
#if 2004001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
|
||||
#error This file was generated by an older version of protoc which is
|
||||
#error incompatible with your Protocol Buffer headers. Please
|
||||
#error regenerate this file with a newer version of protoc.
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
// @@protoc_insertion_point(includes)
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
// Internal implementation detail -- do not call these.
|
||||
void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
class CodeGeneratorRequest;
|
||||
class CodeGeneratorResponse;
|
||||
class CodeGeneratorResponse_File;
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message {
|
||||
public:
|
||||
CodeGeneratorRequest();
|
||||
virtual ~CodeGeneratorRequest();
|
||||
|
||||
CodeGeneratorRequest(const CodeGeneratorRequest& from);
|
||||
|
||||
inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorRequest& default_instance();
|
||||
|
||||
void Swap(CodeGeneratorRequest* other);
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorRequest* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const CodeGeneratorRequest& from);
|
||||
void MergeFrom(const CodeGeneratorRequest& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
void SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const;
|
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
|
||||
int GetCachedSize() const { return _cached_size_; }
|
||||
private:
|
||||
void SharedCtor();
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// repeated string file_to_generate = 1;
|
||||
inline int file_to_generate_size() const;
|
||||
inline void clear_file_to_generate();
|
||||
static const int kFileToGenerateFieldNumber = 1;
|
||||
inline const ::std::string& file_to_generate(int index) const;
|
||||
inline ::std::string* mutable_file_to_generate(int index);
|
||||
inline void set_file_to_generate(int index, const ::std::string& value);
|
||||
inline void set_file_to_generate(int index, const char* value);
|
||||
inline void set_file_to_generate(int index, const char* value, size_t size);
|
||||
inline ::std::string* add_file_to_generate();
|
||||
inline void add_file_to_generate(const ::std::string& value);
|
||||
inline void add_file_to_generate(const char* value);
|
||||
inline void add_file_to_generate(const char* value, size_t size);
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate();
|
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool has_parameter() const;
|
||||
inline void clear_parameter();
|
||||
static const int kParameterFieldNumber = 2;
|
||||
inline const ::std::string& parameter() const;
|
||||
inline void set_parameter(const ::std::string& value);
|
||||
inline void set_parameter(const char* value);
|
||||
inline void set_parameter(const char* value, size_t size);
|
||||
inline ::std::string* mutable_parameter();
|
||||
inline ::std::string* release_parameter();
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int proto_file_size() const;
|
||||
inline void clear_proto_file();
|
||||
static const int kProtoFileFieldNumber = 15;
|
||||
inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const;
|
||||
inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index);
|
||||
inline ::google::protobuf::FileDescriptorProto* add_proto_file();
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
|
||||
proto_file() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
|
||||
mutable_proto_file();
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
|
||||
private:
|
||||
inline void set_has_parameter();
|
||||
inline void clear_has_parameter();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
|
||||
::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_;
|
||||
::std::string* parameter_;
|
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorRequest* default_instance_;
|
||||
};
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message {
|
||||
public:
|
||||
CodeGeneratorResponse_File();
|
||||
virtual ~CodeGeneratorResponse_File();
|
||||
|
||||
CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from);
|
||||
|
||||
inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorResponse_File& default_instance();
|
||||
|
||||
void Swap(CodeGeneratorResponse_File* other);
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorResponse_File* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const CodeGeneratorResponse_File& from);
|
||||
void MergeFrom(const CodeGeneratorResponse_File& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
void SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const;
|
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
|
||||
int GetCachedSize() const { return _cached_size_; }
|
||||
private:
|
||||
void SharedCtor();
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool has_name() const;
|
||||
inline void clear_name();
|
||||
static const int kNameFieldNumber = 1;
|
||||
inline const ::std::string& name() const;
|
||||
inline void set_name(const ::std::string& value);
|
||||
inline void set_name(const char* value);
|
||||
inline void set_name(const char* value, size_t size);
|
||||
inline ::std::string* mutable_name();
|
||||
inline ::std::string* release_name();
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool has_insertion_point() const;
|
||||
inline void clear_insertion_point();
|
||||
static const int kInsertionPointFieldNumber = 2;
|
||||
inline const ::std::string& insertion_point() const;
|
||||
inline void set_insertion_point(const ::std::string& value);
|
||||
inline void set_insertion_point(const char* value);
|
||||
inline void set_insertion_point(const char* value, size_t size);
|
||||
inline ::std::string* mutable_insertion_point();
|
||||
inline ::std::string* release_insertion_point();
|
||||
|
||||
// optional string content = 15;
|
||||
inline bool has_content() const;
|
||||
inline void clear_content();
|
||||
static const int kContentFieldNumber = 15;
|
||||
inline const ::std::string& content() const;
|
||||
inline void set_content(const ::std::string& value);
|
||||
inline void set_content(const char* value);
|
||||
inline void set_content(const char* value, size_t size);
|
||||
inline ::std::string* mutable_content();
|
||||
inline ::std::string* release_content();
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
|
||||
private:
|
||||
inline void set_has_name();
|
||||
inline void clear_has_name();
|
||||
inline void set_has_insertion_point();
|
||||
inline void clear_has_insertion_point();
|
||||
inline void set_has_content();
|
||||
inline void clear_has_content();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
|
||||
::std::string* name_;
|
||||
::std::string* insertion_point_;
|
||||
::std::string* content_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorResponse_File* default_instance_;
|
||||
};
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message {
|
||||
public:
|
||||
CodeGeneratorResponse();
|
||||
virtual ~CodeGeneratorResponse();
|
||||
|
||||
CodeGeneratorResponse(const CodeGeneratorResponse& from);
|
||||
|
||||
inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) {
|
||||
CopyFrom(from);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
|
||||
return _unknown_fields_;
|
||||
}
|
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
|
||||
return &_unknown_fields_;
|
||||
}
|
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor();
|
||||
static const CodeGeneratorResponse& default_instance();
|
||||
|
||||
void Swap(CodeGeneratorResponse* other);
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorResponse* New() const;
|
||||
void CopyFrom(const ::google::protobuf::Message& from);
|
||||
void MergeFrom(const ::google::protobuf::Message& from);
|
||||
void CopyFrom(const CodeGeneratorResponse& from);
|
||||
void MergeFrom(const CodeGeneratorResponse& from);
|
||||
void Clear();
|
||||
bool IsInitialized() const;
|
||||
|
||||
int ByteSize() const;
|
||||
bool MergePartialFromCodedStream(
|
||||
::google::protobuf::io::CodedInputStream* input);
|
||||
void SerializeWithCachedSizes(
|
||||
::google::protobuf::io::CodedOutputStream* output) const;
|
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
|
||||
int GetCachedSize() const { return _cached_size_; }
|
||||
private:
|
||||
void SharedCtor();
|
||||
void SharedDtor();
|
||||
void SetCachedSize(int size) const;
|
||||
public:
|
||||
|
||||
::google::protobuf::Metadata GetMetadata() const;
|
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
typedef CodeGeneratorResponse_File File;
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool has_error() const;
|
||||
inline void clear_error();
|
||||
static const int kErrorFieldNumber = 1;
|
||||
inline const ::std::string& error() const;
|
||||
inline void set_error(const ::std::string& value);
|
||||
inline void set_error(const char* value);
|
||||
inline void set_error(const char* value, size_t size);
|
||||
inline ::std::string* mutable_error();
|
||||
inline ::std::string* release_error();
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int file_size() const;
|
||||
inline void clear_file();
|
||||
static const int kFileFieldNumber = 15;
|
||||
inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const;
|
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index);
|
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file();
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
|
||||
file() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
|
||||
mutable_file();
|
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
|
||||
private:
|
||||
inline void set_has_error();
|
||||
inline void clear_has_error();
|
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_;
|
||||
|
||||
::std::string* error_;
|
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_;
|
||||
|
||||
mutable int _cached_size_;
|
||||
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
|
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto();
|
||||
|
||||
void InitAsDefaultInstance();
|
||||
static CodeGeneratorResponse* default_instance_;
|
||||
};
|
||||
// ===================================================================
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// CodeGeneratorRequest
|
||||
|
||||
// repeated string file_to_generate = 1;
|
||||
inline int CodeGeneratorRequest::file_to_generate_size() const {
|
||||
return file_to_generate_.size();
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_file_to_generate() {
|
||||
file_to_generate_.Clear();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const {
|
||||
return file_to_generate_.Get(index);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) {
|
||||
return file_to_generate_.Mutable(index);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) {
|
||||
file_to_generate_.Mutable(index)->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) {
|
||||
file_to_generate_.Mutable(index)->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) {
|
||||
file_to_generate_.Mutable(index)->assign(
|
||||
reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::add_file_to_generate() {
|
||||
return file_to_generate_.Add();
|
||||
}
|
||||
inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) {
|
||||
file_to_generate_.Add()->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::add_file_to_generate(const char* value) {
|
||||
file_to_generate_.Add()->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) {
|
||||
file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
|
||||
CodeGeneratorRequest::file_to_generate() const {
|
||||
return file_to_generate_;
|
||||
}
|
||||
inline ::google::protobuf::RepeatedPtrField< ::std::string>*
|
||||
CodeGeneratorRequest::mutable_file_to_generate() {
|
||||
return &file_to_generate_;
|
||||
}
|
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool CodeGeneratorRequest::has_parameter() const {
|
||||
return (_has_bits_[0] & 0x00000002u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_has_parameter() {
|
||||
_has_bits_[0] |= 0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_has_parameter() {
|
||||
_has_bits_[0] &= ~0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_parameter() {
|
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_->clear();
|
||||
}
|
||||
clear_has_parameter();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorRequest::parameter() const {
|
||||
return *parameter_;
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const char* value) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
parameter_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::mutable_parameter() {
|
||||
set_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
parameter_ = new ::std::string;
|
||||
}
|
||||
return parameter_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorRequest::release_parameter() {
|
||||
clear_has_parameter();
|
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = parameter_;
|
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int CodeGeneratorRequest::proto_file_size() const {
|
||||
return proto_file_.size();
|
||||
}
|
||||
inline void CodeGeneratorRequest::clear_proto_file() {
|
||||
proto_file_.Clear();
|
||||
}
|
||||
inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const {
|
||||
return proto_file_.Get(index);
|
||||
}
|
||||
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) {
|
||||
return proto_file_.Mutable(index);
|
||||
}
|
||||
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() {
|
||||
return proto_file_.Add();
|
||||
}
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >&
|
||||
CodeGeneratorRequest::proto_file() const {
|
||||
return proto_file_;
|
||||
}
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >*
|
||||
CodeGeneratorRequest::mutable_proto_file() {
|
||||
return &proto_file_;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// CodeGeneratorResponse_File
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool CodeGeneratorResponse_File::has_name() const {
|
||||
return (_has_bits_[0] & 0x00000001u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_name() {
|
||||
_has_bits_[0] |= 0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_name() {
|
||||
_has_bits_[0] &= ~0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_name() {
|
||||
if (name_ != &::google::protobuf::internal::kEmptyString) {
|
||||
name_->clear();
|
||||
}
|
||||
clear_has_name();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::name() const {
|
||||
return *name_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const char* value) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
name_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_name() {
|
||||
set_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
name_ = new ::std::string;
|
||||
}
|
||||
return name_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_name() {
|
||||
clear_has_name();
|
||||
if (name_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = name_;
|
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool CodeGeneratorResponse_File::has_insertion_point() const {
|
||||
return (_has_bits_[0] & 0x00000002u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_insertion_point() {
|
||||
_has_bits_[0] |= 0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_insertion_point() {
|
||||
_has_bits_[0] &= ~0x00000002u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_insertion_point() {
|
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_->clear();
|
||||
}
|
||||
clear_has_insertion_point();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const {
|
||||
return *insertion_point_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
insertion_point_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() {
|
||||
set_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
insertion_point_ = new ::std::string;
|
||||
}
|
||||
return insertion_point_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() {
|
||||
clear_has_insertion_point();
|
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = insertion_point_;
|
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// optional string content = 15;
|
||||
inline bool CodeGeneratorResponse_File::has_content() const {
|
||||
return (_has_bits_[0] & 0x00000004u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_has_content() {
|
||||
_has_bits_[0] |= 0x00000004u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_has_content() {
|
||||
_has_bits_[0] &= ~0x00000004u;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::clear_content() {
|
||||
if (content_ != &::google::protobuf::internal::kEmptyString) {
|
||||
content_->clear();
|
||||
}
|
||||
clear_has_content();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse_File::content() const {
|
||||
return *content_;
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const char* value) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
content_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_content() {
|
||||
set_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
content_ = new ::std::string;
|
||||
}
|
||||
return content_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse_File::release_content() {
|
||||
clear_has_content();
|
||||
if (content_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = content_;
|
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// CodeGeneratorResponse
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool CodeGeneratorResponse::has_error() const {
|
||||
return (_has_bits_[0] & 0x00000001u) != 0;
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_has_error() {
|
||||
_has_bits_[0] |= 0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse::clear_has_error() {
|
||||
_has_bits_[0] &= ~0x00000001u;
|
||||
}
|
||||
inline void CodeGeneratorResponse::clear_error() {
|
||||
if (error_ != &::google::protobuf::internal::kEmptyString) {
|
||||
error_->clear();
|
||||
}
|
||||
clear_has_error();
|
||||
}
|
||||
inline const ::std::string& CodeGeneratorResponse::error() const {
|
||||
return *error_;
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const ::std::string& value) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const char* value) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(value);
|
||||
}
|
||||
inline void CodeGeneratorResponse::set_error(const char* value, size_t size) {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
error_->assign(reinterpret_cast<const char*>(value), size);
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse::mutable_error() {
|
||||
set_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
error_ = new ::std::string;
|
||||
}
|
||||
return error_;
|
||||
}
|
||||
inline ::std::string* CodeGeneratorResponse::release_error() {
|
||||
clear_has_error();
|
||||
if (error_ == &::google::protobuf::internal::kEmptyString) {
|
||||
return NULL;
|
||||
} else {
|
||||
::std::string* temp = error_;
|
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int CodeGeneratorResponse::file_size() const {
|
||||
return file_.size();
|
||||
}
|
||||
inline void CodeGeneratorResponse::clear_file() {
|
||||
file_.Clear();
|
||||
}
|
||||
inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const {
|
||||
return file_.Get(index);
|
||||
}
|
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) {
|
||||
return file_.Mutable(index);
|
||||
}
|
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() {
|
||||
return file_.Add();
|
||||
}
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >&
|
||||
CodeGeneratorResponse::file() const {
|
||||
return file_;
|
||||
}
|
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >*
|
||||
CodeGeneratorResponse::mutable_file() {
|
||||
return &file_;
|
||||
}
|
||||
|
||||
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#ifndef SWIG
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
|
||||
} // namespace google
|
||||
} // namespace protobuf
|
||||
#endif // SWIG
|
||||
|
||||
// @@protoc_insertion_point(global_scope)
|
||||
|
||||
#endif // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
|
@ -0,0 +1,460 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/subprocess.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static void CloseHandleOrDie(HANDLE handle) {
|
||||
if (!CloseHandle(handle)) {
|
||||
GOOGLE_LOG(FATAL) << "CloseHandle: "
|
||||
<< Subprocess::Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
Subprocess::Subprocess()
|
||||
: process_start_error_(ERROR_SUCCESS),
|
||||
child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}
|
||||
|
||||
Subprocess::~Subprocess() {
|
||||
if (child_stdin_ != NULL) {
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
}
|
||||
if (child_stdout_ != NULL) {
|
||||
CloseHandleOrDie(child_stdout_);
|
||||
}
|
||||
}
|
||||
|
||||
void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
// Create the pipes.
|
||||
HANDLE stdin_pipe_read;
|
||||
HANDLE stdin_pipe_write;
|
||||
HANDLE stdout_pipe_read;
|
||||
HANDLE stdout_pipe_write;
|
||||
|
||||
if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
|
||||
GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
|
||||
GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// Make child side of the pipes inheritable.
|
||||
if (!SetHandleInformation(stdin_pipe_read,
|
||||
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
|
||||
GOOGLE_LOG(FATAL) << "SetHandleInformation: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
if (!SetHandleInformation(stdout_pipe_write,
|
||||
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
|
||||
GOOGLE_LOG(FATAL) << "SetHandleInformation: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// Setup STARTUPINFO to redirect handles.
|
||||
STARTUPINFOA startup_info;
|
||||
ZeroMemory(&startup_info, sizeof(startup_info));
|
||||
startup_info.cb = sizeof(startup_info);
|
||||
startup_info.dwFlags = STARTF_USESTDHANDLES;
|
||||
startup_info.hStdInput = stdin_pipe_read;
|
||||
startup_info.hStdOutput = stdout_pipe_write;
|
||||
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
|
||||
GOOGLE_LOG(FATAL) << "GetStdHandle: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
// CreateProcess() mutates its second parameter. WTF?
|
||||
char* name_copy = strdup(program.c_str());
|
||||
|
||||
// Create the process.
|
||||
PROCESS_INFORMATION process_info;
|
||||
|
||||
if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
|
||||
(search_mode == SEARCH_PATH) ? name_copy : NULL,
|
||||
NULL, // process security attributes
|
||||
NULL, // thread security attributes
|
||||
TRUE, // inherit handles?
|
||||
0, // obscure creation flags
|
||||
NULL, // environment (inherit from parent)
|
||||
NULL, // current directory (inherit from parent)
|
||||
&startup_info,
|
||||
&process_info)) {
|
||||
child_handle_ = process_info.hProcess;
|
||||
CloseHandleOrDie(process_info.hThread);
|
||||
child_stdin_ = stdin_pipe_write;
|
||||
child_stdout_ = stdout_pipe_read;
|
||||
} else {
|
||||
process_start_error_ = GetLastError();
|
||||
CloseHandleOrDie(stdin_pipe_write);
|
||||
CloseHandleOrDie(stdout_pipe_read);
|
||||
}
|
||||
|
||||
CloseHandleOrDie(stdin_pipe_read);
|
||||
CloseHandleOrDie(stdout_pipe_write);
|
||||
free(name_copy);
|
||||
}
|
||||
|
||||
bool Subprocess::Communicate(const Message& input, Message* output,
|
||||
string* error) {
|
||||
if (process_start_error_ != ERROR_SUCCESS) {
|
||||
*error = Win32ErrorMessage(process_start_error_);
|
||||
return false;
|
||||
}
|
||||
|
||||
GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";
|
||||
|
||||
string input_data = input.SerializeAsString();
|
||||
string output_data;
|
||||
|
||||
int input_pos = 0;
|
||||
|
||||
while (child_stdout_ != NULL) {
|
||||
HANDLE handles[2];
|
||||
int handle_count = 0;
|
||||
|
||||
if (child_stdin_ != NULL) {
|
||||
handles[handle_count++] = child_stdin_;
|
||||
}
|
||||
if (child_stdout_ != NULL) {
|
||||
handles[handle_count++] = child_stdout_;
|
||||
}
|
||||
|
||||
DWORD wait_result =
|
||||
WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);
|
||||
|
||||
HANDLE signaled_handle;
|
||||
if (wait_result >= WAIT_OBJECT_0 &&
|
||||
wait_result < WAIT_OBJECT_0 + handle_count) {
|
||||
signaled_handle = handles[wait_result - WAIT_OBJECT_0];
|
||||
} else if (wait_result == WAIT_FAILED) {
|
||||
GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
} else {
|
||||
GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
|
||||
<< wait_result;
|
||||
}
|
||||
|
||||
if (signaled_handle == child_stdin_) {
|
||||
DWORD n;
|
||||
if (!WriteFile(child_stdin_,
|
||||
input_data.data() + input_pos,
|
||||
input_data.size() - input_pos,
|
||||
&n, NULL)) {
|
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size();
|
||||
} else {
|
||||
input_pos += n;
|
||||
}
|
||||
|
||||
if (input_pos == input_data.size()) {
|
||||
// We're done writing. Close.
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
child_stdin_ = NULL;
|
||||
}
|
||||
} else if (signaled_handle == child_stdout_) {
|
||||
char buffer[4096];
|
||||
DWORD n;
|
||||
|
||||
if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
|
||||
// We're done reading. Close.
|
||||
CloseHandleOrDie(child_stdout_);
|
||||
child_stdout_ = NULL;
|
||||
} else {
|
||||
output_data.append(buffer, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != NULL) {
|
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
CloseHandleOrDie(child_stdin_);
|
||||
child_stdin_ = NULL;
|
||||
}
|
||||
|
||||
DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);
|
||||
|
||||
if (wait_result == WAIT_FAILED) {
|
||||
GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
} else if (wait_result != WAIT_OBJECT_0) {
|
||||
GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
|
||||
<< wait_result;
|
||||
}
|
||||
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess(child_handle_, &exit_code)) {
|
||||
GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
|
||||
<< Win32ErrorMessage(GetLastError());
|
||||
}
|
||||
|
||||
CloseHandleOrDie(child_handle_);
|
||||
child_handle_ = NULL;
|
||||
|
||||
if (exit_code != 0) {
|
||||
*error = strings::Substitute(
|
||||
"Plugin failed with status code $0.", exit_code);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!output->ParseFromString(output_data)) {
|
||||
*error = "Plugin output is unparseable: " + CEscape(output_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string Subprocess::Win32ErrorMessage(DWORD error_code) {
|
||||
char* message;
|
||||
|
||||
// WTF?
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, error_code, 0,
|
||||
(LPTSTR)&message, // NOT A BUG!
|
||||
0, NULL);
|
||||
|
||||
string result = message;
|
||||
LocalFree(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
Subprocess::Subprocess()
|
||||
: child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}
|
||||
|
||||
Subprocess::~Subprocess() {
|
||||
if (child_stdin_ != -1) {
|
||||
close(child_stdin_);
|
||||
}
|
||||
if (child_stdout_ != -1) {
|
||||
close(child_stdout_);
|
||||
}
|
||||
}
|
||||
|
||||
void Subprocess::Start(const string& program, SearchMode search_mode) {
|
||||
// Note that we assume that there are no other threads, thus we don't have to
|
||||
// do crazy stuff like using socket pairs or avoiding libc locks.
|
||||
|
||||
// [0] is read end, [1] is write end.
|
||||
int stdin_pipe[2];
|
||||
int stdout_pipe[2];
|
||||
|
||||
pipe(stdin_pipe);
|
||||
pipe(stdout_pipe);
|
||||
|
||||
char* argv[2] = { strdup(program.c_str()), NULL };
|
||||
|
||||
child_pid_ = fork();
|
||||
if (child_pid_ == -1) {
|
||||
GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
|
||||
} else if (child_pid_ == 0) {
|
||||
// We are the child.
|
||||
dup2(stdin_pipe[0], STDIN_FILENO);
|
||||
dup2(stdout_pipe[1], STDOUT_FILENO);
|
||||
|
||||
close(stdin_pipe[0]);
|
||||
close(stdin_pipe[1]);
|
||||
close(stdout_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
|
||||
switch (search_mode) {
|
||||
case SEARCH_PATH:
|
||||
execvp(argv[0], argv);
|
||||
break;
|
||||
case EXACT_NAME:
|
||||
execv(argv[0], argv);
|
||||
break;
|
||||
}
|
||||
|
||||
// Write directly to STDERR_FILENO to avoid stdio code paths that may do
|
||||
// stuff that is unsafe here.
|
||||
write(STDERR_FILENO, argv[0], strlen(argv[0]));
|
||||
const char* message = ": program not found or is not executable\n";
|
||||
write(STDERR_FILENO, message, strlen(message));
|
||||
|
||||
// Must use _exit() rather than exit() to avoid flushing output buffers
|
||||
// that will also be flushed by the parent.
|
||||
_exit(1);
|
||||
} else {
|
||||
free(argv[0]);
|
||||
|
||||
close(stdin_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
|
||||
child_stdin_ = stdin_pipe[1];
|
||||
child_stdout_ = stdout_pipe[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool Subprocess::Communicate(const Message& input, Message* output,
|
||||
string* error) {
|
||||
|
||||
GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";
|
||||
|
||||
// The "sighandler_t" typedef is GNU-specific, so define our own.
|
||||
typedef void SignalHandler(int);
|
||||
|
||||
// Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
|
||||
SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
string input_data = input.SerializeAsString();
|
||||
string output_data;
|
||||
|
||||
int input_pos = 0;
|
||||
int max_fd = max(child_stdin_, child_stdout_);
|
||||
|
||||
while (child_stdout_ != -1) {
|
||||
fd_set read_fds;
|
||||
fd_set write_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_ZERO(&write_fds);
|
||||
if (child_stdout_ != -1) {
|
||||
FD_SET(child_stdout_, &read_fds);
|
||||
}
|
||||
if (child_stdin_ != -1) {
|
||||
FD_SET(child_stdin_, &write_fds);
|
||||
}
|
||||
|
||||
if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
|
||||
if (errno == EINTR) {
|
||||
// Interrupted by signal. Try again.
|
||||
continue;
|
||||
} else {
|
||||
GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
|
||||
int n = write(child_stdin_, input_data.data() + input_pos,
|
||||
input_data.size() - input_pos);
|
||||
if (n < 0) {
|
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size();
|
||||
} else {
|
||||
input_pos += n;
|
||||
}
|
||||
|
||||
if (input_pos == input_data.size()) {
|
||||
// We're done writing. Close.
|
||||
close(child_stdin_);
|
||||
child_stdin_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
|
||||
char buffer[4096];
|
||||
int n = read(child_stdout_, buffer, sizeof(buffer));
|
||||
|
||||
if (n > 0) {
|
||||
output_data.append(buffer, n);
|
||||
} else {
|
||||
// We're done reading. Close.
|
||||
close(child_stdout_);
|
||||
child_stdout_ = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (child_stdin_ != -1) {
|
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
close(child_stdin_);
|
||||
child_stdin_ = -1;
|
||||
}
|
||||
|
||||
int status;
|
||||
while (waitpid(child_pid_, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore SIGPIPE handling.
|
||||
signal(SIGPIPE, old_pipe_handler);
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
int error_code = WEXITSTATUS(status);
|
||||
*error = strings::Substitute(
|
||||
"Plugin failed with status code $0.", error_code);
|
||||
return false;
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
int signal = WTERMSIG(status);
|
||||
*error = strings::Substitute(
|
||||
"Plugin killed by signal $0.", signal);
|
||||
return false;
|
||||
} else {
|
||||
*error = "Neither WEXITSTATUS nor WTERMSIG is true?";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!output->ParseFromString(output_data)) {
|
||||
*error = "Plugin output is unparseable.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,108 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN // right...
|
||||
#include <windows.h>
|
||||
#else // _WIN32
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // !_WIN32
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class Message;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// Utility class for launching sub-processes.
|
||||
class Subprocess {
|
||||
public:
|
||||
Subprocess();
|
||||
~Subprocess();
|
||||
|
||||
enum SearchMode {
|
||||
SEARCH_PATH, // Use PATH environment variable.
|
||||
EXACT_NAME // Program is an exact file name; don't use the PATH.
|
||||
};
|
||||
|
||||
// Start the subprocess. Currently we don't provide a way to specify
|
||||
// arguments as protoc plugins don't have any.
|
||||
void Start(const string& program, SearchMode search_mode);
|
||||
|
||||
// Serialize the input message and pipe it to the subprocess's stdin, then
|
||||
// close the pipe. Meanwhile, read from the subprocess's stdout and parse
|
||||
// the data into *output. All this is done carefully to avoid deadlocks.
|
||||
// Returns true if successful. On any sort of error, returns false and sets
|
||||
// *error to a description of the problem.
|
||||
bool Communicate(const Message& input, Message* output, string* error);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Given an error code, returns a human-readable error message. This is
|
||||
// defined here so that CommandLineInterface can share it.
|
||||
static string Win32ErrorMessage(DWORD error_code);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
DWORD process_start_error_;
|
||||
HANDLE child_handle_;
|
||||
|
||||
// The file handles for our end of the child's pipes. We close each and
|
||||
// set it to NULL when no longer needed.
|
||||
HANDLE child_stdin_;
|
||||
HANDLE child_stdout_;
|
||||
|
||||
#else // _WIN32
|
||||
pid_t child_pid_;
|
||||
|
||||
// The file descriptors for our end of the child's pipes. We close each and
|
||||
// set it to -1 when no longer needed.
|
||||
int child_stdin_;
|
||||
int child_stdout_;
|
||||
|
||||
#endif // !_WIN32
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
|
@ -0,0 +1,51 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// This is a dummy code generator plugin used by
|
||||
// command_line_interface_unittest.
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <google/protobuf/compiler/plugin.h>
|
||||
#include <google/protobuf/compiler/mock_code_generator.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _MSC_VER
|
||||
// Don't print a silly message or stick a modal dialog box in my face,
|
||||
// please.
|
||||
_set_abort_behavior(0, ~0);
|
||||
#endif // !_MSC_VER
|
||||
|
||||
google::protobuf::compiler::MockCodeGenerator generator("test_plugin");
|
||||
return google::protobuf::compiler::PluginMain(argc, argv, &generator);
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: ambrose@google.com (Ambrose Feinstein),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
|
||||
#include <google/protobuf/compiler/zip_writer.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
static const uint32 kCRC32Table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
|
||||
static uint32 ComputeCRC32(const string &buf) {
|
||||
uint32 x = ~0U;
|
||||
for (int i = 0; i < buf.size(); ++i) {
|
||||
unsigned char c = buf[i];
|
||||
x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8);
|
||||
}
|
||||
return ~x;
|
||||
}
|
||||
|
||||
static void WriteShort(io::CodedOutputStream *out, uint16 val) {
|
||||
uint8 p[2];
|
||||
p[0] = static_cast<uint8>(val);
|
||||
p[1] = static_cast<uint8>(val >> 8);
|
||||
out->WriteRaw(p, 2);
|
||||
}
|
||||
|
||||
ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output)
|
||||
: raw_output_(raw_output) {}
|
||||
ZipWriter::~ZipWriter() {}
|
||||
|
||||
bool ZipWriter::Write(const string& filename, const string& contents) {
|
||||
FileInfo info;
|
||||
|
||||
info.name = filename;
|
||||
uint16 filename_size = filename.size();
|
||||
info.offset = raw_output_->ByteCount();
|
||||
info.size = contents.size();
|
||||
info.crc32 = ComputeCRC32(contents);
|
||||
|
||||
files_.push_back(info);
|
||||
|
||||
// write file header
|
||||
io::CodedOutputStream output(raw_output_);
|
||||
output.WriteLittleEndian32(0x04034b50); // magic
|
||||
WriteShort(&output, 10); // version needed to extract
|
||||
WriteShort(&output, 0); // flags
|
||||
WriteShort(&output, 0); // compression method: stored
|
||||
WriteShort(&output, 0); // last modified time
|
||||
WriteShort(&output, 0); // last modified date
|
||||
output.WriteLittleEndian32(info.crc32); // crc-32
|
||||
output.WriteLittleEndian32(info.size); // compressed size
|
||||
output.WriteLittleEndian32(info.size); // uncompressed size
|
||||
WriteShort(&output, filename_size); // file name length
|
||||
WriteShort(&output, 0); // extra field length
|
||||
output.WriteString(filename); // file name
|
||||
output.WriteString(contents); // file data
|
||||
|
||||
return !output.HadError();
|
||||
}
|
||||
|
||||
bool ZipWriter::WriteDirectory() {
|
||||
uint16 num_entries = files_.size();
|
||||
uint32 dir_ofs = raw_output_->ByteCount();
|
||||
|
||||
// write central directory
|
||||
io::CodedOutputStream output(raw_output_);
|
||||
for (int i = 0; i < num_entries; ++i) {
|
||||
const string &filename = files_[i].name;
|
||||
uint16 filename_size = filename.size();
|
||||
uint32 crc32 = files_[i].crc32;
|
||||
uint32 size = files_[i].size;
|
||||
uint32 offset = files_[i].offset;
|
||||
|
||||
output.WriteLittleEndian32(0x02014b50); // magic
|
||||
WriteShort(&output, 10); // version made by
|
||||
WriteShort(&output, 10); // version needed to extract
|
||||
WriteShort(&output, 0); // flags
|
||||
WriteShort(&output, 0); // compression method: stored
|
||||
WriteShort(&output, 0); // last modified time
|
||||
WriteShort(&output, 0); // last modified date
|
||||
output.WriteLittleEndian32(crc32); // crc-32
|
||||
output.WriteLittleEndian32(size); // compressed size
|
||||
output.WriteLittleEndian32(size); // uncompressed size
|
||||
WriteShort(&output, filename_size); // file name length
|
||||
WriteShort(&output, 0); // extra field length
|
||||
WriteShort(&output, 0); // file comment length
|
||||
WriteShort(&output, 0); // starting disk number
|
||||
WriteShort(&output, 0); // internal file attributes
|
||||
output.WriteLittleEndian32(0); // external file attributes
|
||||
output.WriteLittleEndian32(offset); // local header offset
|
||||
output.WriteString(filename); // file name
|
||||
}
|
||||
uint32 dir_len = output.ByteCount();
|
||||
|
||||
// write end of central directory marker
|
||||
output.WriteLittleEndian32(0x06054b50); // magic
|
||||
WriteShort(&output, 0); // disk number
|
||||
WriteShort(&output, 0); // disk with start of central directory
|
||||
WriteShort(&output, num_entries); // central directory entries (this disk)
|
||||
WriteShort(&output, num_entries); // central directory entries (total)
|
||||
output.WriteLittleEndian32(dir_len); // central directory byte size
|
||||
output.WriteLittleEndian32(dir_ofs); // central directory offset
|
||||
WriteShort(&output, 0); // comment length
|
||||
|
||||
return output.HadError();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,93 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
|
||||
class ZipWriter {
|
||||
public:
|
||||
ZipWriter(io::ZeroCopyOutputStream* raw_output);
|
||||
~ZipWriter();
|
||||
|
||||
bool Write(const string& filename, const string& contents);
|
||||
bool WriteDirectory();
|
||||
|
||||
private:
|
||||
struct FileInfo {
|
||||
string name;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
uint32 crc32;
|
||||
};
|
||||
|
||||
io::ZeroCopyOutputStream* raw_output_;
|
||||
vector<FileInfo> files_;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,541 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/descriptor_database.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
DescriptorDatabase::~DescriptorDatabase() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
|
||||
const FileDescriptorProto& file,
|
||||
Value value) {
|
||||
if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
|
||||
GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must be careful here -- calling file.package() if file.has_package() is
|
||||
// false could access an uninitialized static-storage variable if we are being
|
||||
// run at startup time.
|
||||
string path = file.has_package() ? file.package() : string();
|
||||
if (!path.empty()) path += '.';
|
||||
|
||||
for (int i = 0; i < file.message_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
|
||||
if (!AddNestedExtensions(file.message_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.enum_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.extension_size(); i++) {
|
||||
if (!AddSymbol(path + file.extension(i).name(), value)) return false;
|
||||
if (!AddExtension(file.extension(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.service_size(); i++) {
|
||||
if (!AddSymbol(path + file.service(i).name(), value)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
const string& name, Value value) {
|
||||
// We need to make sure not to violate our map invariant.
|
||||
|
||||
// If the symbol name is invalid it could break our lookup algorithm (which
|
||||
// relies on the fact that '.' sorts before all other characters that are
|
||||
// valid in symbol names).
|
||||
if (!ValidateSymbolName(name)) {
|
||||
GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to look up the symbol to make sure a super-symbol doesn't already
|
||||
// exist.
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
if (iter == by_symbol_.end()) {
|
||||
// Apparently the map is currently empty. Just insert and be done with it.
|
||||
by_symbol_.insert(typename map<string, Value>::value_type(name, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSubSymbol(iter->first, name)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, that worked. Now we have to make sure that no symbol in the map is
|
||||
// a sub-symbol of the one we are inserting. The only symbol which could
|
||||
// be so is the first symbol that is greater than the new symbol. Since
|
||||
// |iter| points at the last symbol that is less than or equal, we just have
|
||||
// to increment it.
|
||||
++iter;
|
||||
|
||||
if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, no conflicts.
|
||||
|
||||
// Insert the new symbol using the iterator as a hint, the new entry will
|
||||
// appear immediately before the one the iterator is pointing at.
|
||||
by_symbol_.insert(iter, typename map<string, Value>::value_type(name, value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
|
||||
const DescriptorProto& message_type,
|
||||
Value value) {
|
||||
for (int i = 0; i < message_type.nested_type_size(); i++) {
|
||||
if (!AddNestedExtensions(message_type.nested_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < message_type.extension_size(); i++) {
|
||||
if (!AddExtension(message_type.extension(i), value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
|
||||
const FieldDescriptorProto& field,
|
||||
Value value) {
|
||||
if (!field.extendee().empty() && field.extendee()[0] == '.') {
|
||||
// The extension is fully-qualified. We can use it as a lookup key in
|
||||
// the by_symbol_ table.
|
||||
if (!InsertIfNotPresent(&by_extension_,
|
||||
make_pair(field.extendee().substr(1),
|
||||
field.number()),
|
||||
value)) {
|
||||
GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
|
||||
"extend " << field.extendee() << " { "
|
||||
<< field.name() << " = " << field.number() << " }";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Not fully-qualified. We can't really do anything here, unfortunately.
|
||||
// We don't consider this an error, though, because the descriptor is
|
||||
// valid.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
|
||||
const string& filename) {
|
||||
return FindWithDefault(by_name_, filename, Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
|
||||
const string& name) {
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ?
|
||||
iter->second : Value();
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
|
||||
const string& containing_type,
|
||||
int field_number) {
|
||||
return FindWithDefault(by_extension_,
|
||||
make_pair(containing_type, field_number),
|
||||
Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
|
||||
const string& containing_type,
|
||||
vector<int>* output) {
|
||||
typename map<pair<string, int>, Value >::const_iterator it =
|
||||
by_extension_.lower_bound(make_pair(containing_type, 0));
|
||||
bool success = false;
|
||||
|
||||
for (; it != by_extension_.end() && it->first.first == containing_type;
|
||||
++it) {
|
||||
output->push_back(it->first.second);
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
typename map<string, Value>::iterator
|
||||
SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
|
||||
const string& name) {
|
||||
// Find the last key in the map which sorts less than or equal to the
|
||||
// symbol name. Since upper_bound() returns the *first* key that sorts
|
||||
// *greater* than the input, we want the element immediately before that.
|
||||
typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
|
||||
if (iter != by_symbol_.begin()) --iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
|
||||
const string& sub_symbol, const string& super_symbol) {
|
||||
return sub_symbol == super_symbol ||
|
||||
(HasPrefixString(super_symbol, sub_symbol) &&
|
||||
super_symbol[sub_symbol.size()] == '.');
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
|
||||
const string& name) {
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
// I don't trust ctype.h due to locales. :(
|
||||
if (name[i] != '.' && name[i] != '_' &&
|
||||
(name[i] < '0' || name[i] > '9') &&
|
||||
(name[i] < 'A' || name[i] > 'Z') &&
|
||||
(name[i] < 'a' || name[i] > 'z')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
|
||||
SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
|
||||
STLDeleteElements(&files_to_delete_);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
|
||||
FileDescriptorProto* new_file = new FileDescriptorProto;
|
||||
new_file->CopyFrom(file);
|
||||
return AddAndOwn(new_file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
|
||||
files_to_delete_.push_back(file);
|
||||
return index_.AddFile(*file, file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output) {
|
||||
if (file == NULL) return false;
|
||||
output->CopyFrom(*file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
|
||||
EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
|
||||
for (int i = 0; i < files_to_delete_.size(); i++) {
|
||||
operator delete(files_to_delete_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::Add(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
FileDescriptorProto file;
|
||||
if (file.ParseFromArray(encoded_file_descriptor, size)) {
|
||||
return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
|
||||
} else {
|
||||
GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
|
||||
"EncodedDescriptorDatabase::Add().";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::AddCopy(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
void* copy = operator new(size);
|
||||
memcpy(copy, encoded_file_descriptor, size);
|
||||
files_to_delete_.push_back(copy);
|
||||
return Add(copy, size);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
string* output) {
|
||||
pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
|
||||
if (encoded_file.first == NULL) return false;
|
||||
|
||||
// Optimization: The name should be the first field in the encoded message.
|
||||
// Try to just read it directly.
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
|
||||
encoded_file.second);
|
||||
|
||||
const uint32 kNameTag = internal::WireFormatLite::MakeTag(
|
||||
FileDescriptorProto::kNameFieldNumber,
|
||||
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
if (input.ReadTag() == kNameTag) {
|
||||
// Success!
|
||||
return internal::WireFormatLite::ReadString(&input, output);
|
||||
} else {
|
||||
// Slow path. Parse whole message.
|
||||
FileDescriptorProto file_proto;
|
||||
if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
|
||||
return false;
|
||||
}
|
||||
*output = file_proto.name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindExtension(containing_type, field_number),
|
||||
output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::MaybeParse(
|
||||
pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output) {
|
||||
if (encoded_file.first == NULL) return false;
|
||||
return output->ParseFromArray(encoded_file.first, encoded_file.second);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
|
||||
: pool_(pool) {}
|
||||
DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileByName(filename);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
const FieldDescriptor* extension =
|
||||
pool_.FindExtensionByNumber(extendee, field_number);
|
||||
if (extension == NULL) return false;
|
||||
|
||||
output->Clear();
|
||||
extension->file()->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
vector<const FieldDescriptor*> extensions;
|
||||
pool_.FindAllExtensions(extendee, &extensions);
|
||||
|
||||
for (int i = 0; i < extensions.size(); ++i) {
|
||||
output->push_back(extensions[i]->number());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2) {
|
||||
sources_.push_back(source1);
|
||||
sources_.push_back(source2);
|
||||
}
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
const vector<DescriptorDatabase*>& sources)
|
||||
: sources_(sources) {}
|
||||
MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileByName(filename, output)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingExtension(
|
||||
containing_type, field_number, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
set<int> merged_results;
|
||||
vector<int> results;
|
||||
bool success = false;
|
||||
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
|
||||
copy(results.begin(), results.end(),
|
||||
insert_iterator<set<int> >(merged_results, merged_results.begin()));
|
||||
success = true;
|
||||
}
|
||||
results.clear();
|
||||
}
|
||||
|
||||
copy(merged_results.begin(), merged_results.end(),
|
||||
insert_iterator<vector<int> >(*output, output->end()));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,366 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Interface for manipulating databases of descriptors.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class DescriptorDatabase;
|
||||
class SimpleDescriptorDatabase;
|
||||
class EncodedDescriptorDatabase;
|
||||
class DescriptorPoolDatabase;
|
||||
class MergedDescriptorDatabase;
|
||||
|
||||
// Abstract interface for a database of descriptors.
|
||||
//
|
||||
// This is useful if you want to create a DescriptorPool which loads
|
||||
// descriptors on-demand from some sort of large database. If the database
|
||||
// is large, it may be inefficient to enumerate every .proto file inside it
|
||||
// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool
|
||||
// can be created which wraps a DescriptorDatabase and only builds particular
|
||||
// descriptors when they are needed.
|
||||
class LIBPROTOBUF_EXPORT DescriptorDatabase {
|
||||
public:
|
||||
inline DescriptorDatabase() {}
|
||||
virtual ~DescriptorDatabase();
|
||||
|
||||
// Find a file by file name. Fills in in *output and returns true if found.
|
||||
// Otherwise, returns false, leaving the contents of *output undefined.
|
||||
virtual bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file that declares the given fully-qualified symbol name.
|
||||
// If found, fills in *output and returns true, otherwise returns false
|
||||
// and leaves *output undefined.
|
||||
virtual bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file which defines an extension extending the given message type
|
||||
// with the given field number. If found, fills in *output and returns true,
|
||||
// otherwise returns false and leaves *output undefined. containing_type
|
||||
// must be a fully-qualified type name.
|
||||
virtual bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Finds the tag numbers used by all known extensions of
|
||||
// extendee_type, and appends them to output in an undefined
|
||||
// order. This method is best-effort: it's not guaranteed that the
|
||||
// database will find all extensions, and it's not guaranteed that
|
||||
// FindFileContainingExtension will return true on all of the found
|
||||
// numbers. Returns true if the search was successful, otherwise
|
||||
// returns false and leaves output unchanged.
|
||||
//
|
||||
// This method has a default implementation that always returns
|
||||
// false.
|
||||
virtual bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase into which you can insert files manually.
|
||||
//
|
||||
// FindFileContainingSymbol() is fully-implemented. When you add a file, its
|
||||
// symbols will be indexed for this purpose. Note that the implementation
|
||||
// may return false positives, but only if it isn't possible for the symbol
|
||||
// to be defined in any other file. In particular, if a file defines a symbol
|
||||
// "Foo", then searching for "Foo.[anything]" will match that file. This way,
|
||||
// the database does not need to aggressively index all children of a symbol.
|
||||
//
|
||||
// FindFileContainingExtension() is mostly-implemented. It works if and only
|
||||
// if the original FieldDescriptorProto defining the extension has a
|
||||
// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
|
||||
// If the extendee is a relative name, SimpleDescriptorDatabase will not
|
||||
// attempt to resolve the type, so it will not know what type the extension is
|
||||
// extending. Therefore, calling FindFileContainingExtension() with the
|
||||
// extension's containing type will never actually find that extension. Note
|
||||
// that this is an unlikely problem, as all FileDescriptorProtos created by the
|
||||
// protocol compiler (as well as ones created by calling
|
||||
// FileDescriptor::CopyTo()) will always use fully-qualified names for all
|
||||
// types. You only need to worry if you are constructing FileDescriptorProtos
|
||||
// yourself, or are calling compiler::Parser directly.
|
||||
class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
SimpleDescriptorDatabase();
|
||||
~SimpleDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database, making a copy. The object
|
||||
// can be deleted after Add() returns. Returns false if the file conflicted
|
||||
// with a file already in the database, in which case an error will have
|
||||
// been written to GOOGLE_LOG(ERROR).
|
||||
bool Add(const FileDescriptorProto& file);
|
||||
|
||||
// Adds the FileDescriptorProto to the database and takes ownership of it.
|
||||
bool AddAndOwn(const FileDescriptorProto* file);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
// So that it can use DescriptorIndex.
|
||||
friend class EncodedDescriptorDatabase;
|
||||
|
||||
// An index mapping file names, symbol names, and extension numbers to
|
||||
// some sort of values.
|
||||
template <typename Value>
|
||||
class DescriptorIndex {
|
||||
public:
|
||||
// Helpers to recursively add particular descriptors and all their contents
|
||||
// to the index.
|
||||
bool AddFile(const FileDescriptorProto& file,
|
||||
Value value);
|
||||
bool AddSymbol(const string& name, Value value);
|
||||
bool AddNestedExtensions(const DescriptorProto& message_type,
|
||||
Value value);
|
||||
bool AddExtension(const FieldDescriptorProto& field,
|
||||
Value value);
|
||||
|
||||
Value FindFile(const string& filename);
|
||||
Value FindSymbol(const string& name);
|
||||
Value FindExtension(const string& containing_type, int field_number);
|
||||
bool FindAllExtensionNumbers(const string& containing_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
map<string, Value> by_name_;
|
||||
map<string, Value> by_symbol_;
|
||||
map<pair<string, int>, Value> by_extension_;
|
||||
|
||||
// Invariant: The by_symbol_ map does not contain any symbols which are
|
||||
// prefixes of other symbols in the map. For example, "foo.bar" is a
|
||||
// prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
|
||||
//
|
||||
// This invariant is important because it means that given a symbol name,
|
||||
// we can find a key in the map which is a prefix of the symbol in O(lg n)
|
||||
// time, and we know that there is at most one such key.
|
||||
//
|
||||
// The prefix lookup algorithm works like so:
|
||||
// 1) Find the last key in the map which is less than or equal to the
|
||||
// search key.
|
||||
// 2) If the found key is a prefix of the search key, then return it.
|
||||
// Otherwise, there is no match.
|
||||
//
|
||||
// I am sure this algorithm has been described elsewhere, but since I
|
||||
// wasn't able to find it quickly I will instead prove that it works
|
||||
// myself. The key to the algorithm is that if a match exists, step (1)
|
||||
// will find it. Proof:
|
||||
// 1) Define the "search key" to be the key we are looking for, the "found
|
||||
// key" to be the key found in step (1), and the "match key" to be the
|
||||
// key which actually matches the serach key (i.e. the key we're trying
|
||||
// to find).
|
||||
// 2) The found key must be less than or equal to the search key by
|
||||
// definition.
|
||||
// 3) The match key must also be less than or equal to the search key
|
||||
// (because it is a prefix).
|
||||
// 4) The match key cannot be greater than the found key, because if it
|
||||
// were, then step (1) of the algorithm would have returned the match
|
||||
// key instead (since it finds the *greatest* key which is less than or
|
||||
// equal to the search key).
|
||||
// 5) Therefore, the found key must be between the match key and the search
|
||||
// key, inclusive.
|
||||
// 6) Since the search key must be a sub-symbol of the match key, if it is
|
||||
// not equal to the match key, then search_key[match_key.size()] must
|
||||
// be '.'.
|
||||
// 7) Since '.' sorts before any other character that is valid in a symbol
|
||||
// name, then if the found key is not equal to the match key, then
|
||||
// found_key[match_key.size()] must also be '.', because any other value
|
||||
// would make it sort after the search key.
|
||||
// 8) Therefore, if the found key is not equal to the match key, then the
|
||||
// found key must be a sub-symbol of the match key. However, this would
|
||||
// contradict our map invariant which says that no symbol in the map is
|
||||
// a sub-symbol of any other.
|
||||
// 9) Therefore, the found key must match the match key.
|
||||
//
|
||||
// The above proof assumes the match key exists. In the case that the
|
||||
// match key does not exist, then step (1) will return some other symbol.
|
||||
// That symbol cannot be a super-symbol of the search key since if it were,
|
||||
// then it would be a match, and we're assuming the match key doesn't exist.
|
||||
// Therefore, step 2 will correctly return no match.
|
||||
|
||||
// Find the last entry in the by_symbol_ map whose key is less than or
|
||||
// equal to the given name.
|
||||
typename map<string, Value>::iterator FindLastLessOrEqual(
|
||||
const string& name);
|
||||
|
||||
// True if either the arguments are equal or super_symbol identifies a
|
||||
// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
|
||||
// "foo.bar.baz", but not a parent of "foo.barbaz").
|
||||
bool IsSubSymbol(const string& sub_symbol, const string& super_symbol);
|
||||
|
||||
// Returns true if and only if all characters in the name are alphanumerics,
|
||||
// underscores, or periods.
|
||||
bool ValidateSymbolName(const string& name);
|
||||
};
|
||||
|
||||
|
||||
DescriptorIndex<const FileDescriptorProto*> index_;
|
||||
vector<const FileDescriptorProto*> files_to_delete_;
|
||||
|
||||
// If file is non-NULL, copy it into *output and return true, otherwise
|
||||
// return false.
|
||||
bool MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
|
||||
};
|
||||
|
||||
// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
|
||||
// as raw bytes and generally tries to use as little memory as possible.
|
||||
//
|
||||
// The same caveats regarding FindFileContainingExtension() apply as with
|
||||
// SimpleDescriptorDatabase.
|
||||
class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
EncodedDescriptorDatabase();
|
||||
~EncodedDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database. The descriptor is provided
|
||||
// in encoded form. The database does not make a copy of the bytes, nor
|
||||
// does it take ownership; it's up to the caller to make sure the bytes
|
||||
// remain valid for the life of the database. Returns false and logs an error
|
||||
// if the bytes are not a valid FileDescriptorProto or if the file conflicted
|
||||
// with a file already in the database.
|
||||
bool Add(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like Add(), but makes a copy of the data, so that the caller does not
|
||||
// need to keep it around.
|
||||
bool AddCopy(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like FindFileContainingSymbol but returns only the name of the file.
|
||||
bool FindNameOfFileContainingSymbol(const string& symbol_name,
|
||||
string* output);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase::DescriptorIndex<pair<const void*, int> > index_;
|
||||
vector<void*> files_to_delete_;
|
||||
|
||||
// If encoded_file.first is non-NULL, parse the data into *output and return
|
||||
// true, otherwise return false.
|
||||
bool MaybeParse(pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that fetches files from a given pool.
|
||||
class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
DescriptorPoolDatabase(const DescriptorPool& pool);
|
||||
~DescriptorPoolDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool& pool_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that wraps two or more others. It first searches the
|
||||
// first database and, if that fails, tries the second, and so on.
|
||||
class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
// Merge just two databases. The sources remain property of the caller.
|
||||
MergedDescriptorDatabase(DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2);
|
||||
// Merge more than two databases. The sources remain property of the caller.
|
||||
// The vector may be deleted after the constructor returns but the
|
||||
// DescriptorDatabases need to stick around.
|
||||
MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
|
||||
~MergedDescriptorDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
// Merges the results of calling all databases. Returns true iff any
|
||||
// of the databases returned true.
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
vector<DescriptorDatabase*> sources_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
@ -0,0 +1,558 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// DynamicMessage is implemented by constructing a data structure which
|
||||
// has roughly the same memory layout as a generated message would have.
|
||||
// Then, we use GeneratedMessageReflection to implement our reflection
|
||||
// interface. All the other operations we need to implement (e.g.
|
||||
// parsing, copying, etc.) are already implemented in terms of
|
||||
// Reflection, so the rest is easy.
|
||||
//
|
||||
// The up side of this strategy is that it's very efficient. We don't
|
||||
// need to use hash_maps or generic representations of fields. The
|
||||
// down side is that this is a low-level memory management hack which
|
||||
// can be tricky to get right.
|
||||
//
|
||||
// As mentioned in the header, we only expose a DynamicMessageFactory
|
||||
// publicly, not the DynamicMessage class itself. This is because
|
||||
// GenericMessageReflection wants to have a pointer to a "default"
|
||||
// copy of the class, with all fields initialized to their default
|
||||
// values. We only want to construct one of these per message type,
|
||||
// so DynamicMessageFactory stores a cache of default messages for
|
||||
// each type it sees (each unique Descriptor pointer). The code
|
||||
// refers to the "default" copy of the class as the "prototype".
|
||||
//
|
||||
// Note on memory allocation: This module often calls "operator new()"
|
||||
// to allocate untyped memory, rather than calling something like
|
||||
// "new uint8[]". This is because "operator new()" means "Give me some
|
||||
// space which I can use as I please." while "new uint8[]" means "Give
|
||||
// me an array of 8-bit integers.". In practice, the later may return
|
||||
// a pointer that is not aligned correctly for general use. I believe
|
||||
// Item 8 of "More Effective C++" discusses this in more detail, though
|
||||
// I don't have the book on me right now so I'm not sure.
|
||||
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ExtensionSet;
|
||||
using internal::GeneratedMessageReflection;
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Some helper tables and functions...
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the byte size of the in-memory representation of the field.
|
||||
int FieldSpaceUsed(const FieldDescriptor* field) {
|
||||
typedef FieldDescriptor FD; // avoid line wrapping
|
||||
if (field->label() == FD::LABEL_REPEATED) {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(RepeatedField<int32 >);
|
||||
case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField<double >);
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
|
||||
case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
|
||||
case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(RepeatedPtrField<string>);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(int32 );
|
||||
case FD::CPPTYPE_INT64 : return sizeof(int64 );
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(double );
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(float );
|
||||
case FD::CPPTYPE_BOOL : return sizeof(bool );
|
||||
case FD::CPPTYPE_ENUM : return sizeof(int );
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(Message*);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(string*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(DFATAL) << "Can't get here.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int DivideRoundingUp(int i, int j) {
|
||||
return (i + (j - 1)) / j;
|
||||
}
|
||||
|
||||
static const int kSafeAlignment = sizeof(uint64);
|
||||
|
||||
inline int AlignTo(int offset, int alignment) {
|
||||
return DivideRoundingUp(offset, alignment) * alignment;
|
||||
}
|
||||
|
||||
// Rounds the given byte offset up to the next offset aligned such that any
|
||||
// type may be stored at it.
|
||||
inline int AlignOffset(int offset) {
|
||||
return AlignTo(offset, kSafeAlignment);
|
||||
}
|
||||
|
||||
#define bitsizeof(T) (sizeof(T) * 8)
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class DynamicMessage : public Message {
|
||||
public:
|
||||
struct TypeInfo {
|
||||
int size;
|
||||
int has_bits_offset;
|
||||
int unknown_fields_offset;
|
||||
int extensions_offset;
|
||||
|
||||
// Not owned by the TypeInfo.
|
||||
DynamicMessageFactory* factory; // The factory that created this object.
|
||||
const DescriptorPool* pool; // The factory's DescriptorPool.
|
||||
const Descriptor* type; // Type of this DynamicMessage.
|
||||
|
||||
// Warning: The order in which the following pointers are defined is
|
||||
// important (the prototype must be deleted *before* the offsets).
|
||||
scoped_array<int> offsets;
|
||||
scoped_ptr<const GeneratedMessageReflection> reflection;
|
||||
scoped_ptr<const DynamicMessage> prototype;
|
||||
};
|
||||
|
||||
DynamicMessage(const TypeInfo* type_info);
|
||||
~DynamicMessage();
|
||||
|
||||
// Called on the prototype after construction to initialize message fields.
|
||||
void CrossLinkPrototypes();
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
Message* New() const;
|
||||
|
||||
int GetCachedSize() const;
|
||||
void SetCachedSize(int size) const;
|
||||
|
||||
Metadata GetMetadata() const;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
|
||||
|
||||
inline bool is_prototype() const {
|
||||
return type_info_->prototype == this ||
|
||||
// If type_info_->prototype is NULL, then we must be constructing
|
||||
// the prototype now, which means we must be the prototype.
|
||||
type_info_->prototype == NULL;
|
||||
}
|
||||
|
||||
inline void* OffsetToPointer(int offset) {
|
||||
return reinterpret_cast<uint8*>(this) + offset;
|
||||
}
|
||||
inline const void* OffsetToPointer(int offset) const {
|
||||
return reinterpret_cast<const uint8*>(this) + offset;
|
||||
}
|
||||
|
||||
const TypeInfo* type_info_;
|
||||
|
||||
// TODO(kenton): Make this an atomic<int> when C++ supports it.
|
||||
mutable int cached_byte_size_;
|
||||
};
|
||||
|
||||
DynamicMessage::DynamicMessage(const TypeInfo* type_info)
|
||||
: type_info_(type_info),
|
||||
cached_byte_size_(0) {
|
||||
// We need to call constructors for various fields manually and set
|
||||
// default values where appropriate. We use placement new to call
|
||||
// constructors. If you haven't heard of placement new, I suggest Googling
|
||||
// it now. We use placement new even for primitive types that don't have
|
||||
// constructors for consistency. (In theory, placement new should be used
|
||||
// any time you are trying to convert untyped memory to typed memory, though
|
||||
// in practice that's not strictly necessary for types that don't have a
|
||||
// constructor.)
|
||||
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, TYPE) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
if (!field->is_repeated()) { \
|
||||
new(field_ptr) TYPE(field->default_value_##TYPE()); \
|
||||
} else { \
|
||||
new(field_ptr) RepeatedField<TYPE>(); \
|
||||
} \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , int32 );
|
||||
HANDLE_TYPE(INT64 , int64 );
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE(FLOAT , float );
|
||||
HANDLE_TYPE(BOOL , bool );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) int(field->default_value_enum()->number());
|
||||
} else {
|
||||
new(field_ptr) RepeatedField<int>();
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
if (!field->is_repeated()) {
|
||||
if (is_prototype()) {
|
||||
new(field_ptr) const string*(&field->default_value_string());
|
||||
} else {
|
||||
string* default_value =
|
||||
*reinterpret_cast<string* const*>(
|
||||
type_info_->prototype->OffsetToPointer(
|
||||
type_info_->offsets[i]));
|
||||
new(field_ptr) string*(default_value);
|
||||
}
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<string>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) Message*(NULL);
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<Message>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMessage::~DynamicMessage() {
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
reinterpret_cast<UnknownFieldSet*>(
|
||||
OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet();
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
reinterpret_cast<ExtensionSet*>(
|
||||
OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet();
|
||||
}
|
||||
|
||||
// We need to manually run the destructors for repeated fields and strings,
|
||||
// just as we ran their constructors in the the DynamicMessage constructor.
|
||||
// Additionally, if any singular embedded messages have been allocated, we
|
||||
// need to delete them, UNLESS we are the prototype message of this type,
|
||||
// in which case any embedded messages are other prototypes and shouldn't
|
||||
// be touched.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
|
||||
reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
|
||||
->~RepeatedField<LOWERCASE>(); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, int);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
|
||||
->~RepeatedPtrField<string>();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
|
||||
->~RepeatedPtrField<Message>();
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING: {
|
||||
string* ptr = *reinterpret_cast<string**>(field_ptr);
|
||||
if (ptr != &field->default_value_string()) {
|
||||
delete ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
|
||||
!is_prototype()) {
|
||||
Message* message = *reinterpret_cast<Message**>(field_ptr);
|
||||
if (message != NULL) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMessage::CrossLinkPrototypes() {
|
||||
// This should only be called on the prototype message.
|
||||
GOOGLE_CHECK(is_prototype());
|
||||
|
||||
DynamicMessageFactory* factory = type_info_->factory;
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
// Cross-link default messages.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!field->is_repeated()) {
|
||||
// For fields with message types, we need to cross-link with the
|
||||
// prototype for the field's type.
|
||||
// For singular fields, the field is just a pointer which should
|
||||
// point to the prototype.
|
||||
*reinterpret_cast<const Message**>(field_ptr) =
|
||||
factory->GetPrototypeNoLock(field->message_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message* DynamicMessage::New() const {
|
||||
void* new_base = reinterpret_cast<uint8*>(operator new(type_info_->size));
|
||||
memset(new_base, 0, type_info_->size);
|
||||
return new(new_base) DynamicMessage(type_info_);
|
||||
}
|
||||
|
||||
int DynamicMessage::GetCachedSize() const {
|
||||
return cached_byte_size_;
|
||||
}
|
||||
|
||||
void DynamicMessage::SetCachedSize(int size) const {
|
||||
// This is theoretically not thread-compatible, but in practice it works
|
||||
// because if multiple threads write this simultaneously, they will be
|
||||
// writing the exact same value.
|
||||
cached_byte_size_ = size;
|
||||
}
|
||||
|
||||
Metadata DynamicMessage::GetMetadata() const {
|
||||
Metadata metadata;
|
||||
metadata.descriptor = type_info_->type;
|
||||
metadata.reflection = type_info_->reflection.get();
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
struct DynamicMessageFactory::PrototypeMap {
|
||||
typedef hash_map<const Descriptor*, const DynamicMessage::TypeInfo*> Map;
|
||||
Map map_;
|
||||
};
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory()
|
||||
: pool_(NULL), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
|
||||
: pool_(pool), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::~DynamicMessageFactory() {
|
||||
for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
|
||||
iter != prototypes_->map_.end(); ++iter) {
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
MutexLock lock(&prototypes_mutex_);
|
||||
return GetPrototypeNoLock(type);
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototypeNoLock(
|
||||
const Descriptor* type) {
|
||||
if (delegate_to_generated_factory_ &&
|
||||
type->file()->pool() == DescriptorPool::generated_pool()) {
|
||||
return MessageFactory::generated_factory()->GetPrototype(type);
|
||||
}
|
||||
|
||||
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
|
||||
if (*target != NULL) {
|
||||
// Already exists.
|
||||
return (*target)->prototype.get();
|
||||
}
|
||||
|
||||
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
|
||||
*target = type_info;
|
||||
|
||||
type_info->type = type;
|
||||
type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_;
|
||||
type_info->factory = this;
|
||||
|
||||
// We need to construct all the structures passed to
|
||||
// GeneratedMessageReflection's constructor. This includes:
|
||||
// - A block of memory that contains space for all the message's fields.
|
||||
// - An array of integers indicating the byte offset of each field within
|
||||
// this block.
|
||||
// - A big bitfield containing a bit for each field indicating whether
|
||||
// or not that field is set.
|
||||
|
||||
// Compute size and offsets.
|
||||
int* offsets = new int[type->field_count()];
|
||||
type_info->offsets.reset(offsets);
|
||||
|
||||
// Decide all field offsets by packing in order.
|
||||
// We place the DynamicMessage object itself at the beginning of the allocated
|
||||
// space.
|
||||
int size = sizeof(DynamicMessage);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// Next the has_bits, which is an array of uint32s.
|
||||
type_info->has_bits_offset = size;
|
||||
int has_bits_array_size =
|
||||
DivideRoundingUp(type->field_count(), bitsizeof(uint32));
|
||||
size += has_bits_array_size * sizeof(uint32);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// The ExtensionSet, if any.
|
||||
if (type->extension_range_count() > 0) {
|
||||
type_info->extensions_offset = size;
|
||||
size += sizeof(ExtensionSet);
|
||||
size = AlignOffset(size);
|
||||
} else {
|
||||
// No extensions.
|
||||
type_info->extensions_offset = -1;
|
||||
}
|
||||
|
||||
// All the fields.
|
||||
for (int i = 0; i < type->field_count(); i++) {
|
||||
// Make sure field is aligned to avoid bus errors.
|
||||
int field_size = FieldSpaceUsed(type->field(i));
|
||||
size = AlignTo(size, min(kSafeAlignment, field_size));
|
||||
offsets[i] = size;
|
||||
size += field_size;
|
||||
}
|
||||
|
||||
// Add the UnknownFieldSet to the end.
|
||||
size = AlignOffset(size);
|
||||
type_info->unknown_fields_offset = size;
|
||||
size += sizeof(UnknownFieldSet);
|
||||
|
||||
// Align the final size to make sure no clever allocators think that
|
||||
// alignment is not necessary.
|
||||
size = AlignOffset(size);
|
||||
type_info->size = size;
|
||||
|
||||
// Allocate the prototype.
|
||||
void* base = operator new(size);
|
||||
memset(base, 0, size);
|
||||
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
|
||||
type_info->prototype.reset(prototype);
|
||||
|
||||
// Construct the reflection object.
|
||||
type_info->reflection.reset(
|
||||
new GeneratedMessageReflection(
|
||||
type_info->type,
|
||||
type_info->prototype.get(),
|
||||
type_info->offsets.get(),
|
||||
type_info->has_bits_offset,
|
||||
type_info->unknown_fields_offset,
|
||||
type_info->extensions_offset,
|
||||
type_info->pool,
|
||||
this,
|
||||
type_info->size));
|
||||
|
||||
// Cross link prototypes.
|
||||
prototype->CrossLinkPrototypes();
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,136 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines an implementation of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
|
||||
// Constructs implementations of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
//
|
||||
// Sometimes you want to be able to manipulate protocol types that you don't
|
||||
// know about at compile time. It would be nice to be able to construct
|
||||
// a Message object which implements the message type given by any arbitrary
|
||||
// Descriptor. DynamicMessage provides this.
|
||||
//
|
||||
// As it turns out, a DynamicMessage needs to construct extra
|
||||
// information about its type in order to operate. Most of this information
|
||||
// can be shared between all DynamicMessages of the same type. But, caching
|
||||
// this information in some sort of global map would be a bad idea, since
|
||||
// the cached information for a particular descriptor could outlive the
|
||||
// descriptor itself. To avoid this problem, DynamicMessageFactory
|
||||
// encapsulates this "cache". All DynamicMessages of the same type created
|
||||
// from the same factory will share the same support data. Any Descriptors
|
||||
// used with a particular factory must outlive the factory.
|
||||
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
|
||||
public:
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the DescriptorPool in which the exendee is defined.
|
||||
DynamicMessageFactory();
|
||||
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the given DescriptorPool.
|
||||
//
|
||||
// DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the
|
||||
// parser to look for extensions in an alternate pool. However, note that
|
||||
// this is almost never what you want to do. Almost all users should use
|
||||
// the zero-arg constructor.
|
||||
DynamicMessageFactory(const DescriptorPool* pool);
|
||||
|
||||
~DynamicMessageFactory();
|
||||
|
||||
// Call this to tell the DynamicMessageFactory that if it is given a
|
||||
// Descriptor d for which:
|
||||
// d->file()->pool() == DescriptorPool::generated_pool(),
|
||||
// then it should delegate to MessageFactory::generated_factory() instead
|
||||
// of constructing a dynamic implementation of the message. In theory there
|
||||
// is no down side to doing this, so it may become the default in the future.
|
||||
void SetDelegateToGeneratedFactory(bool enable) {
|
||||
delegate_to_generated_factory_ = enable;
|
||||
}
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
|
||||
// Given a Descriptor, constructs the default (prototype) Message of that
|
||||
// type. You can then call that message's New() method to construct a
|
||||
// mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory and will
|
||||
// be destroyed when the factory is destroyed. Also, any objects created
|
||||
// by calling the prototype's New() method share some data with the
|
||||
// prototype, so these must be destoyed before the DynamicMessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the DynamicMessageFactory.
|
||||
//
|
||||
// The method is thread-safe.
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
bool delegate_to_generated_factory_;
|
||||
|
||||
// This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
|
||||
// this header due to hacks needed for hash_map portability in the open source
|
||||
// release. Namely, stubs/hash.h, which defines hash_map portably, is not a
|
||||
// public header (for good reason), but dynamic_message.h is, and public
|
||||
// headers may only #include other public headers.
|
||||
struct PrototypeMap;
|
||||
scoped_ptr<PrototypeMap> prototypes_;
|
||||
mutable Mutex prototypes_mutex_;
|
||||
|
||||
friend class DynamicMessage;
|
||||
const Message* GetPrototypeNoLock(const Descriptor* type);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,904 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
||||
#define GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
class Descriptor; // descriptor.h
|
||||
class FieldDescriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
class MessageLite; // message_lite.h
|
||||
class Message; // message.h
|
||||
class MessageFactory; // message.h
|
||||
class UnknownFieldSet; // unknown_field_set.h
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
namespace internal {
|
||||
class FieldSkipper; // wire_format_lite.h
|
||||
class RepeatedPtrFieldBase; // repeated_field.h
|
||||
}
|
||||
template <typename Element> class RepeatedField; // repeated_field.h
|
||||
template <typename Element> class RepeatedPtrField; // repeated_field.h
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Used to store values of type WireFormatLite::FieldType without having to
|
||||
// #include wire_format_lite.h. Also, ensures that we use only one byte to
|
||||
// store these values, which is important to keep the layout of
|
||||
// ExtensionSet::Extension small.
|
||||
typedef uint8 FieldType;
|
||||
|
||||
// A function which, given an integer value, returns true if the number
|
||||
// matches one of the defined values for the corresponding enum type. This
|
||||
// is used with RegisterEnumExtension, below.
|
||||
typedef bool EnumValidityFunc(int number);
|
||||
|
||||
// Version of the above which takes an argument. This is needed to deal with
|
||||
// extensions that are not compiled in.
|
||||
typedef bool EnumValidityFuncWithArg(const void* arg, int number);
|
||||
|
||||
// Information about a registered extension.
|
||||
struct ExtensionInfo {
|
||||
inline ExtensionInfo() {}
|
||||
inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed)
|
||||
: type(type), is_repeated(is_repeated), is_packed(is_packed),
|
||||
descriptor(NULL) {}
|
||||
|
||||
FieldType type;
|
||||
bool is_repeated;
|
||||
bool is_packed;
|
||||
|
||||
struct EnumValidityCheck {
|
||||
EnumValidityFuncWithArg* func;
|
||||
const void* arg;
|
||||
};
|
||||
|
||||
union {
|
||||
EnumValidityCheck enum_validity_check;
|
||||
const MessageLite* message_prototype;
|
||||
};
|
||||
|
||||
// The descriptor for this extension, if one exists and is known. May be
|
||||
// NULL. Must not be NULL if the descriptor for the extension does not
|
||||
// live in the same pool as the descriptor for the containing type.
|
||||
const FieldDescriptor* descriptor;
|
||||
};
|
||||
|
||||
// Abstract interface for an object which looks up extension definitions. Used
|
||||
// when parsing.
|
||||
class LIBPROTOBUF_EXPORT ExtensionFinder {
|
||||
public:
|
||||
virtual ~ExtensionFinder();
|
||||
|
||||
// Find the extension with the given containing type and number.
|
||||
virtual bool Find(int number, ExtensionInfo* output) = 0;
|
||||
};
|
||||
|
||||
// Implementation of ExtensionFinder which finds extensions defined in .proto
|
||||
// files which have been compiled into the binary.
|
||||
class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
|
||||
public:
|
||||
GeneratedExtensionFinder(const MessageLite* containing_type)
|
||||
: containing_type_(containing_type) {}
|
||||
virtual ~GeneratedExtensionFinder() {}
|
||||
|
||||
// Returns true and fills in *output if found, otherwise returns false.
|
||||
virtual bool Find(int number, ExtensionInfo* output);
|
||||
|
||||
private:
|
||||
const MessageLite* containing_type_;
|
||||
};
|
||||
|
||||
// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
|
||||
// finding extensions from a DescriptorPool.
|
||||
|
||||
// This is an internal helper class intended for use within the protocol buffer
|
||||
// library and generated classes. Clients should not use it directly. Instead,
|
||||
// use the generated accessors such as GetExtension() of the class being
|
||||
// extended.
|
||||
//
|
||||
// This class manages extensions for a protocol message object. The
|
||||
// message's HasExtension(), GetExtension(), MutableExtension(), and
|
||||
// ClearExtension() methods are just thin wrappers around the embedded
|
||||
// ExtensionSet. When parsing, if a tag number is encountered which is
|
||||
// inside one of the message type's extension ranges, the tag is passed
|
||||
// off to the ExtensionSet for parsing. Etc.
|
||||
class LIBPROTOBUF_EXPORT ExtensionSet {
|
||||
public:
|
||||
ExtensionSet();
|
||||
~ExtensionSet();
|
||||
|
||||
// These are called at startup by protocol-compiler-generated code to
|
||||
// register known extensions. The registrations are used by ParseField()
|
||||
// to look up extensions for parsed field numbers. Note that dynamic parsing
|
||||
// does not use ParseField(); only protocol-compiler-generated parsing
|
||||
// methods do.
|
||||
static void RegisterExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed);
|
||||
static void RegisterEnumExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed,
|
||||
EnumValidityFunc* is_valid);
|
||||
static void RegisterMessageExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed,
|
||||
const MessageLite* prototype);
|
||||
|
||||
// =================================================================
|
||||
|
||||
// Add all fields which are currently present to the given vector. This
|
||||
// is useful to implement Reflection::ListFields().
|
||||
void AppendToList(const Descriptor* containing_type,
|
||||
const DescriptorPool* pool,
|
||||
vector<const FieldDescriptor*>* output) const;
|
||||
|
||||
// =================================================================
|
||||
// Accessors
|
||||
//
|
||||
// Generated message classes include type-safe templated wrappers around
|
||||
// these methods. Generally you should use those rather than call these
|
||||
// directly, unless you are doing low-level memory management.
|
||||
//
|
||||
// When calling any of these accessors, the extension number requested
|
||||
// MUST exist in the DescriptorPool provided to the constructor. Otheriwse,
|
||||
// the method will fail an assert. Normally, though, you would not call
|
||||
// these directly; you would either call the generated accessors of your
|
||||
// message class (e.g. GetExtension()) or you would call the accessors
|
||||
// of the reflection interface. In both cases, it is impossible to
|
||||
// trigger this assert failure: the generated accessors only accept
|
||||
// linked-in extension types as parameters, while the Reflection interface
|
||||
// requires you to provide the FieldDescriptor describing the extension.
|
||||
//
|
||||
// When calling any of these accessors, a protocol-compiler-generated
|
||||
// implementation of the extension corresponding to the number MUST
|
||||
// be linked in, and the FieldDescriptor used to refer to it MUST be
|
||||
// the one generated by that linked-in code. Otherwise, the method will
|
||||
// die on an assert failure. The message objects returned by the message
|
||||
// accessors are guaranteed to be of the correct linked-in type.
|
||||
//
|
||||
// These methods pretty much match Reflection except that:
|
||||
// - They're not virtual.
|
||||
// - They identify fields by number rather than FieldDescriptors.
|
||||
// - They identify enum values using integers rather than descriptors.
|
||||
// - Strings provide Mutable() in addition to Set() accessors.
|
||||
|
||||
bool Has(int number) const;
|
||||
int ExtensionSize(int number) const; // Size of a repeated extension.
|
||||
FieldType ExtensionType(int number) const;
|
||||
void ClearExtension(int number);
|
||||
|
||||
// singular fields -------------------------------------------------
|
||||
|
||||
int32 GetInt32 (int number, int32 default_value) const;
|
||||
int64 GetInt64 (int number, int64 default_value) const;
|
||||
uint32 GetUInt32(int number, uint32 default_value) const;
|
||||
uint64 GetUInt64(int number, uint64 default_value) const;
|
||||
float GetFloat (int number, float default_value) const;
|
||||
double GetDouble(int number, double default_value) const;
|
||||
bool GetBool (int number, bool default_value) const;
|
||||
int GetEnum (int number, int default_value) const;
|
||||
const string & GetString (int number, const string& default_value) const;
|
||||
const MessageLite& GetMessage(int number,
|
||||
const MessageLite& default_value) const;
|
||||
const MessageLite& GetMessage(int number, const Descriptor* message_type,
|
||||
MessageFactory* factory) const;
|
||||
|
||||
// |descriptor| may be NULL so long as it is known that the descriptor for
|
||||
// the extension lives in the same pool as the descriptor for the containing
|
||||
// type.
|
||||
#define desc const FieldDescriptor* descriptor // avoid line wrapping
|
||||
void SetInt32 (int number, FieldType type, int32 value, desc);
|
||||
void SetInt64 (int number, FieldType type, int64 value, desc);
|
||||
void SetUInt32(int number, FieldType type, uint32 value, desc);
|
||||
void SetUInt64(int number, FieldType type, uint64 value, desc);
|
||||
void SetFloat (int number, FieldType type, float value, desc);
|
||||
void SetDouble(int number, FieldType type, double value, desc);
|
||||
void SetBool (int number, FieldType type, bool value, desc);
|
||||
void SetEnum (int number, FieldType type, int value, desc);
|
||||
void SetString(int number, FieldType type, const string& value, desc);
|
||||
string * MutableString (int number, FieldType type, desc);
|
||||
MessageLite* MutableMessage(int number, FieldType type,
|
||||
const MessageLite& prototype, desc);
|
||||
MessageLite* MutableMessage(const FieldDescriptor* decsriptor,
|
||||
MessageFactory* factory);
|
||||
#undef desc
|
||||
|
||||
// repeated fields -------------------------------------------------
|
||||
|
||||
int32 GetRepeatedInt32 (int number, int index) const;
|
||||
int64 GetRepeatedInt64 (int number, int index) const;
|
||||
uint32 GetRepeatedUInt32(int number, int index) const;
|
||||
uint64 GetRepeatedUInt64(int number, int index) const;
|
||||
float GetRepeatedFloat (int number, int index) const;
|
||||
double GetRepeatedDouble(int number, int index) const;
|
||||
bool GetRepeatedBool (int number, int index) const;
|
||||
int GetRepeatedEnum (int number, int index) const;
|
||||
const string & GetRepeatedString (int number, int index) const;
|
||||
const MessageLite& GetRepeatedMessage(int number, int index) const;
|
||||
|
||||
void SetRepeatedInt32 (int number, int index, int32 value);
|
||||
void SetRepeatedInt64 (int number, int index, int64 value);
|
||||
void SetRepeatedUInt32(int number, int index, uint32 value);
|
||||
void SetRepeatedUInt64(int number, int index, uint64 value);
|
||||
void SetRepeatedFloat (int number, int index, float value);
|
||||
void SetRepeatedDouble(int number, int index, double value);
|
||||
void SetRepeatedBool (int number, int index, bool value);
|
||||
void SetRepeatedEnum (int number, int index, int value);
|
||||
void SetRepeatedString(int number, int index, const string& value);
|
||||
string * MutableRepeatedString (int number, int index);
|
||||
MessageLite* MutableRepeatedMessage(int number, int index);
|
||||
|
||||
#define desc const FieldDescriptor* descriptor // avoid line wrapping
|
||||
void AddInt32 (int number, FieldType type, bool packed, int32 value, desc);
|
||||
void AddInt64 (int number, FieldType type, bool packed, int64 value, desc);
|
||||
void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc);
|
||||
void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc);
|
||||
void AddFloat (int number, FieldType type, bool packed, float value, desc);
|
||||
void AddDouble(int number, FieldType type, bool packed, double value, desc);
|
||||
void AddBool (int number, FieldType type, bool packed, bool value, desc);
|
||||
void AddEnum (int number, FieldType type, bool packed, int value, desc);
|
||||
void AddString(int number, FieldType type, const string& value, desc);
|
||||
string * AddString (int number, FieldType type, desc);
|
||||
MessageLite* AddMessage(int number, FieldType type,
|
||||
const MessageLite& prototype, desc);
|
||||
MessageLite* AddMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory);
|
||||
#undef desc
|
||||
|
||||
void RemoveLast(int number);
|
||||
void SwapElements(int number, int index1, int index2);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// TODO(kenton): Hardcore memory management accessors
|
||||
|
||||
// =================================================================
|
||||
// convenience methods for implementing methods of Message
|
||||
//
|
||||
// These could all be implemented in terms of the other methods of this
|
||||
// class, but providing them here helps keep the generated code size down.
|
||||
|
||||
void Clear();
|
||||
void MergeFrom(const ExtensionSet& other);
|
||||
void Swap(ExtensionSet* other);
|
||||
bool IsInitialized() const;
|
||||
|
||||
// Parses a single extension from the input. The input should start out
|
||||
// positioned immediately after the tag. |containing_type| is the default
|
||||
// instance for the containing message; it is used only to look up the
|
||||
// extension by number. See RegisterExtension(), above. Unlike the other
|
||||
// methods of ExtensionSet, this only works for generated message types --
|
||||
// it looks up extensions registered using RegisterExtension().
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const MessageLite* containing_type);
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields);
|
||||
|
||||
// Parse an entire message in MessageSet format. Such messages have no
|
||||
// fields, only extensions.
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
const MessageLite* containing_type);
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields);
|
||||
|
||||
// Write all extension fields with field numbers in the range
|
||||
// [start_field_number, end_field_number)
|
||||
// to the output stream, using the cached sizes computed when ByteSize() was
|
||||
// last called. Note that the range bounds are inclusive-exclusive.
|
||||
void SerializeWithCachedSizes(int start_field_number,
|
||||
int end_field_number,
|
||||
io::CodedOutputStream* output) const;
|
||||
|
||||
// Same as SerializeWithCachedSizes, but without any bounds checking.
|
||||
// The caller must ensure that target has sufficient capacity for the
|
||||
// serialized extensions.
|
||||
//
|
||||
// Returns a pointer past the last written byte.
|
||||
uint8* SerializeWithCachedSizesToArray(int start_field_number,
|
||||
int end_field_number,
|
||||
uint8* target) const;
|
||||
|
||||
// Like above but serializes in MessageSet format.
|
||||
void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
|
||||
uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
|
||||
|
||||
// Returns the total serialized size of all the extensions.
|
||||
int ByteSize() const;
|
||||
|
||||
// Like ByteSize() but uses MessageSet format.
|
||||
int MessageSetByteSize() const;
|
||||
|
||||
// Returns (an estimate of) the total number of bytes used for storing the
|
||||
// extensions in memory, excluding sizeof(*this). If the ExtensionSet is
|
||||
// for a lite message (and thus possibly contains lite messages), the results
|
||||
// are undefined (might work, might crash, might corrupt data, might not even
|
||||
// be linked in). It's up to the protocol compiler to avoid calling this on
|
||||
// such ExtensionSets (easy enough since lite messages don't implement
|
||||
// SpaceUsed()).
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
|
||||
private:
|
||||
|
||||
struct Extension {
|
||||
union {
|
||||
int32 int32_value;
|
||||
int64 int64_value;
|
||||
uint32 uint32_value;
|
||||
uint64 uint64_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
bool bool_value;
|
||||
int enum_value;
|
||||
string* string_value;
|
||||
MessageLite* message_value;
|
||||
|
||||
RepeatedField <int32 >* repeated_int32_value;
|
||||
RepeatedField <int64 >* repeated_int64_value;
|
||||
RepeatedField <uint32 >* repeated_uint32_value;
|
||||
RepeatedField <uint64 >* repeated_uint64_value;
|
||||
RepeatedField <float >* repeated_float_value;
|
||||
RepeatedField <double >* repeated_double_value;
|
||||
RepeatedField <bool >* repeated_bool_value;
|
||||
RepeatedField <int >* repeated_enum_value;
|
||||
RepeatedPtrField<string >* repeated_string_value;
|
||||
RepeatedPtrField<MessageLite>* repeated_message_value;
|
||||
};
|
||||
|
||||
FieldType type;
|
||||
bool is_repeated;
|
||||
|
||||
// For singular types, indicates if the extension is "cleared". This
|
||||
// happens when an extension is set and then later cleared by the caller.
|
||||
// We want to keep the Extension object around for reuse, so instead of
|
||||
// removing it from the map, we just set is_cleared = true. This has no
|
||||
// meaning for repeated types; for those, the size of the RepeatedField
|
||||
// simply becomes zero when cleared.
|
||||
bool is_cleared;
|
||||
|
||||
// For repeated types, this indicates if the [packed=true] option is set.
|
||||
bool is_packed;
|
||||
|
||||
// The descriptor for this extension, if one exists and is known. May be
|
||||
// NULL. Must not be NULL if the descriptor for the extension does not
|
||||
// live in the same pool as the descriptor for the containing type.
|
||||
const FieldDescriptor* descriptor;
|
||||
|
||||
// For packed fields, the size of the packed data is recorded here when
|
||||
// ByteSize() is called then used during serialization.
|
||||
// TODO(kenton): Use atomic<int> when C++ supports it.
|
||||
mutable int cached_size;
|
||||
|
||||
// Some helper methods for operations on a single Extension.
|
||||
void SerializeFieldWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const;
|
||||
uint8* SerializeFieldWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const;
|
||||
void SerializeMessageSetItemWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const;
|
||||
uint8* SerializeMessageSetItemWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const;
|
||||
int ByteSize(int number) const;
|
||||
int MessageSetItemByteSize(int number) const;
|
||||
void Clear();
|
||||
int GetSize() const;
|
||||
void Free();
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
};
|
||||
|
||||
|
||||
// Gets the extension with the given number, creating it if it does not
|
||||
// already exist. Returns true if the extension did not already exist.
|
||||
bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
|
||||
Extension** result);
|
||||
|
||||
// Parse a single MessageSet item -- called just after the item group start
|
||||
// tag has been read.
|
||||
bool ParseMessageSetItem(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
|
||||
// Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This
|
||||
// friendship should automatically extend to ExtensionSet::Extension, but
|
||||
// unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
|
||||
// correctly. So, we must provide helpers for calling methods of that
|
||||
// class.
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
static inline int RepeatedMessage_SpaceUsedExcludingSelf(
|
||||
RepeatedPtrFieldBase* field);
|
||||
|
||||
// The Extension struct is small enough to be passed by value, so we use it
|
||||
// directly as the value type in the map rather than use pointers. We use
|
||||
// a map rather than hash_map here because we expect most ExtensionSets will
|
||||
// only contain a small number of extensions whereas hash_map is optimized
|
||||
// for 100 elements or more. Also, we want AppendToList() to order fields
|
||||
// by field number.
|
||||
map<int, Extension> extensions_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
|
||||
};
|
||||
|
||||
// These are just for convenience...
|
||||
inline void ExtensionSet::SetString(int number, FieldType type,
|
||||
const string& value,
|
||||
const FieldDescriptor* descriptor) {
|
||||
MutableString(number, type, descriptor)->assign(value);
|
||||
}
|
||||
inline void ExtensionSet::SetRepeatedString(int number, int index,
|
||||
const string& value) {
|
||||
MutableRepeatedString(number, index)->assign(value);
|
||||
}
|
||||
inline void ExtensionSet::AddString(int number, FieldType type,
|
||||
const string& value,
|
||||
const FieldDescriptor* descriptor) {
|
||||
AddString(number, type, descriptor)->assign(value);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Glue for generated extension accessors
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Template magic
|
||||
|
||||
// First we have a set of classes representing "type traits" for different
|
||||
// field types. A type traits class knows how to implement basic accessors
|
||||
// for extensions of a particular type given an ExtensionSet. The signature
|
||||
// for a type traits class looks like this:
|
||||
//
|
||||
// class TypeTraits {
|
||||
// public:
|
||||
// typedef ? ConstType;
|
||||
// typedef ? MutableType;
|
||||
//
|
||||
// static inline ConstType Get(int number, const ExtensionSet& set);
|
||||
// static inline void Set(int number, ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Mutable(int number, ExtensionSet* set);
|
||||
//
|
||||
// // Variants for repeated fields.
|
||||
// static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
// int index);
|
||||
// static inline void Set(int number, int index,
|
||||
// ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Mutable(int number, int index,
|
||||
// ExtensionSet* set);
|
||||
// static inline void Add(int number, ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Add(int number, ExtensionSet* set);
|
||||
// };
|
||||
//
|
||||
// Not all of these methods make sense for all field types. For example, the
|
||||
// "Mutable" methods only make sense for strings and messages, and the
|
||||
// repeated methods only make sense for repeated types. So, each type
|
||||
// traits class implements only the set of methods from this signature that it
|
||||
// actually supports. This will cause a compiler error if the user tries to
|
||||
// access an extension using a method that doesn't make sense for its type.
|
||||
// For example, if "foo" is an extension of type "optional int32", then if you
|
||||
// try to write code like:
|
||||
// my_message.MutableExtension(foo)
|
||||
// you will get a compile error because PrimitiveTypeTraits<int32> does not
|
||||
// have a "Mutable()" method.
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// PrimitiveTypeTraits
|
||||
|
||||
// Since the ExtensionSet has different methods for each primitive type,
|
||||
// we must explicitly define the methods of the type traits class for each
|
||||
// known type.
|
||||
template <typename Type>
|
||||
class PrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value);
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
ConstType value, ExtensionSet* set);
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class RepeatedPrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline Type Get(int number, const ExtensionSet& set, int index);
|
||||
static inline void Set(int number, int index, Type value, ExtensionSet* set);
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool is_packed, Type value, ExtensionSet* set);
|
||||
};
|
||||
|
||||
#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \
|
||||
template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get( \
|
||||
int number, const ExtensionSet& set, TYPE default_value) { \
|
||||
return set.Get##METHOD(number, default_value); \
|
||||
} \
|
||||
template<> inline void PrimitiveTypeTraits<TYPE>::Set( \
|
||||
int number, FieldType field_type, TYPE value, ExtensionSet* set) { \
|
||||
set->Set##METHOD(number, field_type, value, NULL); \
|
||||
} \
|
||||
\
|
||||
template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get( \
|
||||
int number, const ExtensionSet& set, int index) { \
|
||||
return set.GetRepeated##METHOD(number, index); \
|
||||
} \
|
||||
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set( \
|
||||
int number, int index, TYPE value, ExtensionSet* set) { \
|
||||
set->SetRepeated##METHOD(number, index, value); \
|
||||
} \
|
||||
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
|
||||
int number, FieldType field_type, bool is_packed, \
|
||||
TYPE value, ExtensionSet* set) { \
|
||||
set->Add##METHOD(number, field_type, is_packed, value, NULL); \
|
||||
}
|
||||
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( float, Float)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( bool, Bool)
|
||||
|
||||
#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// StringTypeTraits
|
||||
|
||||
// Strings support both Set() and Mutable().
|
||||
class LIBPROTOBUF_EXPORT StringTypeTraits {
|
||||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return set.GetString(number, default_value);
|
||||
}
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
const string& value, ExtensionSet* set) {
|
||||
set->SetString(number, field_type, value, NULL);
|
||||
}
|
||||
static inline string* Mutable(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return set->MutableString(number, field_type, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
|
||||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
int index) {
|
||||
return set.GetRepeatedString(number, index);
|
||||
}
|
||||
static inline void Set(int number, int index,
|
||||
const string& value, ExtensionSet* set) {
|
||||
set->SetRepeatedString(number, index, value);
|
||||
}
|
||||
static inline string* Mutable(int number, int index, ExtensionSet* set) {
|
||||
return set->MutableRepeatedString(number, index);
|
||||
}
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool /*is_packed*/, const string& value,
|
||||
ExtensionSet* set) {
|
||||
set->AddString(number, field_type, value, NULL);
|
||||
}
|
||||
static inline string* Add(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return set->AddString(number, field_type, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// EnumTypeTraits
|
||||
|
||||
// ExtensionSet represents enums using integers internally, so we have to
|
||||
// static_cast around.
|
||||
template <typename Type, bool IsValid(int)>
|
||||
class EnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return static_cast<Type>(set.GetEnum(number, default_value));
|
||||
}
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->SetEnum(number, field_type, value, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type, bool IsValid(int)>
|
||||
class RepeatedEnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<Type>(set.GetRepeatedEnum(number, index));
|
||||
}
|
||||
static inline void Set(int number, int index,
|
||||
ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->SetRepeatedEnum(number, index, value);
|
||||
}
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool is_packed, ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->AddEnum(number, field_type, is_packed, value, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// MessageTypeTraits
|
||||
|
||||
// ExtensionSet guarantees that when manipulating extensions with message
|
||||
// types, the implementation used will be the compiled-in class representing
|
||||
// that type. So, we can static_cast down to the exact type we expect.
|
||||
template <typename Type>
|
||||
class MessageTypeTraits {
|
||||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return static_cast<const Type&>(
|
||||
set.GetMessage(number, default_value));
|
||||
}
|
||||
static inline MutableType Mutable(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return static_cast<Type*>(
|
||||
set->MutableMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class RepeatedMessageTypeTraits {
|
||||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
|
||||
}
|
||||
static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
|
||||
return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
|
||||
}
|
||||
static inline MutableType Add(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return static_cast<Type*>(
|
||||
set->AddMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ExtensionIdentifier
|
||||
|
||||
// This is the type of actual extension objects. E.g. if you have:
|
||||
// extends Foo with optional int32 bar = 1234;
|
||||
// then "bar" will be defined in C++ as:
|
||||
// ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>, 1, false> bar(1234);
|
||||
//
|
||||
// Note that we could, in theory, supply the field number as a template
|
||||
// parameter, and thus make an instance of ExtensionIdentifier have no
|
||||
// actual contents. However, if we did that, then using at extension
|
||||
// identifier would not necessarily cause the compiler to output any sort
|
||||
// of reference to any simple defined in the extension's .pb.o file. Some
|
||||
// linkers will actually drop object files that are not explicitly referenced,
|
||||
// but that would be bad because it would cause this extension to not be
|
||||
// registered at static initialization, and therefore using it would crash.
|
||||
|
||||
template <typename ExtendeeType, typename TypeTraitsType,
|
||||
FieldType field_type, bool is_packed>
|
||||
class ExtensionIdentifier {
|
||||
public:
|
||||
typedef TypeTraitsType TypeTraits;
|
||||
typedef ExtendeeType Extendee;
|
||||
|
||||
ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value)
|
||||
: number_(number), default_value_(default_value) {}
|
||||
inline int number() const { return number_; }
|
||||
typename TypeTraits::ConstType default_value() const {
|
||||
return default_value_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int number_;
|
||||
typename TypeTraits::ConstType default_value_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Generated accessors
|
||||
|
||||
// This macro should be expanded in the context of a generated type which
|
||||
// has extensions.
|
||||
//
|
||||
// We use "_proto_TypeTraits" as a type name below because "TypeTraits"
|
||||
// causes problems if the class has a nested message or enum type with that
|
||||
// name and "_TypeTraits" is technically reserved for the C++ library since
|
||||
// it starts with an underscore followed by a capital letter.
|
||||
#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \
|
||||
/* Has, Size, Clear */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline bool HasExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.Has(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void ClearExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
_extensions_.ClearExtension(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline int ExtensionSize( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.ExtensionSize(id.number()); \
|
||||
} \
|
||||
\
|
||||
/* Singular accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, \
|
||||
id.default_value()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
/* Repeated accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, index); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index, typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Add(id.number(), field_type, is_packed, \
|
||||
value, &_extensions_); \
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
@ -0,0 +1,457 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Contains methods defined in extension_set.h which cannot be part of the
|
||||
// lite library because they use descriptors or reflection.
|
||||
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Implementation of ExtensionFinder which finds extensions in a given
|
||||
// DescriptorPool, using the given MessageFactory to construct sub-objects.
|
||||
// This class is implemented in extension_set_heavy.cc.
|
||||
class DescriptorPoolExtensionFinder : public ExtensionFinder {
|
||||
public:
|
||||
DescriptorPoolExtensionFinder(const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
const Descriptor* containing_type)
|
||||
: pool_(pool), factory_(factory), containing_type_(containing_type) {}
|
||||
virtual ~DescriptorPoolExtensionFinder() {}
|
||||
|
||||
virtual bool Find(int number, ExtensionInfo* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
MessageFactory* factory_;
|
||||
const Descriptor* containing_type_;
|
||||
};
|
||||
|
||||
void ExtensionSet::AppendToList(const Descriptor* containing_type,
|
||||
const DescriptorPool* pool,
|
||||
vector<const FieldDescriptor*>* output) const {
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
bool has = false;
|
||||
if (iter->second.is_repeated) {
|
||||
has = iter->second.GetSize() > 0;
|
||||
} else {
|
||||
has = !iter->second.is_cleared;
|
||||
}
|
||||
|
||||
if (has) {
|
||||
// TODO(kenton): Looking up each field by number is somewhat unfortunate.
|
||||
// Is there a better way? The problem is that descriptors are lazily-
|
||||
// initialized, so they might not even be constructed until
|
||||
// AppendToList() is called.
|
||||
|
||||
if (iter->second.descriptor == NULL) {
|
||||
output->push_back(pool->FindExtensionByNumber(
|
||||
containing_type, iter->first));
|
||||
} else {
|
||||
output->push_back(iter->second.descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline FieldDescriptor::Type real_type(FieldType type) {
|
||||
GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
|
||||
return static_cast<FieldDescriptor::Type>(type);
|
||||
}
|
||||
|
||||
inline FieldDescriptor::CppType cpp_type(FieldType type) {
|
||||
return FieldDescriptor::TypeToCppType(
|
||||
static_cast<FieldDescriptor::Type>(type));
|
||||
}
|
||||
|
||||
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
|
||||
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
|
||||
: FieldDescriptor::LABEL_OPTIONAL, \
|
||||
FieldDescriptor::LABEL_##LABEL); \
|
||||
GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
|
||||
|
||||
const MessageLite& ExtensionSet::GetMessage(int number,
|
||||
const Descriptor* message_type,
|
||||
MessageFactory* factory) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end() || iter->second.is_cleared) {
|
||||
// Not present. Return the default value.
|
||||
return *factory->GetPrototype(message_type);
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
return *iter->second.message_value;
|
||||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = false;
|
||||
extension->is_packed = false;
|
||||
const MessageLite* prototype =
|
||||
factory->GetPrototype(descriptor->message_type());
|
||||
GOOGLE_CHECK(prototype != NULL);
|
||||
extension->message_value = prototype->New();
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
|
||||
}
|
||||
extension->is_cleared = false;
|
||||
return extension->message_value;
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = true;
|
||||
extension->repeated_message_value =
|
||||
new RepeatedPtrField<MessageLite>();
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
|
||||
}
|
||||
|
||||
// RepeatedPtrField<Message> does not know how to Add() since it cannot
|
||||
// allocate an abstract object, so we have to be tricky.
|
||||
MessageLite* result = extension->repeated_message_value
|
||||
->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
|
||||
if (result == NULL) {
|
||||
const MessageLite* prototype;
|
||||
if (extension->repeated_message_value->size() == 0) {
|
||||
prototype = factory->GetPrototype(descriptor->message_type());
|
||||
GOOGLE_CHECK(prototype != NULL);
|
||||
} else {
|
||||
prototype = &extension->repeated_message_value->Get(0);
|
||||
}
|
||||
result = prototype->New();
|
||||
extension->repeated_message_value->AddAllocated(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
|
||||
return reinterpret_cast<const EnumDescriptor*>(arg)
|
||||
->FindValueByNumber(number) != NULL;
|
||||
}
|
||||
|
||||
bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
|
||||
const FieldDescriptor* extension =
|
||||
pool_->FindExtensionByNumber(containing_type_, number);
|
||||
if (extension == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
output->type = extension->type();
|
||||
output->is_repeated = extension->is_repeated();
|
||||
output->is_packed = extension->options().packed();
|
||||
output->descriptor = extension;
|
||||
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
output->message_prototype =
|
||||
factory_->GetPrototype(extension->message_type());
|
||||
GOOGLE_CHECK(output->message_prototype != NULL)
|
||||
<< "Extension factory's GetPrototype() returned NULL for extension: "
|
||||
<< extension->full_name();
|
||||
} else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
|
||||
output->enum_validity_check.func = ValidateEnumUsingDescriptor;
|
||||
output->enum_validity_check.arg = extension->enum_type();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
UnknownFieldSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
UnknownFieldSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtensionSet::SpaceUsedExcludingSelf() const {
|
||||
int total_size =
|
||||
extensions_.size() * sizeof(map<int, Extension>::value_type);
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin(),
|
||||
end = extensions_.end();
|
||||
iter != end;
|
||||
++iter) {
|
||||
total_size += iter->second.SpaceUsedExcludingSelf();
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf(
|
||||
RepeatedPtrFieldBase* field) {
|
||||
return field->SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
|
||||
int total_size = 0;
|
||||
if (is_repeated) {
|
||||
switch (cpp_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE: \
|
||||
total_size += sizeof(*repeated_##LOWERCASE##_value) + \
|
||||
repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE( UINT32, uint32);
|
||||
HANDLE_TYPE( UINT64, uint64);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( DOUBLE, double);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, enum);
|
||||
HANDLE_TYPE( STRING, string);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
// repeated_message_value is actually a RepeatedPtrField<MessageLite>,
|
||||
// but MessageLite has no SpaceUsed(), so we must directly call
|
||||
// RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type
|
||||
// handler.
|
||||
total_size += sizeof(*repeated_message_value) +
|
||||
RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cpp_type(type)) {
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
total_size += sizeof(*string_value) +
|
||||
StringSpaceUsedExcludingSelf(*string_value);
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
total_size += down_cast<Message*>(message_value)->SpaceUsed();
|
||||
break;
|
||||
default:
|
||||
// No extra storage costs for primitive types.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// The Serialize*ToArray methods are only needed in the heavy library, as
|
||||
// the lite library only generates SerializeWithCachedSizes.
|
||||
uint8* ExtensionSet::SerializeWithCachedSizesToArray(
|
||||
int start_field_number, int end_field_number,
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.lower_bound(start_field_number);
|
||||
iter != extensions_.end() && iter->first < end_field_number;
|
||||
++iter) {
|
||||
target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first,
|
||||
target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
|
||||
target = iter->second.SerializeMessageSetItemWithCachedSizesToArray(
|
||||
iter->first, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
|
||||
int number, uint8* target) const {
|
||||
if (is_repeated) {
|
||||
if (is_packed) {
|
||||
if (cached_size == 0) return target;
|
||||
|
||||
target = WireFormatLite::WriteTagToArray(number,
|
||||
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
|
||||
target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
|
||||
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
case WireFormatLite::TYPE_BYTES:
|
||||
case WireFormatLite::TYPE_GROUP:
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray(number, \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( STRING, String, string);
|
||||
HANDLE_TYPE( BYTES, Bytes, string);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
HANDLE_TYPE( GROUP, Group, message);
|
||||
HANDLE_TYPE( MESSAGE, Message, message);
|
||||
#undef HANDLE_TYPE
|
||||
}
|
||||
}
|
||||
} else if (!is_cleared) {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray( \
|
||||
number, VALUE, target); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32_value);
|
||||
HANDLE_TYPE( INT64, Int64, int64_value);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32_value);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64_value);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32_value);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64_value);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32_value);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64_value);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
|
||||
HANDLE_TYPE( FLOAT, Float, float_value);
|
||||
HANDLE_TYPE( DOUBLE, Double, double_value);
|
||||
HANDLE_TYPE( BOOL, Bool, bool_value);
|
||||
HANDLE_TYPE( STRING, String, *string_value);
|
||||
HANDLE_TYPE( BYTES, Bytes, *string_value);
|
||||
HANDLE_TYPE( ENUM, Enum, enum_value);
|
||||
HANDLE_TYPE( GROUP, Group, *message_value);
|
||||
HANDLE_TYPE( MESSAGE, Message, *message_value);
|
||||
#undef HANDLE_TYPE
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but serialize it the normal way.
|
||||
GOOGLE_LOG(WARNING) << "Invalid message set extension.";
|
||||
return SerializeFieldWithCachedSizesToArray(number, target);
|
||||
}
|
||||
|
||||
if (is_cleared) return target;
|
||||
|
||||
// Start group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemStartTag, target);
|
||||
// Write type ID.
|
||||
target = WireFormatLite::WriteUInt32ToArray(
|
||||
WireFormatLite::kMessageSetTypeIdNumber, number, target);
|
||||
// Write message.
|
||||
target = WireFormatLite::WriteMessageToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber, *message_value, target);
|
||||
// End group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemEndTag, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,642 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
// This test closely mirrors google/protobuf/compiler/cpp/unittest.cc
|
||||
// except that it uses extensions rather than regular fields.
|
||||
|
||||
TEST(ExtensionSetTest, Defaults) {
|
||||
// Check that all default values are set correctly in the initial message.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::ExpectExtensionsClear(message);
|
||||
|
||||
// Messages should return pointers to default instances until first use.
|
||||
// (This is not checked by ExpectClear() since it is not actually true after
|
||||
// the fields have been set and then cleared.)
|
||||
EXPECT_EQ(&unittest::OptionalGroup_extension::default_instance(),
|
||||
&message.GetExtension(unittest::optionalgroup_extension));
|
||||
EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_nested_message_extension));
|
||||
EXPECT_EQ(&unittest::ForeignMessage::default_instance(),
|
||||
&message.GetExtension(
|
||||
unittest::optional_foreign_message_extension));
|
||||
EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_import_message_extension));
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Accessors) {
|
||||
// Set every field to a unique value then go back and check all those
|
||||
// values.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
|
||||
TestUtil::ModifyRepeatedExtensions(&message);
|
||||
TestUtil::ExpectRepeatedExtensionsModified(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Clear) {
|
||||
// Set every field to a unique value, clear the message, then check that
|
||||
// it is cleared.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
message.Clear();
|
||||
TestUtil::ExpectExtensionsClear(message);
|
||||
|
||||
// Unlike with the defaults test, we do NOT expect that requesting embedded
|
||||
// messages will return a pointer to the default instance. Instead, they
|
||||
// should return the objects that were created when mutable_blah() was
|
||||
// called.
|
||||
EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(),
|
||||
&message.GetExtension(unittest::optionalgroup_extension));
|
||||
EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_nested_message_extension));
|
||||
EXPECT_NE(&unittest::ForeignMessage::default_instance(),
|
||||
&message.GetExtension(
|
||||
unittest::optional_foreign_message_extension));
|
||||
EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_import_message_extension));
|
||||
|
||||
// Make sure setting stuff again after clearing works. (This takes slightly
|
||||
// different code paths since the objects are reused.)
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, ClearOneField) {
|
||||
// Set every field to a unique value, then clear one value and insure that
|
||||
// only that one value is cleared.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
int64 original_value =
|
||||
message.GetExtension(unittest::optional_int64_extension);
|
||||
|
||||
// Clear the field and make sure it shows up as cleared.
|
||||
message.ClearExtension(unittest::optional_int64_extension);
|
||||
EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension));
|
||||
EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension));
|
||||
|
||||
// Other adjacent fields should not be cleared.
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension));
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension));
|
||||
|
||||
// Make sure if we set it again, then all fields are set.
|
||||
message.SetExtension(unittest::optional_int64_extension, original_value);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, CopyFrom) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
string data;
|
||||
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
message2.CopyFrom(message1);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, CopyFromUpcasted) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
string data;
|
||||
const Message& upcasted_message = message1;
|
||||
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
message2.CopyFrom(upcasted_message);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SwapWithEmpty) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message1);
|
||||
TestUtil::ExpectExtensionsClear(message2);
|
||||
message1.Swap(&message2);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
TestUtil::ExpectExtensionsClear(message1);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SwapWithSelf) {
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
message.Swap(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SerializationToArray) {
|
||||
// Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
|
||||
// compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to a flat array by explicitly reserving space in
|
||||
// the string and calling the generated message's
|
||||
// SerializeWithCachedSizesToArray.
|
||||
unittest::TestAllExtensions source;
|
||||
unittest::TestAllTypes destination;
|
||||
TestUtil::SetAllExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
uint8* target = reinterpret_cast<uint8*>(string_as_array(&data));
|
||||
uint8* end = source.SerializeWithCachedSizesToArray(target);
|
||||
EXPECT_EQ(size, end - target);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SerializationToStream) {
|
||||
// Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
|
||||
// compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to an output stream by creating an array output
|
||||
// stream that can only buffer 1 byte at a time - this prevents the message
|
||||
// from ever jumping to the fast path, ensuring that serialization happens via
|
||||
// the CodedOutputStream.
|
||||
unittest::TestAllExtensions source;
|
||||
unittest::TestAllTypes destination;
|
||||
TestUtil::SetAllExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
{
|
||||
io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
|
||||
io::CodedOutputStream output_stream(&array_stream);
|
||||
source.SerializeWithCachedSizes(&output_stream);
|
||||
ASSERT_FALSE(output_stream.HadError());
|
||||
}
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedSerializationToArray) {
|
||||
// Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
|
||||
// wire compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to a flat array by explicitly reserving space in
|
||||
// the string and calling the generated message's
|
||||
// SerializeWithCachedSizesToArray.
|
||||
unittest::TestPackedExtensions source;
|
||||
unittest::TestPackedTypes destination;
|
||||
TestUtil::SetPackedExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
uint8* target = reinterpret_cast<uint8*>(string_as_array(&data));
|
||||
uint8* end = source.SerializeWithCachedSizesToArray(target);
|
||||
EXPECT_EQ(size, end - target);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedSerializationToStream) {
|
||||
// Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
|
||||
// wire compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to an output stream by creating an array output
|
||||
// stream that can only buffer 1 byte at a time - this prevents the message
|
||||
// from ever jumping to the fast path, ensuring that serialization happens via
|
||||
// the CodedOutputStream.
|
||||
unittest::TestPackedExtensions source;
|
||||
unittest::TestPackedTypes destination;
|
||||
TestUtil::SetPackedExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
{
|
||||
io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
|
||||
io::CodedOutputStream output_stream(&array_stream);
|
||||
source.SerializeWithCachedSizes(&output_stream);
|
||||
ASSERT_FALSE(output_stream.HadError());
|
||||
}
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Parsing) {
|
||||
// Serialize as TestAllTypes and parse as TestAllExtensions.
|
||||
unittest::TestAllTypes source;
|
||||
unittest::TestAllExtensions destination;
|
||||
string data;
|
||||
|
||||
TestUtil::SetAllFields(&source);
|
||||
source.SerializeToString(&data);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllExtensionsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedParsing) {
|
||||
// Serialize as TestPackedTypes and parse as TestPackedExtensions.
|
||||
unittest::TestPackedTypes source;
|
||||
unittest::TestPackedExtensions destination;
|
||||
string data;
|
||||
|
||||
TestUtil::SetPackedFields(&source);
|
||||
source.SerializeToString(&data);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedExtensionsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, IsInitialized) {
|
||||
// Test that IsInitialized() returns false if required fields in nested
|
||||
// extensions are missing.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::single);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_a(1);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_b(2);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_c(3);
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
|
||||
message.AddExtension(unittest::TestRequired::multi);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3);
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, MutableString) {
|
||||
// Test the mutable string accessors.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
message.MutableExtension(unittest::optional_string_extension)->assign("foo");
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension));
|
||||
EXPECT_EQ("foo", message.GetExtension(unittest::optional_string_extension));
|
||||
|
||||
message.AddExtension(unittest::repeated_string_extension)->assign("bar");
|
||||
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension));
|
||||
EXPECT_EQ("bar",
|
||||
message.GetExtension(unittest::repeated_string_extension, 0));
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
|
||||
// Scalar primitive extensions should increase the extension set size by a
|
||||
// minimum of the size of the primitive type.
|
||||
#define TEST_SCALAR_EXTENSIONS_SPACE_USED(type, value) \
|
||||
do { \
|
||||
unittest::TestAllExtensions message; \
|
||||
const int base_size = message.SpaceUsed(); \
|
||||
message.SetExtension(unittest::optional_##type##_extension, value); \
|
||||
int min_expected_size = base_size + \
|
||||
sizeof(message.GetExtension(unittest::optional_##type##_extension)); \
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed()); \
|
||||
} while (0)
|
||||
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(int32 , 101);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(int64 , 102);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(uint32 , 103);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(uint64 , 104);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sint32 , 105);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sint64 , 106);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed32 , 107);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed64 , 108);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed32, 109);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed64, 110);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(float , 111);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(double , 112);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(bool , true);
|
||||
#undef TEST_SCALAR_EXTENSIONS_SPACE_USED
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
message.SetExtension(unittest::optional_nested_enum_extension,
|
||||
unittest::TestAllTypes::FOO);
|
||||
int min_expected_size = base_size +
|
||||
sizeof(message.GetExtension(unittest::optional_nested_enum_extension));
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
{
|
||||
// Strings may cause extra allocations depending on their length; ensure
|
||||
// that gets included as well.
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
const string s("this is a fairly large string that will cause some "
|
||||
"allocation in order to store it in the extension");
|
||||
message.SetExtension(unittest::optional_string_extension, s);
|
||||
int min_expected_size = base_size + s.length();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
{
|
||||
// Messages also have additional allocation that need to be counted.
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
unittest::ForeignMessage foreign;
|
||||
foreign.set_c(42);
|
||||
message.MutableExtension(unittest::optional_foreign_message_extension)->
|
||||
CopyFrom(foreign);
|
||||
int min_expected_size = base_size + foreign.SpaceUsed();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
|
||||
// Repeated primitive extensions will increase space used by at least a
|
||||
// RepeatedField<T>, and will cause additional allocations when the array
|
||||
// gets too big for the initial space.
|
||||
// This macro:
|
||||
// - Adds a value to the repeated extension, then clears it, establishing
|
||||
// the base size.
|
||||
// - Adds a small number of values, testing that it doesn't increase the
|
||||
// SpaceUsed()
|
||||
// - Adds a large number of values (requiring allocation in the repeated
|
||||
// field), and ensures that that allocation is included in SpaceUsed()
|
||||
#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value) \
|
||||
do { \
|
||||
unittest::TestAllExtensions message; \
|
||||
const int base_size = message.SpaceUsed(); \
|
||||
int min_expected_size = sizeof(RepeatedField<cpptype>) + base_size; \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
message.ClearExtension(unittest::repeated_##type##_extension); \
|
||||
const int empty_repeated_field_size = message.SpaceUsed(); \
|
||||
EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type; \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type; \
|
||||
message.ClearExtension(unittest::repeated_##type##_extension); \
|
||||
for (int i = 0; i < 16; ++i) { \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
} \
|
||||
int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \
|
||||
EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \
|
||||
} while (0)
|
||||
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(int32 , int32 , 101);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(int64 , int64 , 102);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32 , uint32, 103);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64 , uint64, 104);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32 , int32 , 105);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64 , int64 , 106);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32 , uint32, 107);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64 , uint64, 108);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32 , 109);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64 , 110);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(float , float , 111);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(double , double, 112);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(bool , bool , true);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(nested_enum, int,
|
||||
unittest::TestAllTypes::FOO);
|
||||
#undef TEST_REPEATED_EXTENSIONS_SPACE_USED
|
||||
// Repeated strings
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
int min_expected_size = sizeof(RepeatedPtrField<string>) + base_size;
|
||||
const string value(256, 'x');
|
||||
// Once items are allocated, they may stick around even when cleared so
|
||||
// without the hardcore memory management accessors there isn't a notion of
|
||||
// the empty repeated field memory usage as there is with primitive types.
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
message.AddExtension(unittest::repeated_string_extension, value);
|
||||
}
|
||||
min_expected_size += (sizeof(value) + value.size()) * 16;
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
// Repeated messages
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
int min_expected_size = sizeof(RepeatedPtrField<unittest::ForeignMessage>) +
|
||||
base_size;
|
||||
unittest::ForeignMessage prototype;
|
||||
prototype.set_c(2);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
message.AddExtension(unittest::repeated_foreign_message_extension)->
|
||||
CopyFrom(prototype);
|
||||
}
|
||||
min_expected_size += 16 * prototype.SpaceUsed();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ExtensionSetTest, InvalidEnumDeath) {
|
||||
unittest::TestAllExtensions message;
|
||||
EXPECT_DEBUG_DEATH(
|
||||
message.SetExtension(unittest::optional_foreign_enum_extension,
|
||||
static_cast<unittest::ForeignEnum>(53)),
|
||||
"IsValid");
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ExtensionSetTest, DynamicExtensions) {
|
||||
// Test adding a dynamic extension to a compiled-in message object.
|
||||
|
||||
FileDescriptorProto dynamic_proto;
|
||||
dynamic_proto.set_name("dynamic_extensions_test.proto");
|
||||
dynamic_proto.add_dependency(
|
||||
unittest::TestAllExtensions::descriptor()->file()->name());
|
||||
dynamic_proto.set_package("dynamic_extensions");
|
||||
|
||||
// Copy the fields and nested types from TestDynamicExtensions into our new
|
||||
// proto, converting the fields into extensions.
|
||||
const Descriptor* template_descriptor =
|
||||
unittest::TestDynamicExtensions::descriptor();
|
||||
DescriptorProto template_descriptor_proto;
|
||||
template_descriptor->CopyTo(&template_descriptor_proto);
|
||||
dynamic_proto.mutable_message_type()->MergeFrom(
|
||||
template_descriptor_proto.nested_type());
|
||||
dynamic_proto.mutable_enum_type()->MergeFrom(
|
||||
template_descriptor_proto.enum_type());
|
||||
dynamic_proto.mutable_extension()->MergeFrom(
|
||||
template_descriptor_proto.field());
|
||||
|
||||
// For each extension that we added...
|
||||
for (int i = 0; i < dynamic_proto.extension_size(); i++) {
|
||||
// Set its extendee to TestAllExtensions.
|
||||
FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i);
|
||||
extension->set_extendee(
|
||||
unittest::TestAllExtensions::descriptor()->full_name());
|
||||
|
||||
// If the field refers to one of the types nested in TestDynamicExtensions,
|
||||
// make it refer to the type in our dynamic proto instead.
|
||||
string prefix = "." + template_descriptor->full_name() + ".";
|
||||
if (extension->has_type_name()) {
|
||||
string* type_name = extension->mutable_type_name();
|
||||
if (HasPrefixString(*type_name, prefix)) {
|
||||
type_name->replace(0, prefix.size(), ".dynamic_extensions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now build the file, using the generated pool as an underlay.
|
||||
DescriptorPool dynamic_pool(DescriptorPool::generated_pool());
|
||||
const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto);
|
||||
ASSERT_TRUE(file != NULL);
|
||||
DynamicMessageFactory dynamic_factory(&dynamic_pool);
|
||||
dynamic_factory.SetDelegateToGeneratedFactory(true);
|
||||
|
||||
// Construct a message that we can parse with the extensions we defined.
|
||||
// Since the extensions were based off of the fields of TestDynamicExtensions,
|
||||
// we can use that message to create this test message.
|
||||
string data;
|
||||
{
|
||||
unittest::TestDynamicExtensions message;
|
||||
message.set_scalar_extension(123);
|
||||
message.set_enum_extension(unittest::FOREIGN_BAR);
|
||||
message.set_dynamic_enum_extension(
|
||||
unittest::TestDynamicExtensions::DYNAMIC_BAZ);
|
||||
message.mutable_message_extension()->set_c(456);
|
||||
message.mutable_dynamic_message_extension()->set_dynamic_field(789);
|
||||
message.add_repeated_extension("foo");
|
||||
message.add_repeated_extension("bar");
|
||||
message.add_packed_extension(12);
|
||||
message.add_packed_extension(-34);
|
||||
message.add_packed_extension(56);
|
||||
message.add_packed_extension(-78);
|
||||
|
||||
// Also add some unknown fields.
|
||||
|
||||
// An unknown enum value (for a known field).
|
||||
message.mutable_unknown_fields()->AddVarint(
|
||||
unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber,
|
||||
12345);
|
||||
// A regular unknown field.
|
||||
message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown");
|
||||
|
||||
message.SerializeToString(&data);
|
||||
}
|
||||
|
||||
// Now we can parse this using our dynamic extension definitions...
|
||||
unittest::TestAllExtensions message;
|
||||
{
|
||||
io::ArrayInputStream raw_input(data.data(), data.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
|
||||
ASSERT_TRUE(message.ParseFromCodedStream(&input));
|
||||
ASSERT_TRUE(input.ConsumedEntireMessage());
|
||||
}
|
||||
|
||||
// Can we print it?
|
||||
EXPECT_EQ(
|
||||
"[dynamic_extensions.scalar_extension]: 123\n"
|
||||
"[dynamic_extensions.enum_extension]: FOREIGN_BAR\n"
|
||||
"[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n"
|
||||
"[dynamic_extensions.message_extension] {\n"
|
||||
" c: 456\n"
|
||||
"}\n"
|
||||
"[dynamic_extensions.dynamic_message_extension] {\n"
|
||||
" dynamic_field: 789\n"
|
||||
"}\n"
|
||||
"[dynamic_extensions.repeated_extension]: \"foo\"\n"
|
||||
"[dynamic_extensions.repeated_extension]: \"bar\"\n"
|
||||
"[dynamic_extensions.packed_extension]: 12\n"
|
||||
"[dynamic_extensions.packed_extension]: -34\n"
|
||||
"[dynamic_extensions.packed_extension]: 56\n"
|
||||
"[dynamic_extensions.packed_extension]: -78\n"
|
||||
"2002: 12345\n"
|
||||
"54321: \"unknown\"\n",
|
||||
message.DebugString());
|
||||
|
||||
// Can we serialize it?
|
||||
// (Don't use EXPECT_EQ because we don't want to dump raw binary data to the
|
||||
// terminal on failure.)
|
||||
EXPECT_TRUE(message.SerializeAsString() == data);
|
||||
|
||||
// What if we parse using the reflection-based parser?
|
||||
{
|
||||
unittest::TestAllExtensions message2;
|
||||
io::ArrayInputStream raw_input(data.data(), data.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
|
||||
ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2));
|
||||
ASSERT_TRUE(input.ConsumedEntireMessage());
|
||||
EXPECT_EQ(message.DebugString(), message2.DebugString());
|
||||
}
|
||||
|
||||
// Are the embedded generated types actually using the generated objects?
|
||||
{
|
||||
const FieldDescriptor* message_extension =
|
||||
file->FindExtensionByName("message_extension");
|
||||
ASSERT_TRUE(message_extension != NULL);
|
||||
const Message& sub_message =
|
||||
message.GetReflection()->GetMessage(message, message_extension);
|
||||
const unittest::ForeignMessage* typed_sub_message =
|
||||
dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
|
||||
ASSERT_TRUE(typed_sub_message != NULL);
|
||||
EXPECT_EQ(456, typed_sub_message->c());
|
||||
}
|
||||
|
||||
// What does GetMessage() return for the embedded dynamic type if it isn't
|
||||
// present?
|
||||
{
|
||||
const FieldDescriptor* dynamic_message_extension =
|
||||
file->FindExtensionByName("dynamic_message_extension");
|
||||
ASSERT_TRUE(dynamic_message_extension != NULL);
|
||||
const Message& parent = unittest::TestAllExtensions::default_instance();
|
||||
const Message& sub_message =
|
||||
parent.GetReflection()->GetMessage(parent, dynamic_message_extension,
|
||||
&dynamic_factory);
|
||||
const Message* prototype =
|
||||
dynamic_factory.GetPrototype(dynamic_message_extension->message_type());
|
||||
EXPECT_EQ(prototype, &sub_message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,424 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class DescriptorPool;
|
||||
// Generated code needs these to have been forward-declared. Easier to do it
|
||||
// here than to print them inside every .pb.h file.
|
||||
class FileDescriptor;
|
||||
class EnumDescriptor;
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Defined in this file.
|
||||
class GeneratedMessageReflection;
|
||||
|
||||
// Defined in other files.
|
||||
class ExtensionSet; // extension_set.h
|
||||
|
||||
// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use
|
||||
// by generated code. This class is just a big hack that reduces code
|
||||
// size.
|
||||
//
|
||||
// A GeneratedMessageReflection is an implementation of Reflection
|
||||
// which expects all fields to be backed by simple variables located in
|
||||
// memory. The locations are given using a base pointer and a set of
|
||||
// offsets.
|
||||
//
|
||||
// It is required that the user represents fields of each type in a standard
|
||||
// way, so that GeneratedMessageReflection can cast the void* pointer to
|
||||
// the appropriate type. For primitive fields and string fields, each field
|
||||
// should be represented using the obvious C++ primitive type. Enums and
|
||||
// Messages are different:
|
||||
// - Singular Message fields are stored as a pointer to a Message. These
|
||||
// should start out NULL, except for in the default instance where they
|
||||
// should start out pointing to other default instances.
|
||||
// - Enum fields are stored as an int. This int must always contain
|
||||
// a valid value, such that EnumDescriptor::FindValueByNumber() would
|
||||
// not return NULL.
|
||||
// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields
|
||||
// of whatever type the individual field would be. Strings and
|
||||
// Messages use RepeatedPtrFields while everything else uses
|
||||
// RepeatedFields.
|
||||
class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
|
||||
public:
|
||||
// Constructs a GeneratedMessageReflection.
|
||||
// Parameters:
|
||||
// descriptor: The descriptor for the message type being implemented.
|
||||
// default_instance: The default instance of the message. This is only
|
||||
// used to obtain pointers to default instances of embedded
|
||||
// messages, which GetMessage() will return if the particular
|
||||
// sub-message has not been initialized yet. (Thus, all
|
||||
// embedded message fields *must* have non-NULL pointers
|
||||
// in the default instance.)
|
||||
// offsets: An array of ints giving the byte offsets, relative to
|
||||
// the start of the message object, of each field. These can
|
||||
// be computed at compile time using the
|
||||
// GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined
|
||||
// below.
|
||||
// has_bits_offset: Offset in the message of an array of uint32s of size
|
||||
// descriptor->field_count()/32, rounded up. This is a
|
||||
// bitfield where each bit indicates whether or not the
|
||||
// corresponding field of the message has been initialized.
|
||||
// The bit for field index i is obtained by the expression:
|
||||
// has_bits[i / 32] & (1 << (i % 32))
|
||||
// unknown_fields_offset: Offset in the message of the UnknownFieldSet for
|
||||
// the message.
|
||||
// extensions_offset: Offset in the message of the ExtensionSet for the
|
||||
// message, or -1 if the message type has no extension
|
||||
// ranges.
|
||||
// pool: DescriptorPool to search for extension definitions. Only
|
||||
// used by FindKnownExtensionByName() and
|
||||
// FindKnownExtensionByNumber().
|
||||
// factory: MessageFactory to use to construct extension messages.
|
||||
// object_size: The size of a message object of this type, as measured
|
||||
// by sizeof().
|
||||
GeneratedMessageReflection(const Descriptor* descriptor,
|
||||
const Message* default_instance,
|
||||
const int offsets[],
|
||||
int has_bits_offset,
|
||||
int unknown_fields_offset,
|
||||
int extensions_offset,
|
||||
const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
int object_size);
|
||||
~GeneratedMessageReflection();
|
||||
|
||||
// implements Reflection -------------------------------------------
|
||||
|
||||
const UnknownFieldSet& GetUnknownFields(const Message& message) const;
|
||||
UnknownFieldSet* MutableUnknownFields(Message* message) const;
|
||||
|
||||
int SpaceUsed(const Message& message) const;
|
||||
|
||||
bool HasField(const Message& message, const FieldDescriptor* field) const;
|
||||
int FieldSize(const Message& message, const FieldDescriptor* field) const;
|
||||
void ClearField(Message* message, const FieldDescriptor* field) const;
|
||||
void RemoveLast(Message* message, const FieldDescriptor* field) const;
|
||||
void Swap(Message* message1, Message* message2) const;
|
||||
void SwapElements(Message* message, const FieldDescriptor* field,
|
||||
int index1, int index2) const;
|
||||
void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const;
|
||||
|
||||
int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const;
|
||||
const EnumValueDescriptor* GetEnum(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const;
|
||||
void SetEnum (Message* message, const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* MutableMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
const string& GetRepeatedStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index, string* scratch) const;
|
||||
const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
const Message& GetRepeatedMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
// Set the value of a field.
|
||||
void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field, int index, int32 value) const;
|
||||
void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field, int index, int64 value) const;
|
||||
void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field, int index, uint32 value) const;
|
||||
void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field, int index, uint64 value) const;
|
||||
void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field, int index, float value) const;
|
||||
void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field, int index, double value) const;
|
||||
void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field, int index, bool value) const;
|
||||
void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const string& value) const;
|
||||
void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
|
||||
int index, const EnumValueDescriptor* value) const;
|
||||
// Get a mutable pointer to a field with a message type.
|
||||
Message* MutableRepeatedMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void AddString(Message* message,
|
||||
const FieldDescriptor* field, const string& value) const;
|
||||
void AddEnum(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* AddMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
|
||||
const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
|
||||
|
||||
private:
|
||||
friend class GeneratedMessage;
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
const Message* default_instance_;
|
||||
const int* offsets_;
|
||||
|
||||
int has_bits_offset_;
|
||||
int unknown_fields_offset_;
|
||||
int extensions_offset_;
|
||||
int object_size_;
|
||||
|
||||
const DescriptorPool* descriptor_pool_;
|
||||
MessageFactory* message_factory_;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetRaw(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRaw(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
|
||||
inline const Message* GetMessagePrototype(const FieldDescriptor* field) const;
|
||||
|
||||
inline const uint32* GetHasBits(const Message& message) const;
|
||||
inline uint32* MutableHasBits(Message* message) const;
|
||||
inline const ExtensionSet& GetExtensionSet(const Message& message) const;
|
||||
inline ExtensionSet* MutableExtensionSet(Message* message) const;
|
||||
|
||||
inline bool HasBit(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void SetBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void ClearBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetField(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline void SetField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedPtrField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void SetRepeatedField(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
Type value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRepeatedField(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void AddField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* AddField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
int GetExtensionNumberOrDie(const Descriptor* type) const;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
|
||||
};
|
||||
|
||||
// Returns the offset of the given field within the given aggregate type.
|
||||
// This is equivalent to the ANSI C offsetof() macro. However, according
|
||||
// to the C++ standard, offsetof() only works on POD types, and GCC
|
||||
// enforces this requirement with a warning. In practice, this rule is
|
||||
// unnecessarily strict; there is probably no compiler or platform on
|
||||
// which the offsets of the direct fields of a class are non-constant.
|
||||
// Fields inherited from superclasses *can* have non-constant offsets,
|
||||
// but that's not what this macro will be used for.
|
||||
//
|
||||
// Note that we calculate relative to the pointer value 16 here since if we
|
||||
// just use zero, GCC complains about dereferencing a NULL pointer. We
|
||||
// choose 16 rather than some other number just in case the compiler would
|
||||
// be confused by an unaligned pointer.
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
|
||||
static_cast<int>( \
|
||||
reinterpret_cast<const char*>( \
|
||||
&reinterpret_cast<const TYPE*>(16)->FIELD) - \
|
||||
reinterpret_cast<const char*>(16))
|
||||
|
||||
// There are some places in proto2 where dynamic_cast would be useful as an
|
||||
// optimization. For example, take Message::MergeFrom(const Message& other).
|
||||
// For a given generated message FooMessage, we generate these two methods:
|
||||
// void MergeFrom(const FooMessage& other);
|
||||
// void MergeFrom(const Message& other);
|
||||
// The former method can be implemented directly in terms of FooMessage's
|
||||
// inline accessors, but the latter method must work with the reflection
|
||||
// interface. However, if the parameter to the latter method is actually of
|
||||
// type FooMessage, then we'd like to be able to just call the other method
|
||||
// as an optimization. So, we use dynamic_cast to check this.
|
||||
//
|
||||
// That said, dynamic_cast requires RTTI, which many people like to disable
|
||||
// for performance and code size reasons. When RTTI is not available, we
|
||||
// still need to produce correct results. So, in this case we have to fall
|
||||
// back to using reflection, which is what we would have done anyway if the
|
||||
// objects were not of the exact same class.
|
||||
//
|
||||
// dynamic_cast_if_available() implements this logic. If RTTI is
|
||||
// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns
|
||||
// NULL.
|
||||
//
|
||||
// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
|
||||
// On MSVC, this should be detected automatically.
|
||||
template<typename To, typename From>
|
||||
inline To dynamic_cast_if_available(From from) {
|
||||
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
|
||||
return NULL;
|
||||
#else
|
||||
return dynamic_cast<To>(from);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper for EnumType_Parse functions: try to parse the string 'name' as an
|
||||
// enum name of the given type, returning true and filling in value on success,
|
||||
// or returning false and leaving value unchanged on failure.
|
||||
LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
int* value);
|
||||
|
||||
template<typename EnumType>
|
||||
bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
EnumType* value) {
|
||||
int tmp;
|
||||
if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
|
||||
*value = static_cast<EnumType>(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Just a wrapper around printing the name of a value. The main point of this
|
||||
// function is not to be inlined, so that you can do this without including
|
||||
// descriptor.h.
|
||||
LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
@ -0,0 +1,55 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
double Infinity() {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
double NaN() {
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
const ::std::string kEmptyString;
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,82 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains miscellaneous helper code used by generated code --
|
||||
// including lite types -- but which should not be used directly by users.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Annotation for the compiler to emit a deprecation message if a field marked
|
||||
// with option 'deprecated=true' is used in the code, or for other things in
|
||||
// generated code which are deprecated.
|
||||
//
|
||||
// For internal use in the pb.cc files, deprecation warnings are suppressed
|
||||
// there.
|
||||
#undef DEPRECATED_PROTOBUF_FIELD
|
||||
#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
|
||||
# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED
|
||||
#else
|
||||
# define PROTOBUF_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
// Constants for special floating point values.
|
||||
double Infinity();
|
||||
double NaN();
|
||||
|
||||
// Constant used for empty default strings.
|
||||
extern const ::std::string kEmptyString;
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
@ -0,0 +1,839 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This implementation is heavily optimized to make reads and writes
|
||||
// of small values (especially varints) as fast as possible. In
|
||||
// particular, we optimize for the common case that a read or a write
|
||||
// will not cross the end of the buffer, since we can avoid a lot
|
||||
// of branching in this case.
|
||||
|
||||
#include <google/protobuf/io/coded_stream_inl.h>
|
||||
#include <algorithm>
|
||||
#include <limits.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
namespace {
|
||||
|
||||
static const int kMaxVarintBytes = 10;
|
||||
static const int kMaxVarint32Bytes = 5;
|
||||
|
||||
|
||||
inline bool NextNonEmpty(ZeroCopyInputStream* input,
|
||||
const void** data, int* size) {
|
||||
bool success;
|
||||
do {
|
||||
success = input->Next(data, size);
|
||||
} while (success && *size == 0);
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// CodedInputStream ==================================================
|
||||
|
||||
|
||||
void CodedInputStream::BackUpInputToCurrentPosition() {
|
||||
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
|
||||
if (backup_bytes > 0) {
|
||||
input_->BackUp(backup_bytes);
|
||||
|
||||
// total_bytes_read_ doesn't include overflow_bytes_.
|
||||
total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
|
||||
buffer_end_ = buffer_;
|
||||
buffer_size_after_limit_ = 0;
|
||||
overflow_bytes_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void CodedInputStream::RecomputeBufferLimits() {
|
||||
buffer_end_ += buffer_size_after_limit_;
|
||||
int closest_limit = min(current_limit_, total_bytes_limit_);
|
||||
if (closest_limit < total_bytes_read_) {
|
||||
// The limit position is in the current buffer. We must adjust
|
||||
// the buffer size accordingly.
|
||||
buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
|
||||
buffer_end_ -= buffer_size_after_limit_;
|
||||
} else {
|
||||
buffer_size_after_limit_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
|
||||
// Current position relative to the beginning of the stream.
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
Limit old_limit = current_limit_;
|
||||
|
||||
// security: byte_limit is possibly evil, so check for negative values
|
||||
// and overflow.
|
||||
if (byte_limit >= 0 &&
|
||||
byte_limit <= INT_MAX - current_position) {
|
||||
current_limit_ = current_position + byte_limit;
|
||||
} else {
|
||||
// Negative or overflow.
|
||||
current_limit_ = INT_MAX;
|
||||
}
|
||||
|
||||
// We need to enforce all limits, not just the new one, so if the previous
|
||||
// limit was before the new requested limit, we continue to enforce the
|
||||
// previous limit.
|
||||
current_limit_ = min(current_limit_, old_limit);
|
||||
|
||||
RecomputeBufferLimits();
|
||||
return old_limit;
|
||||
}
|
||||
|
||||
void CodedInputStream::PopLimit(Limit limit) {
|
||||
// The limit passed in is actually the *old* limit, which we returned from
|
||||
// PushLimit().
|
||||
current_limit_ = limit;
|
||||
RecomputeBufferLimits();
|
||||
|
||||
// We may no longer be at a legitimate message end. ReadTag() needs to be
|
||||
// called again to find out.
|
||||
legitimate_message_end_ = false;
|
||||
}
|
||||
|
||||
int CodedInputStream::BytesUntilLimit() {
|
||||
if (current_limit_ == INT_MAX) return -1;
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
return current_limit_ - current_position;
|
||||
}
|
||||
|
||||
void CodedInputStream::SetTotalBytesLimit(
|
||||
int total_bytes_limit, int warning_threshold) {
|
||||
// Make sure the limit isn't already past, since this could confuse other
|
||||
// code.
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
total_bytes_limit_ = max(current_position, total_bytes_limit);
|
||||
total_bytes_warning_threshold_ = warning_threshold;
|
||||
RecomputeBufferLimits();
|
||||
}
|
||||
|
||||
void CodedInputStream::PrintTotalBytesLimitError() {
|
||||
GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
|
||||
"big (more than " << total_bytes_limit_
|
||||
<< " bytes). To increase the limit (or to disable these "
|
||||
"warnings), see CodedInputStream::SetTotalBytesLimit() "
|
||||
"in google/protobuf/io/coded_stream.h.";
|
||||
}
|
||||
|
||||
bool CodedInputStream::Skip(int count) {
|
||||
if (count < 0) return false; // security: count is often user-supplied
|
||||
|
||||
const int original_buffer_size = BufferSize();
|
||||
|
||||
if (count <= original_buffer_size) {
|
||||
// Just skipping within the current buffer. Easy.
|
||||
Advance(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buffer_size_after_limit_ > 0) {
|
||||
// We hit a limit inside this buffer. Advance to the limit and fail.
|
||||
Advance(original_buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
count -= original_buffer_size;
|
||||
buffer_ = NULL;
|
||||
buffer_end_ = buffer_;
|
||||
|
||||
// Make sure this skip doesn't try to skip past the current limit.
|
||||
int closest_limit = min(current_limit_, total_bytes_limit_);
|
||||
int bytes_until_limit = closest_limit - total_bytes_read_;
|
||||
if (bytes_until_limit < count) {
|
||||
// We hit the limit. Skip up to it then fail.
|
||||
if (bytes_until_limit > 0) {
|
||||
total_bytes_read_ = closest_limit;
|
||||
input_->Skip(bytes_until_limit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
total_bytes_read_ += count;
|
||||
return input_->Skip(count);
|
||||
}
|
||||
|
||||
bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
|
||||
if (BufferSize() == 0 && !Refresh()) return false;
|
||||
|
||||
*data = buffer_;
|
||||
*size = BufferSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadRaw(void* buffer, int size) {
|
||||
int current_buffer_size;
|
||||
while ((current_buffer_size = BufferSize()) < size) {
|
||||
// Reading past end of buffer. Copy what we have, then refresh.
|
||||
memcpy(buffer, buffer_, current_buffer_size);
|
||||
buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
|
||||
size -= current_buffer_size;
|
||||
Advance(current_buffer_size);
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
memcpy(buffer, buffer_, size);
|
||||
Advance(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadString(string* buffer, int size) {
|
||||
if (size < 0) return false; // security: size is often user-supplied
|
||||
return InternalReadStringInline(buffer, size);
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
|
||||
if (!buffer->empty()) {
|
||||
buffer->clear();
|
||||
}
|
||||
|
||||
int current_buffer_size;
|
||||
while ((current_buffer_size = BufferSize()) < size) {
|
||||
// Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
|
||||
if (current_buffer_size != 0) {
|
||||
// Note: string1.append(string2) is O(string2.size()) (as opposed to
|
||||
// O(string1.size() + string2.size()), which would be bad).
|
||||
buffer->append(reinterpret_cast<const char*>(buffer_),
|
||||
current_buffer_size);
|
||||
}
|
||||
size -= current_buffer_size;
|
||||
Advance(current_buffer_size);
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
buffer->append(reinterpret_cast<const char*>(buffer_), size);
|
||||
Advance(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
|
||||
uint8 bytes[sizeof(*value)];
|
||||
|
||||
const uint8* ptr;
|
||||
if (BufferSize() >= sizeof(*value)) {
|
||||
// Fast path: Enough bytes in the buffer to read directly.
|
||||
ptr = buffer_;
|
||||
Advance(sizeof(*value));
|
||||
} else {
|
||||
// Slow path: Had to read past the end of the buffer.
|
||||
if (!ReadRaw(bytes, sizeof(*value))) return false;
|
||||
ptr = bytes;
|
||||
}
|
||||
ReadLittleEndian32FromArray(ptr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
|
||||
uint8 bytes[sizeof(*value)];
|
||||
|
||||
const uint8* ptr;
|
||||
if (BufferSize() >= sizeof(*value)) {
|
||||
// Fast path: Enough bytes in the buffer to read directly.
|
||||
ptr = buffer_;
|
||||
Advance(sizeof(*value));
|
||||
} else {
|
||||
// Slow path: Had to read past the end of the buffer.
|
||||
if (!ReadRaw(bytes, sizeof(*value))) return false;
|
||||
ptr = bytes;
|
||||
}
|
||||
ReadLittleEndian64FromArray(ptr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline const uint8* ReadVarint32FromArray(
|
||||
const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this read won't cross the end, so we can skip the checks.
|
||||
const uint8* ptr = buffer;
|
||||
uint32 b;
|
||||
uint32 result;
|
||||
|
||||
b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
|
||||
|
||||
// If the input is larger than 32 bits, we still need to read it all
|
||||
// and discard the high-order bits.
|
||||
for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
|
||||
b = *(ptr++); if (!(b & 0x80)) goto done;
|
||||
}
|
||||
|
||||
// We have overrun the maximum size of a varint (10 bytes). Assume
|
||||
// the data is corrupt.
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
*value = result;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CodedInputStream::ReadVarint32Slow(uint32* value) {
|
||||
uint64 result;
|
||||
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
|
||||
// for one-byte varints.
|
||||
if (!ReadVarint64Fallback(&result)) return false;
|
||||
*value = (uint32)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, value);
|
||||
if (end == NULL) return false;
|
||||
buffer_ = end;
|
||||
return true;
|
||||
} else {
|
||||
// Really slow case: we will incur the cost of an extra function call here,
|
||||
// but moving this out of line reduces the size of this function, which
|
||||
// improves the common case. In micro benchmarks, this is worth about 10-15%
|
||||
return ReadVarint32Slow(value);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CodedInputStream::ReadTagSlow() {
|
||||
if (buffer_ == buffer_end_) {
|
||||
// Call refresh.
|
||||
if (!Refresh()) {
|
||||
// Refresh failed. Make sure that it failed due to EOF, not because
|
||||
// we hit total_bytes_limit_, which, unlike normal limits, is not a
|
||||
// valid place to end a message.
|
||||
int current_position = total_bytes_read_ - buffer_size_after_limit_;
|
||||
if (current_position >= total_bytes_limit_) {
|
||||
// Hit total_bytes_limit_. But if we also hit the normal limit,
|
||||
// we're still OK.
|
||||
legitimate_message_end_ = current_limit_ == total_bytes_limit_;
|
||||
} else {
|
||||
legitimate_message_end_ = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
|
||||
// again, since we have now refreshed the buffer.
|
||||
uint64 result;
|
||||
if (!ReadVarint64(&result)) return 0;
|
||||
return static_cast<uint32>(result);
|
||||
}
|
||||
|
||||
uint32 CodedInputStream::ReadTagFallback() {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
uint32 tag;
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, &tag);
|
||||
if (end == NULL) {
|
||||
return 0;
|
||||
}
|
||||
buffer_ = end;
|
||||
return tag;
|
||||
} else {
|
||||
// We are commonly at a limit when attempting to read tags. Try to quickly
|
||||
// detect this case without making another function call.
|
||||
if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
|
||||
// Make sure that the limit we hit is not total_bytes_limit_, since
|
||||
// in that case we still need to call Refresh() so that it prints an
|
||||
// error.
|
||||
total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
|
||||
// We hit a byte limit.
|
||||
legitimate_message_end_ = true;
|
||||
return 0;
|
||||
}
|
||||
return ReadTagSlow();
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint64Slow(uint64* value) {
|
||||
// Slow path: This read might cross the end of the buffer, so we
|
||||
// need to check and refresh the buffer if and when it does.
|
||||
|
||||
uint64 result = 0;
|
||||
int count = 0;
|
||||
uint32 b;
|
||||
|
||||
do {
|
||||
if (count == kMaxVarintBytes) return false;
|
||||
while (buffer_ == buffer_end_) {
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
b = *buffer_;
|
||||
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
|
||||
Advance(1);
|
||||
++count;
|
||||
} while (b & 0x80);
|
||||
|
||||
*value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this read won't cross the end, so we can skip the checks.
|
||||
|
||||
const uint8* ptr = buffer_;
|
||||
uint32 b;
|
||||
|
||||
// Splitting into 32-bit pieces gives better performance on 32-bit
|
||||
// processors.
|
||||
uint32 part0 = 0, part1 = 0, part2 = 0;
|
||||
|
||||
b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
|
||||
// We have overrun the maximum size of a varint (10 bytes). The data
|
||||
// must be corrupt.
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
Advance(ptr - buffer_);
|
||||
*value = (static_cast<uint64>(part0) ) |
|
||||
(static_cast<uint64>(part1) << 28) |
|
||||
(static_cast<uint64>(part2) << 56);
|
||||
return true;
|
||||
} else {
|
||||
return ReadVarint64Slow(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedInputStream::Refresh() {
|
||||
GOOGLE_DCHECK_EQ(0, BufferSize());
|
||||
|
||||
if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
|
||||
total_bytes_read_ == current_limit_) {
|
||||
// We've hit a limit. Stop.
|
||||
int current_position = total_bytes_read_ - buffer_size_after_limit_;
|
||||
|
||||
if (current_position >= total_bytes_limit_ &&
|
||||
total_bytes_limit_ != current_limit_) {
|
||||
// Hit total_bytes_limit_.
|
||||
PrintTotalBytesLimitError();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (total_bytes_warning_threshold_ >= 0 &&
|
||||
total_bytes_read_ >= total_bytes_warning_threshold_) {
|
||||
GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
|
||||
"message turns out to be larger than "
|
||||
<< total_bytes_limit_ << " bytes, parsing will be halted "
|
||||
"for security reasons. To increase the limit (or to "
|
||||
"disable these warnings), see "
|
||||
"CodedInputStream::SetTotalBytesLimit() in "
|
||||
"google/protobuf/io/coded_stream.h.";
|
||||
|
||||
// Don't warn again for this stream.
|
||||
total_bytes_warning_threshold_ = -1;
|
||||
}
|
||||
|
||||
const void* void_buffer;
|
||||
int buffer_size;
|
||||
if (NextNonEmpty(input_, &void_buffer, &buffer_size)) {
|
||||
buffer_ = reinterpret_cast<const uint8*>(void_buffer);
|
||||
buffer_end_ = buffer_ + buffer_size;
|
||||
GOOGLE_CHECK_GE(buffer_size, 0);
|
||||
|
||||
if (total_bytes_read_ <= INT_MAX - buffer_size) {
|
||||
total_bytes_read_ += buffer_size;
|
||||
} else {
|
||||
// Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
|
||||
// We can't get that far anyway, because total_bytes_limit_ is guaranteed
|
||||
// to be less than it. We need to keep track of the number of bytes
|
||||
// we discarded, though, so that we can call input_->BackUp() to back
|
||||
// up over them on destruction.
|
||||
|
||||
// The following line is equivalent to:
|
||||
// overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
|
||||
// except that it avoids overflows. Signed integer overflow has
|
||||
// undefined results according to the C standard.
|
||||
overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
|
||||
buffer_end_ -= overflow_bytes_;
|
||||
total_bytes_read_ = INT_MAX;
|
||||
}
|
||||
|
||||
RecomputeBufferLimits();
|
||||
return true;
|
||||
} else {
|
||||
buffer_ = NULL;
|
||||
buffer_end_ = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// CodedOutputStream =================================================
|
||||
|
||||
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
|
||||
: output_(output),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
total_bytes_(0),
|
||||
had_error_(false) {
|
||||
// Eagerly Refresh() so buffer space is immediately available.
|
||||
Refresh();
|
||||
// The Refresh() may have failed. If the client doesn't write any data,
|
||||
// though, don't consider this an error. If the client does write data, then
|
||||
// another Refresh() will be attempted and it will set the error once again.
|
||||
had_error_ = false;
|
||||
}
|
||||
|
||||
CodedOutputStream::~CodedOutputStream() {
|
||||
if (buffer_size_ > 0) {
|
||||
output_->BackUp(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedOutputStream::Skip(int count) {
|
||||
if (count < 0) return false;
|
||||
|
||||
while (count > buffer_size_) {
|
||||
count -= buffer_size_;
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
Advance(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
|
||||
if (buffer_size_ == 0 && !Refresh()) return false;
|
||||
|
||||
*data = buffer_;
|
||||
*size = buffer_size_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteRaw(const void* data, int size) {
|
||||
while (buffer_size_ < size) {
|
||||
memcpy(buffer_, data, buffer_size_);
|
||||
size -= buffer_size_;
|
||||
data = reinterpret_cast<const uint8*>(data) + buffer_size_;
|
||||
if (!Refresh()) return;
|
||||
}
|
||||
|
||||
memcpy(buffer_, data, size);
|
||||
Advance(size);
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteRawToArray(
|
||||
const void* data, int size, uint8* target) {
|
||||
memcpy(target, data, size);
|
||||
return target + size;
|
||||
}
|
||||
|
||||
|
||||
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
|
||||
uint8 bytes[sizeof(value)];
|
||||
|
||||
bool use_fast = buffer_size_ >= sizeof(value);
|
||||
uint8* ptr = use_fast ? buffer_ : bytes;
|
||||
|
||||
WriteLittleEndian32ToArray(value, ptr);
|
||||
|
||||
if (use_fast) {
|
||||
Advance(sizeof(value));
|
||||
} else {
|
||||
WriteRaw(bytes, sizeof(value));
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteLittleEndian64(uint64 value) {
|
||||
uint8 bytes[sizeof(value)];
|
||||
|
||||
bool use_fast = buffer_size_ >= sizeof(value);
|
||||
uint8* ptr = use_fast ? buffer_ : bytes;
|
||||
|
||||
WriteLittleEndian64ToArray(value, ptr);
|
||||
|
||||
if (use_fast) {
|
||||
Advance(sizeof(value));
|
||||
} else {
|
||||
WriteRaw(bytes, sizeof(value));
|
||||
}
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
|
||||
uint32 value, uint8* target) {
|
||||
target[0] = static_cast<uint8>(value | 0x80);
|
||||
if (value >= (1 << 7)) {
|
||||
target[1] = static_cast<uint8>((value >> 7) | 0x80);
|
||||
if (value >= (1 << 14)) {
|
||||
target[2] = static_cast<uint8>((value >> 14) | 0x80);
|
||||
if (value >= (1 << 21)) {
|
||||
target[3] = static_cast<uint8>((value >> 21) | 0x80);
|
||||
if (value >= (1 << 28)) {
|
||||
target[4] = static_cast<uint8>(value >> 28);
|
||||
return target + 5;
|
||||
} else {
|
||||
target[3] &= 0x7F;
|
||||
return target + 4;
|
||||
}
|
||||
} else {
|
||||
target[2] &= 0x7F;
|
||||
return target + 3;
|
||||
}
|
||||
} else {
|
||||
target[1] &= 0x7F;
|
||||
return target + 2;
|
||||
}
|
||||
} else {
|
||||
target[0] &= 0x7F;
|
||||
return target + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteVarint32(uint32 value) {
|
||||
if (buffer_size_ >= kMaxVarint32Bytes) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this write won't cross the end, so we can skip the checks.
|
||||
uint8* target = buffer_;
|
||||
uint8* end = WriteVarint32FallbackToArrayInline(value, target);
|
||||
int size = end - target;
|
||||
Advance(size);
|
||||
} else {
|
||||
// Slow path: This write might cross the end of the buffer, so we
|
||||
// compose the bytes first then use WriteRaw().
|
||||
uint8 bytes[kMaxVarint32Bytes];
|
||||
int size = 0;
|
||||
while (value > 0x7F) {
|
||||
bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
|
||||
value >>= 7;
|
||||
}
|
||||
bytes[size++] = static_cast<uint8>(value) & 0x7F;
|
||||
WriteRaw(bytes, size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteVarint32FallbackToArray(
|
||||
uint32 value, uint8* target) {
|
||||
return WriteVarint32FallbackToArrayInline(value, target);
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
|
||||
uint64 value, uint8* target) {
|
||||
// Splitting into 32-bit pieces gives better performance on 32-bit
|
||||
// processors.
|
||||
uint32 part0 = static_cast<uint32>(value );
|
||||
uint32 part1 = static_cast<uint32>(value >> 28);
|
||||
uint32 part2 = static_cast<uint32>(value >> 56);
|
||||
|
||||
int size;
|
||||
|
||||
// Here we can't really optimize for small numbers, since the value is
|
||||
// split into three parts. Cheking for numbers < 128, for instance,
|
||||
// would require three comparisons, since you'd have to make sure part1
|
||||
// and part2 are zero. However, if the caller is using 64-bit integers,
|
||||
// it is likely that they expect the numbers to often be very large, so
|
||||
// we probably don't want to optimize for small numbers anyway. Thus,
|
||||
// we end up with a hardcoded binary search tree...
|
||||
if (part2 == 0) {
|
||||
if (part1 == 0) {
|
||||
if (part0 < (1 << 14)) {
|
||||
if (part0 < (1 << 7)) {
|
||||
size = 1; goto size1;
|
||||
} else {
|
||||
size = 2; goto size2;
|
||||
}
|
||||
} else {
|
||||
if (part0 < (1 << 21)) {
|
||||
size = 3; goto size3;
|
||||
} else {
|
||||
size = 4; goto size4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (part1 < (1 << 14)) {
|
||||
if (part1 < (1 << 7)) {
|
||||
size = 5; goto size5;
|
||||
} else {
|
||||
size = 6; goto size6;
|
||||
}
|
||||
} else {
|
||||
if (part1 < (1 << 21)) {
|
||||
size = 7; goto size7;
|
||||
} else {
|
||||
size = 8; goto size8;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (part2 < (1 << 7)) {
|
||||
size = 9; goto size9;
|
||||
} else {
|
||||
size = 10; goto size10;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
|
||||
size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
|
||||
size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
|
||||
size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
|
||||
size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
|
||||
size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
|
||||
size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
|
||||
size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
|
||||
size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
|
||||
size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
|
||||
size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
|
||||
|
||||
target[size-1] &= 0x7F;
|
||||
return target + size;
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteVarint64(uint64 value) {
|
||||
if (buffer_size_ >= kMaxVarintBytes) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this write won't cross the end, so we can skip the checks.
|
||||
uint8* target = buffer_;
|
||||
|
||||
uint8* end = WriteVarint64ToArrayInline(value, target);
|
||||
int size = end - target;
|
||||
Advance(size);
|
||||
} else {
|
||||
// Slow path: This write might cross the end of the buffer, so we
|
||||
// compose the bytes first then use WriteRaw().
|
||||
uint8 bytes[kMaxVarintBytes];
|
||||
int size = 0;
|
||||
while (value > 0x7F) {
|
||||
bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
|
||||
value >>= 7;
|
||||
}
|
||||
bytes[size++] = static_cast<uint8>(value) & 0x7F;
|
||||
WriteRaw(bytes, size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteVarint64ToArray(
|
||||
uint64 value, uint8* target) {
|
||||
return WriteVarint64ToArrayInline(value, target);
|
||||
}
|
||||
|
||||
bool CodedOutputStream::Refresh() {
|
||||
void* void_buffer;
|
||||
if (output_->Next(&void_buffer, &buffer_size_)) {
|
||||
buffer_ = reinterpret_cast<uint8*>(void_buffer);
|
||||
total_bytes_ += buffer_size_;
|
||||
return true;
|
||||
} else {
|
||||
buffer_ = NULL;
|
||||
buffer_size_ = 0;
|
||||
had_error_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CodedOutputStream::VarintSize32Fallback(uint32 value) {
|
||||
if (value < (1 << 7)) {
|
||||
return 1;
|
||||
} else if (value < (1 << 14)) {
|
||||
return 2;
|
||||
} else if (value < (1 << 21)) {
|
||||
return 3;
|
||||
} else if (value < (1 << 28)) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
int CodedOutputStream::VarintSize64(uint64 value) {
|
||||
if (value < (1ull << 35)) {
|
||||
if (value < (1ull << 7)) {
|
||||
return 1;
|
||||
} else if (value < (1ull << 14)) {
|
||||
return 2;
|
||||
} else if (value < (1ull << 21)) {
|
||||
return 3;
|
||||
} else if (value < (1ull << 28)) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
} else {
|
||||
if (value < (1ull << 42)) {
|
||||
return 6;
|
||||
} else if (value < (1ull << 49)) {
|
||||
return 7;
|
||||
} else if (value < (1ull << 56)) {
|
||||
return 8;
|
||||
} else if (value < (1ull << 63)) {
|
||||
return 9;
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,64 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: jasonh@google.com (Jason Hsueh)
|
||||
//
|
||||
// Implements methods of coded_stream.h that need to be inlined for performance
|
||||
// reasons, but should not be defined in a public header.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
||||
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
||||
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
inline bool CodedInputStream::InternalReadStringInline(string* buffer,
|
||||
int size) {
|
||||
if (size < 0) return false; // security: size is often user-supplied
|
||||
|
||||
if (BufferSize() >= size) {
|
||||
STLStringResizeUninitialized(buffer, size);
|
||||
memcpy(string_as_array(buffer), buffer_, size);
|
||||
Advance(size);
|
||||
return true;
|
||||
}
|
||||
|
||||
return ReadStringFallback(buffer, size);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
@ -0,0 +1,335 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the implementation of classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <google/protobuf/io/gzip_stream.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
static const int kDefaultBufferSize = 65536;
|
||||
|
||||
GzipInputStream::GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
|
||||
: format_(format), sub_stream_(sub_stream), zerror_(Z_OK) {
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
if (buffer_size == -1) {
|
||||
output_buffer_length_ = kDefaultBufferSize;
|
||||
} else {
|
||||
output_buffer_length_ = buffer_size;
|
||||
}
|
||||
output_buffer_ = operator new(output_buffer_length_);
|
||||
GOOGLE_CHECK(output_buffer_ != NULL);
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
}
|
||||
GzipInputStream::~GzipInputStream() {
|
||||
operator delete(output_buffer_);
|
||||
zerror_ = inflateEnd(&zcontext_);
|
||||
}
|
||||
|
||||
static inline int internalInflateInit2(
|
||||
z_stream* zcontext, GzipInputStream::Format format) {
|
||||
int windowBitsFormat = 0;
|
||||
switch (format) {
|
||||
case GzipInputStream::GZIP: windowBitsFormat = 16; break;
|
||||
case GzipInputStream::AUTO: windowBitsFormat = 32; break;
|
||||
case GzipInputStream::ZLIB: windowBitsFormat = 0; break;
|
||||
}
|
||||
return inflateInit2(zcontext, /* windowBits */15 | windowBitsFormat);
|
||||
}
|
||||
|
||||
int GzipInputStream::Inflate(int flush) {
|
||||
if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
|
||||
// previous inflate filled output buffer. don't change input params yet.
|
||||
} else if (zcontext_.avail_in == 0) {
|
||||
const void* in;
|
||||
int in_size;
|
||||
bool first = zcontext_.next_in == NULL;
|
||||
bool ok = sub_stream_->Next(&in, &in_size);
|
||||
if (!ok) {
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
return Z_STREAM_END;
|
||||
}
|
||||
zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
|
||||
zcontext_.avail_in = in_size;
|
||||
if (first) {
|
||||
int error = internalInflateInit2(&zcontext_, format_);
|
||||
if (error != Z_OK) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
int error = inflate(&zcontext_, flush);
|
||||
return error;
|
||||
}
|
||||
|
||||
void GzipInputStream::DoNextOutput(const void** data, int* size) {
|
||||
*data = output_position_;
|
||||
*size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
|
||||
output_position_ = zcontext_.next_out;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool GzipInputStream::Next(const void** data, int* size) {
|
||||
bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if ((!ok) || (zcontext_.next_out == NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.next_out != output_position_) {
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
if (zerror_ == Z_STREAM_END) {
|
||||
if (zcontext_.next_out != NULL) {
|
||||
// sub_stream_ may have concatenated streams to follow
|
||||
zerror_ = inflateEnd(&zcontext_);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
zerror_ = internalInflateInit2(&zcontext_, format_);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
zerror_ = Inflate(Z_NO_FLUSH);
|
||||
if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
|
||||
// The underlying stream's Next returned false inside Inflate.
|
||||
return false;
|
||||
}
|
||||
ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
void GzipInputStream::BackUp(int count) {
|
||||
output_position_ = reinterpret_cast<void*>(
|
||||
reinterpret_cast<uintptr_t>(output_position_) - count);
|
||||
}
|
||||
bool GzipInputStream::Skip(int count) {
|
||||
const void* data;
|
||||
int size;
|
||||
bool ok = Next(&data, &size);
|
||||
while (ok && (size < count)) {
|
||||
count -= size;
|
||||
ok = Next(&data, &size);
|
||||
}
|
||||
if (size > count) {
|
||||
BackUp(size - count);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
int64 GzipInputStream::ByteCount() const {
|
||||
return zcontext_.total_out +
|
||||
(((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
GzipOutputStream::Options::Options()
|
||||
: format(GZIP),
|
||||
buffer_size(kDefaultBufferSize),
|
||||
compression_level(Z_DEFAULT_COMPRESSION),
|
||||
compression_strategy(Z_DEFAULT_STRATEGY) {}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
|
||||
Init(sub_stream, Options());
|
||||
}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
Init(sub_stream, options);
|
||||
}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) {
|
||||
Options options;
|
||||
options.format = format;
|
||||
if (buffer_size != -1) {
|
||||
options.buffer_size = buffer_size;
|
||||
}
|
||||
Init(sub_stream, options);
|
||||
}
|
||||
|
||||
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
sub_stream_ = sub_stream;
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
|
||||
input_buffer_length_ = options.buffer_size;
|
||||
input_buffer_ = operator new(input_buffer_length_);
|
||||
GOOGLE_CHECK(input_buffer_ != NULL);
|
||||
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
// default to GZIP format
|
||||
int windowBitsFormat = 16;
|
||||
if (options.format == ZLIB) {
|
||||
windowBitsFormat = 0;
|
||||
}
|
||||
zerror_ = deflateInit2(
|
||||
&zcontext_,
|
||||
options.compression_level,
|
||||
Z_DEFLATED,
|
||||
/* windowBits */15 | windowBitsFormat,
|
||||
/* memLevel (default) */8,
|
||||
options.compression_strategy);
|
||||
}
|
||||
|
||||
GzipOutputStream::~GzipOutputStream() {
|
||||
Close();
|
||||
if (input_buffer_ != NULL) {
|
||||
operator delete(input_buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
// private
|
||||
int GzipOutputStream::Deflate(int flush) {
|
||||
int error = Z_OK;
|
||||
do {
|
||||
if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
|
||||
bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
|
||||
if (!ok) {
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
return Z_BUF_ERROR;
|
||||
}
|
||||
GOOGLE_CHECK_GT(sub_data_size_, 0);
|
||||
zcontext_.next_out = static_cast<Bytef*>(sub_data_);
|
||||
zcontext_.avail_out = sub_data_size_;
|
||||
}
|
||||
error = deflate(&zcontext_, flush);
|
||||
} while (error == Z_OK && zcontext_.avail_out == 0);
|
||||
if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
|
||||
// Notify lower layer of data.
|
||||
sub_stream_->BackUp(zcontext_.avail_out);
|
||||
// We don't own the buffer anymore.
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool GzipOutputStream::Next(void** data, int* size) {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.avail_in != 0) {
|
||||
zerror_ = Deflate(Z_NO_FLUSH);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (zcontext_.avail_in == 0) {
|
||||
// all input was consumed. reset the buffer.
|
||||
zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
|
||||
zcontext_.avail_in = input_buffer_length_;
|
||||
*data = input_buffer_;
|
||||
*size = input_buffer_length_;
|
||||
} else {
|
||||
// The loop in Deflate should consume all avail_in
|
||||
GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void GzipOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(zcontext_.avail_in, count);
|
||||
zcontext_.avail_in -= count;
|
||||
}
|
||||
int64 GzipOutputStream::ByteCount() const {
|
||||
return zcontext_.total_in + zcontext_.avail_in;
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Flush() {
|
||||
do {
|
||||
zerror_ = Deflate(Z_FULL_FLUSH);
|
||||
} while (zerror_ == Z_OK);
|
||||
return zerror_ == Z_OK;
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Close() {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
zerror_ = Deflate(Z_FINISH);
|
||||
} while (zerror_ == Z_OK);
|
||||
zerror_ = deflateEnd(&zcontext_);
|
||||
bool ok = zerror_ == Z_OK;
|
||||
zerror_ = Z_STREAM_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // HAVE_ZLIB
|
@ -0,0 +1,207 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the definition for classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
//
|
||||
// GzipInputStream decompresses data from an underlying
|
||||
// ZeroCopyInputStream and provides the decompressed data as a
|
||||
// ZeroCopyInputStream.
|
||||
//
|
||||
// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
|
||||
// an underlying ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// A ZeroCopyInputStream that reads compressed data through zlib
|
||||
class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// zlib will autodetect gzip header or deflate stream
|
||||
AUTO = 0,
|
||||
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
// buffer_size and format may be -1 for default of 64kB and GZIP format
|
||||
explicit GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream,
|
||||
Format format = AUTO,
|
||||
int buffer_size = -1);
|
||||
virtual ~GzipInputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
Format format_;
|
||||
|
||||
ZeroCopyInputStream* sub_stream_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
|
||||
void* output_buffer_;
|
||||
void* output_position_;
|
||||
size_t output_buffer_length_;
|
||||
|
||||
int Inflate(int flush);
|
||||
void DoNextOutput(const void** data, int* size);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
|
||||
};
|
||||
|
||||
|
||||
class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
// Defaults to GZIP.
|
||||
Format format;
|
||||
|
||||
// What size buffer to use internally. Defaults to 64kB.
|
||||
int buffer_size;
|
||||
|
||||
// A number between 0 and 9, where 0 is no compression and 9 is best
|
||||
// compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
|
||||
int compression_level;
|
||||
|
||||
// Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED,
|
||||
// Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in
|
||||
// zlib.h for definitions of these constants.
|
||||
int compression_strategy;
|
||||
|
||||
Options(); // Initializes with default values.
|
||||
};
|
||||
|
||||
// Create a GzipOutputStream with default options.
|
||||
explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
|
||||
|
||||
// Create a GzipOutputStream with the given options.
|
||||
GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options);
|
||||
|
||||
// DEPRECATED: Use one of the above constructors instead.
|
||||
GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream,
|
||||
Format format,
|
||||
int buffer_size = -1) GOOGLE_ATTRIBUTE_DEPRECATED;
|
||||
|
||||
virtual ~GzipOutputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// Flushes data written so far to zipped data in the underlying stream.
|
||||
// It is the caller's responsibility to flush the underlying stream if
|
||||
// necessary.
|
||||
// Compression may be less efficient stopping and starting around flushes.
|
||||
// Returns true if no error.
|
||||
bool Flush();
|
||||
|
||||
// Writes out all data and closes the gzip stream.
|
||||
// It is the caller's responsibility to close the underlying stream if
|
||||
// necessary.
|
||||
// Returns true if no error.
|
||||
bool Close();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
ZeroCopyOutputStream* sub_stream_;
|
||||
// Result from calling Next() on sub_stream_
|
||||
void* sub_data_;
|
||||
int sub_data_size_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
void* input_buffer_;
|
||||
size_t input_buffer_length_;
|
||||
|
||||
// Shared constructor code.
|
||||
void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
|
||||
|
||||
// Do some compression.
|
||||
// Takes zlib flush mode.
|
||||
// Returns zlib error code.
|
||||
int Deflate(int flush);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
@ -0,0 +1,54 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf::io namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
|
||||
// Auxiliary classes used for I/O.
|
||||
//
|
||||
// The Protocol Buffer library uses the classes in this package to deal with
|
||||
// I/O and encoding/decoding raw bytes. Most users will not need to
|
||||
// deal with this package. However, users who want to adapt the system to
|
||||
// work with their own I/O abstractions -- e.g., to allow Protocol Buffers
|
||||
// to be read from a different kind of input stream without the need for a
|
||||
// temporary buffer -- should take a closer look.
|
||||
namespace io {}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,199 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
|
||||
: variable_delimiter_(variable_delimiter),
|
||||
output_(output),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
at_start_of_line_(true),
|
||||
failed_(false) {
|
||||
}
|
||||
|
||||
Printer::~Printer() {
|
||||
// Only BackUp() if we're sure we've successfully called Next() at least once.
|
||||
if (buffer_size_ > 0) {
|
||||
output_->BackUp(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void Printer::Print(const map<string, string>& variables, const char* text) {
|
||||
int size = strlen(text);
|
||||
int pos = 0; // The number of bytes we've written so far.
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (text[i] == '\n') {
|
||||
// Saw newline. If there is more text, we may need to insert an indent
|
||||
// here. So, write what we have so far, including the '\n'.
|
||||
WriteRaw(text + pos, i - pos + 1);
|
||||
pos = i + 1;
|
||||
|
||||
// Setting this true will cause the next WriteRaw() to insert an indent
|
||||
// first.
|
||||
at_start_of_line_ = true;
|
||||
|
||||
} else if (text[i] == variable_delimiter_) {
|
||||
// Saw the start of a variable name.
|
||||
|
||||
// Write what we have so far.
|
||||
WriteRaw(text + pos, i - pos);
|
||||
pos = i + 1;
|
||||
|
||||
// Find closing delimiter.
|
||||
const char* end = strchr(text + pos, variable_delimiter_);
|
||||
if (end == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
|
||||
end = text + pos;
|
||||
}
|
||||
int endpos = end - text;
|
||||
|
||||
string varname(text + pos, endpos - pos);
|
||||
if (varname.empty()) {
|
||||
// Two delimiters in a row reduce to a literal delimiter character.
|
||||
WriteRaw(&variable_delimiter_, 1);
|
||||
} else {
|
||||
// Replace with the variable's value.
|
||||
map<string, string>::const_iterator iter = variables.find(varname);
|
||||
if (iter == variables.end()) {
|
||||
GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
|
||||
} else {
|
||||
WriteRaw(iter->second.data(), iter->second.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Advance past this variable.
|
||||
i = endpos;
|
||||
pos = endpos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the rest.
|
||||
WriteRaw(text + pos, size - pos);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text) {
|
||||
static map<string, string> empty;
|
||||
Print(empty, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable, const string& value) {
|
||||
map<string, string> vars;
|
||||
vars[variable] = value;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2) {
|
||||
map<string, string> vars;
|
||||
vars[variable1] = value1;
|
||||
vars[variable2] = value2;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2,
|
||||
const char* variable3, const string& value3) {
|
||||
map<string, string> vars;
|
||||
vars[variable1] = value1;
|
||||
vars[variable2] = value2;
|
||||
vars[variable3] = value3;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Indent() {
|
||||
indent_ += " ";
|
||||
}
|
||||
|
||||
void Printer::Outdent() {
|
||||
if (indent_.empty()) {
|
||||
GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
|
||||
return;
|
||||
}
|
||||
|
||||
indent_.resize(indent_.size() - 2);
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const string& data) {
|
||||
WriteRaw(data.data(), data.size());
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const char* data) {
|
||||
if (failed_) return;
|
||||
WriteRaw(data, strlen(data));
|
||||
}
|
||||
|
||||
void Printer::WriteRaw(const char* data, int size) {
|
||||
if (failed_) return;
|
||||
if (size == 0) return;
|
||||
|
||||
if (at_start_of_line_) {
|
||||
// Insert an indent.
|
||||
at_start_of_line_ = false;
|
||||
WriteRaw(indent_.data(), indent_.size());
|
||||
if (failed_) return;
|
||||
}
|
||||
|
||||
while (size > buffer_size_) {
|
||||
// Data exceeds space in the buffer. Copy what we can and request a
|
||||
// new buffer.
|
||||
memcpy(buffer_, data, buffer_size_);
|
||||
data += buffer_size_;
|
||||
size -= buffer_size_;
|
||||
void* void_buffer;
|
||||
failed_ = !output_->Next(&void_buffer, &buffer_size_);
|
||||
if (failed_) return;
|
||||
buffer_ = reinterpret_cast<char*>(void_buffer);
|
||||
}
|
||||
|
||||
// Buffer is big enough to receive the data; copy it.
|
||||
memcpy(buffer_, data, size);
|
||||
buffer_ += size;
|
||||
buffer_size_ -= size;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,136 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Utility class for writing text to a ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
|
||||
// This simple utility class assists in code generation. It basically
|
||||
// allows the caller to define a set of variables and then output some
|
||||
// text with variable substitutions. Example usage:
|
||||
//
|
||||
// Printer printer(output, '$');
|
||||
// map<string, string> vars;
|
||||
// vars["name"] = "Bob";
|
||||
// printer.Print(vars, "My name is $name$.");
|
||||
//
|
||||
// The above writes "My name is Bob." to the output stream.
|
||||
//
|
||||
// Printer aggressively enforces correct usage, crashing (with assert failures)
|
||||
// in the case of undefined variables in debug builds. This helps greatly in
|
||||
// debugging code which uses it.
|
||||
class LIBPROTOBUF_EXPORT Printer {
|
||||
public:
|
||||
// Create a printer that writes text to the given output stream. Use the
|
||||
// given character as the delimiter for variables.
|
||||
Printer(ZeroCopyOutputStream* output, char variable_delimiter);
|
||||
~Printer();
|
||||
|
||||
// Print some text after applying variable substitutions. If a particular
|
||||
// variable in the text is not defined, this will crash. Variables to be
|
||||
// substituted are identified by their names surrounded by delimiter
|
||||
// characters (as given to the constructor). The variable bindings are
|
||||
// defined by the given map.
|
||||
void Print(const map<string, string>& variables, const char* text);
|
||||
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable, const string& value);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2,
|
||||
const char* variable3, const string& value3);
|
||||
// TODO(kenton): Overloaded versions with more variables? Three seems
|
||||
// to be enough.
|
||||
|
||||
// Indent text by two spaces. After calling Indent(), two spaces will be
|
||||
// inserted at the beginning of each line of text. Indent() may be called
|
||||
// multiple times to produce deeper indents.
|
||||
void Indent();
|
||||
|
||||
// Reduces the current indent level by two spaces, or crashes if the indent
|
||||
// level is zero.
|
||||
void Outdent();
|
||||
|
||||
// Write a string to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const string& data);
|
||||
|
||||
// Write a zero-delimited string to output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const char* data);
|
||||
|
||||
// Write some bytes to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void WriteRaw(const char* data, int size);
|
||||
|
||||
// True if any write to the underlying stream failed. (We don't just
|
||||
// crash in this case because this is an I/O failure, not a programming
|
||||
// error.)
|
||||
bool failed() const { return failed_; }
|
||||
|
||||
private:
|
||||
const char variable_delimiter_;
|
||||
|
||||
ZeroCopyOutputStream* const output_;
|
||||
char* buffer_;
|
||||
int buffer_size_;
|
||||
|
||||
string indent_;
|
||||
bool at_start_of_line_;
|
||||
bool failed_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__
|
@ -0,0 +1,694 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Here we have a hand-written lexer. At first you might ask yourself,
|
||||
// "Hand-written text processing? Is Kenton crazy?!" Well, first of all,
|
||||
// yes I am crazy, but that's beside the point. There are actually reasons
|
||||
// why I ended up writing this this way.
|
||||
//
|
||||
// The traditional approach to lexing is to use lex to generate a lexer for
|
||||
// you. Unfortunately, lex's output is ridiculously ugly and difficult to
|
||||
// integrate cleanly with C++ code, especially abstract code or code meant
|
||||
// as a library. Better parser-generators exist but would add dependencies
|
||||
// which most users won't already have, which we'd like to avoid. (GNU flex
|
||||
// has a C++ output option, but it's still ridiculously ugly, non-abstract,
|
||||
// and not library-friendly.)
|
||||
//
|
||||
// The next approach that any good software engineer should look at is to
|
||||
// use regular expressions. And, indeed, I did. I have code which
|
||||
// implements this same class using regular expressions. It's about 200
|
||||
// lines shorter. However:
|
||||
// - Rather than error messages telling you "This string has an invalid
|
||||
// escape sequence at line 5, column 45", you get error messages like
|
||||
// "Parse error on line 5". Giving more precise errors requires adding
|
||||
// a lot of code that ends up basically as complex as the hand-coded
|
||||
// version anyway.
|
||||
// - The regular expression to match a string literal looks like this:
|
||||
// kString = new RE("(\"([^\"\\\\]|" // non-escaped
|
||||
// "\\\\[abfnrtv?\"'\\\\0-7]|" // normal escape
|
||||
// "\\\\x[0-9a-fA-F])*\"|" // hex escape
|
||||
// "\'([^\'\\\\]|" // Also support single-quotes.
|
||||
// "\\\\[abfnrtv?\"'\\\\0-7]|"
|
||||
// "\\\\x[0-9a-fA-F])*\')");
|
||||
// Verifying the correctness of this line noise is actually harder than
|
||||
// verifying the correctness of ConsumeString(), defined below. I'm not
|
||||
// even confident that the above is correct, after staring at it for some
|
||||
// time.
|
||||
// - PCRE is fast, but there's still more overhead involved than the code
|
||||
// below.
|
||||
// - Sadly, regular expressions are not part of the C standard library, so
|
||||
// using them would require depending on some other library. For the
|
||||
// open source release, this could be really annoying. Nobody likes
|
||||
// downloading one piece of software just to find that they need to
|
||||
// download something else to make it work, and in all likelihood
|
||||
// people downloading Protocol Buffers will already be doing so just
|
||||
// to make something else work. We could include a copy of PCRE with
|
||||
// our code, but that obligates us to keep it up-to-date and just seems
|
||||
// like a big waste just to save 200 lines of code.
|
||||
//
|
||||
// On a similar but unrelated note, I'm even scared to use ctype.h.
|
||||
// Apparently functions like isalpha() are locale-dependent. So, if we used
|
||||
// that, then if this code is being called from some program that doesn't
|
||||
// have its locale set to "C", it would behave strangely. We can't just set
|
||||
// the locale to "C" ourselves since we might break the calling program that
|
||||
// way, particularly if it is multi-threaded. WTF? Someone please let me
|
||||
// (Kenton) know if I'm missing something here...
|
||||
//
|
||||
// I'd love to hear about other alternatives, though, as this code isn't
|
||||
// exactly pretty.
|
||||
|
||||
#include <google/protobuf/io/tokenizer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
namespace {
|
||||
|
||||
// As mentioned above, I don't trust ctype.h due to the presence of "locales".
|
||||
// So, I have written replacement functions here. Someone please smack me if
|
||||
// this is a bad idea or if there is some way around this.
|
||||
//
|
||||
// These "character classes" are designed to be used in template methods.
|
||||
// For instance, Tokenizer::ConsumeZeroOrMore<Whitespace>() will eat
|
||||
// whitespace.
|
||||
|
||||
// Note: No class is allowed to contain '\0', since this is used to mark end-
|
||||
// of-input and is handled specially.
|
||||
|
||||
#define CHARACTER_CLASS(NAME, EXPRESSION) \
|
||||
class NAME { \
|
||||
public: \
|
||||
static inline bool InClass(char c) { \
|
||||
return EXPRESSION; \
|
||||
} \
|
||||
}
|
||||
|
||||
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' ||
|
||||
c == '\r' || c == '\v' || c == '\f');
|
||||
|
||||
CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0');
|
||||
|
||||
CHARACTER_CLASS(Digit, '0' <= c && c <= '9');
|
||||
CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7');
|
||||
CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'f') ||
|
||||
('A' <= c && c <= 'F'));
|
||||
|
||||
CHARACTER_CLASS(Letter, ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
(c == '_'));
|
||||
|
||||
CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
('0' <= c && c <= '9') ||
|
||||
(c == '_'));
|
||||
|
||||
CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' ||
|
||||
c == 'r' || c == 't' || c == 'v' || c == '\\' ||
|
||||
c == '?' || c == '\'' || c == '\"');
|
||||
|
||||
#undef CHARACTER_CLASS
|
||||
|
||||
// Given a char, interpret it as a numeric digit and return its value.
|
||||
// This supports any number base up to 36.
|
||||
inline int DigitValue(char digit) {
|
||||
if ('0' <= digit && digit <= '9') return digit - '0';
|
||||
if ('a' <= digit && digit <= 'z') return digit - 'a' + 10;
|
||||
if ('A' <= digit && digit <= 'Z') return digit - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Inline because it's only used in one place.
|
||||
inline char TranslateEscape(char c) {
|
||||
switch (c) {
|
||||
case 'a': return '\a';
|
||||
case 'b': return '\b';
|
||||
case 'f': return '\f';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 't': return '\t';
|
||||
case 'v': return '\v';
|
||||
case '\\': return '\\';
|
||||
case '?': return '\?'; // Trigraphs = :(
|
||||
case '\'': return '\'';
|
||||
case '"': return '\"';
|
||||
|
||||
// We expect escape sequences to have been validated separately.
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ErrorCollector::~ErrorCollector() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
Tokenizer::Tokenizer(ZeroCopyInputStream* input,
|
||||
ErrorCollector* error_collector)
|
||||
: input_(input),
|
||||
error_collector_(error_collector),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
buffer_pos_(0),
|
||||
read_error_(false),
|
||||
line_(0),
|
||||
column_(0),
|
||||
token_start_(-1),
|
||||
allow_f_after_float_(false),
|
||||
comment_style_(CPP_COMMENT_STYLE) {
|
||||
|
||||
current_.line = 0;
|
||||
current_.column = 0;
|
||||
current_.end_column = 0;
|
||||
current_.type = TYPE_START;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
Tokenizer::~Tokenizer() {
|
||||
// If we had any buffer left unread, return it to the underlying stream
|
||||
// so that someone else can read it.
|
||||
if (buffer_size_ > buffer_pos_) {
|
||||
input_->BackUp(buffer_size_ - buffer_pos_);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Internal helpers.
|
||||
|
||||
void Tokenizer::NextChar() {
|
||||
// Update our line and column counters based on the character being
|
||||
// consumed.
|
||||
if (current_char_ == '\n') {
|
||||
++line_;
|
||||
column_ = 0;
|
||||
} else if (current_char_ == '\t') {
|
||||
column_ += kTabWidth - column_ % kTabWidth;
|
||||
} else {
|
||||
++column_;
|
||||
}
|
||||
|
||||
// Advance to the next character.
|
||||
++buffer_pos_;
|
||||
if (buffer_pos_ < buffer_size_) {
|
||||
current_char_ = buffer_[buffer_pos_];
|
||||
} else {
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::Refresh() {
|
||||
if (read_error_) {
|
||||
current_char_ = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're in a token, append the rest of the buffer to it.
|
||||
if (token_start_ >= 0 && token_start_ < buffer_size_) {
|
||||
current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_);
|
||||
token_start_ = 0;
|
||||
}
|
||||
|
||||
const void* data = NULL;
|
||||
buffer_ = NULL;
|
||||
buffer_pos_ = 0;
|
||||
do {
|
||||
if (!input_->Next(&data, &buffer_size_)) {
|
||||
// end of stream (or read error)
|
||||
buffer_size_ = 0;
|
||||
read_error_ = true;
|
||||
current_char_ = '\0';
|
||||
return;
|
||||
}
|
||||
} while (buffer_size_ == 0);
|
||||
|
||||
buffer_ = static_cast<const char*>(data);
|
||||
|
||||
current_char_ = buffer_[0];
|
||||
}
|
||||
|
||||
inline void Tokenizer::StartToken() {
|
||||
token_start_ = buffer_pos_;
|
||||
current_.type = TYPE_START; // Just for the sake of initializing it.
|
||||
current_.text.clear();
|
||||
current_.line = line_;
|
||||
current_.column = column_;
|
||||
}
|
||||
|
||||
inline void Tokenizer::EndToken() {
|
||||
// Note: The if() is necessary because some STL implementations crash when
|
||||
// you call string::append(NULL, 0), presumably because they are trying to
|
||||
// be helpful by detecting the NULL pointer, even though there's nothing
|
||||
// wrong with reading zero bytes from NULL.
|
||||
if (buffer_pos_ != token_start_) {
|
||||
current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_);
|
||||
}
|
||||
token_start_ = -1;
|
||||
current_.end_column = column_;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Helper methods that consume characters.
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline bool Tokenizer::LookingAt() {
|
||||
return CharacterClass::InClass(current_char_);
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline bool Tokenizer::TryConsumeOne() {
|
||||
if (CharacterClass::InClass(current_char_)) {
|
||||
NextChar();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Tokenizer::TryConsume(char c) {
|
||||
if (current_char_ == c) {
|
||||
NextChar();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline void Tokenizer::ConsumeZeroOrMore() {
|
||||
while (CharacterClass::InClass(current_char_)) {
|
||||
NextChar();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline void Tokenizer::ConsumeOneOrMore(const char* error) {
|
||||
if (!CharacterClass::InClass(current_char_)) {
|
||||
AddError(error);
|
||||
} else {
|
||||
do {
|
||||
NextChar();
|
||||
} while (CharacterClass::InClass(current_char_));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Methods that read whole patterns matching certain kinds of tokens
|
||||
// or comments.
|
||||
|
||||
void Tokenizer::ConsumeString(char delimiter) {
|
||||
while (true) {
|
||||
switch (current_char_) {
|
||||
case '\0':
|
||||
case '\n': {
|
||||
AddError("String literals cannot cross line boundaries.");
|
||||
return;
|
||||
}
|
||||
|
||||
case '\\': {
|
||||
// An escape sequence.
|
||||
NextChar();
|
||||
if (TryConsumeOne<Escape>()) {
|
||||
// Valid escape sequence.
|
||||
} else if (TryConsumeOne<OctalDigit>()) {
|
||||
// Possibly followed by two more octal digits, but these will
|
||||
// just be consumed by the main loop anyway so we don't need
|
||||
// to do so explicitly here.
|
||||
} else if (TryConsume('x') || TryConsume('X')) {
|
||||
if (!TryConsumeOne<HexDigit>()) {
|
||||
AddError("Expected hex digits for escape sequence.");
|
||||
}
|
||||
// Possibly followed by another hex digit, but again we don't care.
|
||||
} else {
|
||||
AddError("Invalid escape sequence in string literal.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (current_char_ == delimiter) {
|
||||
NextChar();
|
||||
return;
|
||||
}
|
||||
NextChar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
|
||||
bool started_with_dot) {
|
||||
bool is_float = false;
|
||||
|
||||
if (started_with_zero && (TryConsume('x') || TryConsume('X'))) {
|
||||
// A hex number (started with "0x").
|
||||
ConsumeOneOrMore<HexDigit>("\"0x\" must be followed by hex digits.");
|
||||
|
||||
} else if (started_with_zero && LookingAt<Digit>()) {
|
||||
// An octal number (had a leading zero).
|
||||
ConsumeZeroOrMore<OctalDigit>();
|
||||
if (LookingAt<Digit>()) {
|
||||
AddError("Numbers starting with leading zero must be in octal.");
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
}
|
||||
|
||||
} else {
|
||||
// A decimal number.
|
||||
if (started_with_dot) {
|
||||
is_float = true;
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
} else {
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
|
||||
if (TryConsume('.')) {
|
||||
is_float = true;
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
}
|
||||
}
|
||||
|
||||
if (TryConsume('e') || TryConsume('E')) {
|
||||
is_float = true;
|
||||
TryConsume('-') || TryConsume('+');
|
||||
ConsumeOneOrMore<Digit>("\"e\" must be followed by exponent.");
|
||||
}
|
||||
|
||||
if (allow_f_after_float_ && (TryConsume('f') || TryConsume('F'))) {
|
||||
is_float = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LookingAt<Letter>()) {
|
||||
AddError("Need space between number and identifier.");
|
||||
} else if (current_char_ == '.') {
|
||||
if (is_float) {
|
||||
AddError(
|
||||
"Already saw decimal point or exponent; can't have another one.");
|
||||
} else {
|
||||
AddError("Hex and octal numbers must be integers.");
|
||||
}
|
||||
}
|
||||
|
||||
return is_float ? TYPE_FLOAT : TYPE_INTEGER;
|
||||
}
|
||||
|
||||
void Tokenizer::ConsumeLineComment() {
|
||||
while (current_char_ != '\0' && current_char_ != '\n') {
|
||||
NextChar();
|
||||
}
|
||||
TryConsume('\n');
|
||||
}
|
||||
|
||||
void Tokenizer::ConsumeBlockComment() {
|
||||
int start_line = line_;
|
||||
int start_column = column_ - 2;
|
||||
|
||||
while (true) {
|
||||
while (current_char_ != '\0' &&
|
||||
current_char_ != '*' &&
|
||||
current_char_ != '/') {
|
||||
NextChar();
|
||||
}
|
||||
|
||||
if (TryConsume('*') && TryConsume('/')) {
|
||||
// End of comment.
|
||||
break;
|
||||
} else if (TryConsume('/') && current_char_ == '*') {
|
||||
// Note: We didn't consume the '*' because if there is a '/' after it
|
||||
// we want to interpret that as the end of the comment.
|
||||
AddError(
|
||||
"\"/*\" inside block comment. Block comments cannot be nested.");
|
||||
} else if (current_char_ == '\0') {
|
||||
AddError("End-of-file inside block comment.");
|
||||
error_collector_->AddError(
|
||||
start_line, start_column, " Comment started here.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
bool Tokenizer::Next() {
|
||||
previous_ = current_;
|
||||
|
||||
// Did we skip any characters after the last token?
|
||||
bool skipped_stuff = false;
|
||||
|
||||
while (!read_error_) {
|
||||
if (TryConsumeOne<Whitespace>()) {
|
||||
ConsumeZeroOrMore<Whitespace>();
|
||||
|
||||
} else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
|
||||
// Starting a comment?
|
||||
if (TryConsume('/')) {
|
||||
ConsumeLineComment();
|
||||
} else if (TryConsume('*')) {
|
||||
ConsumeBlockComment();
|
||||
} else {
|
||||
// Oops, it was just a slash. Return it.
|
||||
current_.type = TYPE_SYMBOL;
|
||||
current_.text = "/";
|
||||
current_.line = line_;
|
||||
current_.column = column_ - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
|
||||
ConsumeLineComment();
|
||||
|
||||
} else if (LookingAt<Unprintable>() || current_char_ == '\0') {
|
||||
AddError("Invalid control characters encountered in text.");
|
||||
NextChar();
|
||||
// Skip more unprintable characters, too. But, remember that '\0' is
|
||||
// also what current_char_ is set to after EOF / read error. We have
|
||||
// to be careful not to go into an infinite loop of trying to consume
|
||||
// it, so make sure to check read_error_ explicitly before consuming
|
||||
// '\0'.
|
||||
while (TryConsumeOne<Unprintable>() ||
|
||||
(!read_error_ && TryConsume('\0'))) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
} else {
|
||||
// Reading some sort of token.
|
||||
StartToken();
|
||||
|
||||
if (TryConsumeOne<Letter>()) {
|
||||
ConsumeZeroOrMore<Alphanumeric>();
|
||||
current_.type = TYPE_IDENTIFIER;
|
||||
} else if (TryConsume('0')) {
|
||||
current_.type = ConsumeNumber(true, false);
|
||||
} else if (TryConsume('.')) {
|
||||
// This could be the beginning of a floating-point number, or it could
|
||||
// just be a '.' symbol.
|
||||
|
||||
if (TryConsumeOne<Digit>()) {
|
||||
// It's a floating-point number.
|
||||
if (previous_.type == TYPE_IDENTIFIER && !skipped_stuff) {
|
||||
// We don't accept syntax like "blah.123".
|
||||
error_collector_->AddError(line_, column_ - 2,
|
||||
"Need space between identifier and decimal point.");
|
||||
}
|
||||
current_.type = ConsumeNumber(false, true);
|
||||
} else {
|
||||
current_.type = TYPE_SYMBOL;
|
||||
}
|
||||
} else if (TryConsumeOne<Digit>()) {
|
||||
current_.type = ConsumeNumber(false, false);
|
||||
} else if (TryConsume('\"')) {
|
||||
ConsumeString('\"');
|
||||
current_.type = TYPE_STRING;
|
||||
} else if (TryConsume('\'')) {
|
||||
ConsumeString('\'');
|
||||
current_.type = TYPE_STRING;
|
||||
} else {
|
||||
NextChar();
|
||||
current_.type = TYPE_SYMBOL;
|
||||
}
|
||||
|
||||
EndToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
skipped_stuff = true;
|
||||
}
|
||||
|
||||
// EOF
|
||||
current_.type = TYPE_END;
|
||||
current_.text.clear();
|
||||
current_.line = line_;
|
||||
current_.column = column_;
|
||||
current_.end_column = column_;
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Token-parsing helpers. Remember that these don't need to report
|
||||
// errors since any errors should already have been reported while
|
||||
// tokenizing. Also, these can assume that whatever text they
|
||||
// are given is text that the tokenizer actually parsed as a token
|
||||
// of the given type.
|
||||
|
||||
bool Tokenizer::ParseInteger(const string& text, uint64 max_value,
|
||||
uint64* output) {
|
||||
// Sadly, we can't just use strtoul() since it is only 32-bit and strtoull()
|
||||
// is non-standard. I hate the C standard library. :(
|
||||
|
||||
// return strtoull(text.c_str(), NULL, 0);
|
||||
|
||||
const char* ptr = text.c_str();
|
||||
int base = 10;
|
||||
if (ptr[0] == '0') {
|
||||
if (ptr[1] == 'x' || ptr[1] == 'X') {
|
||||
// This is hex.
|
||||
base = 16;
|
||||
ptr += 2;
|
||||
} else {
|
||||
// This is octal.
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 result = 0;
|
||||
for (; *ptr != '\0'; ptr++) {
|
||||
int digit = DigitValue(*ptr);
|
||||
GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base)
|
||||
<< " Tokenizer::ParseInteger() passed text that could not have been"
|
||||
" tokenized as an integer: " << CEscape(text);
|
||||
if (digit > max_value || result > (max_value - digit) / base) {
|
||||
// Overflow.
|
||||
return false;
|
||||
}
|
||||
result = result * base + digit;
|
||||
}
|
||||
|
||||
*output = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
double Tokenizer::ParseFloat(const string& text) {
|
||||
const char* start = text.c_str();
|
||||
char* end;
|
||||
double result = NoLocaleStrtod(start, &end);
|
||||
|
||||
// "1e" is not a valid float, but if the tokenizer reads it, it will
|
||||
// report an error but still return it as a valid token. We need to
|
||||
// accept anything the tokenizer could possibly return, error or not.
|
||||
if (*end == 'e' || *end == 'E') {
|
||||
++end;
|
||||
if (*end == '-' || *end == '+') ++end;
|
||||
}
|
||||
|
||||
// If the Tokenizer had allow_f_after_float_ enabled, the float may be
|
||||
// suffixed with the letter 'f'.
|
||||
if (*end == 'f' || *end == 'F') {
|
||||
++end;
|
||||
}
|
||||
|
||||
GOOGLE_LOG_IF(DFATAL, end - start != text.size() || *start == '-')
|
||||
<< " Tokenizer::ParseFloat() passed text that could not have been"
|
||||
" tokenized as a float: " << CEscape(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Tokenizer::ParseStringAppend(const string& text, string* output) {
|
||||
// Reminder: text[0] is always the quote character. (If text is
|
||||
// empty, it's invalid, so we'll just return.)
|
||||
if (text.empty()) {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< " Tokenizer::ParseStringAppend() passed text that could not"
|
||||
" have been tokenized as a string: " << CEscape(text);
|
||||
return;
|
||||
}
|
||||
|
||||
output->reserve(output->size() + text.size());
|
||||
|
||||
// Loop through the string copying characters to "output" and
|
||||
// interpreting escape sequences. Note that any invalid escape
|
||||
// sequences or other errors were already reported while tokenizing.
|
||||
// In this case we do not need to produce valid results.
|
||||
for (const char* ptr = text.c_str() + 1; *ptr != '\0'; ptr++) {
|
||||
if (*ptr == '\\' && ptr[1] != '\0') {
|
||||
// An escape sequence.
|
||||
++ptr;
|
||||
|
||||
if (OctalDigit::InClass(*ptr)) {
|
||||
// An octal escape. May one, two, or three digits.
|
||||
int code = DigitValue(*ptr);
|
||||
if (OctalDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 8 + DigitValue(*ptr);
|
||||
}
|
||||
if (OctalDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 8 + DigitValue(*ptr);
|
||||
}
|
||||
output->push_back(static_cast<char>(code));
|
||||
|
||||
} else if (*ptr == 'x') {
|
||||
// A hex escape. May zero, one, or two digits. (The zero case
|
||||
// will have been caught as an error earlier.)
|
||||
int code = 0;
|
||||
if (HexDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = DigitValue(*ptr);
|
||||
}
|
||||
if (HexDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 16 + DigitValue(*ptr);
|
||||
}
|
||||
output->push_back(static_cast<char>(code));
|
||||
|
||||
} else {
|
||||
// Some other escape code.
|
||||
output->push_back(TranslateEscape(*ptr));
|
||||
}
|
||||
|
||||
} else if (*ptr == text[0]) {
|
||||
// Ignore quote matching the starting quote.
|
||||
} else {
|
||||
output->push_back(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,313 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Class for parsing tokenized text from a ZeroCopyInputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
|
||||
// Defined in this file.
|
||||
class ErrorCollector;
|
||||
class Tokenizer;
|
||||
|
||||
// Abstract interface for an object which collects the errors that occur
|
||||
// during parsing. A typical implementation might simply print the errors
|
||||
// to stdout.
|
||||
class LIBPROTOBUF_EXPORT ErrorCollector {
|
||||
public:
|
||||
inline ErrorCollector() {}
|
||||
virtual ~ErrorCollector();
|
||||
|
||||
// Indicates that there was an error in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddError(int line, int column, const string& message) = 0;
|
||||
|
||||
// Indicates that there was a warning in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddWarning(int line, int column, const string& message) { }
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
|
||||
};
|
||||
|
||||
// This class converts a stream of raw text into a stream of tokens for
|
||||
// the protocol definition parser to parse. The tokens recognized are
|
||||
// similar to those that make up the C language; see the TokenType enum for
|
||||
// precise descriptions. Whitespace and comments are skipped. By default,
|
||||
// C- and C++-style comments are recognized, but other styles can be used by
|
||||
// calling set_comment_style().
|
||||
class LIBPROTOBUF_EXPORT Tokenizer {
|
||||
public:
|
||||
// Construct a Tokenizer that reads and tokenizes text from the given
|
||||
// input stream and writes errors to the given error_collector.
|
||||
// The caller keeps ownership of input and error_collector.
|
||||
Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
|
||||
~Tokenizer();
|
||||
|
||||
enum TokenType {
|
||||
TYPE_START, // Next() has not yet been called.
|
||||
TYPE_END, // End of input reached. "text" is empty.
|
||||
|
||||
TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
|
||||
// starting with a digit. It is an error for a number
|
||||
// to be followed by an identifier with no space in
|
||||
// between.
|
||||
TYPE_INTEGER, // A sequence of digits representing an integer. Normally
|
||||
// the digits are decimal, but a prefix of "0x" indicates
|
||||
// a hex number and a leading zero indicates octal, just
|
||||
// like with C numeric literals. A leading negative sign
|
||||
// is NOT included in the token; it's up to the parser to
|
||||
// interpret the unary minus operator on its own.
|
||||
TYPE_FLOAT, // A floating point literal, with a fractional part and/or
|
||||
// an exponent. Always in decimal. Again, never
|
||||
// negative.
|
||||
TYPE_STRING, // A quoted sequence of escaped characters. Either single
|
||||
// or double quotes can be used, but they must match.
|
||||
// A string literal cannot cross a line break.
|
||||
TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
|
||||
// Symbols are always a single character, so "!+$%" is
|
||||
// four tokens.
|
||||
};
|
||||
|
||||
// Structure representing a token read from the token stream.
|
||||
struct Token {
|
||||
TokenType type;
|
||||
string text; // The exact text of the token as it appeared in
|
||||
// the input. e.g. tokens of TYPE_STRING will still
|
||||
// be escaped and in quotes.
|
||||
|
||||
// "line" and "column" specify the position of the first character of
|
||||
// the token within the input stream. They are zero-based.
|
||||
int line;
|
||||
int column;
|
||||
int end_column;
|
||||
};
|
||||
|
||||
// Get the current token. This is updated when Next() is called. Before
|
||||
// the first call to Next(), current() has type TYPE_START and no contents.
|
||||
const Token& current();
|
||||
|
||||
// Return the previous token -- i.e. what current() returned before the
|
||||
// previous call to Next().
|
||||
const Token& previous();
|
||||
|
||||
// Advance to the next token. Returns false if the end of the input is
|
||||
// reached.
|
||||
bool Next();
|
||||
|
||||
// Parse helpers ---------------------------------------------------
|
||||
|
||||
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static double ParseFloat(const string& text);
|
||||
|
||||
// Parses a TYPE_STRING token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static void ParseString(const string& text, string* output);
|
||||
|
||||
// Identical to ParseString, but appends to output.
|
||||
static void ParseStringAppend(const string& text, string* output);
|
||||
|
||||
// Parses a TYPE_INTEGER token. Returns false if the result would be
|
||||
// greater than max_value. Otherwise, returns true and sets *output to the
|
||||
// result. If the text is not from a Token of type TYPE_INTEGER originally
|
||||
// parsed by a Tokenizer, the result is undefined (possibly an assert
|
||||
// failure).
|
||||
static bool ParseInteger(const string& text, uint64 max_value,
|
||||
uint64* output);
|
||||
|
||||
// Options ---------------------------------------------------------
|
||||
|
||||
// Set true to allow floats to be suffixed with the letter 'f'. Tokens
|
||||
// which would otherwise be integers but which have the 'f' suffix will be
|
||||
// forced to be interpreted as floats. For all other purposes, the 'f' is
|
||||
// ignored.
|
||||
void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
|
||||
|
||||
// Valid values for set_comment_style().
|
||||
enum CommentStyle {
|
||||
// Line comments begin with "//", block comments are delimited by "/*" and
|
||||
// "*/".
|
||||
CPP_COMMENT_STYLE,
|
||||
// Line comments begin with "#". No way to write block comments.
|
||||
SH_COMMENT_STYLE
|
||||
};
|
||||
|
||||
// Sets the comment style.
|
||||
void set_comment_style(CommentStyle style) { comment_style_ = style; }
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
|
||||
|
||||
Token current_; // Returned by current().
|
||||
Token previous_; // Returned by previous().
|
||||
|
||||
ZeroCopyInputStream* input_;
|
||||
ErrorCollector* error_collector_;
|
||||
|
||||
char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
|
||||
const char* buffer_; // Current buffer returned from input_.
|
||||
int buffer_size_; // Size of buffer_.
|
||||
int buffer_pos_; // Current position within the buffer.
|
||||
bool read_error_; // Did we previously encounter a read error?
|
||||
|
||||
// Line and column number of current_char_ within the whole input stream.
|
||||
int line_;
|
||||
int column_;
|
||||
|
||||
// Position in buffer_ where StartToken() was called. If the token
|
||||
// started in the previous buffer, this is zero, and current_.text already
|
||||
// contains the part of the token from the previous buffer. If not
|
||||
// currently parsing a token, this is -1.
|
||||
int token_start_;
|
||||
|
||||
// Options.
|
||||
bool allow_f_after_float_;
|
||||
CommentStyle comment_style_;
|
||||
|
||||
// Since we count columns we need to interpret tabs somehow. We'll take
|
||||
// the standard 8-character definition for lack of any way to do better.
|
||||
static const int kTabWidth = 8;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Helper methods.
|
||||
|
||||
// Consume this character and advance to the next one.
|
||||
void NextChar();
|
||||
|
||||
// Read a new buffer from the input.
|
||||
void Refresh();
|
||||
|
||||
// Called when the current character is the first character of a new
|
||||
// token (not including whitespace or comments).
|
||||
inline void StartToken();
|
||||
// Called when the current character is the first character after the
|
||||
// end of the last token. After this returns, current_.text will
|
||||
// contain all text consumed since StartToken() was called.
|
||||
inline void EndToken();
|
||||
|
||||
// Convenience method to add an error at the current line and column.
|
||||
void AddError(const string& message) {
|
||||
error_collector_->AddError(line_, column_, message);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The following four methods are used to consume tokens of specific
|
||||
// types. They are actually used to consume all characters *after*
|
||||
// the first, since the calling function consumes the first character
|
||||
// in order to decide what kind of token is being read.
|
||||
|
||||
// Read and consume a string, ending when the given delimiter is
|
||||
// consumed.
|
||||
void ConsumeString(char delimiter);
|
||||
|
||||
// Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
|
||||
// depending on what was read. This needs to know if the first
|
||||
// character was a zero in order to correctly recognize hex and octal
|
||||
// numbers.
|
||||
// It also needs to know if the first characted was a . to parse floating
|
||||
// point correctly.
|
||||
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
|
||||
|
||||
// Consume the rest of a line.
|
||||
void ConsumeLineComment();
|
||||
// Consume until "*/".
|
||||
void ConsumeBlockComment();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These helper methods make the parsing code more readable. The
|
||||
// "character classes" refered to are defined at the top of the .cc file.
|
||||
// Basically it is a C++ class with one method:
|
||||
// static bool InClass(char c);
|
||||
// The method returns true if c is a member of this "class", like "Letter"
|
||||
// or "Digit".
|
||||
|
||||
// Returns true if the current character is of the given character
|
||||
// class, but does not consume anything.
|
||||
template<typename CharacterClass>
|
||||
inline bool LookingAt();
|
||||
|
||||
// If the current character is in the given class, consume it and return
|
||||
// true. Otherwise return false.
|
||||
// e.g. TryConsumeOne<Letter>()
|
||||
template<typename CharacterClass>
|
||||
inline bool TryConsumeOne();
|
||||
|
||||
// Like above, but try to consume the specific character indicated.
|
||||
inline bool TryConsume(char c);
|
||||
|
||||
// Consume zero or more of the given character class.
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeZeroOrMore();
|
||||
|
||||
// Consume one or more of the given character class or log the given
|
||||
// error message.
|
||||
// e.g. ConsumeOneOrMore<Digit>("Expected digits.");
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeOneOrMore(const char* error);
|
||||
};
|
||||
|
||||
// inline methods ====================================================
|
||||
inline const Tokenizer::Token& Tokenizer::current() {
|
||||
return current_;
|
||||
}
|
||||
|
||||
inline const Tokenizer::Token& Tokenizer::previous() {
|
||||
return previous_;
|
||||
}
|
||||
|
||||
inline void Tokenizer::ParseString(const string& text, string* output) {
|
||||
output->clear();
|
||||
ParseStringAppend(text, output);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
@ -0,0 +1,48 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
ZeroCopyInputStream::~ZeroCopyInputStream() {}
|
||||
ZeroCopyOutputStream::~ZeroCopyOutputStream() {}
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,238 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains the ZeroCopyInputStream and ZeroCopyOutputStream
|
||||
// interfaces, which represent abstract I/O streams to and from which
|
||||
// protocol buffers can be read and written. For a few simple
|
||||
// implementations of these interfaces, see zero_copy_stream_impl.h.
|
||||
//
|
||||
// These interfaces are different from classic I/O streams in that they
|
||||
// try to minimize the amount of data copying that needs to be done.
|
||||
// To accomplish this, responsibility for allocating buffers is moved to
|
||||
// the stream object, rather than being the responsibility of the caller.
|
||||
// So, the stream can return a buffer which actually points directly into
|
||||
// the final data structure where the bytes are to be stored, and the caller
|
||||
// can interact directly with that buffer, eliminating an intermediate copy
|
||||
// operation.
|
||||
//
|
||||
// As an example, consider the common case in which you are reading bytes
|
||||
// from an array that is already in memory (or perhaps an mmap()ed file).
|
||||
// With classic I/O streams, you would do something like:
|
||||
// char buffer[BUFFER_SIZE];
|
||||
// input->Read(buffer, BUFFER_SIZE);
|
||||
// DoSomething(buffer, BUFFER_SIZE);
|
||||
// Then, the stream basically just calls memcpy() to copy the data from
|
||||
// the array into your buffer. With a ZeroCopyInputStream, you would do
|
||||
// this instead:
|
||||
// const void* buffer;
|
||||
// int size;
|
||||
// input->Next(&buffer, &size);
|
||||
// DoSomething(buffer, size);
|
||||
// Here, no copy is performed. The input stream returns a pointer directly
|
||||
// into the backing array, and the caller ends up reading directly from it.
|
||||
//
|
||||
// If you want to be able to read the old-fashion way, you can create
|
||||
// a CodedInputStream or CodedOutputStream wrapping these objects and use
|
||||
// their ReadRaw()/WriteRaw() methods. These will, of course, add a copy
|
||||
// step, but Coded*Stream will handle buffering so at least it will be
|
||||
// reasonably efficient.
|
||||
//
|
||||
// ZeroCopyInputStream example:
|
||||
// // Read in a file and print its contents to stdout.
|
||||
// int fd = open("myfile", O_RDONLY);
|
||||
// ZeroCopyInputStream* input = new FileInputStream(fd);
|
||||
//
|
||||
// const void* buffer;
|
||||
// int size;
|
||||
// while (input->Next(&buffer, &size)) {
|
||||
// cout.write(buffer, size);
|
||||
// }
|
||||
//
|
||||
// delete input;
|
||||
// close(fd);
|
||||
//
|
||||
// ZeroCopyOutputStream example:
|
||||
// // Copy the contents of "infile" to "outfile", using plain read() for
|
||||
// // "infile" but a ZeroCopyOutputStream for "outfile".
|
||||
// int infd = open("infile", O_RDONLY);
|
||||
// int outfd = open("outfile", O_WRONLY);
|
||||
// ZeroCopyOutputStream* output = new FileOutputStream(outfd);
|
||||
//
|
||||
// void* buffer;
|
||||
// int size;
|
||||
// while (output->Next(&buffer, &size)) {
|
||||
// int bytes = read(infd, buffer, size);
|
||||
// if (bytes < size) {
|
||||
// // Reached EOF.
|
||||
// output->BackUp(size - bytes);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// delete output;
|
||||
// close(infd);
|
||||
// close(outfd);
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// Defined in this file.
|
||||
class ZeroCopyInputStream;
|
||||
class ZeroCopyOutputStream;
|
||||
|
||||
// Abstract interface similar to an input stream but designed to minimize
|
||||
// copying.
|
||||
class LIBPROTOBUF_EXPORT ZeroCopyInputStream {
|
||||
public:
|
||||
inline ZeroCopyInputStream() {}
|
||||
virtual ~ZeroCopyInputStream();
|
||||
|
||||
// Obtains a chunk of data from the stream.
|
||||
//
|
||||
// Preconditions:
|
||||
// * "size" and "data" are not NULL.
|
||||
//
|
||||
// Postconditions:
|
||||
// * If the returned value is false, there is no more data to return or
|
||||
// an error occurred. All errors are permanent.
|
||||
// * Otherwise, "size" points to the actual number of bytes read and "data"
|
||||
// points to a pointer to a buffer containing these bytes.
|
||||
// * Ownership of this buffer remains with the stream, and the buffer
|
||||
// remains valid only until some other method of the stream is called
|
||||
// or the stream is destroyed.
|
||||
// * It is legal for the returned buffer to have zero size, as long
|
||||
// as repeatedly calling Next() eventually yields a buffer with non-zero
|
||||
// size.
|
||||
virtual bool Next(const void** data, int* size) = 0;
|
||||
|
||||
// Backs up a number of bytes, so that the next call to Next() returns
|
||||
// data again that was already returned by the last call to Next(). This
|
||||
// is useful when writing procedures that are only supposed to read up
|
||||
// to a certain point in the input, then return. If Next() returns a
|
||||
// buffer that goes beyond what you wanted to read, you can use BackUp()
|
||||
// to return to the point where you intended to finish.
|
||||
//
|
||||
// Preconditions:
|
||||
// * The last method called must have been Next().
|
||||
// * count must be less than or equal to the size of the last buffer
|
||||
// returned by Next().
|
||||
//
|
||||
// Postconditions:
|
||||
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||
// pushed back into the stream. Subsequent calls to Next() will return
|
||||
// the same data again before producing new data.
|
||||
virtual void BackUp(int count) = 0;
|
||||
|
||||
// Skips a number of bytes. Returns false if the end of the stream is
|
||||
// reached or some input error occurred. In the end-of-stream case, the
|
||||
// stream is advanced to the end of the stream (so ByteCount() will return
|
||||
// the total size of the stream).
|
||||
virtual bool Skip(int count) = 0;
|
||||
|
||||
// Returns the total number of bytes read since this object was created.
|
||||
virtual int64 ByteCount() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
|
||||
};
|
||||
|
||||
// Abstract interface similar to an output stream but designed to minimize
|
||||
// copying.
|
||||
class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
|
||||
public:
|
||||
inline ZeroCopyOutputStream() {}
|
||||
virtual ~ZeroCopyOutputStream();
|
||||
|
||||
// Obtains a buffer into which data can be written. Any data written
|
||||
// into this buffer will eventually (maybe instantly, maybe later on)
|
||||
// be written to the output.
|
||||
//
|
||||
// Preconditions:
|
||||
// * "size" and "data" are not NULL.
|
||||
//
|
||||
// Postconditions:
|
||||
// * If the returned value is false, an error occurred. All errors are
|
||||
// permanent.
|
||||
// * Otherwise, "size" points to the actual number of bytes in the buffer
|
||||
// and "data" points to the buffer.
|
||||
// * Ownership of this buffer remains with the stream, and the buffer
|
||||
// remains valid only until some other method of the stream is called
|
||||
// or the stream is destroyed.
|
||||
// * Any data which the caller stores in this buffer will eventually be
|
||||
// written to the output (unless BackUp() is called).
|
||||
// * It is legal for the returned buffer to have zero size, as long
|
||||
// as repeatedly calling Next() eventually yields a buffer with non-zero
|
||||
// size.
|
||||
virtual bool Next(void** data, int* size) = 0;
|
||||
|
||||
// Backs up a number of bytes, so that the end of the last buffer returned
|
||||
// by Next() is not actually written. This is needed when you finish
|
||||
// writing all the data you want to write, but the last buffer was bigger
|
||||
// than you needed. You don't want to write a bunch of garbage after the
|
||||
// end of your data, so you use BackUp() to back up.
|
||||
//
|
||||
// Preconditions:
|
||||
// * The last method called must have been Next().
|
||||
// * count must be less than or equal to the size of the last buffer
|
||||
// returned by Next().
|
||||
// * The caller must not have written anything to the last "count" bytes
|
||||
// of that buffer.
|
||||
//
|
||||
// Postconditions:
|
||||
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||
// ignored.
|
||||
virtual void BackUp(int count) = 0;
|
||||
|
||||
// Returns the total number of bytes written since this object was created.
|
||||
virtual int64 ByteCount() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
@ -0,0 +1,470 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Win32 lseek is broken: If invoked on a non-seekable file descriptor, its
|
||||
// return value is undefined. We re-define it to always produce an error.
|
||||
#define lseek(fd, offset, origin) ((off_t)-1)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// EINTR sucks.
|
||||
int close_no_eintr(int fd) {
|
||||
int result;
|
||||
do {
|
||||
result = close(fd);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileInputStream::FileInputStream(int file_descriptor, int block_size)
|
||||
: copying_input_(file_descriptor),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream() {}
|
||||
|
||||
bool FileInputStream::Close() {
|
||||
return copying_input_.Close();
|
||||
}
|
||||
|
||||
bool FileInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool FileInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 FileInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0),
|
||||
previous_seek_failed_(false) {
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileInputStream::CopyingFileInputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
int result;
|
||||
do {
|
||||
result = read(file_, buffer, size);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result < 0) {
|
||||
// Read error (not EOF).
|
||||
errno_ = errno;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Skip(int count) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
if (!previous_seek_failed_ &&
|
||||
lseek(file_, count, SEEK_CUR) != (off_t)-1) {
|
||||
// Seek succeeded.
|
||||
return count;
|
||||
} else {
|
||||
// Failed to seek.
|
||||
|
||||
// Note to self: Don't seek again. This file descriptor doesn't
|
||||
// support it.
|
||||
previous_seek_failed_ = true;
|
||||
|
||||
// Use the default implementation.
|
||||
return CopyingInputStream::Skip(count);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
|
||||
: copying_output_(file_descriptor),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
FileOutputStream::~FileOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Close() {
|
||||
bool flush_succeeded = impl_.Flush();
|
||||
return copying_output_.Close() && flush_succeeded;
|
||||
}
|
||||
|
||||
bool FileOutputStream::Flush() {
|
||||
return impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 FileOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0) {
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
int total_written = 0;
|
||||
|
||||
const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
|
||||
|
||||
while (total_written < size) {
|
||||
int bytes;
|
||||
do {
|
||||
bytes = write(file_, buffer_base + total_written, size - total_written);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
|
||||
if (bytes <= 0) {
|
||||
// Write error.
|
||||
|
||||
// FIXME(kenton): According to the man page, if write() returns zero,
|
||||
// there was no error; write() simply did not write anything. It's
|
||||
// unclear under what circumstances this might happen, but presumably
|
||||
// errno won't be set in this case. I am confused as to how such an
|
||||
// event should be handled. For now I'm treating it as an error, since
|
||||
// retrying seems like it could lead to an infinite loop. I suspect
|
||||
// this never actually happens anyway.
|
||||
|
||||
if (bytes < 0) {
|
||||
errno_ = errno;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
total_written += bytes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
IstreamInputStream::IstreamInputStream(istream* input, int block_size)
|
||||
: copying_input_(input),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
IstreamInputStream::~IstreamInputStream() {}
|
||||
|
||||
bool IstreamInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void IstreamInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool IstreamInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 IstreamInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
|
||||
istream* input)
|
||||
: input_(input) {
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
|
||||
|
||||
int IstreamInputStream::CopyingIstreamInputStream::Read(
|
||||
void* buffer, int size) {
|
||||
input_->read(reinterpret_cast<char*>(buffer), size);
|
||||
int result = input_->gcount();
|
||||
if (result == 0 && input_->fail() && !input_->eof()) {
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
OstreamOutputStream::OstreamOutputStream(ostream* output, int block_size)
|
||||
: copying_output_(output),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::~OstreamOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void OstreamOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 OstreamOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
|
||||
ostream* output)
|
||||
: output_(output) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::CopyingOstreamOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
output_->write(reinterpret_cast<const char*>(buffer), size);
|
||||
return output_->good();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ConcatenatingInputStream::ConcatenatingInputStream(
|
||||
ZeroCopyInputStream* const streams[], int count)
|
||||
: streams_(streams), stream_count_(count), bytes_retired_(0) {
|
||||
}
|
||||
|
||||
ConcatenatingInputStream::~ConcatenatingInputStream() {
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Next(const void** data, int* size) {
|
||||
while (stream_count_ > 0) {
|
||||
if (streams_[0]->Next(data, size)) return true;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += streams_[0]->ByteCount();
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
// No more streams.
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConcatenatingInputStream::BackUp(int count) {
|
||||
if (stream_count_ > 0) {
|
||||
streams_[0]->BackUp(count);
|
||||
} else {
|
||||
GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
|
||||
}
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Skip(int count) {
|
||||
while (stream_count_ > 0) {
|
||||
// Assume that ByteCount() can be used to find out how much we actually
|
||||
// skipped when Skip() fails.
|
||||
int64 target_byte_count = streams_[0]->ByteCount() + count;
|
||||
if (streams_[0]->Skip(count)) return true;
|
||||
|
||||
// Hit the end of the stream. Figure out how many more bytes we still have
|
||||
// to skip.
|
||||
int64 final_byte_count = streams_[0]->ByteCount();
|
||||
GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
|
||||
count = target_byte_count - final_byte_count;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += final_byte_count;
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int64 ConcatenatingInputStream::ByteCount() const {
|
||||
if (stream_count_ == 0) {
|
||||
return bytes_retired_;
|
||||
} else {
|
||||
return bytes_retired_ + streams_[0]->ByteCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
|
||||
int64 limit)
|
||||
: input_(input), limit_(limit) {}
|
||||
|
||||
LimitingInputStream::~LimitingInputStream() {
|
||||
// If we overshot the limit, back up.
|
||||
if (limit_ < 0) input_->BackUp(-limit_);
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Next(const void** data, int* size) {
|
||||
if (limit_ <= 0) return false;
|
||||
if (!input_->Next(data, size)) return false;
|
||||
|
||||
limit_ -= *size;
|
||||
if (limit_ < 0) {
|
||||
// We overshot the limit. Reduce *size to hide the rest of the buffer.
|
||||
*size += limit_;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LimitingInputStream::BackUp(int count) {
|
||||
if (limit_ < 0) {
|
||||
input_->BackUp(count - limit_);
|
||||
limit_ = count;
|
||||
} else {
|
||||
input_->BackUp(count);
|
||||
limit_ += count;
|
||||
}
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Skip(int count) {
|
||||
if (count > limit_) {
|
||||
if (limit_ < 0) return false;
|
||||
input_->Skip(limit_);
|
||||
limit_ = 0;
|
||||
return false;
|
||||
} else {
|
||||
if (!input_->Skip(count)) return false;
|
||||
limit_ -= count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64 LimitingInputStream::ByteCount() const {
|
||||
if (limit_ < 0) {
|
||||
return input_->ByteCount() + limit_;
|
||||
} else {
|
||||
return input_->ByteCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,357 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains common implementations of the interfaces defined in
|
||||
// zero_copy_stream.h which are only included in the full (non-lite)
|
||||
// protobuf library. These implementations include Unix file descriptors
|
||||
// and C++ iostreams. See also: zero_copy_stream_impl_lite.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from a file descriptor.
|
||||
//
|
||||
// FileInputStream is preferred over using an ifstream with IstreamInputStream.
|
||||
// The latter will introduce an extra layer of buffering, harming performance.
|
||||
// Also, it's conceivable that FileInputStream could someday be enhanced
|
||||
// to use zero-copy file descriptors on OSs which support them.
|
||||
class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used.
|
||||
explicit FileInputStream(int file_descriptor, int block_size = -1);
|
||||
~FileInputStream();
|
||||
|
||||
// Flushes any buffers and closes the underlying file. Returns false if
|
||||
// an error occurs during the process; use GetErrno() to examine the error.
|
||||
// Even if an error occurs, the file descriptor is closed when this returns.
|
||||
bool Close();
|
||||
|
||||
// By default, the file descriptor is not closed when the stream is
|
||||
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
|
||||
// This leaves no way for the caller to detect if close() fails. If
|
||||
// detecting close() errors is important to you, you should arrange
|
||||
// to close the descriptor yourself.
|
||||
void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); }
|
||||
|
||||
// If an I/O error has occurred on this file descriptor, this is the
|
||||
// errno from that error. Otherwise, this is zero. Once an error
|
||||
// occurs, the stream is broken and all subsequent operations will
|
||||
// fail.
|
||||
int GetErrno() { return copying_input_.GetErrno(); }
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
|
||||
public:
|
||||
CopyingFileInputStream(int file_descriptor);
|
||||
~CopyingFileInputStream();
|
||||
|
||||
bool Close();
|
||||
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
|
||||
int GetErrno() { return errno_; }
|
||||
|
||||
// implements CopyingInputStream ---------------------------------
|
||||
int Read(void* buffer, int size);
|
||||
int Skip(int count);
|
||||
|
||||
private:
|
||||
// The file descriptor.
|
||||
const int file_;
|
||||
bool close_on_delete_;
|
||||
bool is_closed_;
|
||||
|
||||
// The errno of the I/O error, if one has occurred. Otherwise, zero.
|
||||
int errno_;
|
||||
|
||||
// Did we try to seek once and fail? If so, we assume this file descriptor
|
||||
// doesn't support seeking and won't try again.
|
||||
bool previous_seek_failed_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream);
|
||||
};
|
||||
|
||||
CopyingFileInputStream copying_input_;
|
||||
CopyingInputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a file descriptor.
|
||||
//
|
||||
// FileOutputStream is preferred over using an ofstream with
|
||||
// OstreamOutputStream. The latter will introduce an extra layer of buffering,
|
||||
// harming performance. Also, it's conceivable that FileOutputStream could
|
||||
// someday be enhanced to use zero-copy file descriptors on OSs which
|
||||
// support them.
|
||||
class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit FileOutputStream(int file_descriptor, int block_size = -1);
|
||||
~FileOutputStream();
|
||||
|
||||
// Flushes any buffers and closes the underlying file. Returns false if
|
||||
// an error occurs during the process; use GetErrno() to examine the error.
|
||||
// Even if an error occurs, the file descriptor is closed when this returns.
|
||||
bool Close();
|
||||
|
||||
// Flushes FileOutputStream's buffers but does not close the
|
||||
// underlying file. No special measures are taken to ensure that
|
||||
// underlying operating system file object is synchronized to disk.
|
||||
bool Flush();
|
||||
|
||||
// By default, the file descriptor is not closed when the stream is
|
||||
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
|
||||
// This leaves no way for the caller to detect if close() fails. If
|
||||
// detecting close() errors is important to you, you should arrange
|
||||
// to close the descriptor yourself.
|
||||
void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); }
|
||||
|
||||
// If an I/O error has occurred on this file descriptor, this is the
|
||||
// errno from that error. Otherwise, this is zero. Once an error
|
||||
// occurs, the stream is broken and all subsequent operations will
|
||||
// fail.
|
||||
int GetErrno() { return copying_output_.GetErrno(); }
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
|
||||
public:
|
||||
CopyingFileOutputStream(int file_descriptor);
|
||||
~CopyingFileOutputStream();
|
||||
|
||||
bool Close();
|
||||
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
|
||||
int GetErrno() { return errno_; }
|
||||
|
||||
// implements CopyingOutputStream --------------------------------
|
||||
bool Write(const void* buffer, int size);
|
||||
|
||||
private:
|
||||
// The file descriptor.
|
||||
const int file_;
|
||||
bool close_on_delete_;
|
||||
bool is_closed_;
|
||||
|
||||
// The errno of the I/O error, if one has occurred. Otherwise, zero.
|
||||
int errno_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream);
|
||||
};
|
||||
|
||||
CopyingFileOutputStream copying_output_;
|
||||
CopyingOutputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from a C++ istream.
|
||||
//
|
||||
// Note that for reading files (or anything represented by a file descriptor),
|
||||
// FileInputStream is more efficient.
|
||||
class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given C++ istream.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used.
|
||||
explicit IstreamInputStream(istream* stream, int block_size = -1);
|
||||
~IstreamInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
|
||||
public:
|
||||
CopyingIstreamInputStream(istream* input);
|
||||
~CopyingIstreamInputStream();
|
||||
|
||||
// implements CopyingInputStream ---------------------------------
|
||||
int Read(void* buffer, int size);
|
||||
// (We use the default implementation of Skip().)
|
||||
|
||||
private:
|
||||
// The stream.
|
||||
istream* input_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream);
|
||||
};
|
||||
|
||||
CopyingIstreamInputStream copying_input_;
|
||||
CopyingInputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a C++ ostream.
|
||||
//
|
||||
// Note that for writing files (or anything represented by a file descriptor),
|
||||
// FileOutputStream is more efficient.
|
||||
class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given C++ ostream.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit OstreamOutputStream(ostream* stream, int block_size = -1);
|
||||
~OstreamOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream {
|
||||
public:
|
||||
CopyingOstreamOutputStream(ostream* output);
|
||||
~CopyingOstreamOutputStream();
|
||||
|
||||
// implements CopyingOutputStream --------------------------------
|
||||
bool Write(const void* buffer, int size);
|
||||
|
||||
private:
|
||||
// The stream.
|
||||
ostream* output_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream);
|
||||
};
|
||||
|
||||
CopyingOstreamOutputStream copying_output_;
|
||||
CopyingOutputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from several other streams in sequence.
|
||||
// ConcatenatingInputStream is unable to distinguish between end-of-stream
|
||||
// and read errors in the underlying streams, so it assumes any errors mean
|
||||
// end-of-stream. So, if the underlying streams fail for any other reason,
|
||||
// ConcatenatingInputStream may do odd things. It is suggested that you do
|
||||
// not use ConcatenatingInputStream on streams that might produce read errors
|
||||
// other than end-of-stream.
|
||||
class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// All streams passed in as well as the array itself must remain valid
|
||||
// until the ConcatenatingInputStream is destroyed.
|
||||
ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
|
||||
~ConcatenatingInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
// As streams are retired, streams_ is incremented and count_ is
|
||||
// decremented.
|
||||
ZeroCopyInputStream* const* streams_;
|
||||
int stream_count_;
|
||||
int64 bytes_retired_; // Bytes read from previous streams.
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which wraps some other stream and limits it to
|
||||
// a particular byte count.
|
||||
class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
|
||||
~LimitingInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
ZeroCopyInputStream* input_;
|
||||
int64 limit_; // Decreases as we go, becomes negative if we overshoot.
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
@ -0,0 +1,393 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
namespace {
|
||||
|
||||
// Default block size for Copying{In,Out}putStreamAdaptor.
|
||||
static const int kDefaultBlockSize = 8192;
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ArrayInputStream::ArrayInputStream(const void* data, int size,
|
||||
int block_size)
|
||||
: data_(reinterpret_cast<const uint8*>(data)),
|
||||
size_(size),
|
||||
block_size_(block_size > 0 ? block_size : size),
|
||||
position_(0),
|
||||
last_returned_size_(0) {
|
||||
}
|
||||
|
||||
ArrayInputStream::~ArrayInputStream() {
|
||||
}
|
||||
|
||||
bool ArrayInputStream::Next(const void** data, int* size) {
|
||||
if (position_ < size_) {
|
||||
last_returned_size_ = min(block_size_, size_ - position_);
|
||||
*data = data_ + position_;
|
||||
*size = last_returned_size_;
|
||||
position_ += last_returned_size_;
|
||||
return true;
|
||||
} else {
|
||||
// We're at the end of the array.
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayInputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GT(last_returned_size_, 0)
|
||||
<< "BackUp() can only be called after a successful Next().";
|
||||
GOOGLE_CHECK_LE(count, last_returned_size_);
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
position_ -= count;
|
||||
last_returned_size_ = 0; // Don't let caller back up further.
|
||||
}
|
||||
|
||||
bool ArrayInputStream::Skip(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
if (count > size_ - position_) {
|
||||
position_ = size_;
|
||||
return false;
|
||||
} else {
|
||||
position_ += count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64 ArrayInputStream::ByteCount() const {
|
||||
return position_;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
|
||||
: data_(reinterpret_cast<uint8*>(data)),
|
||||
size_(size),
|
||||
block_size_(block_size > 0 ? block_size : size),
|
||||
position_(0),
|
||||
last_returned_size_(0) {
|
||||
}
|
||||
|
||||
ArrayOutputStream::~ArrayOutputStream() {
|
||||
}
|
||||
|
||||
bool ArrayOutputStream::Next(void** data, int* size) {
|
||||
if (position_ < size_) {
|
||||
last_returned_size_ = min(block_size_, size_ - position_);
|
||||
*data = data_ + position_;
|
||||
*size = last_returned_size_;
|
||||
position_ += last_returned_size_;
|
||||
return true;
|
||||
} else {
|
||||
// We're at the end of the array.
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GT(last_returned_size_, 0)
|
||||
<< "BackUp() can only be called after a successful Next().";
|
||||
GOOGLE_CHECK_LE(count, last_returned_size_);
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
position_ -= count;
|
||||
last_returned_size_ = 0; // Don't let caller back up further.
|
||||
}
|
||||
|
||||
int64 ArrayOutputStream::ByteCount() const {
|
||||
return position_;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringOutputStream::StringOutputStream(string* target)
|
||||
: target_(target) {
|
||||
}
|
||||
|
||||
StringOutputStream::~StringOutputStream() {
|
||||
}
|
||||
|
||||
bool StringOutputStream::Next(void** data, int* size) {
|
||||
int old_size = target_->size();
|
||||
|
||||
// Grow the string.
|
||||
if (old_size < target_->capacity()) {
|
||||
// Resize the string to match its capacity, since we can get away
|
||||
// without a memory allocation this way.
|
||||
STLStringResizeUninitialized(target_, target_->capacity());
|
||||
} else {
|
||||
// Size has reached capacity, so double the size. Also make sure
|
||||
// that the new size is at least kMinimumSize.
|
||||
STLStringResizeUninitialized(
|
||||
target_,
|
||||
max(old_size * 2,
|
||||
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
|
||||
}
|
||||
|
||||
*data = string_as_array(target_) + old_size;
|
||||
*size = target_->size() - old_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
GOOGLE_CHECK_LE(count, target_->size());
|
||||
target_->resize(target_->size() - count);
|
||||
}
|
||||
|
||||
int64 StringOutputStream::ByteCount() const {
|
||||
return target_->size();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
CopyingInputStream::~CopyingInputStream() {}
|
||||
|
||||
int CopyingInputStream::Skip(int count) {
|
||||
char junk[4096];
|
||||
int skipped = 0;
|
||||
while (skipped < count) {
|
||||
int bytes = Read(junk, min(count - skipped,
|
||||
implicit_cast<int>(sizeof(junk))));
|
||||
if (bytes <= 0) {
|
||||
// EOF or read error.
|
||||
return skipped;
|
||||
}
|
||||
skipped += bytes;
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
|
||||
CopyingInputStream* copying_stream, int block_size)
|
||||
: copying_stream_(copying_stream),
|
||||
owns_copying_stream_(false),
|
||||
failed_(false),
|
||||
position_(0),
|
||||
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
|
||||
buffer_used_(0),
|
||||
backup_bytes_(0) {
|
||||
}
|
||||
|
||||
CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
|
||||
if (owns_copying_stream_) {
|
||||
delete copying_stream_;
|
||||
}
|
||||
}
|
||||
|
||||
bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
|
||||
if (failed_) {
|
||||
// Already failed on a previous read.
|
||||
return false;
|
||||
}
|
||||
|
||||
AllocateBufferIfNeeded();
|
||||
|
||||
if (backup_bytes_ > 0) {
|
||||
// We have data left over from a previous BackUp(), so just return that.
|
||||
*data = buffer_.get() + buffer_used_ - backup_bytes_;
|
||||
*size = backup_bytes_;
|
||||
backup_bytes_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read new data into the buffer.
|
||||
buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
|
||||
if (buffer_used_ <= 0) {
|
||||
// EOF or read error. We don't need the buffer anymore.
|
||||
if (buffer_used_ < 0) {
|
||||
// Read error (not EOF).
|
||||
failed_ = true;
|
||||
}
|
||||
FreeBuffer();
|
||||
return false;
|
||||
}
|
||||
position_ += buffer_used_;
|
||||
|
||||
*size = buffer_used_;
|
||||
*data = buffer_.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::BackUp(int count) {
|
||||
GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
|
||||
<< " BackUp() can only be called after Next().";
|
||||
GOOGLE_CHECK_LE(count, buffer_used_)
|
||||
<< " Can't back up over more bytes than were returned by the last call"
|
||||
" to Next().";
|
||||
GOOGLE_CHECK_GE(count, 0)
|
||||
<< " Parameter to BackUp() can't be negative.";
|
||||
|
||||
backup_bytes_ = count;
|
||||
}
|
||||
|
||||
bool CopyingInputStreamAdaptor::Skip(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
|
||||
if (failed_) {
|
||||
// Already failed on a previous read.
|
||||
return false;
|
||||
}
|
||||
|
||||
// First skip any bytes left over from a previous BackUp().
|
||||
if (backup_bytes_ >= count) {
|
||||
// We have more data left over than we're trying to skip. Just chop it.
|
||||
backup_bytes_ -= count;
|
||||
return true;
|
||||
}
|
||||
|
||||
count -= backup_bytes_;
|
||||
backup_bytes_ = 0;
|
||||
|
||||
int skipped = copying_stream_->Skip(count);
|
||||
position_ += skipped;
|
||||
return skipped == count;
|
||||
}
|
||||
|
||||
int64 CopyingInputStreamAdaptor::ByteCount() const {
|
||||
return position_ - backup_bytes_;
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
|
||||
if (buffer_.get() == NULL) {
|
||||
buffer_.reset(new uint8[buffer_size_]);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::FreeBuffer() {
|
||||
GOOGLE_CHECK_EQ(backup_bytes_, 0);
|
||||
buffer_used_ = 0;
|
||||
buffer_.reset();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
CopyingOutputStream::~CopyingOutputStream() {}
|
||||
|
||||
CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
|
||||
CopyingOutputStream* copying_stream, int block_size)
|
||||
: copying_stream_(copying_stream),
|
||||
owns_copying_stream_(false),
|
||||
failed_(false),
|
||||
position_(0),
|
||||
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
|
||||
buffer_used_(0) {
|
||||
}
|
||||
|
||||
CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
|
||||
WriteBuffer();
|
||||
if (owns_copying_stream_) {
|
||||
delete copying_stream_;
|
||||
}
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::Flush() {
|
||||
return WriteBuffer();
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
|
||||
if (buffer_used_ == buffer_size_) {
|
||||
if (!WriteBuffer()) return false;
|
||||
}
|
||||
|
||||
AllocateBufferIfNeeded();
|
||||
|
||||
*data = buffer_.get() + buffer_used_;
|
||||
*size = buffer_size_ - buffer_used_;
|
||||
buffer_used_ = buffer_size_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
|
||||
<< " BackUp() can only be called after Next().";
|
||||
GOOGLE_CHECK_LE(count, buffer_used_)
|
||||
<< " Can't back up over more bytes than were returned by the last call"
|
||||
" to Next().";
|
||||
|
||||
buffer_used_ -= count;
|
||||
}
|
||||
|
||||
int64 CopyingOutputStreamAdaptor::ByteCount() const {
|
||||
return position_ + buffer_used_;
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::WriteBuffer() {
|
||||
if (failed_) {
|
||||
// Already failed on a previous write.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer_used_ == 0) return true;
|
||||
|
||||
if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
|
||||
position_ += buffer_used_;
|
||||
buffer_used_ = 0;
|
||||
return true;
|
||||
} else {
|
||||
failed_ = true;
|
||||
FreeBuffer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
|
||||
if (buffer_ == NULL) {
|
||||
buffer_.reset(new uint8[buffer_size_]);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::FreeBuffer() {
|
||||
buffer_used_ = 0;
|
||||
buffer_.reset();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,340 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains common implementations of the interfaces defined in
|
||||
// zero_copy_stream.h which are included in the "lite" protobuf library.
|
||||
// These implementations cover I/O on raw arrays and strings, as well as
|
||||
// adaptors which make it easy to implement streams based on traditional
|
||||
// streams. Of course, many users will probably want to write their own
|
||||
// implementations of these interfaces specific to the particular I/O
|
||||
// abstractions they prefer to use, but these should cover the most common
|
||||
// cases.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream backed by an in-memory array of bytes.
|
||||
class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Create an InputStream that returns the bytes pointed to by "data".
|
||||
// "data" remains the property of the caller but must remain valid until
|
||||
// the stream is destroyed. If a block_size is given, calls to Next()
|
||||
// will return data blocks no larger than the given size. Otherwise, the
|
||||
// first call to Next() returns the entire array. block_size is mainly
|
||||
// useful for testing; in production you would probably never want to set
|
||||
// it.
|
||||
ArrayInputStream(const void* data, int size, int block_size = -1);
|
||||
~ArrayInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
const uint8* const data_; // The byte array.
|
||||
const int size_; // Total size of the array.
|
||||
const int block_size_; // How many bytes to return at a time.
|
||||
|
||||
int position_;
|
||||
int last_returned_size_; // How many bytes we returned last time Next()
|
||||
// was called (used for error checking only).
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream backed by an in-memory array of bytes.
|
||||
class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Create an OutputStream that writes to the bytes pointed to by "data".
|
||||
// "data" remains the property of the caller but must remain valid until
|
||||
// the stream is destroyed. If a block_size is given, calls to Next()
|
||||
// will return data blocks no larger than the given size. Otherwise, the
|
||||
// first call to Next() returns the entire array. block_size is mainly
|
||||
// useful for testing; in production you would probably never want to set
|
||||
// it.
|
||||
ArrayOutputStream(void* data, int size, int block_size = -1);
|
||||
~ArrayOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
uint8* const data_; // The byte array.
|
||||
const int size_; // Total size of the array.
|
||||
const int block_size_; // How many bytes to return at a time.
|
||||
|
||||
int position_;
|
||||
int last_returned_size_; // How many bytes we returned last time Next()
|
||||
// was called (used for error checking only).
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which appends bytes to a string.
|
||||
class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Create a StringOutputStream which appends bytes to the given string.
|
||||
// The string remains property of the caller, but it MUST NOT be accessed
|
||||
// in any way until the stream is destroyed.
|
||||
//
|
||||
// Hint: If you call target->reserve(n) before creating the stream,
|
||||
// the first call to Next() will return at least n bytes of buffer
|
||||
// space.
|
||||
explicit StringOutputStream(string* target);
|
||||
~StringOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
static const int kMinimumSize = 16;
|
||||
|
||||
string* target_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
|
||||
};
|
||||
|
||||
// Note: There is no StringInputStream. Instead, just create an
|
||||
// ArrayInputStream as follows:
|
||||
// ArrayInputStream input(str.data(), str.size());
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A generic traditional input stream interface.
|
||||
//
|
||||
// Lots of traditional input streams (e.g. file descriptors, C stdio
|
||||
// streams, and C++ iostreams) expose an interface where every read
|
||||
// involves copying bytes into a buffer. If you want to take such an
|
||||
// interface and make a ZeroCopyInputStream based on it, simply implement
|
||||
// CopyingInputStream and then use CopyingInputStreamAdaptor.
|
||||
//
|
||||
// CopyingInputStream implementations should avoid buffering if possible.
|
||||
// CopyingInputStreamAdaptor does its own buffering and will read data
|
||||
// in large blocks.
|
||||
class LIBPROTOBUF_EXPORT CopyingInputStream {
|
||||
public:
|
||||
virtual ~CopyingInputStream();
|
||||
|
||||
// Reads up to "size" bytes into the given buffer. Returns the number of
|
||||
// bytes read. Read() waits until at least one byte is available, or
|
||||
// returns zero if no bytes will ever become available (EOF), or -1 if a
|
||||
// permanent read error occurred.
|
||||
virtual int Read(void* buffer, int size) = 0;
|
||||
|
||||
// Skips the next "count" bytes of input. Returns the number of bytes
|
||||
// actually skipped. This will always be exactly equal to "count" unless
|
||||
// EOF was reached or a permanent read error occurred.
|
||||
//
|
||||
// The default implementation just repeatedly calls Read() into a scratch
|
||||
// buffer.
|
||||
virtual int Skip(int count);
|
||||
};
|
||||
|
||||
// A ZeroCopyInputStream which reads from a CopyingInputStream. This is
|
||||
// useful for implementing ZeroCopyInputStreams that read from traditional
|
||||
// streams. Note that this class is not really zero-copy.
|
||||
//
|
||||
// If you want to read from file descriptors or C++ istreams, this is
|
||||
// already implemented for you: use FileInputStream or IstreamInputStream
|
||||
// respectively.
|
||||
class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given CopyingInputStream.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used. The caller retains ownership of
|
||||
// copying_stream unless SetOwnsCopyingStream(true) is called.
|
||||
explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
|
||||
int block_size = -1);
|
||||
~CopyingInputStreamAdaptor();
|
||||
|
||||
// Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
|
||||
// delete the underlying CopyingInputStream when it is destroyed.
|
||||
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
// Insures that buffer_ is not NULL.
|
||||
void AllocateBufferIfNeeded();
|
||||
// Frees the buffer and resets buffer_used_.
|
||||
void FreeBuffer();
|
||||
|
||||
// The underlying copying stream.
|
||||
CopyingInputStream* copying_stream_;
|
||||
bool owns_copying_stream_;
|
||||
|
||||
// True if we have seen a permenant error from the underlying stream.
|
||||
bool failed_;
|
||||
|
||||
// The current position of copying_stream_, relative to the point where
|
||||
// we started reading.
|
||||
int64 position_;
|
||||
|
||||
// Data is read into this buffer. It may be NULL if no buffer is currently
|
||||
// in use. Otherwise, it points to an array of size buffer_size_.
|
||||
scoped_array<uint8> buffer_;
|
||||
const int buffer_size_;
|
||||
|
||||
// Number of valid bytes currently in the buffer (i.e. the size last
|
||||
// returned by Next()). 0 <= buffer_used_ <= buffer_size_.
|
||||
int buffer_used_;
|
||||
|
||||
// Number of bytes in the buffer which were backed up over by a call to
|
||||
// BackUp(). These need to be returned again.
|
||||
// 0 <= backup_bytes_ <= buffer_used_
|
||||
int backup_bytes_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A generic traditional output stream interface.
|
||||
//
|
||||
// Lots of traditional output streams (e.g. file descriptors, C stdio
|
||||
// streams, and C++ iostreams) expose an interface where every write
|
||||
// involves copying bytes from a buffer. If you want to take such an
|
||||
// interface and make a ZeroCopyOutputStream based on it, simply implement
|
||||
// CopyingOutputStream and then use CopyingOutputStreamAdaptor.
|
||||
//
|
||||
// CopyingOutputStream implementations should avoid buffering if possible.
|
||||
// CopyingOutputStreamAdaptor does its own buffering and will write data
|
||||
// in large blocks.
|
||||
class LIBPROTOBUF_EXPORT CopyingOutputStream {
|
||||
public:
|
||||
virtual ~CopyingOutputStream();
|
||||
|
||||
// Writes "size" bytes from the given buffer to the output. Returns true
|
||||
// if successful, false on a write error.
|
||||
virtual bool Write(const void* buffer, int size) = 0;
|
||||
};
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a CopyingOutputStream. This is
|
||||
// useful for implementing ZeroCopyOutputStreams that write to traditional
|
||||
// streams. Note that this class is not really zero-copy.
|
||||
//
|
||||
// If you want to write to file descriptors or C++ ostreams, this is
|
||||
// already implemented for you: use FileOutputStream or OstreamOutputStream
|
||||
// respectively.
|
||||
class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
|
||||
int block_size = -1);
|
||||
~CopyingOutputStreamAdaptor();
|
||||
|
||||
// Writes all pending data to the underlying stream. Returns false if a
|
||||
// write error occurred on the underlying stream. (The underlying
|
||||
// stream itself is not necessarily flushed.)
|
||||
bool Flush();
|
||||
|
||||
// Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to
|
||||
// delete the underlying CopyingOutputStream when it is destroyed.
|
||||
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
// Write the current buffer, if it is present.
|
||||
bool WriteBuffer();
|
||||
// Insures that buffer_ is not NULL.
|
||||
void AllocateBufferIfNeeded();
|
||||
// Frees the buffer.
|
||||
void FreeBuffer();
|
||||
|
||||
// The underlying copying stream.
|
||||
CopyingOutputStream* copying_stream_;
|
||||
bool owns_copying_stream_;
|
||||
|
||||
// True if we have seen a permenant error from the underlying stream.
|
||||
bool failed_;
|
||||
|
||||
// The current position of copying_stream_, relative to the point where
|
||||
// we started writing.
|
||||
int64 position_;
|
||||
|
||||
// Data is written from this buffer. It may be NULL if no buffer is
|
||||
// currently in use. Otherwise, it points to an array of size buffer_size_.
|
||||
scoped_array<uint8> buffer_;
|
||||
const int buffer_size_;
|
||||
|
||||
// Number of valid bytes currently in the buffer (i.e. the size last
|
||||
// returned by Next()). When BackUp() is called, we just reduce this.
|
||||
// 0 <= buffer_used_ <= buffer_size_.
|
||||
int buffer_used_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
@ -0,0 +1,318 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <stack>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ReflectionOps;
|
||||
|
||||
Message::~Message() {}
|
||||
|
||||
void Message::MergeFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to merge from a message with a different type. "
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Merge(from, this);
|
||||
}
|
||||
|
||||
void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
|
||||
MergeFrom(*down_cast<const Message*>(&other));
|
||||
}
|
||||
|
||||
void Message::CopyFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to copy from a message with a different type."
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Copy(from, this);
|
||||
}
|
||||
|
||||
string Message::GetTypeName() const {
|
||||
return GetDescriptor()->full_name();
|
||||
}
|
||||
|
||||
void Message::Clear() {
|
||||
ReflectionOps::Clear(this);
|
||||
}
|
||||
|
||||
bool Message::IsInitialized() const {
|
||||
return ReflectionOps::IsInitialized(*this);
|
||||
}
|
||||
|
||||
void Message::FindInitializationErrors(vector<string>* errors) const {
|
||||
return ReflectionOps::FindInitializationErrors(*this, "", errors);
|
||||
}
|
||||
|
||||
string Message::InitializationErrorString() const {
|
||||
vector<string> errors;
|
||||
FindInitializationErrors(&errors);
|
||||
return JoinStrings(errors, ", ");
|
||||
}
|
||||
|
||||
void Message::CheckInitialized() const {
|
||||
GOOGLE_CHECK(IsInitialized())
|
||||
<< "Message of type \"" << GetDescriptor()->full_name()
|
||||
<< "\" is missing required fields: " << InitializationErrorString();
|
||||
}
|
||||
|
||||
void Message::DiscardUnknownFields() {
|
||||
return ReflectionOps::DiscardUnknownFields(this);
|
||||
}
|
||||
|
||||
bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
|
||||
return WireFormat::ParseAndMergePartial(input, this);
|
||||
}
|
||||
|
||||
bool Message::ParseFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParseFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
|
||||
void Message::SerializeWithCachedSizes(
|
||||
io::CodedOutputStream* output) const {
|
||||
WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output);
|
||||
}
|
||||
|
||||
int Message::ByteSize() const {
|
||||
int size = WireFormat::ByteSize(*this);
|
||||
SetCachedSize(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
void Message::SetCachedSize(int size) const {
|
||||
GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
|
||||
<< "\" implements neither SetCachedSize() nor ByteSize(). "
|
||||
"Must implement one or the other.";
|
||||
}
|
||||
|
||||
int Message::SpaceUsed() const {
|
||||
return GetReflection()->SpaceUsed(*this);
|
||||
}
|
||||
|
||||
bool Message::SerializeToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializeToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializePartialToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializeToOstream(ostream* output) const {
|
||||
{
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
|
||||
}
|
||||
return output->good();
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToOstream(ostream* output) const {
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
return SerializePartialToZeroCopyStream(&zero_copy_output);
|
||||
}
|
||||
|
||||
|
||||
Reflection::~Reflection() {}
|
||||
|
||||
// ===================================================================
|
||||
// MessageFactory
|
||||
|
||||
MessageFactory::~MessageFactory() {}
|
||||
|
||||
namespace {
|
||||
|
||||
class GeneratedMessageFactory : public MessageFactory {
|
||||
public:
|
||||
GeneratedMessageFactory();
|
||||
~GeneratedMessageFactory();
|
||||
|
||||
static GeneratedMessageFactory* singleton();
|
||||
|
||||
typedef void RegistrationFunc(const string&);
|
||||
void RegisterFile(const char* file, RegistrationFunc* registration_func);
|
||||
void RegisterType(const Descriptor* descriptor, const Message* prototype);
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
// Only written at static init time, so does not require locking.
|
||||
hash_map<const char*, RegistrationFunc*,
|
||||
hash<const char*>, streq> file_map_;
|
||||
|
||||
// Initialized lazily, so requires locking.
|
||||
Mutex mutex_;
|
||||
hash_map<const Descriptor*, const Message*> type_map_;
|
||||
};
|
||||
|
||||
GeneratedMessageFactory* generated_message_factory_ = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_);
|
||||
|
||||
void ShutdownGeneratedMessageFactory() {
|
||||
delete generated_message_factory_;
|
||||
}
|
||||
|
||||
void InitGeneratedMessageFactory() {
|
||||
generated_message_factory_ = new GeneratedMessageFactory;
|
||||
internal::OnShutdown(&ShutdownGeneratedMessageFactory);
|
||||
}
|
||||
|
||||
GeneratedMessageFactory::GeneratedMessageFactory() {}
|
||||
GeneratedMessageFactory::~GeneratedMessageFactory() {}
|
||||
|
||||
GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
|
||||
::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_,
|
||||
&InitGeneratedMessageFactory);
|
||||
return generated_message_factory_;
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterFile(
|
||||
const char* file, RegistrationFunc* registration_func) {
|
||||
if (!InsertIfNotPresent(&file_map_, file, registration_func)) {
|
||||
GOOGLE_LOG(FATAL) << "File is already registered: " << file;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
|
||||
const Message* prototype) {
|
||||
GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
|
||||
<< "Tried to register a non-generated type with the generated "
|
||||
"type registry.";
|
||||
|
||||
// This should only be called as a result of calling a file registration
|
||||
// function during GetPrototype(), in which case we already have locked
|
||||
// the mutex.
|
||||
mutex_.AssertHeld();
|
||||
if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
|
||||
GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
|
||||
}
|
||||
}
|
||||
|
||||
const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
{
|
||||
ReaderMutexLock lock(&mutex_);
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result != NULL) return result;
|
||||
}
|
||||
|
||||
// If the type is not in the generated pool, then we can't possibly handle
|
||||
// it.
|
||||
if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL;
|
||||
|
||||
// Apparently the file hasn't been registered yet. Let's do that now.
|
||||
RegistrationFunc* registration_func =
|
||||
FindPtrOrNull(file_map_, type->file()->name().c_str());
|
||||
if (registration_func == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
|
||||
"registered: " << type->file()->name();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WriterMutexLock lock(&mutex_);
|
||||
|
||||
// Check if another thread preempted us.
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result == NULL) {
|
||||
// Nope. OK, register everything.
|
||||
registration_func(type->file()->name());
|
||||
// Should be here now.
|
||||
result = FindPtrOrNull(type_map_, type);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
|
||||
<< "registered: " << type->full_name();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessageFactory* MessageFactory::generated_factory() {
|
||||
return GeneratedMessageFactory::singleton();
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&)) {
|
||||
GeneratedMessageFactory::singleton()->RegisterFile(filename,
|
||||
register_messages);
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedMessage(
|
||||
const Descriptor* descriptor, const Message* prototype) {
|
||||
GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
|
||||
}
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,692 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines Message, the abstract interface implemented by non-lite
|
||||
// protocol message objects. Although it's possible to implement this
|
||||
// interface manually, most users will use the protocol compiler to
|
||||
// generate implementations.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// Say you have a message defined as:
|
||||
//
|
||||
// message Foo {
|
||||
// optional string text = 1;
|
||||
// repeated int32 numbers = 2;
|
||||
// }
|
||||
//
|
||||
// Then, if you used the protocol compiler to generate a class from the above
|
||||
// definition, you could use it like so:
|
||||
//
|
||||
// string data; // Will store a serialized version of the message.
|
||||
//
|
||||
// {
|
||||
// // Create a message and serialize it.
|
||||
// Foo foo;
|
||||
// foo.set_text("Hello World!");
|
||||
// foo.add_numbers(1);
|
||||
// foo.add_numbers(5);
|
||||
// foo.add_numbers(42);
|
||||
//
|
||||
// foo.SerializeToString(&data);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Parse the serialized message and check that it contains the
|
||||
// // correct data.
|
||||
// Foo foo;
|
||||
// foo.ParseFromString(data);
|
||||
//
|
||||
// assert(foo.text() == "Hello World!");
|
||||
// assert(foo.numbers_size() == 3);
|
||||
// assert(foo.numbers(0) == 1);
|
||||
// assert(foo.numbers(1) == 5);
|
||||
// assert(foo.numbers(2) == 42);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Same as the last block, but do it dynamically via the Message
|
||||
// // reflection interface.
|
||||
// Message* foo = new Foo;
|
||||
// Descriptor* descriptor = foo->GetDescriptor();
|
||||
//
|
||||
// // Get the descriptors for the fields we're interested in and verify
|
||||
// // their types.
|
||||
// FieldDescriptor* text_field = descriptor->FindFieldByName("text");
|
||||
// assert(text_field != NULL);
|
||||
// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
|
||||
// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL);
|
||||
// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers");
|
||||
// assert(numbers_field != NULL);
|
||||
// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
|
||||
// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED);
|
||||
//
|
||||
// // Parse the message.
|
||||
// foo->ParseFromString(data);
|
||||
//
|
||||
// // Use the reflection interface to examine the contents.
|
||||
// const Reflection* reflection = foo->GetReflection();
|
||||
// assert(reflection->GetString(foo, text_field) == "Hello World!");
|
||||
// assert(reflection->FieldSize(foo, numbers_field) == 3);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42);
|
||||
//
|
||||
// delete foo;
|
||||
// }
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef __DECCXX
|
||||
// HP C++'s iosfwd doesn't work.
|
||||
#include <iostream>
|
||||
#else
|
||||
#include <iosfwd>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/message_lite.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Message;
|
||||
class Reflection;
|
||||
class MessageFactory;
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class FieldDescriptor; // descriptor.h
|
||||
class EnumDescriptor; // descriptor.h
|
||||
class EnumValueDescriptor; // descriptor.h
|
||||
namespace io {
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
class UnknownFieldSet; // unknown_field_set.h
|
||||
|
||||
// A container to hold message metadata.
|
||||
struct Metadata {
|
||||
const Descriptor* descriptor;
|
||||
const Reflection* reflection;
|
||||
};
|
||||
|
||||
// Returns the EnumDescriptor for enum type E, which must be a
|
||||
// proto-declared enum type. Code generated by the protocol compiler
|
||||
// will include specializations of this template for each enum type declared.
|
||||
template <typename E>
|
||||
const EnumDescriptor* GetEnumDescriptor();
|
||||
|
||||
// Abstract interface for protocol messages.
|
||||
//
|
||||
// See also MessageLite, which contains most every-day operations. Message
|
||||
// adds descriptors and reflection on top of that.
|
||||
//
|
||||
// The methods of this class that are virtual but not pure-virtual have
|
||||
// default implementations based on reflection. Message classes which are
|
||||
// optimized for speed will want to override these with faster implementations,
|
||||
// but classes optimized for code size may be happy with keeping them. See
|
||||
// the optimize_for option in descriptor.proto.
|
||||
class LIBPROTOBUF_EXPORT Message : public MessageLite {
|
||||
public:
|
||||
inline Message() {}
|
||||
virtual ~Message();
|
||||
|
||||
// Basic Operations ------------------------------------------------
|
||||
|
||||
// Construct a new instance of the same type. Ownership is passed to the
|
||||
// caller. (This is also defined in MessageLite, but is defined again here
|
||||
// for return-type covariance.)
|
||||
virtual Message* New() const = 0;
|
||||
|
||||
// Make this message into a copy of the given message. The given message
|
||||
// must have the same descriptor, but need not necessarily be the same class.
|
||||
// By default this is just implemented as "Clear(); MergeFrom(from);".
|
||||
virtual void CopyFrom(const Message& from);
|
||||
|
||||
// Merge the fields from the given message into this message. Singular
|
||||
// fields will be overwritten, except for embedded messages which will
|
||||
// be merged. Repeated fields will be concatenated. The given message
|
||||
// must be of the same type as this message (i.e. the exact same class).
|
||||
virtual void MergeFrom(const Message& from);
|
||||
|
||||
// Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with
|
||||
// a nice error message.
|
||||
void CheckInitialized() const;
|
||||
|
||||
// Slowly build a list of all required fields that are not set.
|
||||
// This is much, much slower than IsInitialized() as it is implemented
|
||||
// purely via reflection. Generally, you should not call this unless you
|
||||
// have already determined that an error exists by calling IsInitialized().
|
||||
void FindInitializationErrors(vector<string>* errors) const;
|
||||
|
||||
// Like FindInitializationErrors, but joins all the strings, delimited by
|
||||
// commas, and returns them.
|
||||
string InitializationErrorString() const;
|
||||
|
||||
// Clears all unknown fields from this message and all embedded messages.
|
||||
// Normally, if unknown tag numbers are encountered when parsing a message,
|
||||
// the tag and value are stored in the message's UnknownFieldSet and
|
||||
// then written back out when the message is serialized. This allows servers
|
||||
// which simply route messages to other servers to pass through messages
|
||||
// that have new field definitions which they don't yet know about. However,
|
||||
// this behavior can have security implications. To avoid it, call this
|
||||
// method after parsing.
|
||||
//
|
||||
// See Reflection::GetUnknownFields() for more on unknown fields.
|
||||
virtual void DiscardUnknownFields();
|
||||
|
||||
// Computes (an estimate of) the total number of bytes currently used for
|
||||
// storing the message in memory. The default implementation calls the
|
||||
// Reflection object's SpaceUsed() method.
|
||||
virtual int SpaceUsed() const;
|
||||
|
||||
// Debugging & Testing----------------------------------------------
|
||||
|
||||
// Generates a human readable form of this message, useful for debugging
|
||||
// and other purposes.
|
||||
string DebugString() const;
|
||||
// Like DebugString(), but with less whitespace.
|
||||
string ShortDebugString() const;
|
||||
// Like DebugString(), but do not escape UTF-8 byte sequences.
|
||||
string Utf8DebugString() const;
|
||||
// Convenience function useful in GDB. Prints DebugString() to stdout.
|
||||
void PrintDebugString() const;
|
||||
|
||||
// Heavy I/O -------------------------------------------------------
|
||||
// Additional parsing and serialization methods not implemented by
|
||||
// MessageLite because they are not supported by the lite library.
|
||||
|
||||
// Parse a protocol buffer from a file descriptor. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromFileDescriptor(int file_descriptor);
|
||||
// Like ParseFromFileDescriptor(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromFileDescriptor(int file_descriptor);
|
||||
// Parse a protocol buffer from a C++ istream. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromIstream(istream* input);
|
||||
// Like ParseFromIstream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromIstream(istream* input);
|
||||
|
||||
// Serialize the message and write it to the given file descriptor. All
|
||||
// required fields must be set.
|
||||
bool SerializeToFileDescriptor(int file_descriptor) const;
|
||||
// Like SerializeToFileDescriptor(), but allows missing required fields.
|
||||
bool SerializePartialToFileDescriptor(int file_descriptor) const;
|
||||
// Serialize the message and write it to the given C++ ostream. All
|
||||
// required fields must be set.
|
||||
bool SerializeToOstream(ostream* output) const;
|
||||
// Like SerializeToOstream(), but allows missing required fields.
|
||||
bool SerializePartialToOstream(ostream* output) const;
|
||||
|
||||
|
||||
// Reflection-based methods ----------------------------------------
|
||||
// These methods are pure-virtual in MessageLite, but Message provides
|
||||
// reflection-based default implementations.
|
||||
|
||||
virtual string GetTypeName() const;
|
||||
virtual void Clear();
|
||||
virtual bool IsInitialized() const;
|
||||
virtual void CheckTypeAndMergeFrom(const MessageLite& other);
|
||||
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input);
|
||||
virtual int ByteSize() const;
|
||||
virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const;
|
||||
|
||||
private:
|
||||
// This is called only by the default implementation of ByteSize(), to
|
||||
// update the cached size. If you override ByteSize(), you do not need
|
||||
// to override this. If you do not override ByteSize(), you MUST override
|
||||
// this; the default implementation will crash.
|
||||
//
|
||||
// The method is private because subclasses should never call it; only
|
||||
// override it. Yes, C++ lets you do that. Crazy, huh?
|
||||
virtual void SetCachedSize(int size) const;
|
||||
|
||||
public:
|
||||
|
||||
// Introspection ---------------------------------------------------
|
||||
|
||||
// Typedef for backwards-compatibility.
|
||||
typedef google::protobuf::Reflection Reflection;
|
||||
|
||||
// Get a Descriptor for this message's type. This describes what
|
||||
// fields the message contains, the types of those fields, etc.
|
||||
const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; }
|
||||
|
||||
// Get the Reflection interface for this Message, which can be used to
|
||||
// read and modify the fields of the Message dynamically (in other words,
|
||||
// without knowing the message type at compile time). This object remains
|
||||
// property of the Message.
|
||||
//
|
||||
// This method remains virtual in case a subclass does not implement
|
||||
// reflection and wants to override the default behavior.
|
||||
virtual const Reflection* GetReflection() const {
|
||||
return GetMetadata().reflection;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Get a struct containing the metadata for the Message. Most subclasses only
|
||||
// need to implement this method, rather than the GetDescriptor() and
|
||||
// GetReflection() wrappers.
|
||||
virtual Metadata GetMetadata() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
|
||||
};
|
||||
|
||||
// This interface contains methods that can be used to dynamically access
|
||||
// and modify the fields of a protocol message. Their semantics are
|
||||
// similar to the accessors the protocol compiler generates.
|
||||
//
|
||||
// To get the Reflection for a given Message, call Message::GetReflection().
|
||||
//
|
||||
// This interface is separate from Message only for efficiency reasons;
|
||||
// the vast majority of implementations of Message will share the same
|
||||
// implementation of Reflection (GeneratedMessageReflection,
|
||||
// defined in generated_message.h), and all Messages of a particular class
|
||||
// should share the same Reflection object (though you should not rely on
|
||||
// the latter fact).
|
||||
//
|
||||
// There are several ways that these methods can be used incorrectly. For
|
||||
// example, any of the following conditions will lead to undefined
|
||||
// results (probably assertion failures):
|
||||
// - The FieldDescriptor is not a field of this message type.
|
||||
// - The method called is not appropriate for the field's type. For
|
||||
// each field type in FieldDescriptor::TYPE_*, there is only one
|
||||
// Get*() method, one Set*() method, and one Add*() method that is
|
||||
// valid for that type. It should be obvious which (except maybe
|
||||
// for TYPE_BYTES, which are represented using strings in C++).
|
||||
// - A Get*() or Set*() method for singular fields is called on a repeated
|
||||
// field.
|
||||
// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated
|
||||
// field.
|
||||
// - The Message object passed to any method is not of the right type for
|
||||
// this Reflection object (i.e. message.GetReflection() != reflection).
|
||||
//
|
||||
// You might wonder why there is not any abstract representation for a field
|
||||
// of arbitrary type. E.g., why isn't there just a "GetField()" method that
|
||||
// returns "const Field&", where "Field" is some class with accessors like
|
||||
// "GetInt32Value()". The problem is that someone would have to deal with
|
||||
// allocating these Field objects. For generated message classes, having to
|
||||
// allocate space for an additional object to wrap every field would at least
|
||||
// double the message's memory footprint, probably worse. Allocating the
|
||||
// objects on-demand, on the other hand, would be expensive and prone to
|
||||
// memory leaks. So, instead we ended up with this flat interface.
|
||||
//
|
||||
// TODO(kenton): Create a utility class which callers can use to read and
|
||||
// write fields from a Reflection without paying attention to the type.
|
||||
class LIBPROTOBUF_EXPORT Reflection {
|
||||
public:
|
||||
// TODO(kenton): Remove parameter.
|
||||
inline Reflection() {}
|
||||
virtual ~Reflection();
|
||||
|
||||
// Get the UnknownFieldSet for the message. This contains fields which
|
||||
// were seen when the Message was parsed but were not recognized according
|
||||
// to the Message's definition.
|
||||
virtual const UnknownFieldSet& GetUnknownFields(
|
||||
const Message& message) const = 0;
|
||||
// Get a mutable pointer to the UnknownFieldSet for the message. This
|
||||
// contains fields which were seen when the Message was parsed but were not
|
||||
// recognized according to the Message's definition.
|
||||
virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
|
||||
|
||||
// Estimate the amount of memory used by the message object.
|
||||
virtual int SpaceUsed(const Message& message) const = 0;
|
||||
|
||||
// Check if the given non-repeated field is set.
|
||||
virtual bool HasField(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Get the number of elements of a repeated field.
|
||||
virtual int FieldSize(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Clear the value of a field, so that HasField() returns false or
|
||||
// FieldSize() returns zero.
|
||||
virtual void ClearField(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Remove the last element of a repeated field.
|
||||
// We don't provide a way to remove any element other than the last
|
||||
// because it invites inefficient use, such as O(n^2) filtering loops
|
||||
// that should have been O(n). If you want to remove an element other
|
||||
// than the last, the best way to do it is to re-arrange the elements
|
||||
// (using Swap()) so that the one you want removed is at the end, then
|
||||
// call RemoveLast().
|
||||
virtual void RemoveLast(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Swap the complete contents of two messages.
|
||||
virtual void Swap(Message* message1, Message* message2) const = 0;
|
||||
|
||||
// Swap two elements of a repeated field.
|
||||
virtual void SwapElements(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index1,
|
||||
int index2) const = 0;
|
||||
|
||||
// List all fields of the message which are currently set. This includes
|
||||
// extensions. Singular fields will only be listed if HasField(field) would
|
||||
// return true and repeated fields will only be listed if FieldSize(field)
|
||||
// would return non-zero. Fields (both normal fields and extension fields)
|
||||
// will be listed ordered by field number.
|
||||
virtual void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const = 0;
|
||||
|
||||
// Singular field getters ------------------------------------------
|
||||
// These get the value of a non-repeated field. They return the default
|
||||
// value for fields that aren't set.
|
||||
|
||||
virtual int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual const EnumValueDescriptor* GetEnum(
|
||||
const Message& message, const FieldDescriptor* field) const = 0;
|
||||
// See MutableMessage() for the meaning of the "factory" parameter.
|
||||
virtual const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
// Get a string value without copying, if possible.
|
||||
//
|
||||
// GetString() necessarily returns a copy of the string. This can be
|
||||
// inefficient when the string is already stored in a string object in the
|
||||
// underlying message. GetStringReference() will return a reference to the
|
||||
// underlying string in this case. Otherwise, it will copy the string into
|
||||
// *scratch and return that.
|
||||
//
|
||||
// Note: It is perfectly reasonable and useful to write code like:
|
||||
// str = reflection->GetStringReference(field, &str);
|
||||
// This line would ensure that only one copy of the string is made
|
||||
// regardless of the field's underlying representation. When initializing
|
||||
// a newly-constructed string, though, it's just as fast and more readable
|
||||
// to use code like:
|
||||
// string str = reflection->GetString(field);
|
||||
virtual const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const = 0;
|
||||
|
||||
|
||||
// Singular field mutators -----------------------------------------
|
||||
// These mutate the value of a non-repeated field.
|
||||
|
||||
virtual void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void SetEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to a field with a message type. If a MessageFactory
|
||||
// is provided, it will be used to construct instances of the sub-message;
|
||||
// otherwise, the default factory is used. If the field is an extension that
|
||||
// does not live in the same pool as the containing message's descriptor (e.g.
|
||||
// it lives in an overlay pool), then a MessageFactory must be provided.
|
||||
// If you have no idea what that meant, then you probably don't need to worry
|
||||
// about it (don't provide a MessageFactory). WARNING: If the
|
||||
// FieldDescriptor is for a compiled-in extension, then
|
||||
// factory->GetPrototype(field->message_type() MUST return an instance of the
|
||||
// compiled-in class for this type, NOT DynamicMessage.
|
||||
virtual Message* MutableMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Repeated field getters ------------------------------------------
|
||||
// These get the value of one element of a repeated field.
|
||||
|
||||
virtual int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual const EnumValueDescriptor* GetRepeatedEnum(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
virtual const Message& GetRepeatedMessage(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
// See GetStringReference(), above.
|
||||
virtual const string& GetRepeatedStringReference(
|
||||
const Message& message, const FieldDescriptor* field,
|
||||
int index, string* scratch) const = 0;
|
||||
|
||||
|
||||
// Repeated field mutators -----------------------------------------
|
||||
// These mutate the value of one element of a repeated field.
|
||||
|
||||
virtual void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int32 value) const = 0;
|
||||
virtual void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int64 value) const = 0;
|
||||
virtual void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint32 value) const = 0;
|
||||
virtual void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint64 value) const = 0;
|
||||
virtual void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, float value) const = 0;
|
||||
virtual void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, double value) const = 0;
|
||||
virtual void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, bool value) const = 0;
|
||||
virtual void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, const string& value) const = 0;
|
||||
virtual void SetRepeatedEnum(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to an element of a repeated field with a message
|
||||
// type.
|
||||
virtual Message* MutableRepeatedMessage(
|
||||
Message* message, const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
|
||||
// Repeated field adders -------------------------------------------
|
||||
// These add an element to a repeated field.
|
||||
|
||||
virtual void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void AddString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void AddEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// See MutableMessage() for comments on the "factory" parameter.
|
||||
virtual Message* AddMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Extensions ------------------------------------------------------
|
||||
|
||||
// Try to find an extension of this message type by fully-qualified field
|
||||
// name. Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByName(
|
||||
const string& name) const = 0;
|
||||
|
||||
// Try to find an extension of this message type by field number.
|
||||
// Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByNumber(
|
||||
int number) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
|
||||
};
|
||||
|
||||
// Abstract interface for a factory for message objects.
|
||||
class LIBPROTOBUF_EXPORT MessageFactory {
|
||||
public:
|
||||
inline MessageFactory() {}
|
||||
virtual ~MessageFactory();
|
||||
|
||||
// Given a Descriptor, gets or constructs the default (prototype) Message
|
||||
// of that type. You can then call that message's New() method to construct
|
||||
// a mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory. Also, any
|
||||
// objects created by calling the prototype's New() method share some data
|
||||
// with the prototype, so these must be destoyed before the MessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the MessageFactory.
|
||||
//
|
||||
// Some implementations do not support all types. GetPrototype() will
|
||||
// return NULL if the descriptor passed in is not supported.
|
||||
//
|
||||
// This method may or may not be thread-safe depending on the implementation.
|
||||
// Each implementation should document its own degree thread-safety.
|
||||
virtual const Message* GetPrototype(const Descriptor* type) = 0;
|
||||
|
||||
// Gets a MessageFactory which supports all generated, compiled-in messages.
|
||||
// In other words, for any compiled-in type FooMessage, the following is true:
|
||||
// MessageFactory::generated_factory()->GetPrototype(
|
||||
// FooMessage::descriptor()) == FooMessage::default_instance()
|
||||
// This factory supports all types which are found in
|
||||
// DescriptorPool::generated_pool(). If given a descriptor from any other
|
||||
// pool, GetPrototype() will return NULL. (You can also check if a
|
||||
// descriptor is for a generated message by checking if
|
||||
// descriptor->file()->pool() == DescriptorPool::generated_pool().)
|
||||
//
|
||||
// This factory is 100% thread-safe; calling GetPrototype() does not modify
|
||||
// any shared data.
|
||||
//
|
||||
// This factory is a singleton. The caller must not delete the object.
|
||||
static MessageFactory* generated_factory();
|
||||
|
||||
// For internal use only: Registers a .proto file at static initialization
|
||||
// time, to be placed in generated_factory. The first time GetPrototype()
|
||||
// is called with a descriptor from this file, |register_messages| will be
|
||||
// called, with the file name as the parameter. It must call
|
||||
// InternalRegisterGeneratedMessage() (below) to register each message type
|
||||
// in the file. This strange mechanism is necessary because descriptors are
|
||||
// built lazily, so we can't register types by their descriptor until we
|
||||
// know that the descriptor exists. |filename| must be a permanent string.
|
||||
static void InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&));
|
||||
|
||||
// For internal use only: Registers a message type. Called only by the
|
||||
// functions which are registered with InternalRegisterGeneratedFile(),
|
||||
// above.
|
||||
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
|
||||
const Message* prototype);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MESSAGE_H__
|
@ -0,0 +1,334 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Authors: wink@google.com (Wink Saville),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
MessageLite::~MessageLite() {}
|
||||
|
||||
string MessageLite::InitializationErrorString() const {
|
||||
return "(cannot determine missing fields for lite message)";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// When serializing, we first compute the byte size, then serialize the message.
|
||||
// If serialization produces a different number of bytes than expected, we
|
||||
// call this function, which crashes. The problem could be due to a bug in the
|
||||
// protobuf implementation but is more likely caused by concurrent modification
|
||||
// of the message. This function attempts to distinguish between the two and
|
||||
// provide a useful error message.
|
||||
void ByteSizeConsistencyError(int byte_size_before_serialization,
|
||||
int byte_size_after_serialization,
|
||||
int bytes_produced_by_serialization) {
|
||||
GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
|
||||
<< "Protocol message was modified concurrently during serialization.";
|
||||
GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
|
||||
<< "Byte size calculation and serialization were inconsistent. This "
|
||||
"may indicate a bug in protocol buffers or it may be caused by "
|
||||
"concurrent modification of the message.";
|
||||
GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
|
||||
}
|
||||
|
||||
string InitializationErrorMessage(const char* action,
|
||||
const MessageLite& message) {
|
||||
// Note: We want to avoid depending on strutil in the lite library, otherwise
|
||||
// we'd use:
|
||||
//
|
||||
// return strings::Substitute(
|
||||
// "Can't $0 message of type \"$1\" because it is missing required "
|
||||
// "fields: $2",
|
||||
// action, message.GetTypeName(),
|
||||
// message.InitializationErrorString());
|
||||
|
||||
string result;
|
||||
result += "Can't ";
|
||||
result += action;
|
||||
result += " message of type \"";
|
||||
result += message.GetTypeName();
|
||||
result += "\" because it is missing required fields: ";
|
||||
result += message.InitializationErrorString();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Several of the Parse methods below just do one thing and then call another
|
||||
// method. In a naive implementation, we might have ParseFromString() call
|
||||
// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
|
||||
// ParseFromCodedStream() which would call MergeFromCodedStream() which would
|
||||
// call MergePartialFromCodedStream(). However, when parsing very small
|
||||
// messages, every function call introduces significant overhead. To avoid
|
||||
// this without reproducing code, we use these forced-inline helpers.
|
||||
//
|
||||
// Note: GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not
|
||||
// definitions.
|
||||
inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParseFromArray(const void* data, int size,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParsePartialFromArray(const void* data, int size,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
bool InlineMergeFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
if (!message->MergePartialFromCodedStream(input)) return false;
|
||||
if (!message->IsInitialized()) {
|
||||
GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InlineParseFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
message->Clear();
|
||||
return InlineMergeFromCodedStream(input, message);
|
||||
}
|
||||
|
||||
bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
message->Clear();
|
||||
return message->MergePartialFromCodedStream(input);
|
||||
}
|
||||
|
||||
bool InlineParseFromArray(const void* data, int size, MessageLite* message) {
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
|
||||
return InlineParseFromCodedStream(&input, message) &&
|
||||
input.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool InlineParsePartialFromArray(const void* data, int size,
|
||||
MessageLite* message) {
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
|
||||
return InlineParsePartialFromCodedStream(&input, message) &&
|
||||
input.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineMergeFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineParseFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineParsePartialFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
|
||||
io::CodedInputStream decoder(input);
|
||||
return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input) {
|
||||
io::CodedInputStream decoder(input);
|
||||
return ParsePartialFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromBoundedZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input, int size) {
|
||||
io::CodedInputStream decoder(input);
|
||||
decoder.PushLimit(size);
|
||||
return ParseFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage() &&
|
||||
decoder.BytesUntilLimit() == 0;
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input, int size) {
|
||||
io::CodedInputStream decoder(input);
|
||||
decoder.PushLimit(size);
|
||||
return ParsePartialFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage() &&
|
||||
decoder.BytesUntilLimit() == 0;
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromString(const string& data) {
|
||||
return InlineParseFromArray(data.data(), data.size(), this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromString(const string& data) {
|
||||
return InlineParsePartialFromArray(data.data(), data.size(), this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromArray(const void* data, int size) {
|
||||
return InlineParseFromArray(data, size, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromArray(const void* data, int size) {
|
||||
return InlineParsePartialFromArray(data, size, this);
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
|
||||
// We only optimize this when using optimize_for = SPEED. In other cases
|
||||
// we just use the CodedOutputStream path.
|
||||
int size = GetCachedSize();
|
||||
io::ArrayOutputStream out(target, size);
|
||||
io::CodedOutputStream coded_out(&out);
|
||||
SerializeWithCachedSizes(&coded_out);
|
||||
GOOGLE_CHECK(!coded_out.HadError());
|
||||
return target + size;
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return SerializePartialToCodedStream(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToCodedStream(
|
||||
io::CodedOutputStream* output) const {
|
||||
const int size = ByteSize(); // Force size to be cached.
|
||||
uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
|
||||
if (buffer != NULL) {
|
||||
uint8* end = SerializeWithCachedSizesToArray(buffer);
|
||||
if (end - buffer != size) {
|
||||
ByteSizeConsistencyError(size, ByteSize(), end - buffer);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
int original_byte_count = output->ByteCount();
|
||||
SerializeWithCachedSizes(output);
|
||||
if (output->HadError()) {
|
||||
return false;
|
||||
}
|
||||
int final_byte_count = output->ByteCount();
|
||||
|
||||
if (final_byte_count - original_byte_count != size) {
|
||||
ByteSizeConsistencyError(size, ByteSize(),
|
||||
final_byte_count - original_byte_count);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToZeroCopyStream(
|
||||
io::ZeroCopyOutputStream* output) const {
|
||||
io::CodedOutputStream encoder(output);
|
||||
return SerializeToCodedStream(&encoder);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToZeroCopyStream(
|
||||
io::ZeroCopyOutputStream* output) const {
|
||||
io::CodedOutputStream encoder(output);
|
||||
return SerializePartialToCodedStream(&encoder);
|
||||
}
|
||||
|
||||
bool MessageLite::AppendToString(string* output) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return AppendPartialToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::AppendPartialToString(string* output) const {
|
||||
int old_size = output->size();
|
||||
int byte_size = ByteSize();
|
||||
STLStringResizeUninitialized(output, old_size + byte_size);
|
||||
uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size);
|
||||
uint8* end = SerializeWithCachedSizesToArray(start);
|
||||
if (end - start != byte_size) {
|
||||
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToString(string* output) const {
|
||||
output->clear();
|
||||
return AppendToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToString(string* output) const {
|
||||
output->clear();
|
||||
return AppendPartialToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToArray(void* data, int size) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return SerializePartialToArray(data, size);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToArray(void* data, int size) const {
|
||||
int byte_size = ByteSize();
|
||||
if (size < byte_size) return false;
|
||||
uint8* start = reinterpret_cast<uint8*>(data);
|
||||
uint8* end = SerializeWithCachedSizesToArray(start);
|
||||
if (end - start != byte_size) {
|
||||
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string MessageLite::SerializeAsString() const {
|
||||
// If the compiler implements the (Named) Return Value Optimization,
|
||||
// the local variable 'result' will not actually reside on the stack
|
||||
// of this function, but will be overlaid with the object that the
|
||||
// caller supplied for the return value to be constructed in.
|
||||
string output;
|
||||
if (!AppendToString(&output))
|
||||
output.clear();
|
||||
return output;
|
||||
}
|
||||
|
||||
string MessageLite::SerializePartialAsString() const {
|
||||
string output;
|
||||
if (!AppendPartialToString(&output))
|
||||
output.clear();
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,239 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Authors: wink@google.com (Wink Saville),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines MessageLite, the abstract interface implemented by all (lite
|
||||
// and non-lite) protocol message objects.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Interface to light weight protocol messages.
|
||||
//
|
||||
// This interface is implemented by all protocol message objects. Non-lite
|
||||
// messages additionally implement the Message interface, which is a
|
||||
// subclass of MessageLite. Use MessageLite instead when you only need
|
||||
// the subset of features which it supports -- namely, nothing that uses
|
||||
// descriptors or reflection. You can instruct the protocol compiler
|
||||
// to generate classes which implement only MessageLite, not the full
|
||||
// Message interface, by adding the following line to the .proto file:
|
||||
//
|
||||
// option optimize_for = LITE_RUNTIME;
|
||||
//
|
||||
// This is particularly useful on resource-constrained systems where
|
||||
// the full protocol buffers runtime library is too big.
|
||||
//
|
||||
// Note that on non-constrained systems (e.g. servers) when you need
|
||||
// to link in lots of protocol definitions, a better way to reduce
|
||||
// total code footprint is to use optimize_for = CODE_SIZE. This
|
||||
// will make the generated code smaller while still supporting all the
|
||||
// same features (at the expense of speed). optimize_for = LITE_RUNTIME
|
||||
// is best when you only have a small number of message types linked
|
||||
// into your binary, in which case the size of the protocol buffers
|
||||
// runtime itself is the biggest problem.
|
||||
class LIBPROTOBUF_EXPORT MessageLite {
|
||||
public:
|
||||
inline MessageLite() {}
|
||||
virtual ~MessageLite();
|
||||
|
||||
// Basic Operations ------------------------------------------------
|
||||
|
||||
// Get the name of this message type, e.g. "foo.bar.BazProto".
|
||||
virtual string GetTypeName() const = 0;
|
||||
|
||||
// Construct a new instance of the same type. Ownership is passed to the
|
||||
// caller.
|
||||
virtual MessageLite* New() const = 0;
|
||||
|
||||
// Clear all fields of the message and set them to their default values.
|
||||
// Clear() avoids freeing memory, assuming that any memory allocated
|
||||
// to hold parts of the message will be needed again to hold the next
|
||||
// message. If you actually want to free the memory used by a Message,
|
||||
// you must delete it.
|
||||
virtual void Clear() = 0;
|
||||
|
||||
// Quickly check if all required fields have values set.
|
||||
virtual bool IsInitialized() const = 0;
|
||||
|
||||
// This is not implemented for Lite messages -- it just returns "(cannot
|
||||
// determine missing fields for lite message)". However, it is implemented
|
||||
// for full messages. See message.h.
|
||||
virtual string InitializationErrorString() const;
|
||||
|
||||
// If |other| is the exact same class as this, calls MergeFrom(). Otherwise,
|
||||
// results are undefined (probably crash).
|
||||
virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
|
||||
|
||||
// Parsing ---------------------------------------------------------
|
||||
// Methods for parsing in protocol buffer format. Most of these are
|
||||
// just simple wrappers around MergeFromCodedStream().
|
||||
|
||||
// Fill the message with a protocol buffer parsed from the given input
|
||||
// stream. Returns false on a read error or if the input is in the
|
||||
// wrong format.
|
||||
bool ParseFromCodedStream(io::CodedInputStream* input);
|
||||
// Like ParseFromCodedStream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromCodedStream(io::CodedInputStream* input);
|
||||
// Read a protocol buffer from the given zero-copy input stream. If
|
||||
// successful, the entire input will be consumed.
|
||||
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
|
||||
// Like ParseFromZeroCopyStream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
|
||||
// Read a protocol buffer from the given zero-copy input stream, expecting
|
||||
// the message to be exactly "size" bytes long. If successful, exactly
|
||||
// this many bytes will have been consumed from the input.
|
||||
bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
|
||||
// Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
|
||||
// missing required fields.
|
||||
bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
|
||||
int size);
|
||||
// Parse a protocol buffer contained in a string.
|
||||
bool ParseFromString(const string& data);
|
||||
// Like ParseFromString(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromString(const string& data);
|
||||
// Parse a protocol buffer contained in an array of bytes.
|
||||
bool ParseFromArray(const void* data, int size);
|
||||
// Like ParseFromArray(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromArray(const void* data, int size);
|
||||
|
||||
|
||||
// Reads a protocol buffer from the stream and merges it into this
|
||||
// Message. Singular fields read from the input overwrite what is
|
||||
// already in the Message and repeated fields are appended to those
|
||||
// already present.
|
||||
//
|
||||
// It is the responsibility of the caller to call input->LastTagWas()
|
||||
// (for groups) or input->ConsumedEntireMessage() (for non-groups) after
|
||||
// this returns to verify that the message's end was delimited correctly.
|
||||
//
|
||||
// ParsefromCodedStream() is implemented as Clear() followed by
|
||||
// MergeFromCodedStream().
|
||||
bool MergeFromCodedStream(io::CodedInputStream* input);
|
||||
|
||||
// Like MergeFromCodedStream(), but succeeds even if required fields are
|
||||
// missing in the input.
|
||||
//
|
||||
// MergeFromCodedStream() is just implemented as MergePartialFromCodedStream()
|
||||
// followed by IsInitialized().
|
||||
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0;
|
||||
|
||||
// Serialization ---------------------------------------------------
|
||||
// Methods for serializing in protocol buffer format. Most of these
|
||||
// are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
|
||||
|
||||
// Write a protocol buffer of this message to the given output. Returns
|
||||
// false on a write error. If the message is missing required fields,
|
||||
// this may GOOGLE_CHECK-fail.
|
||||
bool SerializeToCodedStream(io::CodedOutputStream* output) const;
|
||||
// Like SerializeToCodedStream(), but allows missing required fields.
|
||||
bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;
|
||||
// Write the message to the given zero-copy output stream. All required
|
||||
// fields must be set.
|
||||
bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
|
||||
// Like SerializeToZeroCopyStream(), but allows missing required fields.
|
||||
bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
|
||||
// Serialize the message and store it in the given string. All required
|
||||
// fields must be set.
|
||||
bool SerializeToString(string* output) const;
|
||||
// Like SerializeToString(), but allows missing required fields.
|
||||
bool SerializePartialToString(string* output) const;
|
||||
// Serialize the message and store it in the given byte array. All required
|
||||
// fields must be set.
|
||||
bool SerializeToArray(void* data, int size) const;
|
||||
// Like SerializeToArray(), but allows missing required fields.
|
||||
bool SerializePartialToArray(void* data, int size) const;
|
||||
|
||||
// Make a string encoding the message. Is equivalent to calling
|
||||
// SerializeToString() on a string and using that. Returns the empty
|
||||
// string if SerializeToString() would have returned an error.
|
||||
// Note: If you intend to generate many such strings, you may
|
||||
// reduce heap fragmentation by instead re-using the same string
|
||||
// object with calls to SerializeToString().
|
||||
string SerializeAsString() const;
|
||||
// Like SerializeAsString(), but allows missing required fields.
|
||||
string SerializePartialAsString() const;
|
||||
|
||||
// Like SerializeToString(), but appends to the data to the string's existing
|
||||
// contents. All required fields must be set.
|
||||
bool AppendToString(string* output) const;
|
||||
// Like AppendToString(), but allows missing required fields.
|
||||
bool AppendPartialToString(string* output) const;
|
||||
|
||||
// Computes the serialized size of the message. This recursively calls
|
||||
// ByteSize() on all embedded messages. If a subclass does not override
|
||||
// this, it MUST override SetCachedSize().
|
||||
virtual int ByteSize() const = 0;
|
||||
|
||||
// Serializes the message without recomputing the size. The message must
|
||||
// not have changed since the last call to ByteSize(); if it has, the results
|
||||
// are undefined.
|
||||
virtual void SerializeWithCachedSizes(
|
||||
io::CodedOutputStream* output) const = 0;
|
||||
|
||||
// Like SerializeWithCachedSizes, but writes directly to *target, returning
|
||||
// a pointer to the byte immediately after the last byte written. "target"
|
||||
// must point at a byte array of at least ByteSize() bytes.
|
||||
virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
|
||||
|
||||
// Returns the result of the last call to ByteSize(). An embedded message's
|
||||
// size is needed both to serialize it (because embedded messages are
|
||||
// length-delimited) and to compute the outer message's size. Caching
|
||||
// the size avoids computing it multiple times.
|
||||
//
|
||||
// ByteSize() does not automatically use the cached size when available
|
||||
// because this would require invalidating it every time the message was
|
||||
// modified, which would be too hard and expensive. (E.g. if a deeply-nested
|
||||
// sub-message is changed, all of its parents' cached sizes would need to be
|
||||
// invalidated, which is too much work for an otherwise inlined setter
|
||||
// method.)
|
||||
virtual int GetCachedSize() const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
@ -0,0 +1,64 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google {
|
||||
|
||||
// Core components of the Protocol Buffers runtime library.
|
||||
//
|
||||
// The files in this package represent the core of the Protocol Buffer
|
||||
// system. All of them are part of the libprotobuf library.
|
||||
//
|
||||
// A note on thread-safety:
|
||||
//
|
||||
// Thread-safety in the Protocol Buffer library follows a simple rule:
|
||||
// unless explicitly noted otherwise, it is always safe to use an object
|
||||
// from multiple threads simultaneously as long as the object is declared
|
||||
// const in all threads (or, it is only used in ways that would be allowed
|
||||
// if it were declared const). However, if an object is accessed in one
|
||||
// thread in a way that would not be allowed if it were const, then it is
|
||||
// not safe to access that object in any other thread simultaneously.
|
||||
//
|
||||
// Put simply, read-only access to an object can happen in multiple threads
|
||||
// simultaneously, but write access can only happen in a single thread at
|
||||
// a time.
|
||||
//
|
||||
// The implementation does contain some "const" methods which actually modify
|
||||
// the object behind the scenes -- e.g., to cache results -- but in these cases
|
||||
// mutex locking is used to make the access thread-safe.
|
||||
namespace protobuf {}
|
||||
} // namespace google
|
@ -0,0 +1,262 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
void ReflectionOps::Copy(const Message& from, Message* to) {
|
||||
if (&from == to) return;
|
||||
Clear(to);
|
||||
Merge(from, to);
|
||||
}
|
||||
|
||||
void ReflectionOps::Merge(const Message& from, Message* to) {
|
||||
GOOGLE_CHECK_NE(&from, to);
|
||||
|
||||
const Descriptor* descriptor = from.GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
|
||||
<< "Tried to merge messages of different types.";
|
||||
|
||||
const Reflection* from_reflection = from.GetReflection();
|
||||
const Reflection* to_reflection = to->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
from_reflection->ListFields(from, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int count = from_reflection->FieldSize(from, field);
|
||||
for (int j = 0; j < count; j++) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Add##METHOD(to, field, \
|
||||
from_reflection->GetRepeated##METHOD(from, field, j)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->AddMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetRepeatedMessage(from, field, j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Set##METHOD(to, field, \
|
||||
from_reflection->Get##METHOD(from, field)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->MutableMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetMessage(from, field));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_reflection->MutableUnknownFields(to)->MergeFrom(
|
||||
from_reflection->GetUnknownFields(from));
|
||||
}
|
||||
|
||||
void ReflectionOps::Clear(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
reflection->ClearField(message, fields[i]);
|
||||
}
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
}
|
||||
|
||||
bool ReflectionOps::IsInitialized(const Message& message) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that sub-messages are initialized.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!reflection->GetRepeatedMessage(message, field, i)
|
||||
.IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!reflection->GetMessage(message, field).IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReflectionOps::DiscardUnknownFields(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(*message, field);
|
||||
for (int i = 0; i < size; i++) {
|
||||
reflection->MutableRepeatedMessage(message, field, i)
|
||||
->DiscardUnknownFields();
|
||||
}
|
||||
} else {
|
||||
reflection->MutableMessage(message, field)->DiscardUnknownFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string SubMessagePrefix(const string& prefix,
|
||||
const FieldDescriptor* field,
|
||||
int index) {
|
||||
string result(prefix);
|
||||
if (field->is_extension()) {
|
||||
result.append("(");
|
||||
result.append(field->full_name());
|
||||
result.append(")");
|
||||
} else {
|
||||
result.append(field->name());
|
||||
}
|
||||
if (index != -1) {
|
||||
result.append("[");
|
||||
result.append(SimpleItoa(index));
|
||||
result.append("]");
|
||||
}
|
||||
result.append(".");
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReflectionOps::FindInitializationErrors(
|
||||
const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
errors->push_back(prefix + descriptor->field(i)->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check sub-messages.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
const Message& sub_message =
|
||||
reflection->GetRepeatedMessage(message, field, i);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, i),
|
||||
errors);
|
||||
}
|
||||
} else {
|
||||
const Message& sub_message = reflection->GetMessage(message, field);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, -1),
|
||||
errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,80 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
||||
#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Basic operations that can be performed using reflection.
|
||||
// These can be used as a cheap way to implement the corresponding
|
||||
// methods of the Message interface, though they are likely to be
|
||||
// slower than implementations tailored for the specific message type.
|
||||
//
|
||||
// This class should stay limited to operations needed to implement
|
||||
// the Message interface.
|
||||
//
|
||||
// This class is really a namespace that contains only static methods.
|
||||
class LIBPROTOBUF_EXPORT ReflectionOps {
|
||||
public:
|
||||
static void Copy(const Message& from, Message* to);
|
||||
static void Merge(const Message& from, Message* to);
|
||||
static void Clear(Message* message);
|
||||
static bool IsInitialized(const Message& message);
|
||||
static void DiscardUnknownFields(Message* message);
|
||||
|
||||
// Finds all unset required fields in the message and adds their full
|
||||
// paths (e.g. "foo.bar[5].baz") to *names. "prefix" will be attached to
|
||||
// the front of each name.
|
||||
static void FindInitializationErrors(const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors);
|
||||
|
||||
private:
|
||||
// All methods are static. No need to construct.
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
@ -0,0 +1,98 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void RepeatedPtrFieldBase::Reserve(int new_size) {
|
||||
if (total_size_ >= new_size) return;
|
||||
|
||||
void** old_elements = elements_;
|
||||
total_size_ = max(total_size_ * 2, new_size);
|
||||
elements_ = new void*[total_size_];
|
||||
memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
|
||||
if (old_elements != initial_space_) {
|
||||
delete [] old_elements;
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
|
||||
void** swap_elements = elements_;
|
||||
int swap_current_size = current_size_;
|
||||
int swap_allocated_size = allocated_size_;
|
||||
int swap_total_size = total_size_;
|
||||
// We may not be using initial_space_ but it's not worth checking. Just
|
||||
// copy it anyway.
|
||||
void* swap_initial_space[kInitialSize];
|
||||
memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
|
||||
|
||||
elements_ = other->elements_;
|
||||
current_size_ = other->current_size_;
|
||||
allocated_size_ = other->allocated_size_;
|
||||
total_size_ = other->total_size_;
|
||||
memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
|
||||
|
||||
other->elements_ = swap_elements;
|
||||
other->current_size_ = swap_current_size;
|
||||
other->allocated_size_ = swap_allocated_size;
|
||||
other->total_size_ = swap_total_size;
|
||||
memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
|
||||
|
||||
if (elements_ == other->initial_space_) {
|
||||
elements_ = initial_space_;
|
||||
}
|
||||
if (other->elements_ == initial_space_) {
|
||||
other->elements_ = other->initial_space_;
|
||||
}
|
||||
}
|
||||
|
||||
string* StringTypeHandlerBase::New() {
|
||||
return new string;
|
||||
}
|
||||
void StringTypeHandlerBase::Delete(string* value) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,46 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/service.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
Service::~Service() {}
|
||||
RpcChannel::~RpcChannel() {}
|
||||
RpcController::~RpcController() {}
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
@ -0,0 +1,291 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// DEPRECATED: This module declares the abstract interfaces underlying proto2
|
||||
// RPC services. These are intented to be independent of any particular RPC
|
||||
// implementation, so that proto2 services can be used on top of a variety
|
||||
// of implementations. Starting with version 2.3.0, RPC implementations should
|
||||
// not try to build on these, but should instead provide code generator plugins
|
||||
// which generate code specific to the particular RPC implementation. This way
|
||||
// the generated code can be more appropriate for the implementation in use
|
||||
// and can avoid unnecessary layers of indirection.
|
||||
//
|
||||
//
|
||||
// When you use the protocol compiler to compile a service definition, it
|
||||
// generates two classes: An abstract interface for the service (with
|
||||
// methods matching the service definition) and a "stub" implementation.
|
||||
// A stub is just a type-safe wrapper around an RpcChannel which emulates a
|
||||
// local implementation of the service.
|
||||
//
|
||||
// For example, the service definition:
|
||||
// service MyService {
|
||||
// rpc Foo(MyRequest) returns(MyResponse);
|
||||
// }
|
||||
// will generate abstract interface "MyService" and class "MyService::Stub".
|
||||
// You could implement a MyService as follows:
|
||||
// class MyServiceImpl : public MyService {
|
||||
// public:
|
||||
// MyServiceImpl() {}
|
||||
// ~MyServiceImpl() {}
|
||||
//
|
||||
// // implements MyService ---------------------------------------
|
||||
//
|
||||
// void Foo(google::protobuf::RpcController* controller,
|
||||
// const MyRequest* request,
|
||||
// MyResponse* response,
|
||||
// Closure* done) {
|
||||
// // ... read request and fill in response ...
|
||||
// done->Run();
|
||||
// }
|
||||
// };
|
||||
// You would then register an instance of MyServiceImpl with your RPC server
|
||||
// implementation. (How to do that depends on the implementation.)
|
||||
//
|
||||
// To call a remote MyServiceImpl, first you need an RpcChannel connected to it.
|
||||
// How to construct a channel depends, again, on your RPC implementation.
|
||||
// Here we use a hypothentical "MyRpcChannel" as an example:
|
||||
// MyRpcChannel channel("rpc:hostname:1234/myservice");
|
||||
// MyRpcController controller;
|
||||
// MyServiceImpl::Stub stub(&channel);
|
||||
// FooRequest request;
|
||||
// FooRespnose response;
|
||||
//
|
||||
// // ... fill in request ...
|
||||
//
|
||||
// stub.Foo(&controller, request, &response, NewCallback(HandleResponse));
|
||||
//
|
||||
// On Thread-Safety:
|
||||
//
|
||||
// Different RPC implementations may make different guarantees about what
|
||||
// threads they may run callbacks on, and what threads the application is
|
||||
// allowed to use to call the RPC system. Portable software should be ready
|
||||
// for callbacks to be called on any thread, but should not try to call the
|
||||
// RPC system from any thread except for the ones on which it received the
|
||||
// callbacks. Realistically, though, simple software will probably want to
|
||||
// use a single-threaded RPC system while high-end software will want to
|
||||
// use multiple threads. RPC implementations should provide multiple
|
||||
// choices.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_SERVICE_H__
|
||||
#define GOOGLE_PROTOBUF_SERVICE_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Service;
|
||||
class RpcController;
|
||||
class RpcChannel;
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class ServiceDescriptor; // descriptor.h
|
||||
class MethodDescriptor; // descriptor.h
|
||||
class Message; // message.h
|
||||
|
||||
// Abstract base interface for protocol-buffer-based RPC services. Services
|
||||
// themselves are abstract interfaces (implemented either by servers or as
|
||||
// stubs), but they subclass this base interface. The methods of this
|
||||
// interface can be used to call the methods of the Service without knowing
|
||||
// its exact type at compile time (analogous to Reflection).
|
||||
class LIBPROTOBUF_EXPORT Service {
|
||||
public:
|
||||
inline Service() {}
|
||||
virtual ~Service();
|
||||
|
||||
// When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second
|
||||
// parameter to the constructor to tell it to delete its RpcChannel when
|
||||
// destroyed.
|
||||
enum ChannelOwnership {
|
||||
STUB_OWNS_CHANNEL,
|
||||
STUB_DOESNT_OWN_CHANNEL
|
||||
};
|
||||
|
||||
// Get the ServiceDescriptor describing this service and its methods.
|
||||
virtual const ServiceDescriptor* GetDescriptor() = 0;
|
||||
|
||||
// Call a method of the service specified by MethodDescriptor. This is
|
||||
// normally implemented as a simple switch() that calls the standard
|
||||
// definitions of the service's methods.
|
||||
//
|
||||
// Preconditions:
|
||||
// * method->service() == GetDescriptor()
|
||||
// * request and response are of the exact same classes as the objects
|
||||
// returned by GetRequestPrototype(method) and
|
||||
// GetResponsePrototype(method).
|
||||
// * After the call has started, the request must not be modified and the
|
||||
// response must not be accessed at all until "done" is called.
|
||||
// * "controller" is of the correct type for the RPC implementation being
|
||||
// used by this Service. For stubs, the "correct type" depends on the
|
||||
// RpcChannel which the stub is using. Server-side Service
|
||||
// implementations are expected to accept whatever type of RpcController
|
||||
// the server-side RPC implementation uses.
|
||||
//
|
||||
// Postconditions:
|
||||
// * "done" will be called when the method is complete. This may be
|
||||
// before CallMethod() returns or it may be at some point in the future.
|
||||
// * If the RPC succeeded, "response" contains the response returned by
|
||||
// the server.
|
||||
// * If the RPC failed, "response"'s contents are undefined. The
|
||||
// RpcController can be queried to determine if an error occurred and
|
||||
// possibly to get more information about the error.
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
// CallMethod() requires that the request and response passed in are of a
|
||||
// particular subclass of Message. GetRequestPrototype() and
|
||||
// GetResponsePrototype() get the default instances of these required types.
|
||||
// You can then call Message::New() on these instances to construct mutable
|
||||
// objects which you can then pass to CallMethod().
|
||||
//
|
||||
// Example:
|
||||
// const MethodDescriptor* method =
|
||||
// service->GetDescriptor()->FindMethodByName("Foo");
|
||||
// Message* request = stub->GetRequestPrototype (method)->New();
|
||||
// Message* response = stub->GetResponsePrototype(method)->New();
|
||||
// request->ParseFromString(input);
|
||||
// service->CallMethod(method, *request, response, callback);
|
||||
virtual const Message& GetRequestPrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
virtual const Message& GetResponsePrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service);
|
||||
};
|
||||
|
||||
// An RpcController mediates a single method call. The primary purpose of
|
||||
// the controller is to provide a way to manipulate settings specific to the
|
||||
// RPC implementation and to find out about RPC-level errors.
|
||||
//
|
||||
// The methods provided by the RpcController interface are intended to be a
|
||||
// "least common denominator" set of features which we expect all
|
||||
// implementations to support. Specific implementations may provide more
|
||||
// advanced features (e.g. deadline propagation).
|
||||
class LIBPROTOBUF_EXPORT RpcController {
|
||||
public:
|
||||
inline RpcController() {}
|
||||
virtual ~RpcController();
|
||||
|
||||
// Client-side methods ---------------------------------------------
|
||||
// These calls may be made from the client side only. Their results
|
||||
// are undefined on the server side (may crash).
|
||||
|
||||
// Resets the RpcController to its initial state so that it may be reused in
|
||||
// a new call. Must not be called while an RPC is in progress.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// After a call has finished, returns true if the call failed. The possible
|
||||
// reasons for failure depend on the RPC implementation. Failed() must not
|
||||
// be called before a call has finished. If Failed() returns true, the
|
||||
// contents of the response message are undefined.
|
||||
virtual bool Failed() const = 0;
|
||||
|
||||
// If Failed() is true, returns a human-readable description of the error.
|
||||
virtual string ErrorText() const = 0;
|
||||
|
||||
// Advises the RPC system that the caller desires that the RPC call be
|
||||
// canceled. The RPC system may cancel it immediately, may wait awhile and
|
||||
// then cancel it, or may not even cancel the call at all. If the call is
|
||||
// canceled, the "done" callback will still be called and the RpcController
|
||||
// will indicate that the call failed at that time.
|
||||
virtual void StartCancel() = 0;
|
||||
|
||||
// Server-side methods ---------------------------------------------
|
||||
// These calls may be made from the server side only. Their results
|
||||
// are undefined on the client side (may crash).
|
||||
|
||||
// Causes Failed() to return true on the client side. "reason" will be
|
||||
// incorporated into the message returned by ErrorText(). If you find
|
||||
// you need to return machine-readable information about failures, you
|
||||
// should incorporate it into your response protocol buffer and should
|
||||
// NOT call SetFailed().
|
||||
virtual void SetFailed(const string& reason) = 0;
|
||||
|
||||
// If true, indicates that the client canceled the RPC, so the server may
|
||||
// as well give up on replying to it. The server should still call the
|
||||
// final "done" callback.
|
||||
virtual bool IsCanceled() const = 0;
|
||||
|
||||
// Asks that the given callback be called when the RPC is canceled. The
|
||||
// callback will always be called exactly once. If the RPC completes without
|
||||
// being canceled, the callback will be called after completion. If the RPC
|
||||
// has already been canceled when NotifyOnCancel() is called, the callback
|
||||
// will be called immediately.
|
||||
//
|
||||
// NotifyOnCancel() must be called no more than once per request.
|
||||
virtual void NotifyOnCancel(Closure* callback) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController);
|
||||
};
|
||||
|
||||
// Abstract interface for an RPC channel. An RpcChannel represents a
|
||||
// communication line to a Service which can be used to call that Service's
|
||||
// methods. The Service may be running on another machine. Normally, you
|
||||
// should not call an RpcChannel directly, but instead construct a stub Service
|
||||
// wrapping it. Example:
|
||||
// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234");
|
||||
// MyService* service = new MyService::Stub(channel);
|
||||
// service->MyMethod(request, &response, callback);
|
||||
class LIBPROTOBUF_EXPORT RpcChannel {
|
||||
public:
|
||||
inline RpcChannel() {}
|
||||
virtual ~RpcChannel();
|
||||
|
||||
// Call the given method of the remote service. The signature of this
|
||||
// procedure looks the same as Service::CallMethod(), but the requirements
|
||||
// are less strict in one important way: the request and response objects
|
||||
// need not be of any specific class as long as their descriptors are
|
||||
// method->input_type() and method->output_type().
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_SERVICE_H__
|
@ -0,0 +1,377 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf // see comment in strutil.cc
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "No suitable threading library available."
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void VerifyVersion(int headerVersion,
|
||||
int minLibraryVersion,
|
||||
const char* filename) {
|
||||
if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
|
||||
// Library is too old for headers.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program requires version " << VersionString(minLibraryVersion)
|
||||
<< " of the Protocol Buffer runtime library, but the installed version "
|
||||
"is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ". Please update "
|
||||
"your library. If you compiled the program yourself, make sure that "
|
||||
"your headers are from the same version of Protocol Buffers as your "
|
||||
"link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
if (headerVersion < kMinHeaderVersionForLibrary) {
|
||||
// Headers are too old for library.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program was compiled against version "
|
||||
<< VersionString(headerVersion) << " of the Protocol Buffer runtime "
|
||||
"library, which is not compatible with the installed version ("
|
||||
<< VersionString(GOOGLE_PROTOBUF_VERSION) << "). Contact the program "
|
||||
"author for an update. If you compiled the program yourself, make "
|
||||
"sure that your headers are from the same version of Protocol Buffers "
|
||||
"as your link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
}
|
||||
|
||||
string VersionString(int version) {
|
||||
int major = version / 1000000;
|
||||
int minor = (version / 1000) % 1000;
|
||||
int micro = version % 1000;
|
||||
|
||||
// 128 bytes should always be enough, but we use snprintf() anyway to be
|
||||
// safe.
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
|
||||
|
||||
// Guard against broken MSVC snprintf().
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/logging.cc
|
||||
|
||||
namespace internal {
|
||||
|
||||
void DefaultLogHandler(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
|
||||
|
||||
// We use fprintf() instead of cerr because we want this to work at static
|
||||
// initialization time.
|
||||
fprintf(stderr, "libprotobuf %s %s:%d] %s\n",
|
||||
level_names[level], filename, line, message.c_str());
|
||||
fflush(stderr); // Needed on MSVC.
|
||||
}
|
||||
|
||||
void NullLogHandler(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
static LogHandler* log_handler_ = &DefaultLogHandler;
|
||||
static int log_silencer_count_ = 0;
|
||||
|
||||
static Mutex* log_silencer_count_mutex_ = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_);
|
||||
|
||||
void DeleteLogSilencerCount() {
|
||||
delete log_silencer_count_mutex_;
|
||||
log_silencer_count_mutex_ = NULL;
|
||||
}
|
||||
void InitLogSilencerCount() {
|
||||
log_silencer_count_mutex_ = new Mutex;
|
||||
OnShutdown(&DeleteLogSilencerCount);
|
||||
}
|
||||
void InitLogSilencerCountOnce() {
|
||||
GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const string& value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const char* value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Since this is just for logging, we don't care if the current locale changes
|
||||
// the results -- in fact, we probably prefer that. So we use snprintf()
|
||||
// instead of Simple*toa().
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT) \
|
||||
LogMessage& LogMessage::operator<<(TYPE value) { \
|
||||
/* 128 bytes should be big enough for any of the primitive */ \
|
||||
/* values which we print with this, but well use snprintf() */ \
|
||||
/* anyway to be extra safe. */ \
|
||||
char buffer[128]; \
|
||||
snprintf(buffer, sizeof(buffer), FORMAT, value); \
|
||||
/* Guard against broken MSVC snprintf(). */ \
|
||||
buffer[sizeof(buffer)-1] = '\0'; \
|
||||
message_ += buffer; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
DECLARE_STREAM_OPERATOR(char , "%c" )
|
||||
DECLARE_STREAM_OPERATOR(int , "%d" )
|
||||
DECLARE_STREAM_OPERATOR(uint , "%u" )
|
||||
DECLARE_STREAM_OPERATOR(long , "%ld")
|
||||
DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
|
||||
DECLARE_STREAM_OPERATOR(double , "%g" )
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
|
||||
LogMessage::LogMessage(LogLevel level, const char* filename, int line)
|
||||
: level_(level), filename_(filename), line_(line) {}
|
||||
LogMessage::~LogMessage() {}
|
||||
|
||||
void LogMessage::Finish() {
|
||||
bool suppress = false;
|
||||
|
||||
if (level_ != LOGLEVEL_FATAL) {
|
||||
InitLogSilencerCountOnce();
|
||||
MutexLock lock(log_silencer_count_mutex_);
|
||||
suppress = internal::log_silencer_count_ > 0;
|
||||
}
|
||||
|
||||
if (!suppress) {
|
||||
internal::log_handler_(level_, filename_, line_, message_);
|
||||
}
|
||||
|
||||
if (level_ == LOGLEVEL_FATAL) {
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
throw FatalException(filename_, line_, message_);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LogFinisher::operator=(LogMessage& other) {
|
||||
other.Finish();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
LogHandler* SetLogHandler(LogHandler* new_func) {
|
||||
LogHandler* old = internal::log_handler_;
|
||||
if (old == &internal::NullLogHandler) {
|
||||
old = NULL;
|
||||
}
|
||||
if (new_func == NULL) {
|
||||
internal::log_handler_ = &internal::NullLogHandler;
|
||||
} else {
|
||||
internal::log_handler_ = new_func;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
LogSilencer::LogSilencer() {
|
||||
internal::InitLogSilencerCountOnce();
|
||||
MutexLock lock(internal::log_silencer_count_mutex_);
|
||||
++internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
LogSilencer::~LogSilencer() {
|
||||
internal::InitLogSilencerCountOnce();
|
||||
MutexLock lock(internal::log_silencer_count_mutex_);
|
||||
--internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/callback.cc
|
||||
|
||||
Closure::~Closure() {}
|
||||
|
||||
namespace internal { FunctionClosure0::~FunctionClosure0() {} }
|
||||
|
||||
void DoNothing() {}
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/mutex.cc
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct Mutex::Internal {
|
||||
CRITICAL_SECTION mutex;
|
||||
#ifndef NDEBUG
|
||||
// Used only to implement AssertHeld().
|
||||
DWORD thread_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
Mutex::Mutex()
|
||||
: mInternal(new Internal) {
|
||||
InitializeCriticalSection(&mInternal->mutex);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
DeleteCriticalSection(&mInternal->mutex);
|
||||
delete mInternal;
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
EnterCriticalSection(&mInternal->mutex);
|
||||
#ifndef NDEBUG
|
||||
mInternal->thread_id = GetCurrentThreadId();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#ifndef NDEBUG
|
||||
mInternal->thread_id = 0;
|
||||
#endif
|
||||
LeaveCriticalSection(&mInternal->mutex);
|
||||
}
|
||||
|
||||
void Mutex::AssertHeld() {
|
||||
#ifndef NDEBUG
|
||||
GOOGLE_DCHECK_EQ(mInternal->thread_id, GetCurrentThreadId());
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
|
||||
struct Mutex::Internal {
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
Mutex::Mutex()
|
||||
: mInternal(new Internal) {
|
||||
pthread_mutex_init(&mInternal->mutex, NULL);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
pthread_mutex_destroy(&mInternal->mutex);
|
||||
delete mInternal;
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
int result = pthread_mutex_lock(&mInternal->mutex);
|
||||
if (result != 0) {
|
||||
GOOGLE_LOG(FATAL) << "pthread_mutex_lock: " << strerror(result);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
int result = pthread_mutex_unlock(&mInternal->mutex);
|
||||
if (result != 0) {
|
||||
GOOGLE_LOG(FATAL) << "pthread_mutex_unlock: " << strerror(result);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::AssertHeld() {
|
||||
// pthreads dosn't provide a way to check which thread holds the mutex.
|
||||
// TODO(kenton): Maybe keep track of locking thread ID like with WIN32?
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ===================================================================
|
||||
// Shutdown support.
|
||||
|
||||
namespace internal {
|
||||
|
||||
typedef void OnShutdownFunc();
|
||||
vector<void (*)()>* shutdown_functions = NULL;
|
||||
Mutex* shutdown_functions_mutex = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init);
|
||||
|
||||
void InitShutdownFunctions() {
|
||||
shutdown_functions = new vector<void (*)()>;
|
||||
shutdown_functions_mutex = new Mutex;
|
||||
}
|
||||
|
||||
inline void InitShutdownFunctionsOnce() {
|
||||
GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions);
|
||||
}
|
||||
|
||||
void OnShutdown(void (*func)()) {
|
||||
InitShutdownFunctionsOnce();
|
||||
MutexLock lock(shutdown_functions_mutex);
|
||||
shutdown_functions->push_back(func);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
void ShutdownProtobufLibrary() {
|
||||
internal::InitShutdownFunctionsOnce();
|
||||
|
||||
// We don't need to lock shutdown_functions_mutex because it's up to the
|
||||
// caller to make sure that no one is using the library before this is
|
||||
// called.
|
||||
|
||||
// Make it safe to call this multiple times.
|
||||
if (internal::shutdown_functions == NULL) return;
|
||||
|
||||
for (int i = 0; i < internal::shutdown_functions->size(); i++) {
|
||||
internal::shutdown_functions->at(i)();
|
||||
}
|
||||
delete internal::shutdown_functions;
|
||||
internal::shutdown_functions = NULL;
|
||||
delete internal::shutdown_functions_mutex;
|
||||
internal::shutdown_functions_mutex = NULL;
|
||||
}
|
||||
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
FatalException::~FatalException() throw() {}
|
||||
|
||||
const char* FatalException::what() const throw() {
|
||||
return message_.c_str();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,220 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Deals with the fact that hash_map is not defined everywhere.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include "config.h"
|
||||
|
||||
#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
|
||||
#include HASH_MAP_H
|
||||
#include HASH_SET_H
|
||||
#else
|
||||
#define MISSING_HASH
|
||||
#include <map>
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef MISSING_HASH
|
||||
|
||||
// This system doesn't have hash_map or hash_set. Emulate them using map and
|
||||
// set.
|
||||
|
||||
// Make hash<T> be the same as less<T>. Note that everywhere where custom
|
||||
// hash functions are defined in the protobuf code, they are also defined such
|
||||
// that they can be used as "less" functions, which is required by MSVC anyway.
|
||||
template <typename Key>
|
||||
struct hash {
|
||||
// Dummy, just to make derivative hash functions compile.
|
||||
int operator()(const Key& key) {
|
||||
GOOGLE_LOG(FATAL) << "Should never be called.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool operator()(const Key& a, const Key& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
// Make sure char* is compared by value.
|
||||
template <>
|
||||
struct hash<const char*> {
|
||||
// Dummy, just to make derivative hash functions compile.
|
||||
int operator()(const char* key) {
|
||||
GOOGLE_LOG(FATAL) << "Should never be called.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_map : public std::map<Key, Data, HashFcn> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_set : public std::set<Key, HashFcn> {
|
||||
};
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
|
||||
|
||||
template <typename Key>
|
||||
struct hash : public HASH_NAMESPACE::hash_compare<Key> {
|
||||
};
|
||||
|
||||
// MSVC's hash_compare<const char*> hashes based on the string contents but
|
||||
// compares based on the string pointer. WTF?
|
||||
class CstringLess {
|
||||
public:
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<const char*>
|
||||
: public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_map : public HASH_NAMESPACE::hash_map<
|
||||
Key, Data, HashFcn> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_set : public HASH_NAMESPACE::hash_set<
|
||||
Key, HashFcn> {
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <typename Key>
|
||||
struct hash : public HASH_NAMESPACE::hash<Key> {
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct hash<const Key*> {
|
||||
inline size_t operator()(const Key* key) const {
|
||||
return reinterpret_cast<size_t>(key);
|
||||
}
|
||||
};
|
||||
|
||||
// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
|
||||
// we go ahead and provide our own implementation.
|
||||
template <>
|
||||
struct hash<const char*> {
|
||||
inline size_t operator()(const char* str) const {
|
||||
size_t result = 0;
|
||||
for (; *str != '\0'; str++) {
|
||||
result = 5 * result + *str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
|
||||
Key, Data, HashFcn, EqualKey> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
|
||||
Key, HashFcn, EqualKey> {
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct hash<string> {
|
||||
inline size_t operator()(const string& key) const {
|
||||
return hash<const char*>()(key.c_str());
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline size_t operator()(const string& a, const string& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename First, typename Second>
|
||||
struct hash<pair<First, Second> > {
|
||||
inline size_t operator()(const pair<First, Second>& key) const {
|
||||
size_t first_hash = hash<First>()(key.first);
|
||||
size_t second_hash = hash<Second>()(key.second);
|
||||
|
||||
// FIXME(kenton): What is the best way to compute this hash? I have
|
||||
// no idea! This seems a bit better than an XOR.
|
||||
return first_hash * ((1 << 16) - 1) + second_hash;
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline size_t operator()(const pair<First, Second>& a,
|
||||
const pair<First, Second>& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
// Used by GCC/SGI STL only. (Why isn't this provided by the standard
|
||||
// library? :( )
|
||||
struct streq {
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__
|
@ -0,0 +1,119 @@
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/util/gtl/map-util.h
|
||||
// Author: Anton Carver
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present in the map then the value associated with that
|
||||
// key is returned, otherwise the value passed as a default is returned.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type&
|
||||
FindWithDefault(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type*
|
||||
FindOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map whose values are pointers.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
// This function does not distinguish between a missing key and a key mapped
|
||||
// to a NULL value.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type
|
||||
FindPtrOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Change the value associated with a particular key in a map or hash_map.
|
||||
// If the key is not present in the map the key and value are inserted,
|
||||
// otherwise the value is updated to be a copy of the value provided.
|
||||
// True indicates that an insert took place, false indicates an update.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertOrUpdate(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
if (!ret.second) {
|
||||
// update
|
||||
ret.first->second = value;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert a new key and value into a map or hash_map.
|
||||
// If the key is not present in the map the key and value are
|
||||
// inserted, otherwise nothing happens. True indicates that an insert
|
||||
// took place, false indicates the key was already present.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertIfNotPresent(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue