diff options
Diffstat (limited to 'src/google')
143 files changed, 10536 insertions, 6550 deletions
diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0def84d..3413a36 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -43,9 +44,15 @@ namespace compiler { CodeGenerator::~CodeGenerator() {} OutputDirectory::~OutputDirectory() {} +io::ZeroCopyOutputStream* OutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + GOOGLE_LOG(FATAL) << "This OutputDirectory does not support insertion."; + return NULL; // make compiler happy +} + // Parses a set of comma-delimited name/value pairs. void ParseGeneratorParameter(const string& text, - vector<pair<string, string> >* output) { + vector<pair<string, string> >* output) { vector<string> parts; SplitStringUsing(text, ",", &parts); diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index 8a7081f..ea094cd 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -98,11 +98,20 @@ class LIBPROTOC_EXPORT OutputDirectory { // // 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.pb2.h" and "foo/bar.pb2.cc"; note that + // 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); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory); }; @@ -114,7 +123,7 @@ class LIBPROTOC_EXPORT OutputDirectory { // parses to the pairs: // ("foo", "bar"), ("baz", ""), ("qux", "corge") extern void ParseGeneratorParameter(const string&, - vector<pair<string, string> >*); + vector<pair<string, string> >*); } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 3629f68..d3495ca 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -32,6 +32,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/compiler/command_line_interface.h> + #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> @@ -46,15 +48,22 @@ #include <iostream> #include <ctype.h> -#include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/compiler/importer.h> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/plugin.pb.h> +#include <google/protobuf/compiler/subprocess.h> +#include <google/protobuf/compiler/zip_writer.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/text_format.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/stubs/map-util.h> +#include <google/protobuf/stubs/stl_util-inl.h> +#include <google/protobuf/stubs/hash.h> namespace google { @@ -126,6 +135,47 @@ void SetFdToBinaryMode(int fd) { // (Text and binary are the same on non-Windows platforms.) } +void AddTrailingSlash(string* path) { + if (!path->empty() && path->at(path->size() - 1) != '/') { + path->push_back('/'); + } +} + +bool VerifyDirectoryExists(const string& path) { + if (path.empty()) return true; + + if (access(path.c_str(), W_OK) == -1) { + cerr << path << ": " << strerror(errno) << endl; + return false; + } else { + return true; + } +} + +// Try to create the parent directory of the given file, creating the parent's +// parent if necessary, and so on. The full file name is actually +// (prefix + filename), but we assume |prefix| already exists and only create +// directories listed in |filename|. +bool TryCreateParentDirectory(const string& prefix, const string& filename) { + // Recursively create parent directories to the output file. + vector<string> parts; + SplitStringUsing(filename, "/", &parts); + string path_so_far = prefix; + for (int i = 0; i < parts.size() - 1; i++) { + path_so_far += parts[i]; + if (mkdir(path_so_far.c_str(), 0777) != 0) { + if (errno != EEXIST) { + cerr << filename << ": while trying to create directory " + << path_so_far << ": " << strerror(errno) << endl; + return false; + } + } + path_so_far += '/'; + } + + return true; +} + } // namespace // A MultiFileErrorCollector that prints errors to stderr. @@ -169,72 +219,142 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, // ------------------------------------------------------------------- -// An OutputDirectory implementation that writes to disk. -class CommandLineInterface::DiskOutputDirectory : public OutputDirectory { +// An OutputDirectory implementation that buffers files in memory, then dumps +// them all to disk on demand. +class CommandLineInterface::MemoryOutputDirectory : public OutputDirectory { public: - DiskOutputDirectory(const string& root); - ~DiskOutputDirectory(); + MemoryOutputDirectory(); + ~MemoryOutputDirectory(); + + // Write all files in the directory to disk at the given output location, + // which must end in a '/'. + bool WriteAllToDisk(const string& prefix); - bool VerifyExistence(); + // Write the contents of this directory to a ZIP-format archive with the + // given name. + bool WriteAllToZip(const string& filename); - inline bool had_error() { return had_error_; } - inline void set_had_error(bool value) { had_error_ = value; } + // Add a boilerplate META-INF/MANIFEST.MF file as required by the Java JAR + // format, unless one has already been written. + void AddJarManifest(); // implements OutputDirectory -------------------------------------- io::ZeroCopyOutputStream* Open(const string& filename); + io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); private: - string root_; + friend class MemoryOutputStream; + + // map instead of hash_map so that files are written in order (good when + // writing zips). + map<string, string*> files_; bool had_error_; }; -// A FileOutputStream that checks for errors in the destructor and reports -// them. We extend FileOutputStream via wrapping rather than inheritance -// for two reasons: -// 1) Implementation inheritance is evil. -// 2) We need to close the file descriptor *after* the FileOutputStream's -// destructor is run to make sure it flushes the file contents. -class CommandLineInterface::ErrorReportingFileOutput +class CommandLineInterface::MemoryOutputStream : public io::ZeroCopyOutputStream { public: - ErrorReportingFileOutput(int file_descriptor, - const string& filename, - DiskOutputDirectory* directory); - ~ErrorReportingFileOutput(); + MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename); + MemoryOutputStream(MemoryOutputDirectory* directory, const string& filename, + const string& insertion_point); + virtual ~MemoryOutputStream(); // implements ZeroCopyOutputStream --------------------------------- - bool Next(void** data, int* size) { return file_stream_->Next(data, size); } - void BackUp(int count) { file_stream_->BackUp(count); } - int64 ByteCount() const { return file_stream_->ByteCount(); } + virtual bool Next(void** data, int* size) { return inner_->Next(data, size); } + virtual void BackUp(int count) { inner_->BackUp(count); } + virtual int64 ByteCount() const { return inner_->ByteCount(); } private: - scoped_ptr<io::FileOutputStream> file_stream_; - int file_descriptor_; + // Where to insert the string when it's done. + MemoryOutputDirectory* directory_; string filename_; - DiskOutputDirectory* directory_; + string insertion_point_; + + // The string we're building. + string data_; + + // StringOutputStream writing to data_. + scoped_ptr<io::StringOutputStream> inner_; }; // ------------------------------------------------------------------- -CommandLineInterface::DiskOutputDirectory::DiskOutputDirectory( - const string& root) - : root_(root), had_error_(false) { - // Add a '/' to the end if it doesn't already have one. But don't add a - // '/' to an empty string since this probably means the current directory. - if (!root_.empty() && root[root_.size() - 1] != '/') { - root_ += '/'; - } -} +CommandLineInterface::MemoryOutputDirectory::MemoryOutputDirectory() + : had_error_(false) {} -CommandLineInterface::DiskOutputDirectory::~DiskOutputDirectory() { +CommandLineInterface::MemoryOutputDirectory::~MemoryOutputDirectory() { + STLDeleteValues(&files_); } -bool CommandLineInterface::DiskOutputDirectory::VerifyExistence() { - if (!root_.empty()) { - // Make sure the directory exists. If it isn't a directory, this will fail - // because we added a '/' to the end of the name in the constructor. - if (access(root_.c_str(), W_OK) == -1) { - cerr << root_ << ": " << strerror(errno) << endl; +bool CommandLineInterface::MemoryOutputDirectory::WriteAllToDisk( + const string& prefix) { + if (had_error_) { + return false; + } + + if (!VerifyDirectoryExists(prefix)) { + return false; + } + + for (map<string, string*>::const_iterator iter = files_.begin(); + iter != files_.end(); ++iter) { + const string& relative_filename = iter->first; + const char* data = iter->second->data(); + int size = iter->second->size(); + + if (!TryCreateParentDirectory(prefix, relative_filename)) { + return false; + } + string filename = prefix + relative_filename; + + // Create the output file. + int file_descriptor; + do { + file_descriptor = + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (file_descriptor < 0 && errno == EINTR); + + if (file_descriptor < 0) { + int error = errno; + cerr << filename << ": " << strerror(error); + return false; + } + + // Write the file. + while (size > 0) { + int write_result; + do { + write_result = write(file_descriptor, data, size); + } while (write_result < 0 && errno == EINTR); + + if (write_result <= 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 (write_result < 0) { + int error = errno; + cerr << filename << ": write: " << strerror(error); + } else { + cerr << filename << ": write() returned zero?" << endl; + } + return false; + } + + data += write_result; + size -= write_result; + } + + if (close(file_descriptor) != 0) { + int error = errno; + cerr << filename << ": close: " << strerror(error); return false; } } @@ -242,65 +362,183 @@ bool CommandLineInterface::DiskOutputDirectory::VerifyExistence() { return true; } -io::ZeroCopyOutputStream* CommandLineInterface::DiskOutputDirectory::Open( +bool CommandLineInterface::MemoryOutputDirectory::WriteAllToZip( const string& filename) { - // Recursively create parent directories to the output file. - vector<string> parts; - SplitStringUsing(filename, "/", &parts); - string path_so_far = root_; - for (int i = 0; i < parts.size() - 1; i++) { - path_so_far += parts[i]; - if (mkdir(path_so_far.c_str(), 0777) != 0) { - if (errno != EEXIST) { - cerr << filename << ": while trying to create directory " - << path_so_far << ": " << strerror(errno) << endl; - had_error_ = true; - // Return a dummy stream. - return new io::ArrayOutputStream(NULL, 0); - } - } - path_so_far += '/'; + if (had_error_) { + return false; } // Create the output file. int file_descriptor; do { file_descriptor = - open((root_ + filename).c_str(), - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); } while (file_descriptor < 0 && errno == EINTR); if (file_descriptor < 0) { - // Failed to open. - cerr << filename << ": " << strerror(errno) << endl; - had_error_ = true; - // Return a dummy stream. - return new io::ArrayOutputStream(NULL, 0); + int error = errno; + cerr << filename << ": " << strerror(error); + return false; } - return new ErrorReportingFileOutput(file_descriptor, filename, this); -} + // Create the ZipWriter + io::FileOutputStream stream(file_descriptor); + ZipWriter zip_writer(&stream); + + for (map<string, string*>::const_iterator iter = files_.begin(); + iter != files_.end(); ++iter) { + zip_writer.Write(iter->first, *iter->second); + } + + zip_writer.WriteDirectory(); + + if (stream.GetErrno() != 0) { + cerr << filename << ": " << strerror(stream.GetErrno()) << endl; + } -CommandLineInterface::ErrorReportingFileOutput::ErrorReportingFileOutput( - int file_descriptor, - const string& filename, - DiskOutputDirectory* directory) - : file_stream_(new io::FileOutputStream(file_descriptor)), - file_descriptor_(file_descriptor), - filename_(filename), - directory_(directory) {} + if (!stream.Close()) { + cerr << filename << ": " << strerror(stream.GetErrno()) << endl; + } + + return true; +} -CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() { - // Check if we had any errors while writing. - if (file_stream_->GetErrno() != 0) { - cerr << filename_ << ": " << strerror(file_stream_->GetErrno()) << endl; - directory_->set_had_error(true); +void CommandLineInterface::MemoryOutputDirectory::AddJarManifest() { + string** map_slot = &files_["META-INF/MANIFEST.MF"]; + if (*map_slot == NULL) { + *map_slot = new string( + "Manifest-Version: 1.0\n" + "Created-By: 1.6.0 (protoc)\n" + "\n"); } +} + +io::ZeroCopyOutputStream* CommandLineInterface::MemoryOutputDirectory::Open( + const string& filename) { + return new MemoryOutputStream(this, filename); +} + +io::ZeroCopyOutputStream* +CommandLineInterface::MemoryOutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + return new MemoryOutputStream(this, filename, insertion_point); +} + +// ------------------------------------------------------------------- + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + MemoryOutputDirectory* directory, const string& filename) + : directory_(directory), + filename_(filename), + inner_(new io::StringOutputStream(&data_)) { +} + +CommandLineInterface::MemoryOutputStream::MemoryOutputStream( + MemoryOutputDirectory* directory, const string& filename, + const string& insertion_point) + : directory_(directory), + filename_(filename), + insertion_point_(insertion_point), + inner_(new io::StringOutputStream(&data_)) { +} + +CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { + // Make sure all data has been written. + inner_.reset(); - // Close the file stream. - if (!file_stream_->Close()) { - cerr << filename_ << ": " << strerror(file_stream_->GetErrno()) << endl; - directory_->set_had_error(true); + // Insert into the directory. + string** map_slot = &directory_->files_[filename_]; + + if (insertion_point_.empty()) { + // This was just a regular Open(). + if (*map_slot != NULL) { + cerr << filename_ << ": Tried to write the same file twice." << endl; + directory_->had_error_ = true; + return; + } + + *map_slot = new string; + (*map_slot)->swap(data_); + } else { + // This was an OpenForInsert(). + + // If the data doens't end with a clean line break, add one. + if (!data_.empty() && data_[data_.size() - 1] != '\n') { + data_.push_back('\n'); + } + + // Find the file we are going to insert into. + if (*map_slot == NULL) { + cerr << filename_ << ": Tried to insert into file that doesn't exist." + << endl; + directory_->had_error_ = true; + return; + } + string* target = *map_slot; + + // Find the insertion point. + string magic_string = strings::Substitute( + "@@protoc_insertion_point($0)", insertion_point_); + string::size_type pos = target->find(magic_string); + + if (pos == string::npos) { + cerr << filename_ << ": insertion point \"" << insertion_point_ + << "\" not found." << endl; + directory_->had_error_ = true; + return; + } + + // Seek backwards to the beginning of the line, which is where we will + // insert the data. Note that this has the effect of pushing the insertion + // point down, so the data is inserted before it. This is intentional + // because it means that multiple insertions at the same point will end + // up in the expected order in the final output. + pos = target->find_last_of('\n', pos); + if (pos == string::npos) { + // Insertion point is on the first line. + pos = 0; + } else { + // Advance to character after '\n'. + ++pos; + } + + // Extract indent. + string indent_(*target, pos, target->find_first_not_of(" \t", pos) - pos); + + if (indent_.empty()) { + // No indent. This makes things easier. + target->insert(pos, data_); + } else { + // Calculate how much space we need. + int indent_size = 0; + for (int i = 0; i < data_.size(); i++) { + if (data_[i] == '\n') indent_size += indent_.size(); + } + + // Make a hole for it. + target->insert(pos, data_.size() + indent_size, '\0'); + + // Now copy in the data. + string::size_type data_pos = 0; + char* target_ptr = string_as_array(target) + pos; + while (data_pos < data_.size()) { + // Copy indent. + memcpy(target_ptr, indent_.data(), indent_.size()); + target_ptr += indent_.size(); + + // Copy line from data_. + // We already guaranteed that data_ ends with a newline (above), so this + // search can't fail. + string::size_type line_length = + data_.find_first_of('\n', data_pos) + 1 - data_pos; + memcpy(target_ptr, data_.data() + data_pos, line_length); + target_ptr += line_length; + data_pos += line_length; + } + + GOOGLE_CHECK_EQ(target_ptr, + string_as_array(target) + pos + data_.size() + indent_size); + } } } @@ -323,6 +561,10 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name, generators_[flag_name] = info; } +void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) { + plugin_prefix_ = exe_name_prefix; +} + int CommandLineInterface::Run(int argc, const char* const argv[]) { Clear(); if (!ParseArguments(argc, argv)) return 1; @@ -346,7 +588,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { vector<const FileDescriptor*> parsed_files; - // Parse each file and generate output. + // Parse each file. for (int i = 0; i < input_files_.size(); i++) { // Import the file. const FileDescriptor* parsed_file = importer.Import(input_files_[i]); @@ -359,17 +601,60 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { "--disallow_services was used." << endl; return 1; } + } + + // We construct a separate OutputDirectory for each output location. Note + // that two code generators may output to the same location, in which case + // they should share a single OutputDirectory (so that OpenForInsert() works). + typedef hash_map<string, MemoryOutputDirectory*> OutputDirectoryMap; + OutputDirectoryMap output_directories; + + // Generate output. + if (mode_ == MODE_COMPILE) { + for (int i = 0; i < output_directives_.size(); i++) { + string output_location = output_directives_[i].output_location; + if (!HasSuffixString(output_location, ".zip") && + !HasSuffixString(output_location, ".jar")) { + AddTrailingSlash(&output_location); + } + MemoryOutputDirectory** map_slot = &output_directories[output_location]; + + if (*map_slot == NULL) { + // First time we've seen this output location. + *map_slot = new MemoryOutputDirectory; + } + + if (!GenerateOutput(parsed_files, output_directives_[i], *map_slot)) { + STLDeleteValues(&output_directories); + return 1; + } + } + } - if (mode_ == MODE_COMPILE) { - // Generate output files. - for (int i = 0; i < output_directives_.size(); i++) { - if (!GenerateOutput(parsed_file, output_directives_[i])) { - return 1; - } + // Write all output to disk. + for (OutputDirectoryMap::iterator iter = output_directories.begin(); + iter != output_directories.end(); ++iter) { + const string& location = iter->first; + MemoryOutputDirectory* directory = iter->second; + if (HasSuffixString(location, "/")) { + if (!directory->WriteAllToDisk(location)) { + STLDeleteValues(&output_directories); + return 1; + } + } else { + if (HasSuffixString(location, ".jar")) { + directory->AddJarManifest(); + } + + if (!directory->WriteAllToZip(location)) { + STLDeleteValues(&output_directories); + return 1; } } } + STLDeleteValues(&output_directories); + if (!descriptor_set_name_.empty()) { if (!WriteDescriptorSet(parsed_files)) { return 1; @@ -439,7 +724,11 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative( } else { cerr << input_files_[i] << ": File does not reside within any path " "specified using --proto_path (or -I). You must specify a " - "--proto_path which encompasses this file." << endl; + "--proto_path which encompasses this file. Note that the " + "proto_path must be an exact prefix of the .proto file " + "names -- protoc is too dumb to figure out when two paths " + "(e.g. absolute and relative) are equivalent (it's harder " + "than you think)." << endl; } return false; } @@ -682,10 +971,37 @@ bool CommandLineInterface::InterpretArgument(const string& name, return false; } + } else if (name == "--plugin") { + if (plugin_prefix_.empty()) { + cerr << "This compiler does not support plugins." << endl; + return false; + } + + string name; + string path; + + string::size_type equals_pos = value.find_first_of('='); + if (equals_pos == string::npos) { + // Use the basename of the file. + string::size_type slash_pos = value.find_last_of('/'); + if (slash_pos == string::npos) { + name = value; + } else { + name = value.substr(slash_pos + 1); + } + path = value; + } else { + name = value.substr(0, equals_pos); + path = value.substr(equals_pos + 1); + } + + plugins_[name] = path; + } else { // Some other flag. Look it up in the generators list. - GeneratorMap::const_iterator iter = generators_.find(name); - if (iter == generators_.end()) { + const GeneratorInfo* generator_info = FindOrNull(generators_, name); + if (generator_info == NULL && + (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { cerr << "Unknown flag: " << name << endl; return false; } @@ -699,7 +1015,11 @@ bool CommandLineInterface::InterpretArgument(const string& name, OutputDirective directive; directive.name = name; - directive.generator = iter->second.generator; + if (generator_info == NULL) { + directive.generator = NULL; + } else { + directive.generator = generator_info->generator; + } // Split value at ':' to separate the generator parameter from the // filename. However, avoid doing this if the colon is part of a valid @@ -751,6 +1071,17 @@ void CommandLineInterface::PrintHelpText() { " --error_format=FORMAT Set the format in which to print errors.\n" " FORMAT may be 'gcc' (the default) or 'msvs'\n" " (Microsoft Visual Studio format)." << endl; + if (!plugin_prefix_.empty()) { + cerr << +" --plugin=EXECUTABLE Specifies a plugin executable to use.\n" +" Normally, protoc searches the PATH for\n" +" plugins, but you may specify additional\n" +" executables not in the path using this flag.\n" +" Additionally, EXECUTABLE may be of the form\n" +" NAME=PATH, in which case the given plugin name\n" +" is mapped to the given executable even if\n" +" the executable's own name differs." << endl; + } for (GeneratorMap::iterator iter = generators_.begin(); iter != generators_.end(); ++iter) { @@ -764,28 +1095,116 @@ void CommandLineInterface::PrintHelpText() { } bool CommandLineInterface::GenerateOutput( - const FileDescriptor* parsed_file, - const OutputDirective& output_directive) { - // Create the output directory. - DiskOutputDirectory output_directory(output_directive.output_location); - if (!output_directory.VerifyExistence()) { - return false; + const vector<const FileDescriptor*>& parsed_files, + const OutputDirective& output_directive, + OutputDirectory* output_directory) { + // Call the generator. + string error; + if (output_directive.generator == NULL) { + // This is a plugin. + GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && + HasSuffixString(output_directive.name, "_out")) + << "Bad name for plugin generator: " << output_directive.name; + + // Strip the "--" and "_out" and add the plugin prefix. + string plugin_name = plugin_prefix_ + "gen-" + + output_directive.name.substr(2, output_directive.name.size() - 6); + + if (!GeneratePluginOutput(parsed_files, plugin_name, + output_directive.parameter, + output_directory, &error)) { + cerr << output_directive.name << ": " << error << endl; + return false; + } + } else { + // Regular generator. + for (int i = 0; i < parsed_files.size(); i++) { + if (!output_directive.generator->Generate( + parsed_files[i], output_directive.parameter, + output_directory, &error)) { + // Generator returned an error. + cerr << output_directive.name << ": " << parsed_files[i]->name() << ": " + << error << endl; + return false; + } + } } - // Opened successfully. Write it. + return true; +} - // Call the generator. - string error; - if (!output_directive.generator->Generate( - parsed_file, output_directive.parameter, &output_directory, &error)) { - // Generator returned an error. - cerr << parsed_file->name() << ": " << output_directive.name << ": " - << error << endl; +bool CommandLineInterface::GeneratePluginOutput( + const vector<const FileDescriptor*>& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error) { + CodeGeneratorRequest request; + CodeGeneratorResponse response; + + // Build the request. + if (!parameter.empty()) { + request.set_parameter(parameter); + } + + set<const FileDescriptor*> already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + request.add_file_to_generate(parsed_files[i]->name()); + GetTransitiveDependencies(parsed_files[i], &already_seen, + request.mutable_proto_file()); + } + + // Invoke the plugin. + Subprocess subprocess; + + if (plugins_.count(plugin_name) > 0) { + subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME); + } else { + subprocess.Start(plugin_name, Subprocess::SEARCH_PATH); + } + + string communicate_error; + if (!subprocess.Communicate(request, &response, &communicate_error)) { + *error = strings::Substitute("$0: $1", plugin_name, communicate_error); return false; } - // Check for write errors. - if (output_directory.had_error()) { + // Write the files. We do this even if there was a generator error in order + // to match the behavior of a compiled-in generator. + scoped_ptr<io::ZeroCopyOutputStream> current_output; + for (int i = 0; i < response.file_size(); i++) { + const CodeGeneratorResponse::File& output_file = response.file(i); + + if (!output_file.insertion_point().empty()) { + // Open a file for insert. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->OpenForInsert( + output_file.name(), output_file.insertion_point())); + } else if (!output_file.name().empty()) { + // Starting a new file. Open it. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->Open(output_file.name())); + } else if (current_output == NULL) { + *error = strings::Substitute( + "$0: First file chunk returned by plugin did not specify a file name.", + plugin_name); + return false; + } + + // Use CodedOutputStream for convenience; otherwise we'd need to provide + // our own buffer-copying loop. + io::CodedOutputStream writer(current_output.get()); + writer.WriteString(output_file.content()); + } + + // Check for errors. + if (!response.error().empty()) { + // Generator returned an error. + *error = response.error(); return false; } @@ -858,22 +1277,16 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { bool CommandLineInterface::WriteDescriptorSet( const vector<const FileDescriptor*> parsed_files) { FileDescriptorSet file_set; - set<const FileDescriptor*> already_added; - vector<const FileDescriptor*> to_add(parsed_files); - - while (!to_add.empty()) { - const FileDescriptor* file = to_add.back(); - to_add.pop_back(); - if (already_added.insert(file).second) { - // This file was not already in the set. - file->CopyTo(file_set.add_file()); - - if (imports_in_descriptor_set_) { - // Add all of this file's dependencies. - for (int i = 0; i < file->dependency_count(); i++) { - to_add.push_back(file->dependency(i)); - } - } + + if (imports_in_descriptor_set_) { + set<const FileDescriptor*> already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies( + parsed_files[i], &already_seen, file_set.mutable_file()); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + parsed_files[i]->CopyTo(file_set.add_file()); } } @@ -902,6 +1315,24 @@ bool CommandLineInterface::WriteDescriptorSet( return true; } +void CommandLineInterface::GetTransitiveDependencies( + const FileDescriptor* file, + set<const FileDescriptor*>* already_seen, + RepeatedPtrField<FileDescriptorProto>* output) { + if (!already_seen->insert(file).second) { + // Already saw this file. Skip. + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + GetTransitiveDependencies(file->dependency(i), already_seen, output); + } + + // Add this file. + file->CopyTo(output->Add()); +} + } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index ec65863..d25a50e 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -50,10 +50,13 @@ 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 OutputDirectory; // code_generator.h class DiskSourceTree; // importer.h // This class implements the command-line interface to the protocol compiler. @@ -109,6 +112,37 @@ class LIBPROTOC_EXPORT CommandLineInterface { 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(). // @@ -140,8 +174,8 @@ class LIBPROTOC_EXPORT CommandLineInterface { // ----------------------------------------------------------------- class ErrorPrinter; - class DiskOutputDirectory; - class ErrorReportingFileOutput; + class MemoryOutputDirectory; + class MemoryOutputStream; // Clear state from previous Run(). void Clear(); @@ -176,8 +210,14 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Generate the given output file from the given input. struct OutputDirective; // see below - bool GenerateOutput(const FileDescriptor* proto_file, - const OutputDirective& output_directive); + bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files, + const OutputDirective& output_directive, + OutputDirectory* output_directory); + bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error); // Implements --encode and --decode. bool EncodeOrDecode(const DescriptorPool* pool); @@ -185,6 +225,17 @@ class LIBPROTOC_EXPORT CommandLineInterface { // 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]). @@ -201,6 +252,14 @@ class LIBPROTOC_EXPORT CommandLineInterface { 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. @@ -223,8 +282,8 @@ class LIBPROTOC_EXPORT CommandLineInterface { // output_directives_ lists all the files we are supposed to output and what // generator to use for each. struct OutputDirective { - string name; - CodeGenerator* generator; + string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins string parameter; string output_location; }; diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 719771e..9129ebf 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -47,10 +47,12 @@ #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/compiler/command_line_interface.h> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/mock_code_generator.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/unittest.pb.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -66,6 +68,9 @@ namespace compiler { #ifndef STDOUT_FILENO #define STDOUT_FILENO 1 #endif +#ifndef F_OK +#define F_OK 00 // not defined by MSVC for whatever reason +#endif #endif namespace { @@ -83,28 +88,19 @@ class CommandLineInterfaceTest : public testing::Test { // ----------------------------------------------------------------- // Methods to set up the test (called before Run()). - class MockCodeGenerator; class NullCodeGenerator; - // Registers a MockCodeGenerator with the given name. - MockCodeGenerator* RegisterGenerator(const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text); - MockCodeGenerator* RegisterErrorGenerator(const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename, - const string& help_text); - - // Registers a CodeGenerator which will not actually generate anything, - // but records the parameter passed to the generator. - NullCodeGenerator* RegisterNullGenerator(const string& flag_name); + // Normally plugins are allowed for all tests. Call this to explicitly + // disable them. + void DisallowPlugins() { disallow_plugins_ = true; } // Create a temp file within temp_directory_ with the given name. // The containing directory is also created if necessary. void CreateTempFile(const string& name, const string& contents); + // Create a subdirectory within temp_directory_. + void CreateTempDir(const string& name); + void SetInputsAreProtoPathRelative(bool enable) { cli_.SetInputsAreProtoPathRelative(enable); } @@ -130,7 +126,8 @@ class CommandLineInterfaceTest : public testing::Test { bool HasAlternateErrorSubstring(const string& expected_substring); // Checks that MockCodeGenerator::Generate() was called in the given - // context. That is, this tests if the generator with the given name + // context (or the generator in test_plugin.cc, which produces the same + // output). That is, this tests if the generator with the given name // was called with the given parameter and proto file and produced the // given output file. This is checked by reading the output file and // checking that it contains the content that MockCodeGenerator would @@ -140,8 +137,19 @@ class CommandLineInterfaceTest : public testing::Test { void ExpectGenerated(const string& generator_name, const string& parameter, const string& proto_name, + const string& message_name); + void ExpectGenerated(const string& generator_name, + const string& parameter, + const string& proto_name, const string& message_name, - const string& output_file); + const string& output_directory); + void ExpectGeneratedWithInsertions(const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name); + + void ExpectNullCodeGeneratorCalled(const string& parameter); void ReadDescriptorSet(const string& filename, FileDescriptorSet* descriptor_set); @@ -150,6 +158,9 @@ class CommandLineInterfaceTest : public testing::Test { // The object we are testing. CommandLineInterface cli_; + // Was DisallowPlugins() called? + bool disallow_plugins_; + // We create a directory within TestTempDir() in order to add extra // protection against accidentally deleting user files (since we recursively // delete this directory during the test). This is the full path of that @@ -164,40 +175,8 @@ class CommandLineInterfaceTest : public testing::Test { // Pointers which need to be deleted later. vector<CodeGenerator*> mock_generators_to_delete_; -}; - -// A mock CodeGenerator which outputs information about the context in which -// it was called, which can then be checked. Output is written to a filename -// constructed by concatenating the filename_prefix (given to the constructor) -// with the proto file name, separated by a '.'. -class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator { - public: - // Create a MockCodeGenerator whose Generate() method returns true. - MockCodeGenerator(const string& name, const string& filename_prefix); - - // Create a MockCodeGenerator whose Generate() method returns false - // and sets the error string to the given string. - MockCodeGenerator(const string& name, const string& filename_prefix, - const string& error); - - ~MockCodeGenerator(); - - void set_expect_write_error(bool value) { - expect_write_error_ = value; - } - // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const; - - private: - string name_; - string filename_prefix_; - bool return_error_; - string error_; - bool expect_write_error_; + NullCodeGenerator* null_generator_; }; class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { @@ -237,6 +216,22 @@ void CommandLineInterfaceTest::SetUp() { // Create the temp directory. GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE)); + + // Register generators. + CodeGenerator* generator = new MockCodeGenerator("test_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--test_out", generator, "Test output."); + cli_.RegisterGenerator("-t", generator, "Test output."); + + generator = new MockCodeGenerator("alt_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--alt_out", generator, "Alt output."); + + generator = null_generator_ = new NullCodeGenerator(); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--null_out", generator, "Null output."); + + disallow_plugins_ = false; } void CommandLineInterfaceTest::TearDown() { @@ -254,6 +249,44 @@ void CommandLineInterfaceTest::Run(const string& command) { vector<string> args; SplitStringUsing(command, " ", &args); + if (!disallow_plugins_) { + cli_.AllowPlugins("prefix-"); + + const char* possible_paths[] = { + // When building with shared libraries, libtool hides the real executable + // in .libs and puts a fake wrapper in the current directory. + // Unfortunately, due to an apparent bug on Cygwin/MinGW, if one program + // wrapped in this way (e.g. protobuf-tests.exe) tries to execute another + // program wrapped in this way (e.g. test_plugin.exe), the latter fails + // with error code 127 and no explanation message. Presumably the problem + // is that the wrapper for protobuf-tests.exe set some environment + // variables that confuse the wrapper for test_plugin.exe. Luckily, it + // turns out that if we simply invoke the wrapped test_plugin.exe + // directly, it works -- I guess the environment variables set by the + // protobuf-tests.exe wrapper happen to be correct for it too. So we do + // that. + ".libs/test_plugin.exe", // Win32 w/autotool (Cygwin / MinGW) + "test_plugin.exe", // Other Win32 (MSVC) + "test_plugin", // Unix + }; + + string plugin_path; + + for (int i = 0; i < GOOGLE_ARRAYSIZE(possible_paths); i++) { + if (access(possible_paths[i], F_OK) == 0) { + plugin_path = possible_paths[i]; + break; + } + } + + if (plugin_path.empty()) { + GOOGLE_LOG(ERROR) + << "Plugin executable not found. Plugin tests are likely to fail."; + } else { + args.push_back("--plugin=prefix-gen-plug=" + plugin_path); + } + } + scoped_array<const char*> argv(new const char*[args.size()]); for (int i = 0; i < args.size(); i++) { @@ -270,44 +303,6 @@ void CommandLineInterfaceTest::Run(const string& command) { // ------------------------------------------------------------------- -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterGenerator( - const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterErrorGenerator( - const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename_prefix, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename_prefix, error_text); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::NullCodeGenerator* -CommandLineInterfaceTest::RegisterNullGenerator( - const string& flag_name) { - NullCodeGenerator* generator = new NullCodeGenerator; - mock_generators_to_delete_.push_back(generator); - cli_.RegisterGenerator(flag_name, generator, ""); - return generator; -} - void CommandLineInterfaceTest::CreateTempFile( const string& name, const string& contents) { @@ -323,6 +318,10 @@ void CommandLineInterfaceTest::CreateTempFile( File::WriteStringToFileOrDie(contents, full_name); } +void CommandLineInterfaceTest::CreateTempDir(const string& name) { + File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777); +} + // ------------------------------------------------------------------- void CommandLineInterfaceTest::ExpectNoErrors() { @@ -352,21 +351,37 @@ void CommandLineInterfaceTest::ExpectGenerated( const string& generator_name, const string& parameter, const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, temp_directory_); +} + +void CommandLineInterfaceTest::ExpectGenerated( + const string& generator_name, + const string& parameter, + const string& proto_name, const string& message_name, - const string& output_file_prefix) { - // Open and read the file. - string output_file = output_file_prefix + "." + proto_name; - string file_contents; - ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file, - &file_contents)) - << "Failed to open file: " + output_file; + const string& output_directory) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, + temp_directory_ + "/" + output_directory); +} - // Check that the contents are as we expect. - string expected_contents = - generator_name + ": " + parameter + ", " + proto_name + ", " + - message_name + "\n"; - EXPECT_EQ(expected_contents, file_contents) - << "Output file did not have expected contents: " + output_file; +void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( + const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, insertions, proto_name, message_name, + temp_directory_); +} + +void CommandLineInterfaceTest::ExpectNullCodeGeneratorCalled( + const string& parameter) { + EXPECT_TRUE(null_generator_->called_); + EXPECT_EQ(parameter, null_generator_->parameter_); } void CommandLineInterfaceTest::ReadDescriptorSet( @@ -383,77 +398,52 @@ void CommandLineInterfaceTest::ReadDescriptorSet( // =================================================================== -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(false), - expect_write_error_(false) { -} - -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix, const string& error) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(true), - error_(error), - expect_write_error_(false) { -} +TEST_F(CommandLineInterfaceTest, BasicOutput) { + // Test that the common case works. -CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {} + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); -bool CommandLineInterfaceTest::MockCodeGenerator::Generate( - const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const { - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(filename_prefix_ + "." + file->name())); - io::Printer printer(output.get(), '$'); - map<string, string> vars; - vars["name"] = name_; - vars["parameter"] = parameter; - vars["proto_name"] = file->name(); - vars["message_name"] = file->message_type_count() > 0 ? - file->message_type(0)->full_name().c_str() : "(none)"; - - printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n"); - - if (expect_write_error_) { - EXPECT_TRUE(printer.failed()); - } else { - EXPECT_FALSE(printer.failed()); - } + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); - *error = error_; - return !return_error_; + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } -// =================================================================== +TEST_F(CommandLineInterfaceTest, BasicPlugin) { + // Test that basic plugins work. -TEST_F(CommandLineInterfaceTest, BasicOutput) { - // Test that the common case works. + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { + // Invoke a generator and a plugin at the same time. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleInputs) { // Test parsing multiple input files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -461,48 +451,68 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs) { "syntax = \"proto2\";\n" "message Bar {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto bar.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); - ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_generator", "", "bar.proto", "Bar"); } TEST_F(CommandLineInterfaceTest, CreateDirectory) { // Test that when we output to a sub-directory, it is created. - RegisterGenerator("test_generator", "--test_out", - "bar/baz/output.test", "Test output."); - - CreateTempFile("foo.proto", + CreateTempFile("bar/baz/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + CreateTempDir("out"); + CreateTempDir("plugout"); - Run("protocol_compiler --test_out=$tmpdir " - "--proto_path=$tmpdir foo.proto"); + Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " + "--proto_path=$tmpdir bar/baz/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", - "foo.proto", "Foo", "bar/baz/output.test"); + ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); + ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); } TEST_F(CommandLineInterfaceTest, GeneratorParameters) { // Test that generator parameters are correctly parsed from the command line. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); Run("protocol_compiler --test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "TestParameter", - "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, Insert) { + // Test running a generator that inserts code into another's output. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert=test_generator,test_plugin:$tmpdir " + "--plug_out=insert=test_generator,test_plugin:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGeneratedWithInsertions( + "test_generator", "TestParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); + ExpectGeneratedWithInsertions( + "test_plugin", "TestPluginParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); } #if defined(_WIN32) || defined(__CYGWIN__) @@ -510,42 +520,33 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) { TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { // Test that the output path can be a Windows-style path. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=C:\\ " + Run("protocol_compiler --null_out=C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - EXPECT_TRUE(generator->called_); - EXPECT_EQ("", generator->parameter_); + ExpectNullCodeGeneratorCalled(""); } TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { // Test that we can have a windows-style output path and a parameter. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=bar:C:\\ " + Run("protocol_compiler --null_out=bar:C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - EXPECT_TRUE(generator->called_); - EXPECT_EQ("bar", generator->parameter_); + ExpectNullCodeGeneratorCalled("bar"); } TEST_F(CommandLineInterfaceTest, TrailingBackslash) { // Test that the directories can end in backslashes. Some users claim this // doesn't work on their system. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -554,7 +555,7 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { "--proto_path=$tmpdir\\ foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } #endif // defined(_WIN32) || defined(__CYGWIN__) @@ -562,9 +563,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { TEST_F(CommandLineInterfaceTest, PathLookup) { // Test that specifying multiple directories in the proto search path works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -580,15 +578,12 @@ TEST_F(CommandLineInterfaceTest, PathLookup) { "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { // Same as PathLookup, but we provide the proto_path in a single flag. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -613,15 +608,12 @@ TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { #undef PATH_SEPARATOR ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, NonRootMapping) { // Test setting up a search path mapping a directory to a non-root location. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -630,42 +622,34 @@ TEST_F(CommandLineInterfaceTest, NonRootMapping) { "--proto_path=bar=$tmpdir bar/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleGenerators) { // Test that we can have multiple generators and use both in one invocation, // each with a different output directory. - RegisterGenerator("test_generator_1", "--test1_out", - "output1.test", "Test output 1."); - RegisterGenerator("test_generator_2", "--test2_out", - "output2.test", "Test output 2."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); // Create the "a" and "b" sub-directories. - CreateTempFile("a/dummy", ""); - CreateTempFile("b/dummy", ""); + CreateTempDir("a"); + CreateTempDir("b"); Run("protocol_compiler " - "--test1_out=$tmpdir/a " - "--test2_out=$tmpdir/b " + "--test_out=$tmpdir/a " + "--alt_out=$tmpdir/b " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test"); - ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); + ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); } TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { // Test that --disallow_services doesn't cause a problem when there are no // services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -674,15 +658,12 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { // Test that --disallow_services produces an error when there are services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -697,9 +678,6 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { // Test that services work fine as long as --disallow_services is not used. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -709,7 +687,7 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { @@ -717,9 +695,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -728,7 +703,7 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { "--proto_path=$tmpdir $tmpdir/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { @@ -775,8 +750,8 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { if (HasFatalFailure()) return; ASSERT_EQ(2, descriptor_set.file_size()); if (descriptor_set.file(0).name() == "bar.proto") { - swap(descriptor_set.mutable_file()->mutable_data()[0], - descriptor_set.mutable_file()->mutable_data()[1]); + std::swap(descriptor_set.mutable_file()->mutable_data()[0], + descriptor_set.mutable_file()->mutable_data()[1]); } EXPECT_EQ("foo.proto", descriptor_set.file(0).name()); EXPECT_EQ("bar.proto", descriptor_set.file(1).name()); @@ -787,9 +762,6 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { TEST_F(CommandLineInterfaceTest, ParseErrors) { // Test that parse errors are reported. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -804,9 +776,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrors) { TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { // Test that parse errors are reported from multiple files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // We set up files such that foo.proto actually depends on bar.proto in // two ways: Directly and through baz.proto. bar.proto's errors should // only be reported once. @@ -834,9 +803,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { TEST_F(CommandLineInterfaceTest, InputNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); @@ -850,9 +816,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir $tmpdir/foo.proto"); @@ -866,9 +829,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -882,7 +842,11 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { ExpectErrorText( "$tmpdir/foo.proto: File does not reside within any path " "specified using --proto_path (or -I). You must specify a " - "--proto_path which encompasses this file.\n"); + "--proto_path which encompasses this file. Note that the " + "proto_path must be an exact prefix of the .proto file " + "names -- protoc is too dumb to figure out when two paths " + "(e.g. absolute and relative) are equivalent (it's harder " + "than you think).\n"); } TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { @@ -891,9 +855,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // Create a directory called "bar" so that we can point --proto_path at it. CreateTempFile("bar/dummy", ""); @@ -910,9 +871,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -934,9 +892,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir/foo foo.proto"); @@ -948,9 +903,6 @@ TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { TEST_F(CommandLineInterfaceTest, MissingInputError) { // Test that we get an error if no inputs are given. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir"); @@ -958,9 +910,6 @@ TEST_F(CommandLineInterfaceTest, MissingInputError) { } TEST_F(CommandLineInterfaceTest, MissingOutputError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -971,35 +920,59 @@ TEST_F(CommandLineInterfaceTest, MissingOutputError) { } TEST_F(CommandLineInterfaceTest, OutputWriteError) { - MockCodeGenerator* generator = - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - generator->set_expect_write_error(true); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + string output_file = + MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); + // Create a directory blocking our output location. - CreateTempFile("output.test.foo.proto/foo", ""); + CreateTempDir(output_file); Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); + // MockCodeGenerator no longer detects an error because we actually write to + // an in-memory location first, then dump to disk at the end. This is no + // big deal. + // ExpectErrorSubstring("MockCodeGenerator detected write error."); + #if defined(_WIN32) && !defined(__CYGWIN__) // Windows with MSVCRT.dll produces EPERM instead of EISDIR. - if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) { + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { return; } #endif - ExpectErrorSubstring("output.test.foo.proto: Is a directory"); + ExpectErrorSubstring(output_file + ": Is a directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + string output_file = + MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1007,14 +980,21 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { Run("protocol_compiler --test_out=$tmpdir/nosuchdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("nosuchdir/: " - "No such file or directory"); + ExpectErrorSubstring("nosuchdir/: No such file or directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} +TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1033,45 +1013,124 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { } TEST_F(CommandLineInterfaceTest, GeneratorError) { - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { + // Test a generator plugin that returns an error. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" - "message Foo {}\n"); + "message MockCodeGenerator_Error {}\n"); - Run("protocol_compiler --error_out=$tmpdir " + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("--error_out: Test error message."); + ExpectErrorSubstring( + "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); } -TEST_F(CommandLineInterfaceTest, HelpText) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); +TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { + // Test a generator plugin that exits with an error code. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Exit {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { + // Test a generator plugin that crashes. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" + "message MockCodeGenerator_Abort {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); + +#ifdef _WIN32 + // Windows doesn't have signals. It looks like abort()ing causes the process + // to exit with status code 3, but let's not depend on the exact number here. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code"); +#else + // Don't depend on the exact signal number. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin killed by signal"); +#endif +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { + // Test what happens if the plugin isn't found. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " + "--plugin=prefix-gen-badplug=no_such_file " + "--proto_path=$tmpdir error.proto"); + +#ifdef _WIN32 + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: The system cannot find the file " + "specified."); +#else + // Error written to stdout by child process after exec() fails. + ExpectErrorSubstring( + "no_such_file: program not found or is not executable"); + + // Error written by parent process when child fails. + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); +#endif +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { + // Test what happens if plugins aren't allowed. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" "message Foo {}\n"); + DisallowPlugins(); + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring("Unknown flag: --plug_out"); +} + +TEST_F(CommandLineInterfaceTest, HelpText) { Run("test_exec_name --help"); ExpectErrorSubstring("Usage: test_exec_name "); ExpectErrorSubstring("--test_out=OUT_DIR"); ExpectErrorSubstring("Test output."); - ExpectErrorSubstring("--error_out=OUT_DIR"); - ExpectErrorSubstring("Test error output."); + ExpectErrorSubstring("--alt_out=OUT_DIR"); + ExpectErrorSubstring("Alt output."); } TEST_F(CommandLineInterfaceTest, GccFormatErrors) { // Test --error_format=gcc (which is the default, but we want to verify // that it can be set explicitly). - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1086,9 +1145,6 @@ TEST_F(CommandLineInterfaceTest, GccFormatErrors) { TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1104,9 +1160,6 @@ TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1124,9 +1177,6 @@ TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { // Test that a single-character flag works. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1135,15 +1185,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { // Test that separating the flag value with a space works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1152,16 +1199,13 @@ TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { // Test that separating the flag value with a space works for // single-character flags. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1170,15 +1214,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MissingValueError) { // Test that we get an error if a flag is missing its value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); ExpectErrorText("Missing value for flag: --test_out\n"); @@ -1188,9 +1229,6 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { // Test that we get an error if the last argument is a flag requiring a // value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out"); ExpectErrorText("Missing value for flag: --test_out\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index a7bc35b..30b1d2b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -123,8 +123,11 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { Importer importer(&source_tree, &error_collector); const FileDescriptor* proto_file = importer.Import("google/protobuf/descriptor.proto"); + const FileDescriptor* plugin_proto_file = + importer.Import("google/protobuf/compiler/plugin.proto"); EXPECT_EQ("", error_collector.text_); ASSERT_TRUE(proto_file != NULL); + ASSERT_TRUE(plugin_proto_file != NULL); CppGenerator generator; MockOutputDirectory output_directory; @@ -133,11 +136,18 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &output_directory, &error)); + parameter = "dllexport_decl=LIBPROTOC_EXPORT"; + ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, + &output_directory, &error)); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h", "google/protobuf/descriptor.pb.h"); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc", "google/protobuf/descriptor.pb.cc"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h", + "google/protobuf/compiler/plugin.pb.h"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", + "google/protobuf/compiler/plugin.pb.cc"); } } // namespace @@ -145,5 +155,4 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 90e9172..76d2b79 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -98,6 +98,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "$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())) { @@ -149,17 +150,21 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { "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"); + " $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" + "}\n"); + printer->Print(vars, "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" " return $classname$_Name(value);\n" - "}\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" @@ -240,7 +245,8 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { } printer->Print(vars, "const $classname$ $parent$::$nested_name$_MIN;\n" - "const $classname$ $parent$::$nested_name$_MAX;\n"); + "const $classname$ $parent$::$nested_name$_MAX;\n" + "const int $parent$::$nested_name$_ARRAYSIZE;\n"); printer->Print("#endif // _MSC_VER\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 7ca11c8..91ce493 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -114,7 +114,9 @@ void EnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &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())) { @@ -170,24 +172,17 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n" "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 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" "inline $type$ $classname$::$name$(int index) const {\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" @@ -199,6 +194,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " 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:: @@ -223,7 +227,33 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { + // 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" @@ -231,25 +261,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "input->PushLimit(length);\n" "while (input->BytesUntilLimit() > 0) {\n" " int value;\n" - " DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &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"); - } else { - printer->Print(variables_, - "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(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(variables_, - "}\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 20dd57b..0793430 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -83,6 +83,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { 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; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 7208ed3..658a707 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -33,6 +33,7 @@ // 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> @@ -43,6 +44,18 @@ 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), @@ -80,7 +93,7 @@ ExtensionGenerator::~ExtensionGenerator() {} void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { map<string, string> vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; vars["name" ] = descriptor_->name(); @@ -106,6 +119,7 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" " $name$;\n" ); + } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { @@ -115,7 +129,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { string name = scope + descriptor_->name(); map<string, string> vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["type_traits" ] = type_traits_; vars["name" ] = name; vars["constant_name"] = FieldConstantName(descriptor_); @@ -154,7 +168,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { map<string, string> vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + 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"; @@ -193,5 +207,4 @@ void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index c546e96..103cac4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -40,6 +40,7 @@ #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> @@ -61,11 +62,24 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); (*variables)["deprecation"] = descriptor->options().deprecated() - ? " DEPRECATED_PROTOBUF_FIELD" : ""; + ? " 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_( @@ -82,7 +96,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new RepeatedMessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field); + 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: @@ -93,7 +111,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new MessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field); + 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: @@ -110,6 +132,7 @@ const FieldGenerator& FieldGeneratorMap::get( return *field_generators_[field->index()]; } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 00ec2c7..c303a33 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -118,6 +118,11 @@ class FieldGenerator { // 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; @@ -153,6 +158,7 @@ class FieldGeneratorMap { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 51859bb..80da7e4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -38,6 +38,7 @@ #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> @@ -93,12 +94,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // 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( @@ -132,19 +135,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { if (HasDescriptorMethods(file_)) { printer->Print( "#include <google/protobuf/generated_message_reflection.h>\n"); + } - if (file_->service_count() > 0) { - printer->Print( - "#include <google/protobuf/service.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); @@ -198,7 +205,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print(kThickSeparator); printer->Print("\n"); - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate service definitions. for (int i = 0; i < file_->service_count(); i++) { if (i > 0) { @@ -232,6 +239,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { message_generators_[i]->GenerateInlineMethods(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -255,11 +266,15 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "\n" "} // namespace google\n} // namespace protobuf\n" - "#endif // SWIG\n" - "\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); } @@ -285,6 +300,9 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/wire_format.h>\n"); } + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + GenerateNamespaceOpeners(printer); if (HasDescriptorMethods(file_)) { @@ -300,10 +318,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", "name", ClassName(file_->enum_type(i), false)); } - for (int i = 0; i < file_->service_count(); i++) { - printer->Print( - "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", - "name", file_->service(i)->name()); + + 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( @@ -329,7 +350,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { message_generators_[i]->GenerateClassMethods(printer); } - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate services. for (int i = 0; i < file_->service_count(); i++) { if (i == 0) printer->Print("\n"); @@ -344,7 +365,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) { 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) { @@ -397,8 +426,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } - for (int i = 0; i < file_->service_count(); i++) { - service_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(); diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 723a8b4..e3df88b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <limits> #include <vector> #include <google/protobuf/stubs/hash.h> @@ -40,6 +41,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -111,6 +113,7 @@ 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; @@ -141,6 +144,12 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } } + +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); @@ -166,6 +175,12 @@ string FieldConstantName(const FieldDescriptor *field) { 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"); @@ -235,17 +250,37 @@ string DefaultValue(const FieldDescriptor* field) { return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; case FieldDescriptor::CPPTYPE_UINT64: return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()); + 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: { - // If floating point value contains a period (.) or an exponent (either - // E or e), then append suffix 'f' to make it a floating-point literal. - string float_value = SimpleFtoa(field->default_value_float()); - if (float_value.find_first_of(".eE") != string::npos) { - float_value.push_back('f'); + 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; } - return float_value; } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; @@ -259,7 +294,7 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_STRING: return "\"" + CEscape(field->default_value_string()) + "\""; case FieldDescriptor::CPPTYPE_MESSAGE: - return ClassName(field->message_type(), true) + "::default_instance()"; + 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 diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 83e1250..f99b5fe 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -60,6 +60,8 @@ extern const char kThinSeparator[]; 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 @@ -77,6 +79,10 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { 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); @@ -107,33 +113,41 @@ string GlobalAssignDescriptorsName(const string& filename); string GlobalShutdownFileName(const string& filename); // Do message classes in this file keep track of unknown fields? -inline const bool HasUnknownFields(const FileDescriptor *file) { +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 const bool HasGeneratedMethods(const FileDescriptor *file) { +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 const bool HasDescriptorMethods(const FileDescriptor *file) { +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 const bool HasUtf8Verification(const FileDescriptor* file) { +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 const bool HasFastArraySerialization(const FileDescriptor* file) { +inline bool HasFastArraySerialization(const FileDescriptor* file) { return file->options().optimize_for() == FileOptions::SPEED; } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index ae243dd..cbdcce8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -308,11 +308,10 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = dllexport_decl_ + " "; } - vars["superclass"] = HasDescriptorMethods(descriptor_->file()) ? - "Message" : "MessageLite"; + vars["superclass"] = SuperClassName(descriptor_); printer->Print(vars, - "class $dllexport$$classname$ : public ::google::protobuf::$superclass$ {\n" + "class $dllexport$$classname$ : public $superclass$ {\n" " public:\n"); printer->Indent(); @@ -349,6 +348,10 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(vars, "static const $classname$& default_instance();\n" + "\n"); + + + printer->Print(vars, "void Swap($classname$* other);\n" "\n" "// implements Message ----------------------------------------------\n" @@ -387,7 +390,7 @@ GenerateClassDefinition(io::Printer* printer) { "private:\n" "void SharedCtor();\n" "void SharedDtor();\n" - "void SetCachedSize(int size) const { _cached_size_ = size; }\n" + "void SetCachedSize(int size) const;\n" "public:\n" "\n"); @@ -436,6 +439,11 @@ GenerateClassDefinition(io::Printer* printer) { extension_generators_[i]->GenerateDeclaration(printer); } + + printer->Print( + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + // Generate private members for fields. printer->Outdent(); printer->Print(" private:\n"); @@ -623,6 +631,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); } + } void MessageGenerator:: @@ -751,6 +760,7 @@ GenerateClassMethods(io::Printer* printer) { "classname", classname_, "type_name", descriptor_->full_name()); } + } void MessageGenerator:: @@ -833,12 +843,16 @@ GenerateSharedDestructorCode(io::Printer* printer) { void MessageGenerator:: GenerateStructors(io::Printer* printer) { + string superclass = SuperClassName(descriptor_); + // Generate the default constructor. printer->Print( - "$classname$::$classname$() {\n" + "$classname$::$classname$()\n" + " : $superclass$() {\n" " SharedCtor();\n" "}\n", - "classname", classname_); + "classname", classname_, + "superclass", superclass); printer->Print( "\n" @@ -859,7 +873,7 @@ GenerateStructors(io::Printer* printer) { printer->Print( " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", "name", FieldName(field), - "type", ClassName(field->message_type(), true)); + "type", FieldMessageTypeName(field)); } } printer->Print( @@ -868,12 +882,14 @@ GenerateStructors(io::Printer* printer) { // Generate the copy constructor. printer->Print( - "$classname$::$classname$(const $classname$& from) {\n" + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$() {\n" " SharedCtor();\n" " MergeFrom(from);\n" "}\n" "\n", - "classname", classname_); + "classname", classname_, + "superclass", superclass); // Generate the shared constructor code. GenerateSharedConstructorCode(printer); @@ -889,6 +905,15 @@ GenerateStructors(io::Printer* printer) { // Generate the shared destructor code. GenerateSharedDestructorCode(printer); + // Generate SetCachedSize. + printer->Print( + "void $classname$::SetCachedSize(int size) const {\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + " _cached_size_ = size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + "}\n", + "classname", classname_); + // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file()) && !descriptor_->options().no_standard_descriptor_accessor()) { @@ -917,6 +942,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "adddescriptorsname", GlobalAddDescriptorsName(descriptor_->file()->name())); + } void MessageGenerator:: @@ -1230,12 +1256,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { PrintFieldComment(printer, field); printer->Print( - "case $number$: {\n" - " if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) !=\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n" - " goto handle_uninterpreted;\n" - " }\n", - "number", SimpleItoa(field->number()), + "case $number$: {\n", + "number", SimpleItoa(field->number())); + printer->Indent(); + const FieldGenerator& field_generator = field_generators_.get(field); + + // Emit code to parse the common, expected case. + printer->Print( + "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n", "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]); if (i > 0 || (field->is_repeated() && !field->options().packed())) { @@ -1245,8 +1274,38 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Indent(); + if (field->options().packed()) { + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + } else { + field_generator.GenerateMergeFromCodedStream(printer); + } + printer->Outdent(); - field_generators_.get(field).GenerateMergeFromCodedStream(printer); + // Emit code to parse unexpectedly packed or unpacked values. + if (field->is_packable() && field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_$wiretype$) {\n", + "wiretype", + kWireTypeNames[WireFormat::WireTypeForFieldType(field->type())]); + printer->Indent(); + field_generator.GenerateMergeFromCodedStream(printer); + printer->Outdent(); + } else if (field->is_packable() && !field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_LENGTH_DELIMITED) {\n"); + printer->Indent(); + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + printer->Outdent(); + } + + printer->Print( + "} else {\n" + " goto handle_uninterpreted;\n" + "}\n"); // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. @@ -1427,18 +1486,6 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { "classname", classname_); printer->Indent(); - if (HasFastArraySerialization(descriptor_->file())) { - printer->Print( - "::google::protobuf::uint8* raw_buffer = " - "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n" - "if (raw_buffer != NULL) {\n" - " $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n" - " return;\n" - "}\n" - "\n", - "classname", classname_); - } - GenerateSerializeWithCachedSizesBody(printer, false); printer->Outdent(); @@ -1548,7 +1595,9 @@ GenerateByteSize(io::Printer* printer) { " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"); } printer->Print( + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" " _cached_size_ = total_size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" " return total_size;\n" "}\n"); return; @@ -1640,7 +1689,9 @@ GenerateByteSize(io::Printer* printer) { // exact same value, it works on all common processors. In a future version // of C++, _cached_size_ should be made into an atomic<int>. printer->Print( + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" "_cached_size_ = total_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "return total_size;\n"); printer->Outdent(); @@ -1712,6 +1763,7 @@ GenerateIsInitialized(io::Printer* printer) { "}\n"); } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index f1c5714..04778f6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -150,6 +150,7 @@ class MessageGenerator { io::Printer* printer, const Descriptor::ExtensionRange* range, bool unbounded); + const Descriptor* descriptor_; string classname_; string dllexport_decl_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 059fba6..c04bdc6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -47,7 +47,11 @@ namespace { void SetMessageVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { SetCommonFieldVariables(descriptor, variables); - (*variables)["type"] = ClassName(descriptor->message_type(), true); + (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["stream_writer"] = (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file()) ? + "MaybeToArray" : + ""); } } // namespace @@ -125,7 +129,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n" + "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(), output);\n"); } @@ -164,26 +168,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const" - "$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$()" - "$deprecation$;\n" "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 ::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" "inline const $type$& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -193,6 +190,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "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:: @@ -232,7 +238,7 @@ 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$declared_type$NoVirtual(\n" + " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(i), output);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc new file mode 100644 index 0000000..440b716 --- /dev/null +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -0,0 +1,121 @@ +// 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) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <google/protobuf/compiler/cpp/cpp_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + TryInsert("test.pb.h", "includes", output_directory); + TryInsert("test.pb.h", "namespace_scope", output_directory); + TryInsert("test.pb.h", "global_scope", output_directory); + TryInsert("test.pb.h", "class_scope:foo.Bar", output_directory); + TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", output_directory); + + TryInsert("test.pb.cc", "includes", output_directory); + TryInsert("test.pb.cc", "namespace_scope", output_directory); + TryInsert("test.pb.cc", "global_scope", output_directory); + return true; + } + + void TryInsert(const string& filename, const string& insertion_point, + OutputDirectory* output_directory) const { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(CppPluginTest, PluginTest) { + File::WriteStringToFileOrDie( + "syntax = \"proto2\";\n" + "package foo;\n" + "message Bar {\n" + " message Baz {}\n" + "}\n", + TestTempDir() + "/test.proto"); + + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + CppGenerator cpp_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + string proto_path = "-I" + TestTempDir(); + string cpp_out = "--cpp_out=" + TestTempDir(); + string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = { + "protoc", + proto_path.c_str(), + cpp_out.c_str(), + test_out.c_str(), + "test.proto" + }; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +} // namespace +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 81f5ce0..a69c48b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -84,10 +84,14 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, 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 @@ -149,8 +153,9 @@ GenerateConstructorCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &$name$_));\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, $wire_format_field_type$>(\n" + " input, &$name$_)));\n" "_set_bit($index$);\n"); } @@ -188,6 +193,14 @@ 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() {} @@ -205,25 +218,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const\n" - " $deprecation$;\n" - "inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$()$deprecation$;\n" "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 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" "inline $type$ $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -233,6 +240,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "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:: @@ -257,30 +273,18 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print("{\n"); - printer->Indent(); - printer->Print(variables_, - "::google::protobuf::uint32 length;\n" - "DO_(input->ReadVarint32(&length));\n" - "::google::protobuf::io::CodedInputStream::Limit limit =\n" - " input->PushLimit(length);\n" - "while (input->BytesUntilLimit() > 0) {\n" - " $type$ value;\n" - " DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - " add_$name$(value);\n" - "}\n" - "input->PopLimit(limit);\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print(variables_, - "$type$ value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - "add_$name$(value);\n"); - } + 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:: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 6b96614..8fcd74a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -83,6 +83,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { 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; diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 72258e8..ea6809a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -91,7 +91,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { // 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().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -107,7 +107,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$deprecation$;\n" "inline ::std::string* mutable_$name$()$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -278,7 +278,7 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { // See comment above about unknown ctypes. - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -287,10 +287,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" - "$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" - "$deprecation$;\n" "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" @@ -304,7 +300,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline void add_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + 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(); @@ -314,14 +316,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { 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" "inline const ::std::string& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -353,6 +347,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "$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:: diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index d7575c0..a7e852d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -49,6 +49,7 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_optimize_for.pb.h> #include <google/protobuf/unittest_embed_optimize_for.pb.h> +#include <google/protobuf/unittest_no_generic_services.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h> #include <google/protobuf/compiler/importer.h> @@ -154,6 +155,16 @@ TEST(GeneratedMessageTest, FloatingPointDefaults) { EXPECT_EQ(-1.5f, extreme_default.negative_float()); EXPECT_EQ(2.0e8f, extreme_default.large_float()); EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(numeric_limits<double>::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-numeric_limits<double>::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(numeric_limits<float>::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-numeric_limits<float>::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); } TEST(GeneratedMessageTest, Accessors) { @@ -779,22 +790,39 @@ TEST(GeneratedEnumTest, IsValidValue) { } TEST(GeneratedEnumTest, MinAndMax) { - EXPECT_EQ(unittest::TestAllTypes::FOO,unittest::TestAllTypes::NestedEnum_MIN); - EXPECT_EQ(unittest::TestAllTypes::BAZ,unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(unittest::TestAllTypes::FOO, + unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(unittest::TestAllTypes::BAZ, + unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, unittest::TestAllTypes::NestedEnum_ARRAYSIZE); EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN); EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX); + EXPECT_EQ(7, unittest::ForeignEnum_ARRAYSIZE); EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN); EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, unittest::TestEnumWithDupValue_ARRAYSIZE); EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN); EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX); + EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE); - // Make sure we can use _MIN and _MAX as switch cases. - switch(unittest::SPARSE_A) { + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* nullptr = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(nullptr, &unittest::ForeignEnum_MIN); + EXPECT_NE(nullptr, &unittest::ForeignEnum_MAX); + EXPECT_NE(nullptr, &unittest::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases. + switch (unittest::SPARSE_A) { case unittest::TestSparseEnum_MIN: case unittest::TestSparseEnum_MAX: + case unittest::TestSparseEnum_ARRAYSIZE: break; default: break; @@ -1136,6 +1164,43 @@ TEST_F(GeneratedServiceTest, NotImplemented) { EXPECT_TRUE(controller.called_); } +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GeneratedServiceTest, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension(no_generic_services_test::test_extension, 123); + no_generic_services_test::TestEnum e = no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + no_generic_services_test::TestMessage::descriptor()->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS // =================================================================== diff --git a/src/google/protobuf/compiler/importer.cc b/src/google/protobuf/compiler/importer.cc index 8a07dfc..7689ce9 100644 --- a/src/google/protobuf/compiler/importer.cc +++ b/src/google/protobuf/compiler/importer.cc @@ -59,6 +59,7 @@ namespace compiler { #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 diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 8ade50c..85e39f5 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -223,6 +223,11 @@ void EnumGenerator::Generate(io::Printer* printer) { "file", ClassName(descriptor_->file())); } + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + printer->Outdent(); printer->Print("}\n\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index dc36e06..af6b1cd 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -62,7 +62,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); } } // namespace @@ -81,7 +81,7 @@ void EnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $default$;\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -111,6 +111,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void EnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + +void EnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (other.has$capitalized_name$()) {\n" @@ -241,6 +246,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void RepeatedEnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + +void RepeatedEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (!other.$name$_.isEmpty()) {\n" @@ -262,15 +272,6 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - // If packed, set up the while loop - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int oldLimit = input.pushLimit(length);\n" - "while(input.getBytesUntilLimit() > 0) {\n"); - printer->Indent(); - } - // Read and store the enum printer->Print(variables_, "int rawValue = input.readEnum();\n" @@ -287,13 +288,24 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, " add$capitalized_name$(value);\n" "}\n"); +} - if (descriptor_->options().packed()) { - printer->Outdent(); - printer->Print(variables_, - "}\n" - "input.popLimit(oldLimit);\n"); - } +void RepeatedEnumFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Wrap GenerateParsingCode's contents with a while loop. + + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + + GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); } void RepeatedEnumFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 63f6815..c54a0fa 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -52,6 +52,7 @@ class EnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 4403220..903b0a9 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -112,16 +112,20 @@ void ExtensionGenerator::Generate(io::Printer* printer) { "public static final int $constant_name$ = $number$;\n"); if (descriptor_->is_repeated()) { printer->Print(vars, - "public static\n" + "public static final\n" " com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n" " $containing_type$,\n" - " java.util.List<$type$>> $name$;\n"); + " java.util.List<$type$>> $name$ =\n" + " com.google.protobuf.GeneratedMessage$lite$\n" + " .newGeneratedExtension();\n"); } else { printer->Print(vars, - "public static\n" + "public static final\n" " com.google.protobuf.GeneratedMessage$lite$.GeneratedExtension<\n" " $containing_type$,\n" - " $type$> $name$;\n"); + " $type$> $name$ =\n" + " com.google.protobuf.GeneratedMessage$lite$\n" + " .newGeneratedExtension();\n"); } } @@ -133,7 +137,7 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) { vars["extendee"] = ClassName(descriptor_->containing_type()); vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_); vars["number"] = SimpleItoa(descriptor_->number()); - vars["type_constant"] = TypeName(descriptor_->type()); + vars["type_constant"] = TypeName(GetType(descriptor_)); vars["packed"] = descriptor_->options().packed() ? "true" : "false"; vars["enum_map"] = "null"; vars["prototype"] = "null"; @@ -157,43 +161,29 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) { } if (HasDescriptorMethods(descriptor_->file())) { - if (descriptor_->is_repeated()) { - printer->Print(vars, - "$scope$.$name$ =\n" - " com.google.protobuf.GeneratedMessage\n" - " .newRepeatedGeneratedExtension(\n" - " $scope$.getDescriptor().getExtensions().get($index$),\n" - " $type$.class);\n"); - } else { - printer->Print(vars, - "$scope$.$name$ =\n" - " com.google.protobuf.GeneratedMessage.newGeneratedExtension(\n" - " $scope$.getDescriptor().getExtensions().get($index$),\n" - " $type$.class);\n"); - } + printer->Print(vars, + "$scope$.$name$.internalInit(\n" + " $scope$.getDescriptor().getExtensions().get($index$),\n" + " $type$.class);\n"); } else { if (descriptor_->is_repeated()) { printer->Print(vars, - "$scope$.$name$ =\n" - " com.google.protobuf.GeneratedMessageLite\n" - " .newRepeatedGeneratedExtension(\n" - " $extendee$.getDefaultInstance(),\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $packed$);\n"); + "$scope$.$name$.internalInitRepeated(\n" + " $extendee$.getDefaultInstance(),\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $packed$);\n"); } else { printer->Print(vars, - "$scope$.$name$ =\n" - " com.google.protobuf.GeneratedMessageLite\n" - " .newGeneratedExtension(\n" - " $extendee$.getDefaultInstance(),\n" - " $default$,\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$);\n"); + "$scope$.$name$.internalInitSingular(\n" + " $extendee$.getDefaultInstance(),\n" + " $default$,\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$);\n"); } } } @@ -208,5 +198,4 @@ void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) { } // namespace java } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index f9d34ad..978c8f3 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -46,6 +46,16 @@ namespace java { FieldGenerator::~FieldGenerator() {} +void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " + << "called on field generator that does not support packing."; +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) : descriptor_(descriptor), field_generators_( diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index cab463c..f5bef7a 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -57,9 +57,11 @@ class FieldGenerator { virtual void GenerateMembers(io::Printer* printer) const = 0; virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; virtual void GenerateMergingCode(io::Printer* printer) const = 0; virtual void GenerateBuildingCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; virtual void GenerateSerializationCode(io::Printer* printer) const = 0; virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 2aedde5..7ea127c 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -64,7 +64,7 @@ bool UsesExtensions(const Message& message) { for (int i = 0; i < fields.size(); i++) { if (fields[i]->is_extension()) return true; - if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { if (fields[i]->is_repeated()) { int size = reflection->FieldSize(message, fields[i]); for (int j = 0; j < size; j++) { @@ -82,6 +82,7 @@ bool UsesExtensions(const Message& message) { return false; } + } // namespace FileGenerator::FileGenerator(const FileDescriptor* file) @@ -134,7 +135,9 @@ void FileGenerator::Generate(io::Printer* printer) { // fully-qualified names in the generated source. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); + "// source: $filename$\n" + "\n", + "filename", file_->name()); if (!java_package_.empty()) { printer->Print( "package $package$;\n" @@ -178,8 +181,10 @@ void FileGenerator::Generate(io::Printer* printer) { for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator(file_->message_type(i)).Generate(printer); } - for (int i = 0; i < file_->service_count(); i++) { - ServiceGenerator(file_->service(i)).Generate(printer); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + ServiceGenerator(file_->service(i)).Generate(printer); + } } } @@ -228,6 +233,10 @@ void FileGenerator::Generate(io::Printer* printer) { "\n" "public static void internalForceInit() {}\n"); + printer->Print( + "\n" + "// @@protoc_insertion_point(outer_class_scope)\n"); + printer->Outdent(); printer->Print("}\n"); } @@ -245,6 +254,7 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { // embedded raw, which is what we want. FileDescriptorProto file_proto; file_->CopyTo(&file_proto); + string file_data; file_proto.SerializeToString(&file_data); @@ -343,9 +353,11 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < file_->dependency_count(); i++) { - printer->Print( - " $dependency$.getDescriptor(),\n", - "dependency", ClassName(file_->dependency(i))); + if (ShouldIncludeDependency(file_->dependency(i))) { + printer->Print( + " $dependency$.getDescriptor(),\n", + "dependency", ClassName(file_->dependency(i))); + } } printer->Print( @@ -396,14 +408,20 @@ void FileGenerator::GenerateSiblings(const string& package_dir, file_->message_type(i), output_directory, file_list); } - for (int i = 0; i < file_->service_count(); i++) { - GenerateSibling<ServiceGenerator>(package_dir, java_package_, - file_->service(i), - output_directory, file_list); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + GenerateSibling<ServiceGenerator>(package_dir, java_package_, + file_->service(i), + output_directory, file_list); + } } } } +bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { + return true; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index cb82cea..9e35d33 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -77,6 +77,11 @@ class FileGenerator { const string& classname() { return classname_; } private: + // Returns whether the dependency should be included in the output file. + // Always returns true for opensource, but used internally at Google to help + // improve compatibility with version 1 of protocol buffers. + bool ShouldIncludeDependency(const FileDescriptor* descriptor); + const FileDescriptor* file_; string java_package_; string classname_; diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index 8ed3aff..745b55a 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -45,6 +45,7 @@ namespace protobuf { namespace compiler { namespace java { + JavaGenerator::JavaGenerator() {} JavaGenerator::~JavaGenerator() {} diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index dc6748e..7ed0c3c 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <limits> #include <vector> #include <google/protobuf/compiler/java/java_helpers.h> @@ -57,7 +58,7 @@ const string& FieldName(const FieldDescriptor* field) { // Groups are hacky: The name of the field is just the lower-cased name // of the group type. In Java, though, we would like to retain the original // capitalization of the type name. - if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(field) == FieldDescriptor::TYPE_GROUP) { return field->message_type()->name(); } else { return field->name(); @@ -178,8 +179,12 @@ string FieldConstantName(const FieldDescriptor *field) { return name; } -JavaType GetJavaType(FieldDescriptor::Type field_type) { - switch (field_type) { +FieldDescriptor::Type GetType(const FieldDescriptor* field) { + return field->type(); +} + +JavaType GetJavaType(const FieldDescriptor* field) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_SINT32: @@ -254,7 +259,7 @@ bool AllAscii(const string& text) { } string DefaultValue(const FieldDescriptor* field) { - // Switch on cpp_type since we need to know which default_value_* method + // Switch on CppType since we need to know which default_value_* method // of FieldDescriptor to call. switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -267,14 +272,34 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + "L"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()) + "D"; - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field->default_value_float()) + "F"; + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits<double>::infinity()) { + return "Double.POSITIVE_INFINITY"; + } else if (value == -numeric_limits<double>::infinity()) { + return "Double.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Double.NaN"; + } else { + return SimpleDtoa(value) + "D"; + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field->default_value_float(); + if (value == numeric_limits<float>::infinity()) { + return "Float.POSITIVE_INFINITY"; + } else if (value == -numeric_limits<float>::infinity()) { + return "Float.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Float.NaN"; + } else { + return SimpleFtoa(value) + "F"; + } + } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { + if (GetType(field) == FieldDescriptor::TYPE_BYTES) { if (field->has_default_value()) { // See comments in Internal.java for gory details. return strings::Substitute( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index f1b643c..3c8974c 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -93,6 +93,11 @@ string ClassName(const FileDescriptor* descriptor); // number constant. string FieldConstantName(const FieldDescriptor *field); +// Returns the type of the FieldDescriptor. +// This does nothing interesting for the open source release, but is used for +// hacks that improve compatability with version 1 protocol buffers at Google. +FieldDescriptor::Type GetType(const FieldDescriptor* field); + enum JavaType { JAVATYPE_INT, JAVATYPE_LONG, @@ -105,11 +110,7 @@ enum JavaType { JAVATYPE_MESSAGE }; -JavaType GetJavaType(FieldDescriptor::Type field_type); - -inline JavaType GetJavaType(const FieldDescriptor* field) { - return GetJavaType(field->type()); -} +JavaType GetJavaType(const FieldDescriptor* field); // Get the fully-qualified class name for a boxed primitive type, e.g. // "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message @@ -145,6 +146,13 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { 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().java_generic_services(); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 332a118..a326057 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -127,7 +127,7 @@ static bool HasRequiredFields( if (field->is_required()) { return true; } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { if (HasRequiredFields(field->message_type(), already_seen)) { return true; } @@ -292,9 +292,14 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Indent(); printer->Print( "// Use $classname$.newBuilder() to construct.\n" - "private $classname$() {}\n" + "private $classname$() {\n" + " initFields();\n" + "}\n" + // Used when constructing the default instance, which cannot be initialized + // immediately because it may cyclically refer to other default instances. + "private $classname$(boolean noInit) {}\n" "\n" - "private static final $classname$ defaultInstance = new $classname$();\n" + "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" " return defaultInstance;\n" "}\n" @@ -344,6 +349,17 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } + // Called by the constructor, except in the case of the default instance, + // in which case this is called by static init code later on. + printer->Print("private void initFields() {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + printer->Outdent(); + printer->Print("}\n"); + if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); @@ -352,25 +368,23 @@ void MessageGenerator::Generate(io::Printer* printer) { GenerateParseFromMethods(printer); GenerateBuilder(printer); - if (HasDescriptorMethods(descriptor_)) { - // Force the static initialization code for the file to run, since it may - // initialize static variables declared in this class. - printer->Print( - "\n" - "static {\n" - " $file$.getDescriptor();\n" - "}\n", - "file", ClassName(descriptor_->file())); - } - // Force initialization of outer class. Otherwise, nested extensions may - // not be initialized. + // not be initialized. Also carefully initialize the default instance in + // such a way that it doesn't conflict with other initialization. printer->Print( "\n" "static {\n" + " defaultInstance = new $classname$(true);\n" " $file$.internalForceInit();\n" + " defaultInstance.initFields();\n" "}\n", - "file", ClassName(descriptor_->file())); + "file", ClassName(descriptor_->file()), + "classname", descriptor_->name()); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); @@ -394,6 +408,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) { "public void writeTo(com.google.protobuf.CodedOutputStream output)\n" " throws java.io.IOException {\n"); printer->Indent(); + // writeTo(CodedOutputStream output) might be invoked without + // getSerializedSize() ever being called, but we need the memoized + // sizes in case this message has packed fields. Rather than emit checks for + // each packed field, just call getSerializedSize() up front for all messages. + // In most cases, getSerializedSize() will have already been called anyway by + // one of the wrapper writeTo() methods, making this call cheap. + printer->Print( + "getSerializedSize();\n"); if (descriptor_->extension_range_count() > 0) { if (descriptor_->options().message_set_wire_format()) { @@ -521,14 +543,23 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input).buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n" - " .buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" @@ -614,6 +645,11 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) { .GenerateBuilderMembers(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(builder_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + printer->Outdent(); printer->Print("}\n"); } @@ -819,7 +855,7 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForField(field)); + WireFormat::WireTypeForFieldType(field->type())); printer->Print( "case $tag$: {\n", @@ -832,6 +868,24 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { printer->Print( " break;\n" "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(packed_tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } } printer->Outdent(); @@ -867,7 +921,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all embedded messages are initialized. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + if (GetJavaType(field) == JAVATYPE_MESSAGE && HasRequiredFields(field->message_type())) { switch (field->label()) { case FieldDescriptor::LABEL_REQUIRED: diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index bbddddd..71edc02 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -59,7 +59,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["type"] = ClassName(descriptor->message_type()); (*variables)["group_or_message"] = - (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; } @@ -79,7 +79,7 @@ void MessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $type$.getDefaultInstance();\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -125,6 +125,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); +} + +void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (other.has$capitalized_name$()) {\n" @@ -145,7 +150,7 @@ GenerateParsingCode(io::Printer* printer) const { " subBuilder.mergeFrom(get$capitalized_name$());\n" "}\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { @@ -262,6 +267,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + +void RepeatedMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (!other.$name$_.isEmpty()) {\n" @@ -286,7 +296,7 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "$type$.Builder subBuilder = $type$.newBuilder();\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h index 90a9097..66bdd88 100644 --- a/src/google/protobuf/compiler/java/java_message_field.h +++ b/src/google/protobuf/compiler/java/java_message_field.h @@ -52,6 +52,7 @@ class MessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,6 +76,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc new file mode 100644 index 0000000..cfe0188 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -0,0 +1,121 @@ +// 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) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <google/protobuf/compiler/java/java_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + TryInsert("Test.java", "outer_class_scope", output_directory); + TryInsert("Test.java", "class_scope:foo.Bar", output_directory); + TryInsert("Test.java", "class_scope:foo.Bar.Baz", output_directory); + TryInsert("Test.java", "builder_scope:foo.Bar", output_directory); + TryInsert("Test.java", "builder_scope:foo.Bar.Baz", output_directory); + TryInsert("Test.java", "enum_scope:foo.Qux", output_directory); + return true; + } + + void TryInsert(const string& filename, const string& insertion_point, + OutputDirectory* output_directory) const { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(JavaPluginTest, PluginTest) { + File::WriteStringToFileOrDie( + "syntax = \"proto2\";\n" + "package foo;\n" + "option java_package = \"\";\n" + "option java_outer_classname = \"Test\";\n" + "message Bar {\n" + " message Baz {}\n" + "}\n" + "enum Qux { BLAH = 1; }\n", + TestTempDir() + "/test.proto"); + + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + JavaGenerator java_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--java_out", &java_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + string proto_path = "-I" + TestTempDir(); + string java_out = "--java_out=" + TestTempDir(); + string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = { + "protoc", + proto_path.c_str(), + java_out.c_str(), + test_out.c_str(), + "test.proto" + }; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +} // namespace +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 327c205..f6179bf 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -93,7 +93,7 @@ bool IsReferenceType(JavaType type) { } const char* GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32 : return "Int32" ; case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; @@ -166,7 +166,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - WireFormat::TagSize(descriptor->number(), descriptor->type())); + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { (*variables)["null_check"] = " if (value == null) {\n" @@ -175,7 +175,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, } else { (*variables)["null_check"] = ""; } - int fixed_size = FixedSize(descriptor->type()); + int fixed_size = FixedSize(GetType(descriptor)); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } @@ -218,7 +218,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n" "public Builder clear$capitalized_name$() {\n" " result.has$capitalized_name$ = false;\n"); - if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { // The default value is not a simple literal so we want to avoid executing // it multiple times. Instead, get the default out of the default instance. printer->Print(variables_, @@ -233,6 +234,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void PrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + +void PrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (other.has$capitalized_name$()) {\n" @@ -298,7 +304,7 @@ GenerateMembers(io::Printer* printer) const { if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, - "private int $name$MemoizedSerializedSize;\n"); + "private int $name$MemoizedSerializedSize = -1;\n"); } } @@ -346,6 +352,11 @@ GenerateBuilderMembers(io::Printer* printer) const { } void RepeatedPrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + +void RepeatedPrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, "if (!other.$name$_.isEmpty()) {\n" @@ -367,18 +378,19 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" - "}\n" - "input.popLimit(limit);\n"); - } else { - printer->Print(variables_, - "add$capitalized_name$(input.read$capitalized_type$());\n"); - } + printer->Print(variables_, + "add$capitalized_name$(input.read$capitalized_type$());\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " add$capitalized_name$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -407,7 +419,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { " int dataSize = 0;\n"); printer->Indent(); - if (FixedSize(descriptor_->type()) == -1) { + if (FixedSize(GetType(descriptor_)) == -1) { printer->Print(variables_, "for ($type$ element : get$capitalized_name$List()) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h index f9da0a6..4e482a0 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.h +++ b/src/google/protobuf/compiler/java/java_primitive_field.h @@ -52,6 +52,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum.cc deleted file mode 100644 index d74a149..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_enum.cc +++ /dev/null @@ -1,96 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <map> -#include <string> - -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/compiler/javamicro/javamicro_enum.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& params) - : params_(params), descriptor_(descriptor) { - for (int i = 0; i < descriptor_->value_count(); i++) { - const EnumValueDescriptor* value = descriptor_->value(i); - const EnumValueDescriptor* canonical_value = - descriptor_->FindValueByNumber(value->number()); - - if (value == canonical_value) { - canonical_values_.push_back(value); - } else { - Alias alias; - alias.value = value; - alias.canonical_value = canonical_value; - aliases_.push_back(alias); - } - } -} - -EnumGenerator::~EnumGenerator() {} - -void EnumGenerator::Generate(io::Printer* printer) { - printer->Print("// enum $classname$\n", "classname", descriptor_->name()); - for (int i = 0; i < canonical_values_.size(); i++) { - map<string, string> vars; - vars["name"] = canonical_values_[i]->name(); - vars["canonical_value"] = SimpleItoa(canonical_values_[i]->number()); - printer->Print(vars, - "public static final int $name$ = $canonical_value$;\n"); - } - - // ----------------------------------------------------------------- - - for (int i = 0; i < aliases_.size(); i++) { - map<string, string> vars; - vars["name"] = aliases_[i].value->name(); - vars["canonical_name"] = aliases_[i].canonical_value->name(); - printer->Print(vars, - "public static final int $name$ = $canonical_name$;\n"); - } - - printer->Print("\n"); -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.h b/src/google/protobuf/compiler/javamicro/javamicro_enum.h deleted file mode 100644 index 9cf226f..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_enum.h +++ /dev/null @@ -1,87 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ - -#include <string> -#include <vector> - -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/descriptor.h> - -namespace google { -namespace protobuf { - namespace io { - class Printer; // printer.h - } -} - -namespace protobuf { -namespace compiler { -namespace javamicro { - -class EnumGenerator { - public: - explicit EnumGenerator(const EnumDescriptor* descriptor, const Params& params); - ~EnumGenerator(); - - void Generate(io::Printer* printer); - - private: - const Params& params_; - const EnumDescriptor* descriptor_; - - // The proto language allows multiple enum constants to have the same numeric - // value. Java, however, does not allow multiple enum constants to be - // considered equivalent. We treat the first defined constant for any - // given numeric value as "canonical" and the rest as aliases of that - // canonical value. - vector<const EnumValueDescriptor*> canonical_values_; - - struct Alias { - const EnumValueDescriptor* value; - const EnumValueDescriptor* canonical_value; - }; - vector<Alias> aliases_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc deleted file mode 100644 index 0ff49a3..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc +++ /dev/null @@ -1,333 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <map> -#include <string> - -#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -namespace { - -// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of -// repeat code between this and the other field types. -void SetEnumVariables(const Params& params, - const FieldDescriptor* descriptor, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["type"] = "int"; - (*variables)["default"] = DefaultValue(params, descriptor); - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - (*variables)["tag_size"] = SimpleItoa( - internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); - (*variables)["message_name"] = descriptor->containing_type()->name(); -} - -} // namespace - -// =================================================================== - -EnumFieldGenerator:: -EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetEnumVariables(params, descriptor, &variables_); -} - -EnumFieldGenerator::~EnumFieldGenerator() {} - -void EnumFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - printer->Print(variables_, - "private boolean has$capitalized_name$;\n" - "private int $name$_ = $default$;\n" - "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" - "public int get$capitalized_name$() { return $name$_; }\n" - "public $message_name$ set$capitalized_name$(int value) {\n" - " has$capitalized_name$ = true;\n" - " $name$_ = value;\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " has$capitalized_name$ = false;\n" - " $name$_ = $default$;\n" - " return this;\n" - "}\n"); -} - -void EnumFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "what is other??" - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); -} - -void EnumFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - " set$capitalized_name$(input.readInt32());\n"); -} - -void EnumFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " output.writeInt32($number$, get$capitalized_name$());\n" - "}\n"); -} - -void EnumFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeInt32Size($number$, get$capitalized_name$());\n" - "}\n"); -} - -string EnumFieldGenerator::GetBoxedType() const { - return ClassName(params_, descriptor_->enum_type()); -} - -// =================================================================== - -RepeatedEnumFieldGenerator:: -RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetEnumVariables(params, descriptor, &variables_); - if (descriptor_->options().packed()) { - GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed"; - } -} - -RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} - -void RepeatedEnumFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "private java.util.Vector $name$_ = new java.util.Vector();\n" - "public java.util.Vector get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public int get$capitalized_name$(int index) {\n" - " return ((Integer)$name$_.elementAt(index)).intValue();\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, int value) {\n" - " $name$_.setElementAt(new Integer(value), index);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$(int value) {\n" - " $name$_.addElement(new Integer(value));\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_.removeAllElements();\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "private java.util.List<Integer> $name$_ =\n" - " java.util.Collections.emptyList();\n" - "public java.util.List<Integer> get$capitalized_name$List() {\n" - " return $name$_;\n" // note: unmodifiable list - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public int get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, int value) {\n" - " $name$_.set(index, value);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$(int value) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = new java.util.ArrayList<java.lang.Integer>();\n" - " }\n" - " $name$_.add(value);\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_ = java.util.Collections.emptyList();\n" - " return this;\n" - "}\n"); - } - if (descriptor_->options().packed()) { - printer->Print(variables_, - "private int $name$MemoizedSerializedSize;\n"); - } -} - -void RepeatedEnumFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "if (other.$name$_.size() != 0) {\n" - " for (int i = 0; i < other.$name$_.size(); i++)) {\n" - " result.$name$_.addElement(other.$name$_.elementAt(i));\n" - " }\n" - "}\n"); - } else { - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if (result.$name$_.isEmpty()) {\n" - " result.$name$_ = new java.util.ArrayList<java.lang.Integer>();\n" - " }\n" - " result.$name$_.addAll(other.$name$_);\n" - "}\n"); - } -} - -void RepeatedEnumFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - // If packed, set up the while loop - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int oldLimit = input.pushLimit(length);\n" - "while(input.getBytesUntilLimit() > 0) {\n"); - printer->Indent(); - } - - // Read and store the enum - printer->Print(variables_, - " add$capitalized_name$(input.readInt32());\n"); - - if (descriptor_->options().packed()) { - printer->Outdent(); - printer->Print(variables_, - "}\n" - "input.popLimit(oldLimit);\n"); - } -} - -void RepeatedEnumFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() > 0) {\n" - " output.writeRawVarint32($tag$);\n" - " output.writeRawVarint32($name$MemoizedSerializedSize);\n" - "}\n"); - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.writeRawVarint32(get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.writeRawVarint32(element.getNumber());\n" - "}\n"); - } - } else { - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.writeInt32($number$, (int)get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for (java.lang.Integer element : get$capitalized_name$List()) {\n" - " output.writeInt32($number$, element);\n" - "}\n"); - } - } -} - -void RepeatedEnumFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - printer->Print(variables_, - "{\n" - " int dataSize = 0;\n"); - printer->Indent(); - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeInt32SizeNoTag(get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for (java.lang.Integer element : get$capitalized_name$List()) {\n" - " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeInt32SizeNoTag(element);\n" - "}\n"); - } - printer->Print( - "size += dataSize;\n"); - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() != 0) {" - " size += $tag_size$;\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeRawVarint32Size(dataSize);\n" - "}"); - } else { - printer->Print(variables_, - "size += $tag_size$ * get$capitalized_name$List().size();\n"); - } - - // cache the data size for packed fields. - if (descriptor_->options().packed()) { - printer->Print(variables_, - "$name$MemoizedSerializedSize = dataSize;\n"); - } - - printer->Outdent(); - printer->Print("}\n"); -} - -string RepeatedEnumFieldGenerator::GetBoxedType() const { - return ClassName(params_, descriptor_->enum_type()); -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h deleted file mode 100644 index ab671c1..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h +++ /dev/null @@ -1,94 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ - -#include <map> -#include <string> -#include <google/protobuf/compiler/javamicro/javamicro_field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -class EnumFieldGenerator : public FieldGenerator { - public: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params); - ~EnumFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); -}; - -class RepeatedEnumFieldGenerator : public FieldGenerator { - public: - explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params); - ~RepeatedEnumFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_field.cc deleted file mode 100644 index a2ea4f9..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_field.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/javamicro/javamicro_field.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h> -#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h> -#include <google/protobuf/compiler/javamicro/javamicro_message_field.h> -#include <google/protobuf/stubs/common.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -FieldGenerator::~FieldGenerator() {} - -FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms) - : descriptor_(descriptor), - field_generators_( - new scoped_ptr<FieldGenerator>[descriptor->field_count()]), - extension_generators_( - new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { - - // Construct all the FieldGenerators. - for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(MakeGenerator(descriptor->field(i), params)); - } - for (int i = 0; i < descriptor->extension_count(); i++) { - extension_generators_[i].reset(MakeGenerator(descriptor->extension(i), params)); - } -} - -FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, const Params ¶ms) { - if (field->is_repeated()) { - switch (GetJavaType(field)) { - case JAVATYPE_MESSAGE: - return new RepeatedMessageFieldGenerator(field, params); - case JAVATYPE_ENUM: - return new RepeatedEnumFieldGenerator(field, params); - default: - return new RepeatedPrimitiveFieldGenerator(field, params); - } - } else { - switch (GetJavaType(field)) { - case JAVATYPE_MESSAGE: - return new MessageFieldGenerator(field, params); - case JAVATYPE_ENUM: - return new EnumFieldGenerator(field, params); - default: - return new PrimitiveFieldGenerator(field, params); - } - } -} - -FieldGeneratorMap::~FieldGeneratorMap() {} - -const FieldGenerator& FieldGeneratorMap::get( - const FieldDescriptor* field) const { - GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); - return *field_generators_[field->index()]; -} - -const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { - return *extension_generators_[index]; -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.cc b/src/google/protobuf/compiler/javamicro/javamicro_file.cc deleted file mode 100644 index 0985538..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_file.cc +++ /dev/null @@ -1,251 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/javamicro/javamicro_file.h> -#include <google/protobuf/compiler/javamicro/javamicro_enum.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/compiler/javamicro/javamicro_message.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -namespace { - -// Recursively searches the given message to see if it contains any extensions. -bool UsesExtensions(const Message& message) { - const Reflection* reflection = message.GetReflection(); - - // We conservatively assume that unknown fields are extensions. - if (reflection->GetUnknownFields(message).field_count() > 0) return true; - - vector<const FieldDescriptor*> fields; - reflection->ListFields(message, &fields); - - for (int i = 0; i < fields.size(); i++) { - if (fields[i]->is_extension()) return true; - - if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (fields[i]->is_repeated()) { - int size = reflection->FieldSize(message, fields[i]); - for (int j = 0; j < size; j++) { - const Message& sub_message = - reflection->GetRepeatedMessage(message, fields[i], j); - if (UsesExtensions(sub_message)) return true; - } - } else { - const Message& sub_message = reflection->GetMessage(message, fields[i]); - if (UsesExtensions(sub_message)) return true; - } - } - } - - return false; -} - -} // namespace - -FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params) - : file_(file), - params_(params), - java_package_(FileJavaPackage(params, file)), - classname_(FileClassName(params, file)) {} - -FileGenerator::~FileGenerator() {} - -bool FileGenerator::Validate(string* error) { - // Check for extensions - FileDescriptorProto file_proto; - file_->CopyTo(&file_proto); - if (UsesExtensions(file_proto)) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME does not support extensions\""); - return false; - } - - // If there is no outer class name then there must be only - // message and no enums defined in the file scope. - if (!params_.has_java_outer_classname(file_->name())) { - if (file_->message_type_count() != 1) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\""); - return false; - } - - if (file_->enum_type_count() != 0) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\""); - return false; - } - } - - // Check that no class name matches the file's class name. This is a common - // problem that leads to Java compile errors that can be hard to understand. - // It's especially bad when using the java_multiple_files, since we would - // end up overwriting the outer class with one of the inner ones. - int found_fileName = 0; - for (int i = 0; i < file_->enum_type_count(); i++) { - if (file_->enum_type(i)->name() == classname_) { - found_fileName += 1; - } - } - for (int i = 0; i < file_->message_type_count(); i++) { - if (file_->message_type(i)->name() == classname_) { - found_fileName += 1; - } - } - if (file_->service_count() != 0) { - error->assign(file_->name()); - error->append( - ": Java MICRO_RUNTIME does not support services\""); - return false; - } - - if (found_fileName > 1) { - error->assign(file_->name()); - error->append( - ": Cannot generate Java output because there is more than one class name, \""); - error->append(classname_); - error->append( - "\", matches the name of one of the types declared inside it. " - "Please either rename the type or use the java_outer_classname " - "option to specify a different outer class name for the .proto file." - " -- FIX THIS MESSAGE"); - return false; - } - return true; -} - -void FileGenerator::Generate(io::Printer* printer) { - // We don't import anything because we refer to all classes by their - // fully-qualified names in the generated source. - printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); - if (!java_package_.empty()) { - printer->Print( - "package $package$;\n" - "\n", - "package", java_package_); - } - - if (params_.has_java_outer_classname(file_->name())) { - printer->Print( - "public final class $classname$ {\n" - " private $classname$() {}\n", - "classname", classname_); - printer->Indent(); - } - - // ----------------------------------------------------------------- - - if (!params_.java_multiple_files()) { - for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator(file_->enum_type(i), params_).Generate(printer); - } - for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator(file_->message_type(i), params_).Generate(printer); - } - } - - // Static variables. - for (int i = 0; i < file_->message_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); - } - - if (params_.has_java_outer_classname(file_->name())) { - printer->Outdent(); - printer->Print( - "}\n"); - } -} - -template<typename GeneratorClass, typename DescriptorClass> -static void GenerateSibling(const string& package_dir, - const string& java_package, - const DescriptorClass* descriptor, - OutputDirectory* output_directory, - vector<string>* file_list, - const Params& params) { - string filename = package_dir + descriptor->name() + ".java"; - file_list->push_back(filename); - - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(filename)); - io::Printer printer(output.get(), '$'); - - printer.Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); - if (!java_package.empty()) { - printer.Print( - "package $package$;\n" - "\n", - "package", java_package); - } - - GeneratorClass(descriptor, params).Generate(&printer); -} - -void FileGenerator::GenerateSiblings(const string& package_dir, - OutputDirectory* output_directory, - vector<string>* file_list) { - if (params_.java_multiple_files()) { - for (int i = 0; i < file_->enum_type_count(); i++) { - GenerateSibling<EnumGenerator>(package_dir, java_package_, - file_->enum_type(i), - output_directory, file_list, params_); - } - for (int i = 0; i < file_->message_type_count(); i++) { - GenerateSibling<MessageGenerator>(package_dir, java_package_, - file_->message_type(i), - output_directory, file_list, params_); - } - } -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.h b/src/google/protobuf/compiler/javamicro/javamicro_file.h deleted file mode 100644 index 430172a..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_file.h +++ /dev/null @@ -1,94 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ - -#include <string> -#include <vector> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/javamicro/javamicro_params.h> - -namespace google { -namespace protobuf { - class FileDescriptor; // descriptor.h - namespace io { - class Printer; // printer.h - } - namespace compiler { - class OutputDirectory; // code_generator.h - } -} - -namespace protobuf { -namespace compiler { -namespace javamicro { - -class FileGenerator { - public: - explicit FileGenerator(const FileDescriptor* file, const Params& params); - ~FileGenerator(); - - // Checks for problems that would otherwise lead to cryptic compile errors. - // Returns true if there are no problems, or writes an error description to - // the given string and returns false otherwise. - bool Validate(string* error); - - void Generate(io::Printer* printer); - - // If we aren't putting everything into one file, this will write all the - // files other than the outer file (i.e. one for each message, enum, and - // service type). - void GenerateSiblings(const string& package_dir, - OutputDirectory* output_directory, - vector<string>* file_list); - - const string& java_package() { return java_package_; } - const string& classname() { return classname_; } - - private: - const FileDescriptor* file_; - const Params& params_; - string java_package_; - string classname_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc deleted file mode 100644 index bfba8c5..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc +++ /dev/null @@ -1,209 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/compiler/javamicro/javamicro_generator.h> -#include <google/protobuf/compiler/javamicro/javamicro_file.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -void UpdateParamsRecursively(Params& params, - const FileDescriptor* file) { - // Add any parameters for this file - if (file->options().has_java_outer_classname()) { - params.set_java_outer_classname( - file->name(), file->options().java_outer_classname()); - } - if (file->options().has_java_package()) { - params.set_java_package( - file->name(), file->options().java_package()); - } - - // Loop through all dependent files recursively - // adding dep - for (int i = 0; i < file->dependency_count(); i++) { - UpdateParamsRecursively(params, file->dependency(i)); - } -} - -JavaMicroGenerator::JavaMicroGenerator() {} -JavaMicroGenerator::~JavaMicroGenerator() {} - -bool JavaMicroGenerator::Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const { - vector<pair<string, string> > options; - -// GOOGLE_LOG(INFO) << "wink: JavaMicroGenerator::Generate INFO"; -// GOOGLE_LOG(WARNING) << "wink: JavaMicroGenerator::Generate WARNING"; -// GOOGLE_LOG(ERROR) << "wink: JavaMicroGenerator::Generate ERROR"; -// GOOGLE_LOG(FATAL) << "wink: JavaMicroGenerator::Generate"; - - ParseGeneratorParameter(parameter, &options); - - // ----------------------------------------------------------------- - // parse generator options - - // Name a file where we will write a list of generated file names, one - // per line. - string output_list_file; - Params params(file->name()); - - // Get options from the proto file - if (file->options().has_java_multiple_files()) { - params.set_java_multiple_files(file->options().java_multiple_files()); - } - - // Update per file params - UpdateParamsRecursively(params, file); - - // Replace any existing options with ones from command line - for (int i = 0; i < options.size(); i++) { - // GOOGLE_LOG(WARNING) << "first=" << options[i].first - // << " second=" << options[i].second; - if (options[i].first == "output_list_file") { - output_list_file = options[i].second; - } else if (options[i].first == "opt") { - if (options[i].second == "speed") { - params.set_optimization(JAVAMICRO_OPT_SPEED); - } else if (options[i].second == "space") { - params.set_optimization(JAVAMICRO_OPT_SPACE); - } else { - *error = "Unknown javamicro generator option: opt=" - + options[i].second + " expecting opt=space or opt=speed"; - return false; - } - } else if (options[i].first == "java_package") { - vector<string> parts; - SplitStringUsing(options[i].second, "|", &parts); - if (parts.size() != 2) { - *error = "Bad java_package, expecting filename|PackageName found '" - + options[i].second + "'"; - return false; - } - params.set_java_package(parts[0], parts[1]); - } else if (options[i].first == "java_outer_classname") { - vector<string> parts; - SplitStringUsing(options[i].second, "|", &parts); - if (parts.size() != 2) { - *error = "Bad java_outer_classname, " - "expecting filename|ClassName found '" - + options[i].second + "'"; - return false; - } - params.set_java_outer_classname(parts[0], parts[1]); - } else if (options[i].first == "java_multiple_files") { - params.set_java_multiple_files(options[i].second == "true"); - } else if (options[i].first == "java_use_vector") { - params.set_java_use_vector(options[i].second == "true"); - } else { - *error = "Ignore unknown javamicro generator option: " + options[i].first; - } - } - -#if 0 - GOOGLE_LOG(WARNING) << "optimization()=" << params.optimization(); - GOOGLE_LOG(WARNING) << "java_multiple_files()=" << params.java_multiple_files(); - GOOGLE_LOG(WARNING) << "java_use_vector()=" << params.java_use_vector(); - - GOOGLE_LOG(WARNING) << "----------"; - for (Params::NameMap::const_iterator it = params.java_packages().begin(); - it != params.java_packages().end(); - ++it) { - GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " package=" << it->second; - } - for (Params::NameMap::const_iterator it = params.java_outer_classnames().begin(); - it != params.java_outer_classnames().end(); - ++it) { - GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " classname=" << it->second; - } - GOOGLE_LOG(WARNING) << "=========="; - -#endif - - // ----------------------------------------------------------------- - - FileGenerator file_generator(file, params); - if (!file_generator.Validate(error)) { - return false; - } - - string package_dir = - StringReplace(file_generator.java_package(), ".", "/", true); - if (!package_dir.empty()) package_dir += "/"; - - vector<string> all_files; - - string java_filename = package_dir; - java_filename += file_generator.classname(); - java_filename += ".java"; - all_files.push_back(java_filename); - - // Generate main java file. - scoped_ptr<io::ZeroCopyOutputStream> output( - output_directory->Open(java_filename)); - io::Printer printer(output.get(), '$'); - file_generator.Generate(&printer); - - // Generate sibling files. - file_generator.GenerateSiblings(package_dir, output_directory, &all_files); - - // Generate output list if requested. - if (!output_list_file.empty()) { - // Generate output list. This is just a simple text file placed in a - // deterministic location which lists the .java files being generated. - scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output( - output_directory->Open(output_list_file)); - io::Printer srclist_printer(srclist_raw_output.get(), '$'); - for (int i = 0; i < all_files.size(); i++) { - srclist_printer.Print("$filename$\n", "filename", all_files[i]); - } - } - - return true; -} - -} // namespace java -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc deleted file mode 100644 index 11ba71a..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc +++ /dev/null @@ -1,381 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <vector> - -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/substitute.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -const char kThickSeparator[] = - "// ===================================================================\n"; -const char kThinSeparator[] = - "// -------------------------------------------------------------------\n"; - -namespace { - -const char* kDefaultPackage = ""; - -const string& FieldName(const FieldDescriptor* field) { - // Groups are hacky: The name of the field is just the lower-cased name - // of the group type. In Java, though, we would like to retain the original - // capitalization of the type name. - if (field->type() == FieldDescriptor::TYPE_GROUP) { - return field->message_type()->name(); - } else { - return field->name(); - } -} - -string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { - string result; - // Note: I distrust ctype.h due to locales. - for (int i = 0; i < input.size(); i++) { - if ('a' <= input[i] && input[i] <= 'z') { - if (cap_next_letter) { - result += input[i] + ('A' - 'a'); - } else { - result += input[i]; - } - cap_next_letter = false; - } else if ('A' <= input[i] && input[i] <= 'Z') { - if (i == 0 && !cap_next_letter) { - // Force first letter to lower-case unless explicitly told to - // capitalize it. - result += input[i] + ('a' - 'A'); - } else { - // Capital letters after the first are left as-is. - result += input[i]; - } - cap_next_letter = false; - } else if ('0' <= input[i] && input[i] <= '9') { - result += input[i]; - cap_next_letter = true; - } else { - cap_next_letter = true; - } - } - return result; -} - -} // namespace - -string UnderscoresToCamelCase(const FieldDescriptor* field) { - return UnderscoresToCamelCaseImpl(FieldName(field), false); -} - -string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { - return UnderscoresToCamelCaseImpl(FieldName(field), true); -} - -string UnderscoresToCamelCase(const MethodDescriptor* method) { - return UnderscoresToCamelCaseImpl(method->name(), false); -} - -string StripProto(const string& filename) { - if (HasSuffixString(filename, ".protodevel")) { - return StripSuffixString(filename, ".protodevel"); - } else { - return StripSuffixString(filename, ".proto"); - } -} - -string FileClassName(const Params& params, const FileDescriptor* file) { - string name; - - if (params.has_java_outer_classname(file->name())) { - name = params.java_outer_classname(file->name()); - } else { - if ((file->message_type_count() == 1) - || (file->enum_type_count() == 0)) { - // If no outer calls and only one message then - // use the message name as the file name - name = file->message_type(0)->name(); - } else { - // Use the filename it self with underscores removed - // and a CamelCase style name. - string basename; - string::size_type last_slash = file->name().find_last_of('/'); - if (last_slash == string::npos) { - basename = file->name(); - } else { - basename = file->name().substr(last_slash + 1); - } - name = UnderscoresToCamelCaseImpl(StripProto(basename), true); - } - } - - return name; -} - -string FileJavaPackage(const Params& params, const FileDescriptor* file) { - if (params.has_java_package(file->name())) { - return params.java_package(file->name()); - } else { - string result = kDefaultPackage; - if (!file->package().empty()) { - if (!result.empty()) result += '.'; - result += file->package(); - } - return result; - } -} - -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file) { - string result; - if (params.java_multiple_files()) { - result = FileJavaPackage(params, file); - } else { - result = ClassName(params, file); - } - if (file->package().empty()) { - result += '.'; - result += full_name; - } else { - // Strip the proto package from full_name since we've replaced it with - // the Java package. If there isn't an outer classname then strip it too. - int sizeToSkipPackageName = file->package().size(); - int sizeToSkipOutClassName; - if (params.has_java_outer_classname(file->name())) { - sizeToSkipOutClassName = 0; - } else { - sizeToSkipOutClassName = - full_name.find_first_of('.', sizeToSkipPackageName + 1); - } - int sizeToSkip = sizeToSkipOutClassName > 0 ? - sizeToSkipOutClassName : sizeToSkipPackageName; - string class_name = full_name.substr(sizeToSkip + 1); - if (class_name == FileClassName(params, file)) { - // Done class_name is already present. - } else { - result += '.'; - result += class_name; - } - } - return result; -} - -string ClassName(const Params& params, const FileDescriptor* descriptor) { - string result = FileJavaPackage(params, descriptor); - if (!result.empty()) result += '.'; - result += FileClassName(params, descriptor); - return result; -} - -string ClassName(const Params& params, const EnumDescriptor* descriptor) { - string result; - const FileDescriptor* file = descriptor->file(); - const string file_name = file->name(); - const string full_name = descriptor->full_name(); - int last_period = full_name.find_last_of('.'); - int first_period = full_name.find_first_of('.'); - - // Remove class_name as we're using public static final int's not enums - string base_name = full_name.substr(0, full_name.find_last_of('.')); - - if (!file->package().empty()) { - // Remove package name. - int offset = first_period; - if (last_period > first_period) { - // There was two or more periods so we need to remove this one too. - offset += 1; - } - base_name = base_name.substr(offset); - } - - if (params.has_java_package(file_name)) { - result += params.java_package(file_name); - } - if (params.has_java_outer_classname(file_name)) { - result += "."; - result += params.java_outer_classname(file_name); - } - if (!base_name.empty()) { - result += "."; - result += base_name; - } - return result; -} - -string FieldConstantName(const FieldDescriptor *field) { - string name = field->name() + "_FIELD_NUMBER"; - UpperString(&name); - return name; -} - -JavaType GetJavaType(FieldDescriptor::Type field_type) { - switch (field_type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return JAVATYPE_INT; - - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return JAVATYPE_LONG; - - case FieldDescriptor::TYPE_FLOAT: - return JAVATYPE_FLOAT; - - case FieldDescriptor::TYPE_DOUBLE: - return JAVATYPE_DOUBLE; - - case FieldDescriptor::TYPE_BOOL: - return JAVATYPE_BOOLEAN; - - case FieldDescriptor::TYPE_STRING: - return JAVATYPE_STRING; - - case FieldDescriptor::TYPE_BYTES: - return JAVATYPE_BYTES; - - case FieldDescriptor::TYPE_ENUM: - return JAVATYPE_ENUM; - - case FieldDescriptor::TYPE_GROUP: - case FieldDescriptor::TYPE_MESSAGE: - return JAVATYPE_MESSAGE; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return JAVATYPE_INT; -} - -const char* BoxedPrimitiveTypeName(JavaType type) { - switch (type) { - case JAVATYPE_INT : return "java.lang.Integer"; - case JAVATYPE_LONG : return "java.lang.Long"; - case JAVATYPE_FLOAT : return "java.lang.Float"; - case JAVATYPE_DOUBLE : return "java.lang.Double"; - case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; - case JAVATYPE_STRING : return "java.lang.String"; - case JAVATYPE_BYTES : return "com.google.protobuf.micro.ByteStringMicro"; - case JAVATYPE_ENUM : return "java.lang.Integer"; - case JAVATYPE_MESSAGE: return NULL; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - -bool AllAscii(const string& text) { - for (int i = 0; i < text.size(); i++) { - if ((text[i] & 0x80) != 0) { - return false; - } - } - return true; -} - -string DefaultValue(const Params& params, const FieldDescriptor* field) { - // Switch on cpp_type since we need to know which default_value_* method - // of FieldDescriptor to call. - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_INT32: - return SimpleItoa(field->default_value_int32()); - case FieldDescriptor::CPPTYPE_UINT32: - // Need to print as a signed int since Java has no unsigned. - return SimpleItoa(static_cast<int32>(field->default_value_uint32())); - case FieldDescriptor::CPPTYPE_INT64: - return SimpleItoa(field->default_value_int64()) + "L"; - case FieldDescriptor::CPPTYPE_UINT64: - return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + - "L"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()) + "D"; - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field->default_value_float()) + "F"; - case FieldDescriptor::CPPTYPE_BOOL: - return field->default_value_bool() ? "true" : "false"; - case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { - if (field->has_default_value()) { - // See comments in Internal.java for gory details. - return strings::Substitute( - "com.google.protobuf.micro.ByteStringMicro.copyFromUtf8(\"$0\")", - CEscape(field->default_value_string())); - } else { - return "com.google.protobuf.micro.ByteStringMicro.EMPTY"; - } - } else { - if (AllAscii(field->default_value_string())) { - // All chars are ASCII. In this case CEscape() works fine. - return "\"" + CEscape(field->default_value_string()) + "\""; - } else { - // See comments in Internal.java for gory details. - // BUG: Internal NOT SUPPORTED need to fix!! - return strings::Substitute( - "com.google.protobuf.micro.Internal.stringDefaultValue(\"$0\")", - CEscape(field->default_value_string())); - } - } - - case FieldDescriptor::CPPTYPE_ENUM: - return ClassName(params, field->enum_type()) + "." + - field->default_value_enum()->name(); - - case FieldDescriptor::CPPTYPE_MESSAGE: - return ClassName(params, field->message_type()) + ".getDefaultInstance()"; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return ""; -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h deleted file mode 100644 index eeddbf9..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h +++ /dev/null @@ -1,128 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ - -#include <string> -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/descriptor.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -// Commonly-used separator comments. Thick is a line of '=', thin is a line -// of '-'. -extern const char kThickSeparator[]; -extern const char kThinSeparator[]; - -// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes -// "fooBarBaz" or "FooBarBaz", respectively. -string UnderscoresToCamelCase(const FieldDescriptor* field); -string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); - -// Similar, but for method names. (Typically, this merely has the effect -// of lower-casing the first letter of the name.) -string UnderscoresToCamelCase(const MethodDescriptor* method); - -// Strips ".proto" or ".protodevel" from the end of a filename. -string StripProto(const string& filename); - -// Gets the unqualified class name for the file. Each .proto file becomes a -// single Java class, with all its contents nested in that class. -string FileClassName(const Params& params, const FileDescriptor* file); - -// Returns the file's Java package name. -string FileJavaPackage(const Params& params, const FileDescriptor* file); - -// Converts the given fully-qualified name in the proto namespace to its -// fully-qualified name in the Java namespace, given that it is in the given -// file. -string ToJavaName(const Params& params, const string& full_name, - const FileDescriptor* file); - -// These return the fully-qualified class name corresponding to the given -// descriptor. -inline string ClassName(const Params& params, const Descriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); -} -string ClassName(const Params& params, const EnumDescriptor* descriptor); -inline string ClassName(const Params& params, - const ServiceDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); -} -inline string ExtensionIdentifierName(const Params& params, - const FieldDescriptor* descriptor) { - return ToJavaName(params, descriptor->full_name(), descriptor->file()); -} -string ClassName(const Params& params, const FileDescriptor* descriptor); - -// Get the unqualified name that should be used for a field's field -// number constant. -string FieldConstantName(const FieldDescriptor *field); - -enum JavaType { - JAVATYPE_INT, - JAVATYPE_LONG, - JAVATYPE_FLOAT, - JAVATYPE_DOUBLE, - JAVATYPE_BOOLEAN, - JAVATYPE_STRING, - JAVATYPE_BYTES, - JAVATYPE_ENUM, - JAVATYPE_MESSAGE -}; - -JavaType GetJavaType(FieldDescriptor::Type field_type); - -inline JavaType GetJavaType(const FieldDescriptor* field) { - return GetJavaType(field->type()); -} - -// Get the fully-qualified class name for a boxed primitive type, e.g. -// "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message -// types. -const char* BoxedPrimitiveTypeName(JavaType type); - -string DefaultValue(const Params& params, const FieldDescriptor* field); - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.cc b/src/google/protobuf/compiler/javamicro/javamicro_message.cc deleted file mode 100644 index 7fc6c3d..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_message.cc +++ /dev/null @@ -1,474 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <algorithm> -#include <google/protobuf/stubs/hash.h> -#include <google/protobuf/compiler/javamicro/javamicro_message.h> -#include <google/protobuf/compiler/javamicro/javamicro_enum.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/descriptor.pb.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -using internal::WireFormat; -using internal::WireFormatLite; - -namespace { - -void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { - // Print the field's proto-syntax definition as a comment. We don't want to - // print group bodies so we cut off after the first line. - string def = field->DebugString(); - printer->Print("// $def$\n", - "def", def.substr(0, def.find_first_of('\n'))); -} - -struct FieldOrderingByNumber { - inline bool operator()(const FieldDescriptor* a, - const FieldDescriptor* b) const { - return a->number() < b->number(); - } -}; - -// Sort the fields of the given Descriptor by number into a new[]'d array -// and return it. -const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { - const FieldDescriptor** fields = - new const FieldDescriptor*[descriptor->field_count()]; - for (int i = 0; i < descriptor->field_count(); i++) { - fields[i] = descriptor->field(i); - } - sort(fields, fields + descriptor->field_count(), - FieldOrderingByNumber()); - return fields; -} - -// Get an identifier that uniquely identifies this type within the file. -// This is used to declare static variables related to this type at the -// outermost file scope. -string UniqueFileScopeIdentifier(const Descriptor* descriptor) { - return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); -} - -// Returns true if the message type has any required fields. If it doesn't, -// we can optimize out calls to its isInitialized() method. -// -// already_seen is used to avoid checking the same type multiple times -// (and also to protect against recursion). -static bool HasRequiredFields( - const Descriptor* type, - hash_set<const Descriptor*>* already_seen) { - if (already_seen->count(type) > 0) { - // The type is already in cache. This means that either: - // a. The type has no required fields. - // b. We are in the midst of checking if the type has required fields, - // somewhere up the stack. In this case, we know that if the type - // has any required fields, they'll be found when we return to it, - // and the whole call to HasRequiredFields() will return true. - // Therefore, we don't have to check if this type has required fields - // here. - return false; - } - already_seen->insert(type); - - // If the type has extensions, an extension with message type could contain - // required fields, so we have to be conservative and assume such an - // extension exists. - if (type->extension_range_count() > 0) return true; - - for (int i = 0; i < type->field_count(); i++) { - const FieldDescriptor* field = type->field(i); - if (field->is_required()) { - return true; - } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (HasRequiredFields(field->message_type(), already_seen)) { - return true; - } - } - } - - return false; -} - -static bool HasRequiredFields(const Descriptor* type) { - hash_set<const Descriptor*> already_seen; - return HasRequiredFields(type, &already_seen); -} - -} // namespace - -// =================================================================== - -MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params) - : params_(params), - descriptor_(descriptor), - field_generators_(descriptor, params) { -} - -MessageGenerator::~MessageGenerator() {} - -void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { - // Generate static members for all nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(descriptor_->nested_type(i), params_) - .GenerateStaticVariables(printer); - } -} - -void MessageGenerator::GenerateStaticVariableInitializers( - io::Printer* printer) { - // Generate static member initializers for all nested types. - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - // TODO(kenton): Reuse MessageGenerator objects? - MessageGenerator(descriptor_->nested_type(i), params_) - .GenerateStaticVariableInitializers(printer); - } - - if (descriptor_->extension_count() != 0) { - GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; - } -} - -void MessageGenerator::Generate(io::Printer* printer) { - bool is_own_file = - params_.java_multiple_files() || ((descriptor_->containing_type() == NULL) - && !params_.has_java_outer_classname(descriptor_->file()->name())); - -#if 0 - GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file; - GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null"); - GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files(); - GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name()); -#endif - - if ((descriptor_->extension_count() != 0) - || (descriptor_->extension_range_count() != 0)) { - GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; - } - - printer->Print( - "public $modifiers$ final class $classname$ extends\n" - " com.google.protobuf.micro.MessageMicro {\n", - "modifiers", is_own_file ? "" : "static", - "classname", descriptor_->name()); - printer->Indent(); - printer->Print( - "public $classname$() {}\n" - "\n", - "classname", descriptor_->name()); - - // Nested types and extensions - for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer); - } - - // Fields - for (int i = 0; i < descriptor_->field_count(); i++) { - PrintFieldComment(printer, descriptor_->field(i)); - printer->Print("public static final int $constant_name$ = $number$;\n", - "constant_name", FieldConstantName(descriptor_->field(i)), - "number", SimpleItoa(descriptor_->field(i)->number())); - field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); - printer->Print("\n"); - } - - GenerateClear(printer); - GenerateIsInitialized(printer); - GenerateMessageSerializationMethods(printer); - GenerateMergeFromMethods(printer); - GenerateParseFromMethods(printer); - - printer->Outdent(); - printer->Print("}\n\n"); -} - -// =================================================================== - -void MessageGenerator:: -GenerateMessageSerializationMethods(io::Printer* printer) { - scoped_array<const FieldDescriptor*> sorted_fields( - SortFieldsByNumber(descriptor_)); - - if (descriptor_->extension_range_count() != 0) { - GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; - } - - printer->Print( - "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n" - " throws java.io.IOException {\n"); - printer->Indent(); - - // Output the fields in sorted order - for (int i = 0; i < descriptor_->field_count(); i++) { - GenerateSerializeOneField(printer, sorted_fields[i]); - } - - printer->Outdent(); - printer->Print( - "}\n" - "\n" - "private int cachedSize = -1;\n" - "public int getCachedSize() {\n" - " if (cachedSize < 0) {\n" - " // getSerializedSize sets cachedSize\n" - " getSerializedSize();\n" - " }\n" - " return cachedSize;\n" - "}\n" - "\n" - "public int getSerializedSize() {\n" - " int size = 0;\n"); - printer->Indent(); - - for (int i = 0; i < descriptor_->field_count(); i++) { - field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); - } - - printer->Outdent(); - printer->Print( - " cachedSize = size;\n" - " return size;\n" - "}\n" - "\n"); -} - -void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { - scoped_array<const FieldDescriptor*> sorted_fields( - SortFieldsByNumber(descriptor_)); - - if (params_.java_use_vector()) { - printer->Print( - "public com.google.protobuf.micro.MessageMicro mergeFrom(\n" - " com.google.protobuf.micro.CodedInputStreamMicro input)\n" - " throws java.io.IOException {\n", - "classname", descriptor_->name()); - } else { - printer->Print( - "public $classname$ mergeFrom(\n" - " com.google.protobuf.micro.CodedInputStreamMicro input)\n" - " throws java.io.IOException {\n", - "classname", descriptor_->name()); - } - printer->Indent(); - - printer->Print( - "while (true) {\n"); - printer->Indent(); - - printer->Print( - "int tag = input.readTag();\n" - "switch (tag) {\n"); - printer->Indent(); - - printer->Print( - "case 0:\n" // zero signals EOF / limit reached - " return this;\n" - "default: {\n" - " if (!parseUnknownField(input, tag)) {\n" - " return this;\n" // it's an endgroup tag - " }\n" - " break;\n" - "}\n"); - - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = sorted_fields[i]; - uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForField(field)); - - printer->Print( - "case $tag$: {\n", - "tag", SimpleItoa(tag)); - printer->Indent(); - - field_generators_.get(field).GenerateParsingCode(printer); - - printer->Outdent(); - printer->Print( - " break;\n" - "}\n"); - } - - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " }\n" // switch (tag) - " }\n" // while (true) - "}\n" - "\n"); -} - -void MessageGenerator:: -GenerateParseFromMethods(io::Printer* printer) { - bool is_own_file = - descriptor_->containing_type() == NULL; - - // Note: These are separate from GenerateMessageSerializationMethods() - // because they need to be generated even for messages that are optimized - // for code size. - printer->Print( - "public $static$ $classname$ parseFrom(byte[] data)\n" - " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n" - " return ($classname$) (new $classname$().mergeFrom(data));\n" - "}\n" - "\n" - "public $static$ $classname$ parseFrom(\n" - " com.google.protobuf.micro.CodedInputStreamMicro input)\n" - " throws java.io.IOException {\n" - " return ($classname$) (new $classname$().mergeFrom(input));\n" - "}\n" - "\n", - "static", (is_own_file ? "static" : ""), - "classname", descriptor_->name()); -} - -void MessageGenerator::GenerateSerializeOneField( - io::Printer* printer, const FieldDescriptor* field) { - field_generators_.get(field).GenerateSerializationCode(printer); -} - -void MessageGenerator::GenerateClear(io::Printer* printer) { - printer->Print( - "public final $classname$ clear() {\n", - "classname", descriptor_->name()); - printer->Indent(); - - // Call clear for all of the fields. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - printer->Print( - "clear$name$();\n", - "name", UnderscoresToCapitalizedCamelCase(field)); - } - - printer->Outdent(); - printer->Print( - " cachedSize = -1;\n" - " return this;\n" - "}\n" - "\n"); -} - - -void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { - printer->Print( - "public final boolean isInitialized() {\n"); - printer->Indent(); - - // Check that all required fields in this message are set. - // TODO(kenton): We can optimize this when we switch to putting all the - // "has" fields into a single bitfield. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - if (field->is_required()) { - printer->Print( - "if (!has$name$) return false;\n", - "name", UnderscoresToCapitalizedCamelCase(field)); - } - } - - // Now check that all embedded messages are initialized. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - HasRequiredFields(field->message_type())) { - switch (field->label()) { - case FieldDescriptor::LABEL_REQUIRED: - printer->Print( - "if (!get$name$().isInitialized()) return false;\n", - "type", ClassName(params_, field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field)); - break; - case FieldDescriptor::LABEL_OPTIONAL: - printer->Print( - "if (has$name$()) {\n" - " if (!get$name$().isInitialized()) return false;\n" - "}\n", - "type", ClassName(params_, field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field)); - break; - case FieldDescriptor::LABEL_REPEATED: - if (params_.java_use_vector()) { - printer->Print( - "for (int i = 0; i < get$name$List().size(); i++) {\n" - " if (get$name$(i).isInitialized()) return false;\n" - "}\n", - "type", ClassName(params_, field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field)); - } else { - printer->Print( - "for ($type$ element : get$name$List()) {\n" - " if (!element.isInitialized()) return false;\n" - "}\n", - "type", ClassName(params_, field->message_type()), - "name", UnderscoresToCapitalizedCamelCase(field)); - } - break; - } - } - } - - if (descriptor_->extension_range_count() > 0) { - printer->Print( - "if (!extensionsAreInitialized()) return false;\n"); - } - - printer->Outdent(); - printer->Print( - " return true;\n" - "}\n" - "\n"); -} - -// =================================================================== - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.h b/src/google/protobuf/compiler/javamicro/javamicro_message.h deleted file mode 100644 index f44c7a7..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_message.h +++ /dev/null @@ -1,93 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ - -#include <string> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/javamicro/javamicro_params.h> -#include <google/protobuf/compiler/javamicro/javamicro_field.h> - -namespace google { -namespace protobuf { - namespace io { - class Printer; // printer.h - } -} - -namespace protobuf { -namespace compiler { -namespace javamicro { - -class MessageGenerator { - public: - explicit MessageGenerator(const Descriptor* descriptor, const Params& params); - ~MessageGenerator(); - - // All static variables have to be declared at the top-level of the file - // so that we can control initialization order, which is important for - // DescriptorProto bootstrapping to work. - void GenerateStaticVariables(io::Printer* printer); - - // Output code which initializes the static variables generated by - // GenerateStaticVariables(). - void GenerateStaticVariableInitializers(io::Printer* printer); - - // Generate the class itself. - void Generate(io::Printer* printer); - - private: - void GenerateMessageSerializationMethods(io::Printer* printer); - void GenerateMergeFromMethods(io::Printer* printer); - void GenerateParseFromMethods(io::Printer* printer); - void GenerateSerializeOneField(io::Printer* printer, - const FieldDescriptor* field); - - void GenerateClear(io::Printer* printer); - void GenerateIsInitialized(io::Printer* printer); - - const Params& params_; - const Descriptor* descriptor_; - FieldGeneratorMap field_generators_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc deleted file mode 100644 index 103c302..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc +++ /dev/null @@ -1,302 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <map> -#include <string> - -#include <google/protobuf/compiler/javamicro/javamicro_message_field.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -namespace { - -// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of -// repeat code between this and the other field types. -void SetMessageVariables(const Params& params, - const FieldDescriptor* descriptor, map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["type"] = ClassName(params, descriptor->message_type()); - (*variables)["group_or_message"] = - (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? - "Group" : "Message"; - (*variables)["message_name"] = descriptor->containing_type()->name(); - //(*variables)["message_type"] = descriptor->message_type()->name(); -} - -} // namespace - -// =================================================================== - -MessageFieldGenerator:: -MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetMessageVariables(params, descriptor, &variables_); -} - -MessageFieldGenerator::~MessageFieldGenerator() {} - -void MessageFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - printer->Print(variables_, - "private boolean has$capitalized_name$;\n" -// "private $type$ $name$_ = null;\n" -// "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" -// "public $type$ get$capitalized_name$() { return $name$_; }\n" - "private $type$ $name$_ = null;\n" - "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" - "public $type$ get$capitalized_name$() { return $name$_; }\n" - "public $message_name$ set$capitalized_name$($type$ value) {\n" - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n" - " has$capitalized_name$ = true;\n" - " $name$_ = value;\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " has$capitalized_name$ = false;\n" - " $name$_ = null;\n" - " return this;\n" - "}\n"); -} - -void MessageFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " merge$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); -} - -void MessageFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "$type$ value = new $type$();\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { - printer->Print(variables_, - "input.readGroup(value, $number$);\n"); - } else { - printer->Print(variables_, - "input.readMessage(value);\n"); - } - - printer->Print(variables_, - "set$capitalized_name$(value);\n"); -} - -void MessageFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " output.write$group_or_message$($number$, get$capitalized_name$());\n" - "}\n"); -} - -void MessageFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .compute$group_or_message$Size($number$, get$capitalized_name$());\n" - "}\n"); -} - -string MessageFieldGenerator::GetBoxedType() const { - return ClassName(params_, descriptor_->message_type()); -} - -// =================================================================== - -RepeatedMessageFieldGenerator:: -RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetMessageVariables(params, descriptor, &variables_); -} - -RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} - -void RepeatedMessageFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "private java.util.Vector $name$_ = new java.util.Vector();\n" - "public java.util.Vector get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public $type$ get$capitalized_name$(int index) {\n" - " return ($type$) $name$_.elementAt(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n" - " $name$_.setElementAt(value, index);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$($type$ value) {\n" - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n" - " $name$_.addElement(value);\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_.removeAllElements();\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "private java.util.List<$type$> $name$_ =\n" - " java.util.Collections.emptyList();\n" - "public java.util.List<$type$> get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n" - " $name$_.set(index, value);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$($type$ value) {\n" - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = new java.util.ArrayList<$type$>();\n" - " }\n" - " $name$_.add(value);\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_ = java.util.Collections.emptyList();\n" - " return this;\n" - "}\n"); - } -} - -void RepeatedMessageFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "if (other.$name$_.size() != 0) {\n" - " for (int i = 0; i < other.$name$_.size(); i++) {\n" - " result.$name$_.addElement(other.$name$_.elementAt(i));\n" - " }\n" - "}\n"); - } else { - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if (result.$name$_.isEmpty()) {\n" - " result.$name$_ = new java.util.ArrayList<$type$>();\n" - " }\n" - " result.$name$_.addAll(other.$name$_);\n" - "}\n"); - } -} - -void RepeatedMessageFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "$type$ value = new $type$();\n"); - - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { - printer->Print(variables_, - "input.readGroup(value, $number$);\n"); - } else { - printer->Print(variables_, - "input.readMessage(value);\n"); - } - - printer->Print(variables_, - "add$capitalized_name$(value);\n"); -} - -void RepeatedMessageFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.write$group_or_message$($number$, get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.write$group_or_message$($number$, element);\n" - "}\n"); - } -} - -void RepeatedMessageFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .compute$group_or_message$Size($number$, get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .compute$group_or_message$Size($number$, element);\n" - "}\n"); - } -} - -string RepeatedMessageFieldGenerator::GetBoxedType() const { - return ClassName(params_, descriptor_->message_type()); -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.h b/src/google/protobuf/compiler/javamicro/javamicro_message_field.h deleted file mode 100644 index a32aa4e..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_message_field.h +++ /dev/null @@ -1,95 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ - -#include <map> -#include <string> -#include <google/protobuf/compiler/javamicro/javamicro_field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -class MessageFieldGenerator : public FieldGenerator { - public: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params); - ~MessageFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); -}; - -class RepeatedMessageFieldGenerator : public FieldGenerator { - public: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Params& params); - ~RepeatedMessageFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_params.h b/src/google/protobuf/compiler/javamicro/javamicro_params.h deleted file mode 100644 index a4a72b7..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_params.h +++ /dev/null @@ -1,143 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2010 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: wink@google.com (Wink Saville) - -#ifndef PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ -#define PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ - -#include <map> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -enum eOptimization { JAVAMICRO_OPT_SPEED, JAVAMICRO_OPT_SPACE, JAVAMICRO_OPT_DEFAULT = JAVAMICRO_OPT_SPACE }; - -// Parameters for used by the generators -class Params { - public: - typedef map<string, string> NameMap; - private: - string empty_; - string base_name_; - eOptimization optimization_; - bool java_multiple_files_; - bool java_use_vector_; - NameMap java_packages_; - NameMap java_outer_classnames_; - - public: - Params(const string & base_name) : - empty_(""), - base_name_(base_name), - optimization_(JAVAMICRO_OPT_DEFAULT), - java_multiple_files_(false), - java_use_vector_(false) { - } - - const string& base_name() const { - return base_name_; - } - - bool has_java_package(const string& file_name) const { - return java_packages_.find(file_name) - != java_packages_.end(); - } - void set_java_package(const string& file_name, - const string& java_package) { - java_packages_[file_name] = java_package; - } - const string& java_package(const string& file_name) const { - NameMap::const_iterator itr; - - itr = java_packages_.find(file_name); - if (itr == java_packages_.end()) { - return empty_; - } else { - return itr->second; - } - } - const NameMap& java_packages() { - return java_packages_; - } - - bool has_java_outer_classname(const string& file_name) const { - return java_outer_classnames_.find(file_name) - != java_outer_classnames_.end(); - } - void set_java_outer_classname(const string& file_name, - const string& java_outer_classname) { - java_outer_classnames_[file_name] = java_outer_classname; - } - const string& java_outer_classname(const string& file_name) const { - NameMap::const_iterator itr; - - itr = java_outer_classnames_.find(file_name); - if (itr == java_outer_classnames_.end()) { - return empty_; - } else { - return itr->second; - } - } - const NameMap& java_outer_classnames() { - return java_outer_classnames_; - } - - void set_optimization(eOptimization optimization) { - optimization_ = optimization; - } - eOptimization optimization() const { - return optimization_; - } - - void set_java_multiple_files(bool value) { - java_multiple_files_ = value; - } - bool java_multiple_files() const { - return java_multiple_files_; - } - - void set_java_use_vector(bool value) { - java_use_vector_ = value; - } - bool java_use_vector() const { - return java_use_vector_; - } - -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google -#endif // PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_ diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc deleted file mode 100644 index d6daa44..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc +++ /dev/null @@ -1,660 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#include <map> -#include <string> - -#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h> -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> -#include <google/protobuf/stubs/strutil.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -using internal::WireFormat; -using internal::WireFormatLite; - -namespace { - -const char* PrimitiveTypeName(JavaType type) { - switch (type) { - case JAVATYPE_INT : return "int"; - case JAVATYPE_LONG : return "long"; - case JAVATYPE_FLOAT : return "float"; - case JAVATYPE_DOUBLE : return "double"; - case JAVATYPE_BOOLEAN: return "boolean"; - case JAVATYPE_STRING : return "java.lang.String"; - case JAVATYPE_BYTES : return "com.google.protobuf.micro.ByteStringMicro"; - case JAVATYPE_ENUM : return NULL; - case JAVATYPE_MESSAGE: return NULL; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - -bool IsReferenceType(JavaType type) { - switch (type) { - case JAVATYPE_INT : return false; - case JAVATYPE_LONG : return false; - case JAVATYPE_FLOAT : return false; - case JAVATYPE_DOUBLE : return false; - case JAVATYPE_BOOLEAN: return false; - case JAVATYPE_STRING : return true; - case JAVATYPE_BYTES : return true; - case JAVATYPE_ENUM : return false; - case JAVATYPE_MESSAGE: return true; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - -const char* GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { - case FieldDescriptor::TYPE_INT32 : return "Int32" ; - case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; - case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; - case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; - case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; - case FieldDescriptor::TYPE_INT64 : return "Int64" ; - case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; - case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; - case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; - case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; - case FieldDescriptor::TYPE_FLOAT : return "Float" ; - case FieldDescriptor::TYPE_DOUBLE : return "Double" ; - case FieldDescriptor::TYPE_BOOL : return "Bool" ; - case FieldDescriptor::TYPE_STRING : return "String" ; - case FieldDescriptor::TYPE_BYTES : return "Bytes" ; - case FieldDescriptor::TYPE_ENUM : return "Enum" ; - case FieldDescriptor::TYPE_GROUP : return "Group" ; - case FieldDescriptor::TYPE_MESSAGE : return "Message" ; - - // No default because we want the compiler to complain if any new - // types are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return NULL; -} - -// For encodings with fixed sizes, returns that size in bytes. Otherwise -// returns -1. -int FixedSize(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32 : return -1; - case FieldDescriptor::TYPE_INT64 : return -1; - case FieldDescriptor::TYPE_UINT32 : return -1; - case FieldDescriptor::TYPE_UINT64 : return -1; - case FieldDescriptor::TYPE_SINT32 : return -1; - case FieldDescriptor::TYPE_SINT64 : return -1; - case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; - case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; - case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; - case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; - case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; - case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; - - case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; - case FieldDescriptor::TYPE_ENUM : return -1; - - case FieldDescriptor::TYPE_STRING : return -1; - case FieldDescriptor::TYPE_BYTES : return -1; - case FieldDescriptor::TYPE_GROUP : return -1; - case FieldDescriptor::TYPE_MESSAGE : return -1; - - // No default because we want the compiler to complain if any new - // types are added. - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return -1; -} - -// Return true if the type is a that has variable length -// for instance String's. -bool IsVariableLenType(JavaType type) { - switch (type) { - case JAVATYPE_INT : return false; - case JAVATYPE_LONG : return false; - case JAVATYPE_FLOAT : return false; - case JAVATYPE_DOUBLE : return false; - case JAVATYPE_BOOLEAN: return false; - case JAVATYPE_STRING : return true; - case JAVATYPE_BYTES : return true; - case JAVATYPE_ENUM : return false; - case JAVATYPE_MESSAGE: return true; - - // No default because we want the compiler to complain if any new - // JavaTypes are added. - } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return false; -} - -bool IsStringUtf8Handling(const FieldDescriptor* descriptor, - const Params params) { - return ((params.optimization() == JAVAMICRO_OPT_SPEED) - && (GetJavaType(descriptor) == JAVATYPE_STRING)); -} - -void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, - map<string, string>* variables) { - (*variables)["name"] = - UnderscoresToCamelCase(descriptor); - (*variables)["capitalized_name"] = - UnderscoresToCapitalizedCamelCase(descriptor); - (*variables)["number"] = SimpleItoa(descriptor->number()); - if (IsStringUtf8Handling(descriptor, params)) { - (*variables)["type"] = "com.google.protobuf.micro.StringUtf8Micro"; - string defaultValue = DefaultValue(params, descriptor); - if (defaultValue == "\"\"") { - (*variables)["default"] = - "com.google.protobuf.micro.StringUtf8Micro.EMPTY"; - } else { - (*variables)["default"] = "new com.google.protobuf.micro.StringUtf8Micro(" - + defaultValue + ")"; - } - } else { - (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); - (*variables)["default"] = DefaultValue(params, descriptor); - } - (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); - (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); - (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); - (*variables)["tag_size"] = SimpleItoa( - WireFormat::TagSize(descriptor->number(), descriptor->type())); - if (IsReferenceType(GetJavaType(descriptor))) { - (*variables)["null_check"] = - " if (value == null) {\n" - " throw new NullPointerException();\n" - " }\n"; - } else { - (*variables)["null_check"] = ""; - } - int fixed_size = FixedSize(descriptor->type()); - if (fixed_size != -1) { - (*variables)["fixed_size"] = SimpleItoa(fixed_size); - } - (*variables)["message_name"] = descriptor->containing_type()->name(); -} -} // namespace - -// =================================================================== - -PrimitiveFieldGenerator:: -PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetPrimitiveVariables(descriptor, params, &variables_); -} - -PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} - -void PrimitiveFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - printer->Print(variables_, - "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $default$;\n" - "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"); - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - "public String get$capitalized_name$() { return $name$_.getString(); }\n" - "public $type$ get$capitalized_name$StringUtf8() { return $name$_; }\n" - "public $message_name$ set$capitalized_name$(String value) {\n" - " has$capitalized_name$ = true;\n" - " if ($name$_ == $default$) {\n" - " $name$_ = new $type$(value);\n" - " } else {\n" - " $name$_.setString(value);\n" - " }\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " has$capitalized_name$ = false;\n" - " $name$_ = $default$;\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "public $type$ get$capitalized_name$() { return $name$_; }\n"); - if (IsVariableLenType(GetJavaType(descriptor_))) { - printer->Print(variables_, - "public $message_name$ set$capitalized_name$($type$ value) {\n" - " has$capitalized_name$ = true;\n" - " $name$_ = value;\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " has$capitalized_name$ = false;\n" - " $name$_ = $default$;\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "public $message_name$ set$capitalized_name$($type$ value) {\n" - " has$capitalized_name$ = true;\n" - " $name$_ = value;\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " has$capitalized_name$ = false;\n" - " $name$_ = $default$;\n" - " return this;\n" - "}\n"); - } - } -} - -void PrimitiveFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); -} - -void PrimitiveFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - printer->Print(variables_, - "set$capitalized_name$(input.read$capitalized_type$());\n"); -} - -void PrimitiveFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " output.writeStringUtf8($number$, get$capitalized_name$StringUtf8());\n" - "}\n"); - } else { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " output.write$capitalized_type$($number$, get$capitalized_name$());\n" - "}\n"); - } -} - -void PrimitiveFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeStringUtf8Size($number$, get$capitalized_name$StringUtf8());\n" - "}\n"); - } else { - printer->Print(variables_, - "if (has$capitalized_name$()) {\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .compute$capitalized_type$Size($number$, get$capitalized_name$());\n" - "}\n"); - } -} - -string PrimitiveFieldGenerator::GetBoxedType() const { - return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); -} - -// =================================================================== - -RepeatedPrimitiveFieldGenerator:: -RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) - : FieldGenerator(params), descriptor_(descriptor) { - SetPrimitiveVariables(descriptor, params, &variables_); - if (descriptor_->options().packed()) { - GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed"; - } -} - -RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} - -void RepeatedPrimitiveFieldGenerator:: -GenerateMembers(io::Printer* printer) const { - if (IsStringUtf8Handling(descriptor_, params_)) { - if (params_.java_use_vector()) { - printer->Print(variables_, - "private java.util.Vector $name$_ = new java.util.Vector();\n" - "public java.util.Vector get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public String get$capitalized_name$(int index) {\n" - " return (($type$)$name$_.elementAt(index)).getString();\n" - "}\n" - "public $type$ get$capitalized_name$StringUtf8(int index) {\n" - " return ($type$)$name$_.elementAt(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, String value) {\n" - "$null_check$" - " $name$_.setElementAt(new $type$(value), index);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$(String value) {\n" - "$null_check$" - " $name$_.addElement(new $type$(value));\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_.removeAllElements();\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "private java.util.List<$type$> $name$_ =\n" - " java.util.Collections.emptyList();\n" - "public java.util.List<$type$> get$capitalized_name$List() {\n" - " return $name$_;\n" // note: unmodifiable list - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public String get$capitalized_name$(int index) {\n" - " return $name$_.get(index).getString();\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, String value) {\n" - "$null_check$" - " $name$_.set(index, new $type$(value));\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$(String value) {\n" - "$null_check$" - " if ($name$_.isEmpty()) {\n" - " $name$_ = new java.util.ArrayList<$type$>();\n" - " }\n" - " $name$_.add(new $type$(value));\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_ = java.util.Collections.emptyList();\n" - " return this;\n" - "}\n"); - } - } else if (params_.java_use_vector()) { - if (IsReferenceType(GetJavaType(descriptor_))) { - printer->Print(variables_, - "private java.util.Vector $name$_ = new java.util.Vector();\n" - "public java.util.Vector get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public $type$ get$capitalized_name$(int index) {\n" - " return ($type$) $name$_.elementAt(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" - "$null_check$" - " $name$_.setElementAt(value, index);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$($type$ value) {\n" - "$null_check$" - " $name$_.addElement(value);\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_.removeAllElements();\n" - " return this;\n" - "}\n"); - } else { - printer->Print(variables_, - "private java.util.Vector $name$_ = new java.util.Vector();\n" - "public java.util.Vector get$capitalized_name$List() {\n" - " return $name$_;\n" - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public $type$ get$capitalized_name$(int index) {\n" - " return (($boxed_type$)$name$_.elementAt(index)).$type$Value();\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" - "$null_check$" - " $name$_.setElementAt(new $boxed_type$(value), index);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$($type$ value) {\n" - "$null_check$" - " $name$_.addElement(new $boxed_type$(value));\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_.removeAllElements();\n" - " return this;\n" - "}\n"); - } - } else { - printer->Print(variables_, - "private java.util.List<$boxed_type$> $name$_ =\n" - " java.util.Collections.emptyList();\n" - "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n" - " return $name$_;\n" // note: unmodifiable list - "}\n" - "public int get$capitalized_name$Count() { return $name$_.size(); }\n" - "public $type$ get$capitalized_name$(int index) {\n" - " return $name$_.get(index);\n" - "}\n" - "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n" - "$null_check$" - " $name$_.set(index, value);\n" - " return this;\n" - "}\n" - "public $message_name$ add$capitalized_name$($type$ value) {\n" - "$null_check$" - " if ($name$_.isEmpty()) {\n" - " $name$_ = new java.util.ArrayList<$boxed_type$>();\n" - " }\n" - " $name$_.add(value);\n" - " return this;\n" - "}\n" - "public $message_name$ clear$capitalized_name$() {\n" - " $name$_ = java.util.Collections.emptyList();\n" - " return this;\n" - "}\n"); - } - if (descriptor_->options().packed()) { - printer->Print(variables_, - "private int $name$MemoizedSerializedSize;\n"); - } -} - -void RepeatedPrimitiveFieldGenerator:: -GenerateMergingCode(io::Printer* printer) const { - if (params_.java_use_vector()) { - printer->Print(variables_, - "if (other.$name$_.size() != 0) {\n" - " for (int i = 0; i < other.$name$_.size(); i++)) {\n" - " result.$name$_.addElement(other.$name$_.elementAt(i));\n" - " }\n" - "}\n"); - } else { - printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if (result.$name$_.isEmpty()) {\n" - " result.$name$_ = new java.util.ArrayList<$type$>();\n" - " }\n" - " result.$name$_.addAll(other.$name$_);\n" - "}\n"); - } -} - -void RepeatedPrimitiveFieldGenerator:: -GenerateParsingCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" - "}\n" - "input.popLimit(limit);\n"); - } else { - printer->Print(variables_, - "add$capitalized_name$(input.read$capitalized_type$());\n"); - } -} - -void RepeatedPrimitiveFieldGenerator:: -GenerateSerializationCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() > 0) {\n" - " output.writeRawVarint32($tag$);\n" - " output.writeRawVarint32($name$MemoizedSerializedSize);\n" - "}\n"); - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.write$capitalized_type$NoTag(get$capitalized_name$(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.write$capitalized_type$NoTag(element);\n" - "}\n"); - } - } else { - if (params_.java_use_vector()) { - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.writeStringUtf8($number$, get$capitalized_name$StringUtf8(i));\n" - "}\n"); - } else { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " output.write$capitalized_type$($number$, get$capitalized_name$(i));\n" - "}\n"); - } - } else { - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.writeStringUtf8($number$, element);\n" - "}\n"); - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " output.write$capitalized_type$($number$, element);\n" - "}\n"); - } - } - } -} - -void RepeatedPrimitiveFieldGenerator:: -GenerateSerializedSizeCode(io::Printer* printer) const { - printer->Print(variables_, - "{\n" - " int dataSize = 0;\n"); - printer->Indent(); - - if (FixedSize(descriptor_->type()) == -1) { - if (params_.java_use_vector()) { - printer->Print(variables_, - "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n" - " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"); - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - " .computeStringUtf8SizeNoTag(get$capitalized_name$StringUtf8(i));\n" - "}\n"); - } else { - printer->Print(variables_, - " .compute$capitalized_type$SizeNoTag(($type$)get$capitalized_name$(i));\n" - "}\n"); - } - } else { - printer->Print(variables_, - "for ($type$ element : get$capitalized_name$List()) {\n" - " dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"); - if (IsStringUtf8Handling(descriptor_, params_)) { - printer->Print(variables_, - " .computeStringUtf8SizeNoTag(element);\n" - "}\n"); - } else { - printer->Print(variables_, - " .compute$capitalized_type$SizeNoTag(element);\n" - "}\n"); - } - } - } else { - printer->Print(variables_, - "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); - } - - printer->Print( - "size += dataSize;\n"); - - if (descriptor_->options().packed()) { - if (params_.java_use_vector()) { - printer->Print(variables_, - "if (get$capitalized_name$List().size() != 0) {\n"); - } else { - printer->Print(variables_, - "if (!get$capitalized_name$List().isEmpty()) {\n"); - } - printer->Print(variables_, - " size += $tag_size$;\n" - " size += com.google.protobuf.micro.CodedOutputStreamMicro\n" - " .computeInt32SizeNoTag(dataSize);\n" - "}\n"); - } else { - printer->Print(variables_, - "size += $tag_size$ * get$capitalized_name$List().size();\n"); - } - - // cache the data size for packed fields. - if (descriptor_->options().packed()) { - printer->Print(variables_, - "$name$MemoizedSerializedSize = dataSize;\n"); - } - - printer->Outdent(); - printer->Print("}\n"); -} - -string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { - return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); -} - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf -} // namespace google diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h deleted file mode 100644 index 88d8eec..0000000 --- a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h +++ /dev/null @@ -1,94 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ - -#include <map> -#include <string> -#include <google/protobuf/compiler/javamicro/javamicro_field.h> - -namespace google { -namespace protobuf { -namespace compiler { -namespace javamicro { - -class PrimitiveFieldGenerator : public FieldGenerator { - public: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params ¶ms); - ~PrimitiveFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); -}; - -class RepeatedPrimitiveFieldGenerator : public FieldGenerator { - public: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params); - ~RepeatedPrimitiveFieldGenerator(); - - // implements FieldGenerator --------------------------------------- - void GenerateMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateParsingCode(io::Printer* printer) const; - void GenerateSerializationCode(io::Printer* printer) const; - void GenerateSerializedSizeCode(io::Printer* printer) const; - - string GetBoxedType() const; - - private: - const FieldDescriptor* descriptor_; - map<string, string> variables_; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); -}; - -} // namespace javamicro -} // namespace compiler -} // namespace protobuf - -} // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 41dc5b9..d9b0c3f 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -34,12 +34,12 @@ #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> -#include <google/protobuf/compiler/javamicro/javamicro_generator.h> int main(int argc, char* argv[]) { google::protobuf::compiler::CommandLineInterface cli; + cli.AllowPlugins("protoc-"); // Proto2 C++ google::protobuf::compiler::cpp::CppGenerator cpp_generator; @@ -57,10 +57,5 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--python_out", &py_generator, "Generate Python source file."); - // Proto2 JavaMicro - google::protobuf::compiler::javamicro::JavaMicroGenerator javamicro_generator; - cli.RegisterGenerator("--javamicro_out", &javamicro_generator, - "Generate Java source file micro runtime."); - return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc new file mode 100644 index 0000000..83d5a4e --- /dev/null +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -0,0 +1,209 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) + +#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 { + +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& 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_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, 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, first_message_name), + lines[2 + insertion_list.size() + i]); + } +} + +bool MockCodeGenerator::Generate( + const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + 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( + output_directory->OpenForInsert( + GetOutputFileName(insert_into[i], file), + kFirstInsertionPointName)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, "first_insert", file)); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + + { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->OpenForInsert( + GetOutputFileName(insert_into[i], file), + kSecondInsertionPointName)); + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, "second_insert", file)); + if (printer.failed()) { + *error = "MockCodeGenerator detected write error."; + return false; + } + } + } + } else { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(GetOutputFileName(name_, file))); + + io::Printer printer(output.get(), '$'); + printer.PrintRaw(GetOutputFileContent(name_, parameter, file)); + 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) { + return GetOutputFileContent( + generator_name, parameter, file->name(), + 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& first_message_name) { + return strings::Substitute("$0: $1, $2, $3\n", + generator_name, parameter, file, first_message_name); +} + +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h new file mode 100644 index 0000000..01d69dd --- /dev/null +++ b/src/google/protobuf/compiler/mock_code_generator.h @@ -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_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. + static void ExpectGenerated(const string& name, + const string& parameter, + const string& insertions, + const string& file, + const string& first_message_name, + 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, + OutputDirectory* output_directory, + string* error) const; + + private: + string name_; + + static string GetOutputFileContent(const string& generator_name, + const string& parameter, + const FileDescriptor* file); + static string GetOutputFileContent(const string& generator_name, + const string& parameter, + const string& file, + const string& first_message_name); +}; + +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 02304d6..758f70d 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -34,8 +34,9 @@ // // Recursive descent FTW. -#include <google/protobuf/stubs/hash.h> #include <float.h> +#include <google/protobuf/stubs/hash.h> +#include <limits> #include <google/protobuf/compiler/parser.h> @@ -206,6 +207,14 @@ bool Parser::ConsumeNumber(double* output, const char* error) { *output = value; input_->Next(); return true; + } else if (LookingAt("inf")) { + *output = numeric_limits<double>::infinity(); + input_->Next(); + return true; + } else if (LookingAt("nan")) { + *output = numeric_limits<double>::quiet_NaN(); + input_->Next(); + return true; } else { AddError(error); return false; diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index c4f08e7..e2262b8 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -336,6 +336,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " required double foo = 1 [default= 10.5];\n" " required double foo = 1 [default=-11.5];\n" " required double foo = 1 [default= 12 ];\n" + " required double foo = 1 [default= inf ];\n" + " required double foo = 1 [default=-inf ];\n" + " required double foo = 1 [default= nan ];\n" " required string foo = 1 [default='13\\001'];\n" " required string foo = 1 [default='a' \"b\" \n \"c\"];\n" " required bytes foo = 1 [default='14\\002'];\n" @@ -367,6 +370,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }" " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }" " field { type:TYPE_STRING default_value:\"abc\" "ETC" }" " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }" diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc new file mode 100644 index 0000000..a4aedaf --- /dev/null +++ b/src/google/protobuf/compiler/plugin.cc @@ -0,0 +1,152 @@ +// 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 GeneratorResponseOutputDirectory : public OutputDirectory { + public: + GeneratorResponseOutputDirectory(CodeGeneratorResponse* response) + : response_(response) {} + virtual ~GeneratorResponseOutputDirectory() {} + + // implements OutputDirectory -------------------------------------- + + 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()); + } + + private: + CodeGeneratorResponse* response_; +}; + +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; + } + } + + CodeGeneratorResponse response; + GeneratorResponseOutputDirectory output_directory(&response); + + for (int i = 0; i < request.file_to_generate_size(); i++) { + const FileDescriptor* file = + pool.FindFileByName(request.file_to_generate(i)); + if (file == 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; + } + + string error; + bool succeeded = generator->Generate( + file, request.parameter(), &output_directory, &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 diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.h b/src/google/protobuf/compiler/plugin.h index a1c33b7..7c40333 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_generator.h +++ b/src/google/protobuf/compiler/plugin.h @@ -29,44 +29,45 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. // -// Generates Java micro code for a given .proto file. +// 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_JAVA_MICRO_GENERATOR_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__ +#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ -#include <string> -#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/common.h> namespace google { namespace protobuf { namespace compiler { -namespace javamicro { - -// CodeGenerator implementation which generates Java micro code. If you create your -// own protocol compiler binary and you want it to support Java output for the -// micro runtime, you can do so by registering an instance of this CodeGenerator with -// the CommandLineInterface in your main() function. -class LIBPROTOC_EXPORT JavaMicroGenerator : public CodeGenerator { - public: - JavaMicroGenerator(); - ~JavaMicroGenerator(); - // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const; +class CodeGenerator; // code_generator.h - private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaMicroGenerator); -}; +// Implements main() for a protoc plugin exposing the given code generator. +LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator); -} // namespace javamicro } // namespace compiler } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__ +#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc new file mode 100644 index 0000000..6b0dd55 --- /dev/null +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -0,0 +1,1084 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION +#include "google/protobuf/compiler/plugin.pb.h" +#include <google/protobuf/stubs/once.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/wire_format_lite_inl.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/reflection_ops.h> +#include <google/protobuf/wire_format.h> +// @@protoc_insertion_point(includes) + +namespace google { +namespace protobuf { +namespace compiler { + +namespace { + +const ::google::protobuf::Descriptor* CodeGeneratorRequest_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorRequest_reflection_ = NULL; +const ::google::protobuf::Descriptor* CodeGeneratorResponse_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorResponse_reflection_ = NULL; +const ::google::protobuf::Descriptor* CodeGeneratorResponse_File_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + CodeGeneratorResponse_File_reflection_ = NULL; + +} // namespace + + +void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + const ::google::protobuf::FileDescriptor* file = + ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( + "google/protobuf/compiler/plugin.proto"); + GOOGLE_CHECK(file != NULL); + CodeGeneratorRequest_descriptor_ = file->message_type(0); + static const int CodeGeneratorRequest_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, file_to_generate_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, parameter_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, proto_file_), + }; + CodeGeneratorRequest_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorRequest_descriptor_, + CodeGeneratorRequest::default_instance_, + CodeGeneratorRequest_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorRequest)); + CodeGeneratorResponse_descriptor_ = file->message_type(1); + static const int CodeGeneratorResponse_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, file_), + }; + CodeGeneratorResponse_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorResponse_descriptor_, + CodeGeneratorResponse::default_instance_, + CodeGeneratorResponse_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorResponse)); + CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); + static const int CodeGeneratorResponse_File_offsets_[3] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, insertion_point_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, content_), + }; + CodeGeneratorResponse_File_reflection_ = + new ::google::protobuf::internal::GeneratedMessageReflection( + CodeGeneratorResponse_File_descriptor_, + CodeGeneratorResponse_File::default_instance_, + CodeGeneratorResponse_File_offsets_, + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _has_bits_[0]), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _unknown_fields_), + -1, + ::google::protobuf::DescriptorPool::generated_pool(), + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(CodeGeneratorResponse_File)); +} + +namespace { + +GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); +inline void protobuf_AssignDescriptorsOnce() { + ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, + &protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto); +} + +void protobuf_RegisterTypes(const ::std::string&) { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorRequest_descriptor_, &CodeGeneratorRequest::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorResponse_descriptor_, &CodeGeneratorResponse::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + CodeGeneratorResponse_File_descriptor_, &CodeGeneratorResponse_File::default_instance()); +} + +} // namespace + +void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + delete CodeGeneratorRequest::default_instance_; + delete CodeGeneratorRequest_reflection_; + delete CodeGeneratorResponse::default_instance_; + delete CodeGeneratorResponse_reflection_; + delete CodeGeneratorResponse_File::default_instance_; + delete CodeGeneratorResponse_File_reflection_; +} + +void protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + static bool already_here = false; + if (already_here) return; + already_here = true; + GOOGLE_PROTOBUF_VERIFY_VERSION; + + ::google::protobuf::protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); + ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( + "\n%google/protobuf/compiler/plugin.proto\022" + "\030google.protobuf.compiler\032 google/protob" + "uf/descriptor.proto\"}\n\024CodeGeneratorRequ" + "est\022\030\n\020file_to_generate\030\001 \003(\t\022\021\n\tparamet" + "er\030\002 \001(\t\0228\n\nproto_file\030\017 \003(\0132$.google.pr" + "otobuf.FileDescriptorProto\"\252\001\n\025CodeGener" + "atorResponse\022\r\n\005error\030\001 \001(\t\022B\n\004file\030\017 \003(" + "\01324.google.protobuf.compiler.CodeGenerat" + "orResponse.File\032>\n\004File\022\014\n\004name\030\001 \001(\t\022\027\n" + "\017insertion_point\030\002 \001(\t\022\017\n\007content\030\017 \001(\t", 399); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( + "google/protobuf/compiler/plugin.proto", &protobuf_RegisterTypes); + CodeGeneratorRequest::default_instance_ = new CodeGeneratorRequest(); + CodeGeneratorResponse::default_instance_ = new CodeGeneratorResponse(); + CodeGeneratorResponse_File::default_instance_ = new CodeGeneratorResponse_File(); + CodeGeneratorRequest::default_instance_->InitAsDefaultInstance(); + CodeGeneratorResponse::default_instance_->InitAsDefaultInstance(); + CodeGeneratorResponse_File::default_instance_->InitAsDefaultInstance(); + ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto); +} + +// Force AddDescriptors() to be called at static initialization time. +struct StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto { + StaticDescriptorInitializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { + protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); + } +} static_descriptor_initializer_google_2fprotobuf_2fcompiler_2fplugin_2eproto_; + + +// =================================================================== + +const ::std::string CodeGeneratorRequest::_default_parameter_; +#ifndef _MSC_VER +const int CodeGeneratorRequest::kFileToGenerateFieldNumber; +const int CodeGeneratorRequest::kParameterFieldNumber; +const int CodeGeneratorRequest::kProtoFileFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorRequest::CodeGeneratorRequest() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorRequest::InitAsDefaultInstance() { +} + +CodeGeneratorRequest::CodeGeneratorRequest(const CodeGeneratorRequest& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorRequest::SharedCtor() { + _cached_size_ = 0; + parameter_ = const_cast< ::std::string*>(&_default_parameter_); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorRequest::~CodeGeneratorRequest() { + SharedDtor(); +} + +void CodeGeneratorRequest::SharedDtor() { + if (parameter_ != &_default_parameter_) { + delete parameter_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorRequest::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorRequest::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorRequest_descriptor_; +} + +const CodeGeneratorRequest& CodeGeneratorRequest::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorRequest* CodeGeneratorRequest::default_instance_ = NULL; + +CodeGeneratorRequest* CodeGeneratorRequest::New() const { + return new CodeGeneratorRequest; +} + +void CodeGeneratorRequest::Clear() { + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (_has_bit(1)) { + if (parameter_ != &_default_parameter_) { + parameter_->clear(); + } + } + } + file_to_generate_.Clear(); + proto_file_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorRequest::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // repeated string file_to_generate = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file_to_generate: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_file_to_generate())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(0).data(), this->file_to_generate(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(10)) goto parse_file_to_generate; + if (input->ExpectTag(18)) goto parse_parameter; + break; + } + + // optional string parameter = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_parameter: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_parameter())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_proto_file; + break; + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_proto_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_proto_file())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_proto_file; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorRequest::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // repeated string file_to_generate = 1; + for (int i = 0; i < this->file_to_generate_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(i).data(), this->file_to_generate(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->file_to_generate(i), output); + } + + // optional string parameter = 2; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->parameter(), output); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + for (int i = 0; i < this->proto_file_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 15, this->proto_file(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorRequest::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // repeated string file_to_generate = 1; + for (int i = 0; i < this->file_to_generate_size(); i++) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->file_to_generate(i).data(), this->file_to_generate(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = ::google::protobuf::internal::WireFormatLite:: + WriteStringToArray(1, this->file_to_generate(i), target); + } + + // optional string parameter = 2; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->parameter().data(), this->parameter().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->parameter(), target); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + for (int i = 0; i < this->proto_file_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 15, this->proto_file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorRequest::ByteSize() const { + int total_size = 0; + + if (_has_bits_[1 / 32] & (0xffu << (1 % 32))) { + // optional string parameter = 2; + if (has_parameter()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->parameter()); + } + + } + // repeated string file_to_generate = 1; + total_size += 1 * this->file_to_generate_size(); + for (int i = 0; i < this->file_to_generate_size(); i++) { + total_size += ::google::protobuf::internal::WireFormatLite::StringSize( + this->file_to_generate(i)); + } + + // repeated .google.protobuf.FileDescriptorProto proto_file = 15; + total_size += 1 * this->proto_file_size(); + for (int i = 0; i < this->proto_file_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->proto_file(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorRequest* source = + ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorRequest*>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { + GOOGLE_CHECK_NE(&from, this); + file_to_generate_.MergeFrom(from.file_to_generate_); + proto_file_.MergeFrom(from.proto_file_); + if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { + if (from._has_bit(1)) { + set_parameter(from.parameter()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorRequest::IsInitialized() const { + + for (int i = 0; i < proto_file_size(); i++) { + if (!this->proto_file(i).IsInitialized()) return false; + } + return true; +} + +void CodeGeneratorRequest::Swap(CodeGeneratorRequest* other) { + if (other != this) { + file_to_generate_.Swap(&other->file_to_generate_); + std::swap(parameter_, other->parameter_); + proto_file_.Swap(&other->proto_file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorRequest_descriptor_; + metadata.reflection = CodeGeneratorRequest_reflection_; + return metadata; +} + + +// =================================================================== + +const ::std::string CodeGeneratorResponse_File::_default_name_; +const ::std::string CodeGeneratorResponse_File::_default_insertion_point_; +const ::std::string CodeGeneratorResponse_File::_default_content_; +#ifndef _MSC_VER +const int CodeGeneratorResponse_File::kNameFieldNumber; +const int CodeGeneratorResponse_File::kInsertionPointFieldNumber; +const int CodeGeneratorResponse_File::kContentFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorResponse_File::CodeGeneratorResponse_File() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorResponse_File::InitAsDefaultInstance() { +} + +CodeGeneratorResponse_File::CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorResponse_File::SharedCtor() { + _cached_size_ = 0; + name_ = const_cast< ::std::string*>(&_default_name_); + insertion_point_ = const_cast< ::std::string*>(&_default_insertion_point_); + content_ = const_cast< ::std::string*>(&_default_content_); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorResponse_File::~CodeGeneratorResponse_File() { + SharedDtor(); +} + +void CodeGeneratorResponse_File::SharedDtor() { + if (name_ != &_default_name_) { + delete name_; + } + if (insertion_point_ != &_default_insertion_point_) { + delete insertion_point_; + } + if (content_ != &_default_content_) { + delete content_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorResponse_File::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorResponse_File::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorResponse_File_descriptor_; +} + +const CodeGeneratorResponse_File& CodeGeneratorResponse_File::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorResponse_File* CodeGeneratorResponse_File::default_instance_ = NULL; + +CodeGeneratorResponse_File* CodeGeneratorResponse_File::New() const { + return new CodeGeneratorResponse_File; +} + +void CodeGeneratorResponse_File::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bit(0)) { + if (name_ != &_default_name_) { + name_->clear(); + } + } + if (_has_bit(1)) { + if (insertion_point_ != &_default_insertion_point_) { + insertion_point_->clear(); + } + } + if (_has_bit(2)) { + if (content_ != &_default_content_) { + content_->clear(); + } + } + } + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorResponse_File::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string name = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(18)) goto parse_insertion_point; + break; + } + + // optional string insertion_point = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_insertion_point: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_insertion_point())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_content; + break; + } + + // optional string content = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_content: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_content())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorResponse_File::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string name = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->name(), output); + } + + // optional string insertion_point = 2; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 2, this->insertion_point(), output); + } + + // optional string content = 15; + if (_has_bit(2)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 15, this->content(), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string name = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string insertion_point = 2; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->insertion_point().data(), this->insertion_point().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->insertion_point(), target); + } + + // optional string content = 15; + if (_has_bit(2)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->content().data(), this->content().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 15, this->content(), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorResponse_File::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string name = 1; + if (has_name()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional string insertion_point = 2; + if (has_insertion_point()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->insertion_point()); + } + + // optional string content = 15; + if (has_content()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->content()); + } + + } + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorResponse_File* source = + ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse_File*>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) { + GOOGLE_CHECK_NE(&from, this); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from._has_bit(0)) { + set_name(from.name()); + } + if (from._has_bit(1)) { + set_insertion_point(from.insertion_point()); + } + if (from._has_bit(2)) { + set_content(from.content()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse_File::IsInitialized() const { + + return true; +} + +void CodeGeneratorResponse_File::Swap(CodeGeneratorResponse_File* other) { + if (other != this) { + std::swap(name_, other->name_); + std::swap(insertion_point_, other->insertion_point_); + std::swap(content_, other->content_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorResponse_File_descriptor_; + metadata.reflection = CodeGeneratorResponse_File_reflection_; + return metadata; +} + + +// ------------------------------------------------------------------- + +const ::std::string CodeGeneratorResponse::_default_error_; +#ifndef _MSC_VER +const int CodeGeneratorResponse::kErrorFieldNumber; +const int CodeGeneratorResponse::kFileFieldNumber; +#endif // !_MSC_VER + +CodeGeneratorResponse::CodeGeneratorResponse() + : ::google::protobuf::Message() { + SharedCtor(); +} + +void CodeGeneratorResponse::InitAsDefaultInstance() { +} + +CodeGeneratorResponse::CodeGeneratorResponse(const CodeGeneratorResponse& from) + : ::google::protobuf::Message() { + SharedCtor(); + MergeFrom(from); +} + +void CodeGeneratorResponse::SharedCtor() { + _cached_size_ = 0; + error_ = const_cast< ::std::string*>(&_default_error_); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +CodeGeneratorResponse::~CodeGeneratorResponse() { + SharedDtor(); +} + +void CodeGeneratorResponse::SharedDtor() { + if (error_ != &_default_error_) { + delete error_; + } + if (this != default_instance_) { + } +} + +void CodeGeneratorResponse::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* CodeGeneratorResponse::descriptor() { + protobuf_AssignDescriptorsOnce(); + return CodeGeneratorResponse_descriptor_; +} + +const CodeGeneratorResponse& CodeGeneratorResponse::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); return *default_instance_; +} + +CodeGeneratorResponse* CodeGeneratorResponse::default_instance_ = NULL; + +CodeGeneratorResponse* CodeGeneratorResponse::New() const { + return new CodeGeneratorResponse; +} + +void CodeGeneratorResponse::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (_has_bit(0)) { + if (error_ != &_default_error_) { + error_->clear(); + } + } + } + file_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); + mutable_unknown_fields()->Clear(); +} + +bool CodeGeneratorResponse::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // optional string error = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_error())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_file; + break; + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + case 15: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(122)) goto parse_file; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormat::SkipField( + input, tag, mutable_unknown_fields())); + break; + } + } + } + return true; +#undef DO_ +} + +void CodeGeneratorResponse::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // optional string error = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + ::google::protobuf::internal::WireFormatLite::WriteString( + 1, this->error(), output); + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + for (int i = 0; i < this->file_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 15, this->file(i), output); + } + + if (!unknown_fields().empty()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + unknown_fields(), output); + } +} + +::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // optional string error = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->error().data(), this->error().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->error(), target); + } + + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + for (int i = 0; i < this->file_size(); i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 15, this->file(i), target); + } + + if (!unknown_fields().empty()) { + target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( + unknown_fields(), target); + } + return target; +} + +int CodeGeneratorResponse::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // optional string error = 1; + if (has_error()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->error()); + } + + } + // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15; + total_size += 1 * this->file_size(); + for (int i = 0; i < this->file_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->file(i)); + } + + if (!unknown_fields().empty()) { + total_size += + ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( + unknown_fields()); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { + GOOGLE_CHECK_NE(&from, this); + const CodeGeneratorResponse* source = + ::google::protobuf::internal::dynamic_cast_if_available<const CodeGeneratorResponse*>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { + GOOGLE_CHECK_NE(&from, this); + file_.MergeFrom(from.file_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from._has_bit(0)) { + set_error(from.error()); + } + } + mutable_unknown_fields()->MergeFrom(from.unknown_fields()); +} + +void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool CodeGeneratorResponse::IsInitialized() const { + + return true; +} + +void CodeGeneratorResponse::Swap(CodeGeneratorResponse* other) { + if (other != this) { + std::swap(error_, other->error_); + file_.Swap(&other->file_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + _unknown_fields_.Swap(&other->_unknown_fields_); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = CodeGeneratorResponse_descriptor_; + metadata.reflection = CodeGeneratorResponse_reflection_; + return metadata; +} + + +// @@protoc_insertion_point(namespace_scope) + +} // namespace compiler +} // namespace protobuf +} // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h new file mode 100644 index 0000000..f8f8053 --- /dev/null +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -0,0 +1,727 @@ +// 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 < 2003000 +#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 2003000 < 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(); + + // 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: + ::google::protobuf::UnknownFieldSet _unknown_fields_; + mutable int _cached_size_; + + ::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; + ::std::string* parameter_; + static const ::std::string _default_parameter_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; + 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(); + + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? + inline bool _has_bit(int index) const { + return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; + } + inline void _set_bit(int index) { + _has_bits_[index / 32] |= (1u << (index % 32)); + } + inline void _clear_bit(int index) { + _has_bits_[index / 32] &= ~(1u << (index % 32)); + } + + 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(); + + // 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(); + + // 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(); + + // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File) + private: + ::google::protobuf::UnknownFieldSet _unknown_fields_; + mutable int _cached_size_; + + ::std::string* name_; + static const ::std::string _default_name_; + ::std::string* insertion_point_; + static const ::std::string _default_insertion_point_; + ::std::string* content_; + static const ::std::string _default_content_; + 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(); + + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? + inline bool _has_bit(int index) const { + return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; + } + inline void _set_bit(int index) { + _has_bits_[index / 32] |= (1u << (index % 32)); + } + inline void _clear_bit(int index) { + _has_bits_[index / 32] &= ~(1u << (index % 32)); + } + + 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(); + + // 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: + ::google::protobuf::UnknownFieldSet _unknown_fields_; + mutable int _cached_size_; + + ::std::string* error_; + static const ::std::string _default_error_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; + 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(); + + ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; + + // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? + inline bool _has_bit(int index) const { + return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; + } + inline void _set_bit(int index) { + _has_bits_[index / 32] |= (1u << (index % 32)); + } + inline void _clear_bit(int index) { + _has_bits_[index / 32] &= ~(1u << (index % 32)); + } + + 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_bit(1); +} +inline void CodeGeneratorRequest::clear_parameter() { + if (parameter_ != &_default_parameter_) { + parameter_->clear(); + } + _clear_bit(1); +} +inline const ::std::string& CodeGeneratorRequest::parameter() const { + return *parameter_; +} +inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) { + _set_bit(1); + if (parameter_ == &_default_parameter_) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value) { + _set_bit(1); + if (parameter_ == &_default_parameter_) { + parameter_ = new ::std::string; + } + parameter_->assign(value); +} +inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { + _set_bit(1); + if (parameter_ == &_default_parameter_) { + parameter_ = new ::std::string; + } + parameter_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* CodeGeneratorRequest::mutable_parameter() { + _set_bit(1); + if (parameter_ == &_default_parameter_) { + parameter_ = new ::std::string; + } + return parameter_; +} + +// 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_bit(0); +} +inline void CodeGeneratorResponse_File::clear_name() { + if (name_ != &_default_name_) { + name_->clear(); + } + _clear_bit(0); +} +inline const ::std::string& CodeGeneratorResponse_File::name() const { + return *name_; +} +inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(value); +} +inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + name_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_name() { + _set_bit(0); + if (name_ == &_default_name_) { + name_ = new ::std::string; + } + return name_; +} + +// optional string insertion_point = 2; +inline bool CodeGeneratorResponse_File::has_insertion_point() const { + return _has_bit(1); +} +inline void CodeGeneratorResponse_File::clear_insertion_point() { + if (insertion_point_ != &_default_insertion_point_) { + insertion_point_->clear(); + } + _clear_bit(1); +} +inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const { + return *insertion_point_; +} +inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { + _set_bit(1); + if (insertion_point_ == &_default_insertion_point_) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) { + _set_bit(1); + if (insertion_point_ == &_default_insertion_point_) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(value); +} +inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { + _set_bit(1); + if (insertion_point_ == &_default_insertion_point_) { + insertion_point_ = new ::std::string; + } + insertion_point_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { + _set_bit(1); + if (insertion_point_ == &_default_insertion_point_) { + insertion_point_ = new ::std::string; + } + return insertion_point_; +} + +// optional string content = 15; +inline bool CodeGeneratorResponse_File::has_content() const { + return _has_bit(2); +} +inline void CodeGeneratorResponse_File::clear_content() { + if (content_ != &_default_content_) { + content_->clear(); + } + _clear_bit(2); +} +inline const ::std::string& CodeGeneratorResponse_File::content() const { + return *content_; +} +inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) { + _set_bit(2); + if (content_ == &_default_content_) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value) { + _set_bit(2); + if (content_ == &_default_content_) { + content_ = new ::std::string; + } + content_->assign(value); +} +inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { + _set_bit(2); + if (content_ == &_default_content_) { + content_ = new ::std::string; + } + content_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* CodeGeneratorResponse_File::mutable_content() { + _set_bit(2); + if (content_ == &_default_content_) { + content_ = new ::std::string; + } + return content_; +} + +// ------------------------------------------------------------------- + +// CodeGeneratorResponse + +// optional string error = 1; +inline bool CodeGeneratorResponse::has_error() const { + return _has_bit(0); +} +inline void CodeGeneratorResponse::clear_error() { + if (error_ != &_default_error_) { + error_->clear(); + } + _clear_bit(0); +} +inline const ::std::string& CodeGeneratorResponse::error() const { + return *error_; +} +inline void CodeGeneratorResponse::set_error(const ::std::string& value) { + _set_bit(0); + if (error_ == &_default_error_) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value) { + _set_bit(0); + if (error_ == &_default_error_) { + error_ = new ::std::string; + } + error_->assign(value); +} +inline void CodeGeneratorResponse::set_error(const char* value, size_t size) { + _set_bit(0); + if (error_ == &_default_error_) { + error_ = new ::std::string; + } + error_->assign(reinterpret_cast<const char*>(value), size); +} +inline ::std::string* CodeGeneratorResponse::mutable_error() { + _set_bit(0); + if (error_ == &_default_error_) { + error_ = new ::std::string; + } + return error_; +} + +// 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 diff --git a/src/google/protobuf/compiler/plugin.proto b/src/google/protobuf/compiler/plugin.proto new file mode 100644 index 0000000..4e928b0 --- /dev/null +++ b/src/google/protobuf/compiler/plugin.proto @@ -0,0 +1,145 @@ +// 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) +// +// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to +// change. +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +package google.protobuf.compiler; + +import "google/protobuf/descriptor.proto"; + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + repeated FileDescriptorProto proto_file = 15; +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocatino of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + } + repeated File file = 15; +} diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index d301f01..fae83a3 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -42,8 +42,9 @@ // performance-minded Python code leverage the fast C++ implementation // directly. -#include <utility> +#include <limits> #include <map> +#include <utility> #include <string> #include <vector> @@ -105,6 +106,13 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, const char kDescriptorKey[] = "DESCRIPTOR"; +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().py_generic_services(); +} + + // Prints the common boilerplate needed at the top of every .py // file output by this generator. void PrintTopBoilerplate( @@ -115,14 +123,21 @@ void PrintTopBoilerplate( "\n" "from google.protobuf import descriptor\n" "from google.protobuf import message\n" - "from google.protobuf import reflection\n" - "from google.protobuf import service\n" - "from google.protobuf import service_reflection\n"); + "from google.protobuf import reflection\n"); + if (HasGenericServices(file)) { + printer->Print( + "from google.protobuf import service\n" + "from google.protobuf import service_reflection\n"); + } + // Avoid circular imports if this module is descriptor_pb2. if (!descriptor_proto) { printer->Print( "from google.protobuf import descriptor_pb2\n"); } + printer->Print( + "# @@protoc_insertion_point(imports)\n"); + printer->Print("\n\n"); } @@ -150,10 +165,38 @@ string StringifyDefaultValue(const FieldDescriptor& field) { return SimpleItoa(field.default_value_int64()); case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(field.default_value_uint64()); - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field.default_value_double()); - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field.default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field.default_value_double(); + if (value == numeric_limits<double>::infinity()) { + // Python pre-2.6 on Windows does not parse "inf" correctly. However, + // a numeric literal that is too big for a double will become infinity. + return "1e10000"; + } else if (value == -numeric_limits<double>::infinity()) { + // See above. + return "-1e10000"; + } else if (value != value) { + // infinity * 0 = nan + return "(1e10000 * 0)"; + } else { + return SimpleDtoa(value); + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field.default_value_float(); + if (value == numeric_limits<float>::infinity()) { + // Python pre-2.6 on Windows does not parse "inf" correctly. However, + // a numeric literal that is too big for a double will become infinity. + return "1e10000"; + } else if (value == -numeric_limits<float>::infinity()) { + // See above. + return "-1e10000"; + } else if (value != value) { + // infinity - infinity = nan + return "(1e10000 * 0)"; + } else { + return SimpleFtoa(value); + } + } case FieldDescriptor::CPPTYPE_BOOL: return field.default_value_bool() ? "True" : "False"; case FieldDescriptor::CPPTYPE_ENUM: @@ -204,6 +247,10 @@ bool Generator::Generate(const FileDescriptor* file, StripString(&filename, ".", '/'); filename += ".py"; + FileDescriptorProto fdp; + file_->CopyTo(&fdp); + fdp.SerializeToString(&file_descriptor_serialized_); + scoped_ptr<io::ZeroCopyOutputStream> output(output_directory->Open(filename)); GOOGLE_CHECK(output.get()); @@ -211,6 +258,7 @@ bool Generator::Generate(const FileDescriptor* file, printer_ = &printer; PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto()); + PrintFileDescriptor(); PrintTopLevelEnums(); PrintTopLevelExtensions(); PrintAllNestedEnumsInFile(); @@ -224,7 +272,13 @@ bool Generator::Generate(const FileDescriptor* file, // since they need to call static RegisterExtension() methods on these // classes. FixForeignFieldsInExtensions(); - PrintServices(); + if (HasGenericServices(file)) { + PrintServices(); + } + + printer.Print( + "# @@protoc_insertion_point(module_scope)\n"); + return !printer.failed(); } @@ -238,6 +292,30 @@ void Generator::PrintImports() const { printer_->Print("\n"); } +// Prints the single file descriptor for this file. +void Generator::PrintFileDescriptor() const { + map<string, string> m; + m["descriptor_name"] = kDescriptorKey; + m["name"] = file_->name(); + m["package"] = file_->package(); + const char file_descriptor_template[] = + "$descriptor_name$ = descriptor.FileDescriptor(\n" + " name='$name$',\n" + " package='$package$',\n"; + printer_->Print(m, file_descriptor_template); + printer_->Indent(); + printer_->Print( + "serialized_pb='$value$'", + "value", strings::CHexEscape(file_descriptor_serialized_)); + + // TODO(falk): Also print options and fix the message_type, enum_type, + // service and extension later in the generation. + + printer_->Outdent(); + printer_->Print(")\n"); + printer_->Print("\n"); +} + // Prints descriptors and module-level constants for all top-level // enums defined in |file|. void Generator::PrintTopLevelEnums() const { @@ -277,12 +355,13 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor); m["name"] = enum_descriptor.name(); m["full_name"] = enum_descriptor.full_name(); - m["filename"] = enum_descriptor.name(); + m["file"] = kDescriptorKey; const char enum_descriptor_template[] = "$descriptor_name$ = descriptor.EnumDescriptor(\n" " name='$name$',\n" " full_name='$full_name$',\n" - " filename='$filename$',\n" + " filename=None,\n" + " file=$file$,\n" " values=[\n"; string options_string; enum_descriptor.options().SerializeToString(&options_string); @@ -295,9 +374,12 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { } printer_->Outdent(); printer_->Print("],\n"); + printer_->Print("containing_type=None,\n"); printer_->Print("options=$options_value$,\n", "options_value", OptionsValue("EnumOptions", CEscape(options_string))); + EnumDescriptorProto edp; + PrintSerializedPbInterval(enum_descriptor, edp); printer_->Outdent(); printer_->Print(")\n"); printer_->Print("\n"); @@ -362,15 +444,21 @@ void Generator::PrintServiceDescriptor( map<string, string> m; m["name"] = descriptor.name(); m["full_name"] = descriptor.full_name(); + m["file"] = kDescriptorKey; m["index"] = SimpleItoa(descriptor.index()); m["options_value"] = OptionsValue("ServiceOptions", options_string); const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" + "file=$file$,\n" "index=$index$,\n" - "options=$options_value$,\n" - "methods=[\n"; + "options=$options_value$,\n"; printer_->Print(m, required_function_arguments); + + ServiceDescriptorProto sdp; + PrintSerializedPbInterval(descriptor, sdp); + + printer_->Print("methods=[\n"); for (int i = 0; i < descriptor.method_count(); ++i) { const MethodDescriptor* method = descriptor.method(i); string options_string; @@ -444,17 +532,27 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { map<string, string> m; m["name"] = message_descriptor.name(); m["full_name"] = message_descriptor.full_name(); - m["filename"] = message_descriptor.file()->name(); + m["file"] = kDescriptorKey; const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" - "filename='$filename$',\n" - "containing_type=None,\n"; // TODO(robinson): Implement containing_type. + "filename=None,\n" + "file=$file$,\n" + "containing_type=None,\n"; printer_->Print(m, required_function_arguments); PrintFieldsInDescriptor(message_descriptor); PrintExtensionsInDescriptor(message_descriptor); - // TODO(robinson): implement printing of nested_types. - printer_->Print("nested_types=[], # TODO(robinson): Implement.\n"); + + // Nested types + printer_->Print("nested_types=["); + for (int i = 0; i < message_descriptor.nested_type_count(); ++i) { + const string nested_name = ModuleLevelDescriptorName( + *message_descriptor.nested_type(i)); + printer_->Print("$name$, ", "name", nested_name); + } + printer_->Print("],\n"); + + // Enum types printer_->Print("enum_types=[\n"); printer_->Indent(); for (int i = 0; i < message_descriptor.enum_type_count(); ++i) { @@ -468,8 +566,28 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { string options_string; message_descriptor.options().SerializeToString(&options_string); printer_->Print( - "options=$options_value$", - "options_value", OptionsValue("MessageOptions", options_string)); + "options=$options_value$,\n" + "is_extendable=$extendable$", + "options_value", OptionsValue("MessageOptions", options_string), + "extendable", message_descriptor.extension_range_count() > 0 ? + "True" : "False"); + printer_->Print(",\n"); + + // Extension ranges + printer_->Print("extension_ranges=["); + for (int i = 0; i < message_descriptor.extension_range_count(); ++i) { + const Descriptor::ExtensionRange* range = + message_descriptor.extension_range(i); + printer_->Print("($start$, $end$), ", + "start", SimpleItoa(range->start), + "end", SimpleItoa(range->end)); + } + printer_->Print("],\n"); + + // Serialization of proto + DescriptorProto edp; + PrintSerializedPbInterval(message_descriptor, edp); + printer_->Outdent(); printer_->Print(")\n"); } @@ -511,6 +629,12 @@ void Generator::PrintMessage( m["descriptor_key"] = kDescriptorKey; m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); printer_->Print(m, "$descriptor_key$ = $descriptor_name$\n"); + + printer_->Print( + "\n" + "# @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", message_descriptor.full_name()); + printer_->Outdent(); } @@ -527,16 +651,27 @@ void Generator::PrintNestedMessages( // Recursively fixes foreign fields in all nested types in |descriptor|, then // sets the message_type and enum_type of all message and enum fields to point // to their respective descriptors. +// Args: +// descriptor: descriptor to print fields for. +// containing_descriptor: if descriptor is a nested type, this is its +// containing type, or NULL if this is a root/top-level type. void Generator::FixForeignFieldsInDescriptor( - const Descriptor& descriptor) const { + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const { for (int i = 0; i < descriptor.nested_type_count(); ++i) { - FixForeignFieldsInDescriptor(*descriptor.nested_type(i)); + FixForeignFieldsInDescriptor(*descriptor.nested_type(i), &descriptor); } for (int i = 0; i < descriptor.field_count(); ++i) { const FieldDescriptor& field_descriptor = *descriptor.field(i); FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name"); } + + FixContainingTypeInDescriptor(descriptor, containing_descriptor); + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i); + FixContainingTypeInDescriptor(enum_descriptor, &descriptor); + } } // Sets any necessary message_type and enum_type attributes @@ -593,13 +728,29 @@ string Generator::FieldReferencingExpression( python_dict_name, field.name()); } +// Prints containing_type for nested descriptors or enum descriptors. +template <typename DescriptorT> +void Generator::FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const { + if (containing_descriptor != NULL) { + const string nested_name = ModuleLevelDescriptorName(descriptor); + const string parent_name = ModuleLevelDescriptorName( + *containing_descriptor); + printer_->Print( + "$nested_name$.containing_type = $parent_name$;\n", + "nested_name", nested_name, + "parent_name", parent_name); + } +} + // Prints statements setting the message_type and enum_type fields in the // Python descriptor objects we've already output in ths file. We must // do this in a separate step due to circular references (otherwise, we'd // just set everything in the initial assignment statements). void Generator::FixForeignFieldsInDescriptors() const { for (int i = 0; i < file_->message_type_count(); ++i) { - FixForeignFieldsInDescriptor(*file_->message_type(i)); + FixForeignFieldsInDescriptor(*file_->message_type(i), NULL); } printer_->Print("\n"); } @@ -696,6 +847,7 @@ void Generator::PrintFieldDescriptor( m["type"] = SimpleItoa(field.type()); m["cpp_type"] = SimpleItoa(field.cpp_type()); m["label"] = SimpleItoa(field.label()); + m["has_default_value"] = field.has_default_value() ? "True" : "False"; m["default_value"] = StringifyDefaultValue(field); m["is_extension"] = is_extension ? "True" : "False"; m["options"] = OptionsValue("FieldOptions", options_string); @@ -703,13 +855,13 @@ void Generator::PrintFieldDescriptor( // these fields in correctly after all referenced descriptors have been // defined and/or imported (see FixForeignFieldsInDescriptors()). const char field_descriptor_decl[] = - "descriptor.FieldDescriptor(\n" - " name='$name$', full_name='$full_name$', index=$index$,\n" - " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" - " default_value=$default_value$,\n" - " message_type=None, enum_type=None, containing_type=None,\n" - " is_extension=$is_extension$, extension_scope=None,\n" - " options=$options$)"; + "descriptor.FieldDescriptor(\n" + " name='$name$', full_name='$full_name$', index=$index$,\n" + " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" + " has_default_value=$has_default_value$, default_value=$default_value$,\n" + " message_type=None, enum_type=None, containing_type=None,\n" + " is_extension=$is_extension$, extension_scope=None,\n" + " options=$options$)"; printer_->Print(m, field_descriptor_decl); } @@ -811,6 +963,29 @@ string Generator::ModuleLevelServiceDescriptorName( return name; } +// Prints standard constructor arguments serialized_start and serialized_end. +// Args: +// descriptor: The cpp descriptor to have a serialized reference. +// proto: A proto +// Example printer output: +// serialized_start=41, +// serialized_end=43, +// +template <typename DescriptorT, typename DescriptorProtoT> +void Generator::PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const { + descriptor.CopyTo(&proto); + string sp; + proto.SerializeToString(&sp); + int offset = file_descriptor_serialized_.find(sp); + GOOGLE_CHECK_GE(offset, 0); + + printer_->Print("serialized_start=$serialized_start$,\n" + "serialized_end=$serialized_end$,\n", + "serialized_start", SimpleItoa(offset), + "serialized_end", SimpleItoa(offset + sp.size())); +} + } // namespace python } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 8b99d62..43c2087 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -71,6 +71,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { private: void PrintImports() const; + void PrintFileDescriptor() const; void PrintTopLevelEnums() const; void PrintAllNestedEnumsInFile() const; void PrintNestedEnums(const Descriptor& descriptor) const; @@ -97,13 +98,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { void PrintNestedMessages(const Descriptor& containing_descriptor) const; void FixForeignFieldsInDescriptors() const; - void FixForeignFieldsInDescriptor(const Descriptor& descriptor) const; + void FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInField(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; string FieldReferencingExpression(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; + template <typename DescriptorT> + void FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInExtensions() const; void FixForeignFieldsInExtension( @@ -126,10 +133,15 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { string ModuleLevelServiceDescriptorName( const ServiceDescriptor& descriptor) const; + template <typename DescriptorT, typename DescriptorProtoT> + void PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const; + // Very coarse-grained lock to ensure that Generate() is reentrant. - // Guards file_ and printer_. + // Guards file_, printer_ and file_descriptor_serialized_. mutable Mutex mutex_; mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable string file_descriptor_serialized_; mutable io::Printer* printer_; // Set in Generate(). Under mutex_. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc new file mode 100644 index 0000000..fde8876 --- /dev/null +++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc @@ -0,0 +1,116 @@ +// 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) +// +// TODO(kenton): Share code with the versions of this test in other languages? +// It seemed like parameterizing it would add more complexity than it is +// worth. + +#include <google/protobuf/compiler/python/python_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { +namespace { + +class TestGenerator : public CodeGenerator { + public: + TestGenerator() {} + ~TestGenerator() {} + + virtual bool Generate(const FileDescriptor* file, + const string& parameter, + OutputDirectory* output_directory, + string* error) const { + TryInsert("test_pb2.py", "imports", output_directory); + TryInsert("test_pb2.py", "module_scope", output_directory); + TryInsert("test_pb2.py", "class_scope:foo.Bar", output_directory); + TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", output_directory); + return true; + } + + void TryInsert(const string& filename, const string& insertion_point, + OutputDirectory* output_directory) const { + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->OpenForInsert(filename, insertion_point)); + io::Printer printer(output.get(), '$'); + printer.Print("// inserted $name$\n", "name", insertion_point); + } +}; + +// This test verifies that all the expected insertion points exist. It does +// not verify that they are correctly-placed; that would require actually +// compiling the output which is a bit more than I care to do for this test. +TEST(PythonPluginTest, PluginTest) { + File::WriteStringToFileOrDie( + "syntax = \"proto2\";\n" + "package foo;\n" + "message Bar {\n" + " message Baz {}\n" + "}\n", + TestTempDir() + "/test.proto"); + + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + python::Generator python_generator; + TestGenerator test_generator; + cli.RegisterGenerator("--python_out", &python_generator, ""); + cli.RegisterGenerator("--test_out", &test_generator, ""); + + string proto_path = "-I" + TestTempDir(); + string python_out = "--python_out=" + TestTempDir(); + string test_out = "--test_out=" + TestTempDir(); + + const char* argv[] = { + "protoc", + proto_path.c_str(), + python_out.c_str(), + test_out.c_str(), + "test.proto" + }; + + EXPECT_EQ(0, cli.Run(5, argv)); +} + +} // namespace +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc new file mode 100644 index 0000000..de46a3e --- /dev/null +++ b/src/google/protobuf/compiler/subprocess.cc @@ -0,0 +1,458 @@ +// 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> + +#ifndef _WIN32 +#include <errno.h> +#include <sys/wait.h> +#include <signal.h> +#endif + +#include <algorithm> +#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. + STARTUPINFO 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 (CreateProcess((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 diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.h b/src/google/protobuf/compiler/subprocess.h index 1530778..f9e8ae8 100644 --- a/src/google/protobuf/compiler/javamicro/javamicro_field.h +++ b/src/google/protobuf/compiler/subprocess.h @@ -29,70 +29,79 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ -#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ +#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 <string> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/javamicro/javamicro_params.h> namespace google { namespace protobuf { - namespace io { - class Printer; // printer.h - } -} -namespace protobuf { +class Message; + namespace compiler { -namespace javamicro { -class FieldGenerator { +// Utility class for launching sub-processes. +class Subprocess { public: - //FieldGenerator() {} - FieldGenerator(const Params& params) : params_(params) {} - virtual ~FieldGenerator(); - - virtual void GenerateMembers(io::Printer* printer) const = 0; - virtual void GenerateMergingCode(io::Printer* printer) const = 0; - virtual void GenerateParsingCode(io::Printer* printer) const = 0; - virtual void GenerateSerializationCode(io::Printer* printer) const = 0; - virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; - - virtual string GetBoxedType() const = 0; + 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 Subprocess::Win32ErrorMessage(DWORD error_code); +#endif - protected: - const Params& params_; private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); -}; - -// Convenience class which constructs FieldGenerators for a Descriptor. -class FieldGeneratorMap { - public: - explicit FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms); - ~FieldGeneratorMap(); +#ifdef _WIN32 + DWORD process_start_error_; + HANDLE child_handle_; - const FieldGenerator& get(const FieldDescriptor* field) const; - const FieldGenerator& get_extension(int index) const; + // 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_; - private: - const Descriptor* descriptor_; - scoped_array<scoped_ptr<FieldGenerator> > field_generators_; - scoped_array<scoped_ptr<FieldGenerator> > extension_generators_; +#else // _WIN32 + pid_t child_pid_; - static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Params ¶ms); + // 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_; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +#endif // !_WIN32 }; -} // namespace javamicro } // namespace compiler } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ +#endif // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ diff --git a/src/google/protobuf/unittest_simple_micro.proto b/src/google/protobuf/compiler/test_plugin.cc index 057bf3d..5cbbf3d 100644 --- a/src/google/protobuf/unittest_simple_micro.proto +++ b/src/google/protobuf/compiler/test_plugin.cc @@ -28,25 +28,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Author: wink@google.com (Wink Saville) +// Author: kenton@google.com (Kenton Varda) // +// This is a dummy code generator plugin used by +// command_line_interface_unittest. -package protobuf_unittest_import; +#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> -option java_package = "com.google.protobuf.micro"; +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 -message SimpleMessageMicro { - message NestedMessage { - optional int32 bb = 1; - } - - enum NestedEnum { - FOO = 1; - BAR = 2; - BAZ = 3; - } - - optional int32 d = 1 [default = 123]; - optional NestedMessage nested_msg = 2; - optional NestedEnum default_nested_enum = 3 [default = BAZ]; + google::protobuf::compiler::MockCodeGenerator generator("test_plugin"); + return google::protobuf::compiler::PluginMain(argc, argv, &generator); } diff --git a/src/google/protobuf/compiler/zip_output_unittest.sh b/src/google/protobuf/compiler/zip_output_unittest.sh new file mode 100755 index 0000000..259d5d2 --- /dev/null +++ b/src/google/protobuf/compiler/zip_output_unittest.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Protocol Buffers - Google's data interchange format +# Copyright 2009 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) +# +# Test protoc's zip output mode. + +fail() { + echo "$@" >&2 + exit 1 +} + +echo ' + option java_multiple_files = true; + option java_package = "test.jar"; + option java_outer_classname = "Outer"; + message Foo {} + message Bar {} +' > testzip.proto + +./protoc --cpp_out=testzip.zip --python_out=testzip.zip --java_out=testzip.jar \ + testzip.proto || fail 'protoc failed.' + +echo "Testing output to zip..." +if unzip -h > /dev/null; then + unzip -t testzip.zip > testzip.list || fail 'unzip failed.' + + grep 'testing: testzip\.pb\.cc *OK$' testzip.list > /dev/null \ + || fail 'testzip.pb.cc not found in output zip.' + grep 'testing: testzip\.pb\.h *OK$' testzip.list > /dev/null \ + || fail 'testzip.pb.h not found in output zip.' + grep 'testing: testzip_pb2\.py *OK$' testzip.list > /dev/null \ + || fail 'testzip_pb2.py not found in output zip.' + grep -i 'manifest' testzip.list > /dev/null \ + && fail 'Zip file contained manifest.' +else + echo "Warning: 'unzip' command not available. Skipping test." +fi + +echo "Testing output to jar..." +if jar c testzip.proto > /dev/null; then + jar tf testzip.jar > testzip.list || fail 'jar failed.' + + grep '^test/jar/Foo\.java$' testzip.list > /dev/null \ + || fail 'Foo.java not found in output jar.' + grep '^test/jar/Bar\.java$' testzip.list > /dev/null \ + || fail 'Bar.java not found in output jar.' + grep '^test/jar/Outer\.java$' testzip.list > /dev/null \ + || fail 'Outer.java not found in output jar.' + grep '^META-INF/MANIFEST\.MF$' testzip.list > /dev/null \ + || fail 'Manifest not ofund in output jar.' +else + echo "Warning: 'jar' command not available. Skipping test." +fi + +echo PASS diff --git a/src/google/protobuf/compiler/zip_writer.cc b/src/google/protobuf/compiler/zip_writer.cc new file mode 100644 index 0000000..53c1877 --- /dev/null +++ b/src/google/protobuf/compiler/zip_writer.cc @@ -0,0 +1,188 @@ +// 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 google +} // namespace protobuf +} // namespace compiler diff --git a/src/google/protobuf/unittest_recursive_micro.proto b/src/google/protobuf/compiler/zip_writer.h index a256852..4289553 100644 --- a/src/google/protobuf/unittest_recursive_micro.proto +++ b/src/google/protobuf/compiler/zip_writer.h @@ -28,20 +28,36 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Author: wink@google.com (Wink Saville) -// +// 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(); -package protobuf_unittest_import; + bool Write(const string& filename, const string& contents); + bool WriteDirectory(); -option java_package = "com.google.protobuf.micro"; + private: + struct FileInfo { + string name; + uint32 offset; + uint32 size; + uint32 crc32; + }; -message RecursiveMessageMicro { - message NestedMessage { - optional RecursiveMessageMicro a = 1; - } + io::ZeroCopyOutputStream* raw_output_; + vector<FileInfo> files_; +}; - required int32 id = 1; - optional NestedMessage nested_message = 2; - optional RecursiveMessageMicro optional_recursive_message_micro = 3; - repeated RecursiveMessageMicro repeated_recursive_message_micro = 4; -} +} // namespace google +} // namespace protobuf +} // namespace compiler diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index a12e4e7..81c4ac0 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -37,6 +37,7 @@ #include <set> #include <vector> #include <algorithm> +#include <limits> #include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor_database.h> @@ -796,6 +797,7 @@ bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { namespace { + EncodedDescriptorDatabase* generated_database_ = NULL; DescriptorPool* generated_pool_ = NULL; GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_); @@ -810,6 +812,7 @@ void DeleteGeneratedPool() { void InitGeneratedPool() { generated_database_ = new EncodedDescriptorDatabase; generated_pool_ = new DescriptorPool(generated_database_); + internal::OnShutdown(&DeleteGeneratedPool); } @@ -2998,12 +3001,28 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, strtou64(proto.default_value().c_str(), &end_pos, 0); break; case FieldDescriptor::CPPTYPE_FLOAT: - result->default_value_float_ = - NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + if (proto.default_value() == "inf") { + result->default_value_float_ = numeric_limits<float>::infinity(); + } else if (proto.default_value() == "-inf") { + result->default_value_float_ = -numeric_limits<float>::infinity(); + } else if (proto.default_value() == "nan") { + result->default_value_float_ = numeric_limits<float>::quiet_NaN(); + } else { + result->default_value_float_ = + NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + } break; case FieldDescriptor::CPPTYPE_DOUBLE: - result->default_value_double_ = - NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + if (proto.default_value() == "inf") { + result->default_value_double_ = numeric_limits<double>::infinity(); + } else if (proto.default_value() == "-inf") { + result->default_value_double_ = -numeric_limits<double>::infinity(); + } else if (proto.default_value() == "nan") { + result->default_value_double_ = numeric_limits<double>::quiet_NaN(); + } else { + result->default_value_double_ = + NoLocaleStrtod(proto.default_value().c_str(), &end_pos); + } break; case FieldDescriptor::CPPTYPE_BOOL: if (proto.default_value() == "true") { @@ -3651,17 +3670,11 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, } // Only repeated primitive fields may be packed. - if (field->options().packed()) { - if (!field->is_repeated() || - field->type() == FieldDescriptor::TYPE_STRING || - field->type() == FieldDescriptor::TYPE_GROUP || - field->type() == FieldDescriptor::TYPE_MESSAGE || - field->type() == FieldDescriptor::TYPE_BYTES) { - AddError( - field->full_name(), proto, - DescriptorPool::ErrorCollector::TYPE, - "[packed = true] can only be specified for repeated primitive fields."); - } + if (field->options().packed() && !field->is_packable()) { + AddError( + field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "[packed = true] can only be specified for repeated primitive fields."); } // Note: Default instance may not yet be initialized here, so we have to diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 5b629a5..7f87dd8 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -395,6 +395,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { bool is_required() const; // shorthand for label() == LABEL_REQUIRED bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL bool is_repeated() const; // shorthand for label() == LABEL_REPEATED + bool is_packable() const; // shorthand for is_repeated() && + // IsTypePackable(type()) // Index of this field within the message's field array, or the file or // extension scope's extensions array. @@ -474,6 +476,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // Helper method to get the CppType for a particular Type. static CppType TypeToCppType(Type type); + // Return true iff [packed = true] is valid for fields of this type. + static inline bool IsTypePackable(Type field_type); + private: typedef FieldOptions OptionsType; @@ -1069,10 +1074,6 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // These methods may contain hidden pitfalls and may be removed in a // future library version. - // DEPRECATED: Use of underlays can lead to many subtle gotchas. Instead, - // try to formulate what you want to do in terms of DescriptorDatabases. - // This constructor will be removed soon. - // // Create a DescriptorPool which is overlaid on top of some other pool. // If you search for a descriptor in the overlay and it is not found, the // underlay will be searched as a backup. If the underlay has its own @@ -1090,6 +1091,9 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // types directly into generated_pool(): this is not allowed, and would be // bad design anyway. So, instead, you could use generated_pool() as an // underlay for a new DescriptorPool in which you add only the new file. + // + // WARNING: Use of underlays can lead to many subtle gotchas. Instead, + // try to formulate what you want to do in terms of DescriptorDatabases. explicit DescriptorPool(const DescriptorPool* underlay); // Called by generated classes at init time to add their descriptors to @@ -1294,6 +1298,10 @@ inline bool FieldDescriptor::is_repeated() const { return label() == LABEL_REPEATED; } +inline bool FieldDescriptor::is_packable() const { + return is_repeated() && IsTypePackable(type()); +} + // To save space, index() is computed by looking at the descriptor's position // in the parent's array of children. inline int FieldDescriptor::index() const { @@ -1342,6 +1350,13 @@ inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { return kTypeToCppTypeMap[type]; } +inline bool FieldDescriptor::IsTypePackable(Type field_type) { + return (field_type != FieldDescriptor::TYPE_STRING && + field_type != FieldDescriptor::TYPE_GROUP && + field_type != FieldDescriptor::TYPE_MESSAGE && + field_type != FieldDescriptor::TYPE_BYTES); +} + inline const FileDescriptor* FileDescriptor::dependency(int index) const { return dependencies_[index]; } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index a68a6a4..f61e7cd 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -8,6 +8,7 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/reflection_ops.h> #include <google/protobuf/wire_format.h> +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -250,11 +251,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { ::google::protobuf::MessageFactory::generated_factory(), sizeof(MethodDescriptorProto)); FileOptions_descriptor_ = file->message_type(8); - static const int FileOptions_offsets_[5] = { + static const int FileOptions_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -552,43 +556,47 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "ptions\"\177\n\025MethodDescriptorProto\022\014\n\004name\030" "\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output_type" "\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.protobu" - "f.MethodOptions\"\271\002\n\013FileOptions\022\024\n\014java_" + "f.MethodOptions\"\244\003\n\013FileOptions\022\024\n\014java_" "package\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 " "\001(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022" "F\n\014optimize_for\030\t \001(\0162).google.protobuf." - "FileOptions.OptimizeMode:\005SPEED\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" - "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" - "*\t\010\350\007\020\200\200\200\200\002\"\270\001\n\016MessageOptions\022&\n\027messag" - "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" - "ndard_descriptor_accessor\030\002 \001(\010:\005false\022C" - "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" - "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\200" - "\002\n\014FieldOptions\0222\n\005ctype\030\001 \001(\0162#.google." - "protobuf.FieldOptions.CType\022\016\n\006packed\030\002 " - "\001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experi" - "mental_map_key\030\t \001(\t\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_P" - "IECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024unin" - "terpreted_option\030\347\007 \003(\0132$.google.protobu" - "f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020Enum" - "ValueOptions\022C\n\024uninterpreted_option\030\347\007 " - "\003(\0132$.google.protobuf.UninterpretedOptio" - "n*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninte" - "rpreted_option\030\347\007 \003(\0132$.google.protobuf." - "UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethod" - "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$" - ".google.protobuf.UninterpretedOption*\t\010\350" - "\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;\n\004name\030" - "\002 \003(\0132-.google.protobuf.UninterpretedOpt" - "ion.NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032" - "\n\022positive_int_value\030\004 \001(\004\022\032\n\022negative_i" - "nt_value\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014" - "string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_p" - "art\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.g" - "oogle.protobufB\020DescriptorProtosH\001", 3554); + "FileOptions.OptimizeMode:\005SPEED\022!\n\023cc_ge" + "neric_services\030\020 \001(\010:\004true\022#\n\025java_gener" + "ic_services\030\021 \001(\010:\004true\022!\n\023py_generic_se" + "rvices\030\022 \001(\010:\004true\022C\n\024uninterpreted_opti" + "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete" + "dOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCO" + "DE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\270" + "\001\n\016MessageOptions\022&\n\027message_set_wire_fo" + "rmat\030\001 \001(\010:\005false\022.\n\037no_standard_descrip" + "tor_accessor\030\002 \001(\010:\005false\022C\n\024uninterpret" + "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" + "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptio" + "ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel" + "dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experimenta" + "l_map_key\030\t \001(\t\022C\n\024uninterpreted_option\030" + "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" + "tion\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014S" + "TRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022" + "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." + "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" + "b\n\020EnumValueOptions\022C\n\024uninterpreted_opt" + "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" + "edOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n" + "\024uninterpreted_option\030\347\007 \003(\0132$.google.pr" + "otobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n" + "\rMethodOptions\022C\n\024uninterpreted_option\030\347" + "\007 \003(\0132$.google.protobuf.UninterpretedOpt" + "ion*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;" + "\n\004name\030\002 \003(\0132-.google.protobuf.Uninterpr" + "etedOption.NamePart\022\030\n\020identifier_value\030" + "\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022neg" + "ative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006 " + "\001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n" + "\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)" + "\n\023com.google.protobufB\020DescriptorProtosH" + "\001", 3681); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -644,14 +652,16 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2fdescriptor_2eproto { const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER -FileDescriptorSet::FileDescriptorSet() { +FileDescriptorSet::FileDescriptorSet() + : ::google::protobuf::Message() { SharedCtor(); } void FileDescriptorSet::InitAsDefaultInstance() { } -FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) { +FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -670,6 +680,11 @@ void FileDescriptorSet::SharedDtor() { } } +void FileDescriptorSet::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorSet_descriptor_; @@ -699,13 +714,14 @@ bool FileDescriptorSet::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.FileDescriptorProto file = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { goto handle_uninterpreted; } - parse_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_file())); if (input->ExpectTag(10)) goto parse_file; if (input->ExpectAtEnd()) return true; break; @@ -729,15 +745,9 @@ bool FileDescriptorSet::MergePartialFromCodedStream( void FileDescriptorSet::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorSet::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.FileDescriptorProto file = 1; for (int i = 0; i < this->file_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 1, this->file(i), output); } @@ -779,7 +789,9 @@ int FileDescriptorSet::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -854,7 +866,8 @@ const int FileDescriptorProto::kExtensionFieldNumber; const int FileDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -FileDescriptorProto::FileDescriptorProto() { +FileDescriptorProto::FileDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -862,7 +875,8 @@ void FileDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FileOptions*>(&::google::protobuf::FileOptions::default_instance()); } -FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) { +FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -891,6 +905,11 @@ void FileDescriptorProto::SharedDtor() { } } +void FileDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorProto_descriptor_; @@ -939,47 +958,50 @@ bool FileDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_package; break; } // optional string package = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_package: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_package: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->package().data(), this->package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; break; } // repeated string dependency = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_dependency: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_dependency())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(0).data(), this->dependency(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_dependency: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->add_dependency())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->dependency(0).data(), this->dependency(0).length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; if (input->ExpectTag(34)) goto parse_message_type; break; @@ -987,13 +1009,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto message_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_message_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_message_type())); + } else { goto handle_uninterpreted; } - parse_message_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_message_type())); if (input->ExpectTag(34)) goto parse_message_type; if (input->ExpectTag(42)) goto parse_enum_type; break; @@ -1001,13 +1024,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(42)) goto parse_enum_type; if (input->ExpectTag(50)) goto parse_service; break; @@ -1015,13 +1039,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.ServiceDescriptorProto service = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_service: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_service())); + } else { goto handle_uninterpreted; } - parse_service: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_service())); if (input->ExpectTag(50)) goto parse_service; if (input->ExpectTag(58)) goto parse_extension; break; @@ -1029,13 +1054,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(58)) goto parse_extension; if (input->ExpectTag(66)) goto parse_options; break; @@ -1043,13 +1069,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FileOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1072,12 +1099,6 @@ bool FileDescriptorProto::MergePartialFromCodedStream( void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1107,31 +1128,31 @@ void FileDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.DescriptorProto message_type = 4; for (int i = 0; i < this->message_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->message_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->enum_type(i), output); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; for (int i = 0; i < this->service_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->service(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->extension(i), output); } // optional .google.protobuf.FileOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -1284,7 +1305,9 @@ int FileDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1385,14 +1408,16 @@ const int DescriptorProto_ExtensionRange::kStartFieldNumber; const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER -DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() { +DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() + : ::google::protobuf::Message() { SharedCtor(); } void DescriptorProto_ExtensionRange::InitAsDefaultInstance() { } -DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) { +DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1413,6 +1438,11 @@ void DescriptorProto_ExtensionRange::SharedDtor() { } } +void DescriptorProto_ExtensionRange::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_ExtensionRange_descriptor_; @@ -1445,27 +1475,31 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional int32 start = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &start_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &start_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_end; break; } // optional int32 end = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_end: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &end_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -1488,12 +1522,6 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional int32 start = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output); @@ -1553,7 +1581,9 @@ int DescriptorProto_ExtensionRange::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1631,7 +1661,8 @@ const int DescriptorProto::kExtensionRangeFieldNumber; const int DescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -DescriptorProto::DescriptorProto() { +DescriptorProto::DescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -1639,7 +1670,8 @@ void DescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MessageOptions*>(&::google::protobuf::MessageOptions::default_instance()); } -DescriptorProto::DescriptorProto(const DescriptorProto& from) { +DescriptorProto::DescriptorProto(const DescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1664,6 +1696,11 @@ void DescriptorProto::SharedDtor() { } } +void DescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_descriptor_; @@ -1707,28 +1744,30 @@ bool DescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_field; break; } // repeated .google.protobuf.FieldDescriptorProto field = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_field: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_field())); + } else { goto handle_uninterpreted; } - parse_field: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_field())); if (input->ExpectTag(18)) goto parse_field; if (input->ExpectTag(26)) goto parse_nested_type; break; @@ -1736,13 +1775,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto nested_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_nested_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_nested_type())); + } else { goto handle_uninterpreted; } - parse_nested_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_nested_type())); if (input->ExpectTag(26)) goto parse_nested_type; if (input->ExpectTag(34)) goto parse_enum_type; break; @@ -1750,13 +1790,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(34)) goto parse_enum_type; if (input->ExpectTag(42)) goto parse_extension_range; break; @@ -1764,13 +1805,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension_range())); + } else { goto handle_uninterpreted; } - parse_extension_range: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension_range())); if (input->ExpectTag(42)) goto parse_extension_range; if (input->ExpectTag(50)) goto parse_extension; break; @@ -1778,13 +1820,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(50)) goto parse_extension; if (input->ExpectTag(58)) goto parse_options; break; @@ -1792,13 +1835,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.MessageOptions options = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1821,12 +1865,6 @@ bool DescriptorProto::MergePartialFromCodedStream( void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1838,37 +1876,37 @@ void DescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.FieldDescriptorProto field = 2; for (int i = 0; i < this->field_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->field(i), output); } // repeated .google.protobuf.DescriptorProto nested_type = 3; for (int i = 0; i < this->nested_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->nested_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->enum_type(i), output); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; for (int i = 0; i < this->extension_range_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->extension_range(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->extension(i), output); } // optional .google.protobuf.MessageOptions options = 7; if (_has_bit(6)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->options(), output); } @@ -2003,7 +2041,9 @@ int DescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2146,6 +2186,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32; const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; +const int FieldDescriptorProto::Type_ARRAYSIZE; #endif // _MSC_VER const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { protobuf_AssignDescriptorsOnce(); @@ -2168,6 +2209,7 @@ const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; +const int FieldDescriptorProto::Label_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldDescriptorProto::_default_name_; const ::std::string FieldDescriptorProto::_default_type_name_; @@ -2184,7 +2226,8 @@ const int FieldDescriptorProto::kDefaultValueFieldNumber; const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -FieldDescriptorProto::FieldDescriptorProto() { +FieldDescriptorProto::FieldDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -2192,7 +2235,8 @@ void FieldDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::FieldOptions*>(&::google::protobuf::FieldOptions::default_instance()); } -FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) { +FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2232,6 +2276,11 @@ void FieldDescriptorProto::SharedDtor() { } } +void FieldDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_descriptor_; @@ -2288,62 +2337,69 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_extendee; break; } // optional string extendee = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extendee: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_extendee())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_extendee: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_extendee())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->extendee().data(), this->extendee().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(24)) goto parse_number; break; } // optional int32 number = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(32)) goto parse_label; break; } // optional .google.protobuf.FieldDescriptorProto.Label label = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_label: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { - set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + parse_label: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { + set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + } else { + mutable_unknown_fields()->AddVarint(4, value); + } } else { - mutable_unknown_fields()->AddVarint(4, value); + goto handle_uninterpreted; } if (input->ExpectTag(40)) goto parse_type; break; @@ -2351,17 +2407,20 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FieldDescriptorProto.Type type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_type: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { - set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { + set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + } else { + mutable_unknown_fields()->AddVarint(5, value); + } } else { - mutable_unknown_fields()->AddVarint(5, value); + goto handle_uninterpreted; } if (input->ExpectTag(50)) goto parse_type_name; break; @@ -2369,45 +2428,48 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional string type_name = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_type_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_type_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_type_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_type_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->type_name().data(), this->type_name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(58)) goto parse_default_value; break; } // optional string default_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_default_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_default_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_default_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_default_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->default_value().data(), this->default_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_options; break; } // optional .google.protobuf.FieldOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2430,12 +2492,6 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2491,7 +2547,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.FieldOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -2638,7 +2694,9 @@ int FieldDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2739,7 +2797,8 @@ const int EnumDescriptorProto::kValueFieldNumber; const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -EnumDescriptorProto::EnumDescriptorProto() { +EnumDescriptorProto::EnumDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -2747,7 +2806,8 @@ void EnumDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumOptions*>(&::google::protobuf::EnumOptions::default_instance()); } -EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) { +EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2772,6 +2832,11 @@ void EnumDescriptorProto::SharedDtor() { } } +void EnumDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumDescriptorProto_descriptor_; @@ -2811,28 +2876,30 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_value; break; } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_value())); + } else { goto handle_uninterpreted; } - parse_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_value())); if (input->ExpectTag(18)) goto parse_value; if (input->ExpectTag(26)) goto parse_options; break; @@ -2840,13 +2907,14 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.EnumOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2869,12 +2937,6 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2886,13 +2948,13 @@ void EnumDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.EnumValueDescriptorProto value = 2; for (int i = 0; i < this->value_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->value(i), output); } // optional .google.protobuf.EnumOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -2967,7 +3029,9 @@ int EnumDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3049,7 +3113,8 @@ const int EnumValueDescriptorProto::kNumberFieldNumber; const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -EnumValueDescriptorProto::EnumValueDescriptorProto() { +EnumValueDescriptorProto::EnumValueDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -3057,7 +3122,8 @@ void EnumValueDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::EnumValueOptions*>(&::google::protobuf::EnumValueOptions::default_instance()); } -EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) { +EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3083,6 +3149,11 @@ void EnumValueDescriptorProto::SharedDtor() { } } +void EnumValueDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueDescriptorProto_descriptor_; @@ -3122,42 +3193,46 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_number; break; } // optional int32 number = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(26)) goto parse_options; break; } // optional .google.protobuf.EnumValueOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3180,12 +3255,6 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3202,7 +3271,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.EnumValueOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3274,7 +3343,9 @@ int EnumValueDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3355,7 +3426,8 @@ const int ServiceDescriptorProto::kMethodFieldNumber; const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -ServiceDescriptorProto::ServiceDescriptorProto() { +ServiceDescriptorProto::ServiceDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -3363,7 +3435,8 @@ void ServiceDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::ServiceOptions*>(&::google::protobuf::ServiceOptions::default_instance()); } -ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) { +ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3388,6 +3461,11 @@ void ServiceDescriptorProto::SharedDtor() { } } +void ServiceDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceDescriptorProto_descriptor_; @@ -3427,28 +3505,30 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_method; break; } // repeated .google.protobuf.MethodDescriptorProto method = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_method: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_method())); + } else { goto handle_uninterpreted; } - parse_method: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_method())); if (input->ExpectTag(18)) goto parse_method; if (input->ExpectTag(26)) goto parse_options; break; @@ -3456,13 +3536,14 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.ServiceOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3485,12 +3566,6 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3502,13 +3577,13 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.MethodDescriptorProto method = 2; for (int i = 0; i < this->method_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->method(i), output); } // optional .google.protobuf.ServiceOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3583,7 +3658,9 @@ int ServiceDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3668,7 +3745,8 @@ const int MethodDescriptorProto::kOutputTypeFieldNumber; const int MethodDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER -MethodDescriptorProto::MethodDescriptorProto() { +MethodDescriptorProto::MethodDescriptorProto() + : ::google::protobuf::Message() { SharedCtor(); } @@ -3676,7 +3754,8 @@ void MethodDescriptorProto::InitAsDefaultInstance() { options_ = const_cast< ::google::protobuf::MethodOptions*>(&::google::protobuf::MethodOptions::default_instance()); } -MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) { +MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3709,6 +3788,11 @@ void MethodDescriptorProto::SharedDtor() { } } +void MethodDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodDescriptorProto_descriptor_; @@ -3757,60 +3841,64 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_input_type; break; } // optional string input_type = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_input_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_input_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_input_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_input_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->input_type().data(), this->input_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_output_type; break; } // optional string output_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_output_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_output_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_output_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_output_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->output_type().data(), this->output_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(34)) goto parse_options; break; } // optional .google.protobuf.MethodOptions options = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3833,12 +3921,6 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3868,7 +3950,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.MethodOptions options = 4; if (_has_bit(3)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->options(), output); } @@ -3962,7 +4044,9 @@ int MethodDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4061,6 +4145,7 @@ const FileOptions_OptimizeMode FileOptions::CODE_SIZE; const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; +const int FileOptions::OptimizeMode_ARRAYSIZE; #endif // _MSC_VER const ::std::string FileOptions::_default_java_package_; const ::std::string FileOptions::_default_java_outer_classname_; @@ -4069,17 +4154,22 @@ const int FileOptions::kJavaPackageFieldNumber; const int FileOptions::kJavaOuterClassnameFieldNumber; const int FileOptions::kJavaMultipleFilesFieldNumber; const int FileOptions::kOptimizeForFieldNumber; +const int FileOptions::kCcGenericServicesFieldNumber; +const int FileOptions::kJavaGenericServicesFieldNumber; +const int FileOptions::kPyGenericServicesFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -FileOptions::FileOptions() { +FileOptions::FileOptions() + : ::google::protobuf::Message() { SharedCtor(); } void FileOptions::InitAsDefaultInstance() { } -FileOptions::FileOptions(const FileOptions& from) { +FileOptions::FileOptions(const FileOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4090,6 +4180,9 @@ void FileOptions::SharedCtor() { java_outer_classname_ = const_cast< ::std::string*>(&_default_java_outer_classname_); java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4108,6 +4201,11 @@ void FileOptions::SharedDtor() { } } +void FileOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FileOptions_descriptor_; @@ -4138,6 +4236,9 @@ void FileOptions::Clear() { } java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; } uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -4152,48 +4253,53 @@ bool FileOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string java_package = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_package().data(), this->java_package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_java_outer_classname; break; } // optional string java_outer_classname = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_java_outer_classname: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_outer_classname())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_java_outer_classname: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_outer_classname())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_outer_classname().data(), this->java_outer_classname().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(72)) goto parse_optimize_for; break; } // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_optimize_for: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { - set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + parse_optimize_for: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { + set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + } else { + mutable_unknown_fields()->AddVarint(9, value); + } } else { - mutable_unknown_fields()->AddVarint(9, value); + goto handle_uninterpreted; } if (input->ExpectTag(80)) goto parse_java_multiple_files; break; @@ -4201,27 +4307,78 @@ bool FileOptions::MergePartialFromCodedStream( // optional bool java_multiple_files = 10 [default = false]; case 10: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_multiple_files: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_multiple_files_))); + _set_bit(2); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(128)) goto parse_cc_generic_services; + break; + } + + // optional bool cc_generic_services = 16 [default = true]; + case 16: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_cc_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &cc_generic_services_))); + _set_bit(4); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(136)) goto parse_java_generic_services; + break; + } + + // optional bool java_generic_services = 17 [default = true]; + case 17: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_generic_services_))); + _set_bit(5); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(144)) goto parse_py_generic_services; + break; + } + + // optional bool py_generic_services = 18 [default = true]; + case 18: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_py_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &py_generic_services_))); + _set_bit(6); + } else { goto handle_uninterpreted; } - parse_java_multiple_files: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &java_multiple_files_)); - _set_bit(2); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4250,12 +4407,6 @@ bool FileOptions::MergePartialFromCodedStream( void FileOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string java_package = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -4285,9 +4436,24 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4334,6 +4500,21 @@ void FileOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -4381,6 +4562,21 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for()); } + // optional bool cc_generic_services = 16 [default = true]; + if (has_cc_generic_services()) { + total_size += 2 + 1; + } + + // optional bool java_generic_services = 17 [default = true]; + if (has_java_generic_services()) { + total_size += 2 + 1; + } + + // optional bool py_generic_services = 18 [default = true]; + if (has_py_generic_services()) { + total_size += 2 + 1; + } + } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -4397,7 +4593,9 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4429,6 +4627,15 @@ void FileOptions::MergeFrom(const FileOptions& from) { if (from._has_bit(3)) { set_optimize_for(from.optimize_for()); } + if (from._has_bit(4)) { + set_cc_generic_services(from.cc_generic_services()); + } + if (from._has_bit(5)) { + set_java_generic_services(from.java_generic_services()); + } + if (from._has_bit(6)) { + set_py_generic_services(from.py_generic_services()); + } } _extensions_.MergeFrom(from._extensions_); mutable_unknown_fields()->MergeFrom(from.unknown_fields()); @@ -4461,6 +4668,9 @@ void FileOptions::Swap(FileOptions* other) { std::swap(java_outer_classname_, other->java_outer_classname_); std::swap(java_multiple_files_, other->java_multiple_files_); std::swap(optimize_for_, other->optimize_for_); + std::swap(cc_generic_services_, other->cc_generic_services_); + std::swap(java_generic_services_, other->java_generic_services_); + std::swap(py_generic_services_, other->py_generic_services_); uninterpreted_option_.Swap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); @@ -4486,14 +4696,16 @@ const int MessageOptions::kNoStandardDescriptorAccessorFieldNumber; const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -MessageOptions::MessageOptions() { +MessageOptions::MessageOptions() + : ::google::protobuf::Message() { SharedCtor(); } void MessageOptions::InitAsDefaultInstance() { } -MessageOptions::MessageOptions(const MessageOptions& from) { +MessageOptions::MessageOptions(const MessageOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4514,6 +4726,11 @@ void MessageOptions::SharedDtor() { } } +void MessageOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MessageOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MessageOptions_descriptor_; @@ -4548,40 +4765,45 @@ bool MessageOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional bool message_set_wire_format = 1 [default = false]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &message_set_wire_format_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &message_set_wire_format_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor; break; } // optional bool no_standard_descriptor_accessor = 2 [default = false]; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_no_standard_descriptor_accessor: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &no_standard_descriptor_accessor_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_no_standard_descriptor_accessor: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &no_standard_descriptor_accessor_)); - _set_bit(1); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4610,12 +4832,6 @@ bool MessageOptions::MergePartialFromCodedStream( void MessageOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MessageOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional bool message_set_wire_format = 1 [default = false]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output); @@ -4628,7 +4844,7 @@ void MessageOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4702,7 +4918,9 @@ int MessageOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4783,6 +5001,7 @@ const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() { } bool FieldOptions_CType_IsValid(int value) { switch(value) { + case 0: case 1: case 2: return true; @@ -4792,10 +5011,12 @@ bool FieldOptions_CType_IsValid(int value) { } #ifndef _MSC_VER +const FieldOptions_CType FieldOptions::STRING; const FieldOptions_CType FieldOptions::CORD; const FieldOptions_CType FieldOptions::STRING_PIECE; const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; +const int FieldOptions::CType_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldOptions::_default_experimental_map_key_; #ifndef _MSC_VER @@ -4806,21 +5027,23 @@ const int FieldOptions::kExperimentalMapKeyFieldNumber; const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -FieldOptions::FieldOptions() { +FieldOptions::FieldOptions() + : ::google::protobuf::Message() { SharedCtor(); } void FieldOptions::InitAsDefaultInstance() { } -FieldOptions::FieldOptions(const FieldOptions& from) { +FieldOptions::FieldOptions(const FieldOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } void FieldOptions::SharedCtor() { _cached_size_ = 0; - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; experimental_map_key_ = const_cast< ::std::string*>(&_default_experimental_map_key_); @@ -4839,6 +5062,11 @@ void FieldOptions::SharedDtor() { } } +void FieldOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldOptions_descriptor_; @@ -4857,7 +5085,7 @@ FieldOptions* FieldOptions::New() const { void FieldOptions::Clear() { _extensions_.Clear(); if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; if (_has_bit(3)) { @@ -4877,18 +5105,21 @@ bool FieldOptions::MergePartialFromCodedStream( ::google::protobuf::uint32 tag; while ((tag = input->ReadTag()) != 0) { switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldOptions_CType_IsValid(value)) { - set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldOptions_CType_IsValid(value)) { + set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + } else { + mutable_unknown_fields()->AddVarint(1, value); + } } else { - mutable_unknown_fields()->AddVarint(1, value); + goto handle_uninterpreted; } if (input->ExpectTag(16)) goto parse_packed; break; @@ -4896,57 +5127,63 @@ bool FieldOptions::MergePartialFromCodedStream( // optional bool packed = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_packed: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &packed_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_packed: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &packed_)); - _set_bit(1); if (input->ExpectTag(24)) goto parse_deprecated; break; } // optional bool deprecated = 3 [default = false]; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_deprecated: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &deprecated_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_deprecated: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &deprecated_)); - _set_bit(2); if (input->ExpectTag(74)) goto parse_experimental_map_key; break; } // optional string experimental_map_key = 9; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_experimental_map_key: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_experimental_map_key())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_experimental_map_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_experimental_map_key())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4975,13 +5212,7 @@ bool FieldOptions::MergePartialFromCodedStream( void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteEnum( 1, this->ctype(), output); @@ -5008,7 +5239,7 @@ void FieldOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5024,7 +5255,7 @@ void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray( ::google::protobuf::uint8* target) const { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( 1, this->ctype(), target); @@ -5072,7 +5303,7 @@ int FieldOptions::ByteSize() const { int total_size = 0; if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (has_ctype()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype()); @@ -5111,7 +5342,9 @@ int FieldOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5198,14 +5431,16 @@ void FieldOptions::Swap(FieldOptions* other) { const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -EnumOptions::EnumOptions() { +EnumOptions::EnumOptions() + : ::google::protobuf::Message() { SharedCtor(); } void EnumOptions::InitAsDefaultInstance() { } -EnumOptions::EnumOptions(const EnumOptions& from) { +EnumOptions::EnumOptions(const EnumOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5224,6 +5459,11 @@ void EnumOptions::SharedDtor() { } } +void EnumOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumOptions_descriptor_; @@ -5254,13 +5494,14 @@ bool EnumOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5289,15 +5530,9 @@ bool EnumOptions::MergePartialFromCodedStream( void EnumOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5349,7 +5584,9 @@ int EnumOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5418,14 +5655,16 @@ void EnumOptions::Swap(EnumOptions* other) { const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -EnumValueOptions::EnumValueOptions() { +EnumValueOptions::EnumValueOptions() + : ::google::protobuf::Message() { SharedCtor(); } void EnumValueOptions::InitAsDefaultInstance() { } -EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) { +EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5444,6 +5683,11 @@ void EnumValueOptions::SharedDtor() { } } +void EnumValueOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueOptions_descriptor_; @@ -5474,13 +5718,14 @@ bool EnumValueOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5509,15 +5754,9 @@ bool EnumValueOptions::MergePartialFromCodedStream( void EnumValueOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5569,7 +5808,9 @@ int EnumValueOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5638,14 +5879,16 @@ void EnumValueOptions::Swap(EnumValueOptions* other) { const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -ServiceOptions::ServiceOptions() { +ServiceOptions::ServiceOptions() + : ::google::protobuf::Message() { SharedCtor(); } void ServiceOptions::InitAsDefaultInstance() { } -ServiceOptions::ServiceOptions(const ServiceOptions& from) { +ServiceOptions::ServiceOptions(const ServiceOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5664,6 +5907,11 @@ void ServiceOptions::SharedDtor() { } } +void ServiceOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceOptions_descriptor_; @@ -5694,13 +5942,14 @@ bool ServiceOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5729,15 +5978,9 @@ bool ServiceOptions::MergePartialFromCodedStream( void ServiceOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5789,7 +6032,9 @@ int ServiceOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5858,14 +6103,16 @@ void ServiceOptions::Swap(ServiceOptions* other) { const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER -MethodOptions::MethodOptions() { +MethodOptions::MethodOptions() + : ::google::protobuf::Message() { SharedCtor(); } void MethodOptions::InitAsDefaultInstance() { } -MethodOptions::MethodOptions(const MethodOptions& from) { +MethodOptions::MethodOptions(const MethodOptions& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5884,6 +6131,11 @@ void MethodOptions::SharedDtor() { } } +void MethodOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodOptions_descriptor_; @@ -5914,13 +6166,14 @@ bool MethodOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5949,15 +6202,9 @@ bool MethodOptions::MergePartialFromCodedStream( void MethodOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -6009,7 +6256,9 @@ int MethodOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6080,14 +6329,16 @@ const int UninterpretedOption_NamePart::kNamePartFieldNumber; const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER -UninterpretedOption_NamePart::UninterpretedOption_NamePart() { +UninterpretedOption_NamePart::UninterpretedOption_NamePart() + : ::google::protobuf::Message() { SharedCtor(); } void UninterpretedOption_NamePart::InitAsDefaultInstance() { } -UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) { +UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6111,6 +6362,11 @@ void UninterpretedOption_NamePart::SharedDtor() { } } +void UninterpretedOption_NamePart::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_NamePart_descriptor_; @@ -6147,29 +6403,32 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // required string name_part = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name_part())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name_part())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name_part().data(), this->name_part().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_is_extension; break; } // required bool is_extension = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_is_extension: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &is_extension_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_is_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &is_extension_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -6192,12 +6451,6 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // required string name_part = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -6264,7 +6517,9 @@ int UninterpretedOption_NamePart::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6343,14 +6598,16 @@ const int UninterpretedOption::kDoubleValueFieldNumber; const int UninterpretedOption::kStringValueFieldNumber; #endif // !_MSC_VER -UninterpretedOption::UninterpretedOption() { +UninterpretedOption::UninterpretedOption() + : ::google::protobuf::Message() { SharedCtor(); } void UninterpretedOption::InitAsDefaultInstance() { } -UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) { +UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6380,6 +6637,11 @@ void UninterpretedOption::SharedDtor() { } } +void UninterpretedOption::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_descriptor_; @@ -6424,13 +6686,14 @@ bool UninterpretedOption::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_name())); + } else { goto handle_uninterpreted; } - parse_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_name())); if (input->ExpectTag(18)) goto parse_name; if (input->ExpectTag(26)) goto parse_identifier_value; break; @@ -6438,71 +6701,79 @@ bool UninterpretedOption::MergePartialFromCodedStream( // optional string identifier_value = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_identifier_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_identifier_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_identifier_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_identifier_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->identifier_value().data(), this->identifier_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(32)) goto parse_positive_int_value; break; } // optional uint64 positive_int_value = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_positive_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &positive_int_value_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_positive_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadUInt64( - input, &positive_int_value_)); - _set_bit(2); if (input->ExpectTag(40)) goto parse_negative_int_value; break; } // optional int64 negative_int_value = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_negative_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( + input, &negative_int_value_))); + _set_bit(3); + } else { goto handle_uninterpreted; } - parse_negative_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt64( - input, &negative_int_value_)); - _set_bit(3); if (input->ExpectTag(49)) goto parse_double_value; break; } // optional double double_value = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) { + parse_double_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>( + input, &double_value_))); + _set_bit(4); + } else { goto handle_uninterpreted; } - parse_double_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadDouble( - input, &double_value_)); - _set_bit(4); if (input->ExpectTag(58)) goto parse_string_value; break; } // optional bytes string_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_string_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_string_value())); + } else { goto handle_uninterpreted; } - parse_string_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_string_value())); if (input->ExpectAtEnd()) return true; break; } @@ -6525,15 +6796,9 @@ bool UninterpretedOption::MergePartialFromCodedStream( void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; for (int i = 0; i < this->name_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->name(i), output); } @@ -6672,7 +6937,9 @@ int UninterpretedOption::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6754,5 +7021,9 @@ void UninterpretedOption::Swap(UninterpretedOption* other) { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index bc4ec31..2743b6f 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1,4 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto #ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED #define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED @@ -7,12 +8,12 @@ #include <google/protobuf/stubs/common.h> -#if GOOGLE_PROTOBUF_VERSION < 2002000 +#if GOOGLE_PROTOBUF_VERSION < 2003000 #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 2002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION +#if 2003000 < 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. @@ -22,6 +23,7 @@ #include <google/protobuf/repeated_field.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/generated_message_reflection.h> +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -73,6 +75,7 @@ enum FieldDescriptorProto_Type { LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; +const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { @@ -92,6 +95,7 @@ enum FieldDescriptorProto_Label { LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; +const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { @@ -111,6 +115,7 @@ enum FileOptions_OptimizeMode { LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME; +const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { @@ -123,12 +128,14 @@ inline bool FileOptions_OptimizeMode_Parse( FileOptions_OptimizeMode_descriptor(), name, value); } enum FieldOptions_CType { + FieldOptions_CType_STRING = 0, FieldOptions_CType_CORD = 1, FieldOptions_CType_STRING_PIECE = 2 }; LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); -const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD; +const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor(); inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { @@ -164,6 +171,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorSet& default_instance(); + void Swap(FileDescriptorSet* other); // implements Message ---------------------------------------------- @@ -186,7 +194,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -199,12 +207,15 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message inline int file_size() const; inline void clear_file(); static const int kFileFieldNumber = 1; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& file() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_file(); inline const ::google::protobuf::FileDescriptorProto& file(int index) const; inline ::google::protobuf::FileDescriptorProto* mutable_file(int index); inline ::google::protobuf::FileDescriptorProto* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_file(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -254,6 +265,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorProto& default_instance(); + void Swap(FileDescriptorProto* other); // implements Message ---------------------------------------------- @@ -276,7 +288,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -309,8 +321,6 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline int dependency_size() const; inline void clear_dependency(); static const int kDependencyFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); inline const ::std::string& dependency(int index) const; inline ::std::string* mutable_dependency(int index); inline void set_dependency(int index, const ::std::string& value); @@ -320,46 +330,56 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline void add_dependency(const ::std::string& value); inline void add_dependency(const char* value); inline void add_dependency(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); // repeated .google.protobuf.DescriptorProto message_type = 4; inline int message_type_size() const; inline void clear_message_type(); static const int kMessageTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& message_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type(); inline const ::google::protobuf::DescriptorProto& message_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_message_type(int index); inline ::google::protobuf::DescriptorProto* add_message_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_message_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int service_size() const; inline void clear_service(); static const int kServiceFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& service() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service(); inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const; inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); inline ::google::protobuf::ServiceDescriptorProto* add_service(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* + mutable_service(); // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 7; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // optional .google.protobuf.FileOptions options = 8; inline bool has_options() const; @@ -368,6 +388,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::FileOptions& options() const; inline ::google::protobuf::FileOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -426,6 +447,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto_ExtensionRange& default_instance(); + void Swap(DescriptorProto_ExtensionRange* other); // implements Message ---------------------------------------------- @@ -448,7 +470,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -471,6 +493,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto inline ::google::protobuf::int32 end() const; inline void set_end(::google::protobuf::int32 value); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -521,6 +544,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto& default_instance(); + void Swap(DescriptorProto* other); // implements Message ---------------------------------------------- @@ -543,7 +567,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -568,51 +592,61 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline int field_size() const; inline void clear_field(); static const int kFieldFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& field() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field(); inline const ::google::protobuf::FieldDescriptorProto& field(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index); inline ::google::protobuf::FieldDescriptorProto* add_field(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_field(); // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int nested_type_size() const; inline void clear_nested_type(); static const int kNestedTypeFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& nested_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type(); inline const ::google::protobuf::DescriptorProto& nested_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index); inline ::google::protobuf::DescriptorProto* add_nested_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_nested_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int extension_range_size() const; inline void clear_extension_range(); static const int kExtensionRangeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& extension_range() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range(); inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* + mutable_extension_range(); // optional .google.protobuf.MessageOptions options = 7; inline bool has_options() const; @@ -621,6 +655,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline const ::google::protobuf::MessageOptions& options() const; inline ::google::protobuf::MessageOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -677,6 +712,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa static const ::google::protobuf::Descriptor* descriptor(); static const FieldDescriptorProto& default_instance(); + void Swap(FieldDescriptorProto* other); // implements Message ---------------------------------------------- @@ -699,7 +735,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -732,6 +768,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Type_Type_MIN; static const Type Type_MAX = FieldDescriptorProto_Type_Type_MAX; + static const int Type_ARRAYSIZE = + FieldDescriptorProto_Type_Type_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Type_descriptor() { return FieldDescriptorProto_Type_descriptor(); @@ -755,6 +793,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Label_Label_MIN; static const Label Label_MAX = FieldDescriptorProto_Label_Label_MAX; + static const int Label_ARRAYSIZE = + FieldDescriptorProto_Label_Label_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Label_descriptor() { return FieldDescriptorProto_Label_descriptor(); @@ -837,6 +877,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::google::protobuf::FieldOptions& options() const; inline ::google::protobuf::FieldOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -897,6 +938,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const EnumDescriptorProto& default_instance(); + void Swap(EnumDescriptorProto* other); // implements Message ---------------------------------------------- @@ -919,7 +961,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -942,11 +984,13 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline int value_size() const; inline void clear_value(); static const int kValueFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& value() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value(); inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); inline ::google::protobuf::EnumValueDescriptorProto* add_value(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* + mutable_value(); // optional .google.protobuf.EnumOptions options = 3; inline bool has_options() const; @@ -955,6 +999,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::EnumOptions& options() const; inline ::google::protobuf::EnumOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1007,6 +1052,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueDescriptorProto& default_instance(); + void Swap(EnumValueDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1029,7 +1075,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1062,6 +1108,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline const ::google::protobuf::EnumValueOptions& options() const; inline ::google::protobuf::EnumValueOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1114,6 +1161,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes static const ::google::protobuf::Descriptor* descriptor(); static const ServiceDescriptorProto& default_instance(); + void Swap(ServiceDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1136,7 +1184,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1159,11 +1207,13 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline int method_size() const; inline void clear_method(); static const int kMethodFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& method() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method(); inline const ::google::protobuf::MethodDescriptorProto& method(int index) const; inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index); inline ::google::protobuf::MethodDescriptorProto* add_method(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* + mutable_method(); // optional .google.protobuf.ServiceOptions options = 3; inline bool has_options() const; @@ -1172,6 +1222,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline const ::google::protobuf::ServiceOptions& options() const; inline ::google::protobuf::ServiceOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1224,6 +1275,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess static const ::google::protobuf::Descriptor* descriptor(); static const MethodDescriptorProto& default_instance(); + void Swap(MethodDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1246,7 +1298,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1292,6 +1344,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::google::protobuf::MethodOptions& options() const; inline ::google::protobuf::MethodOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1347,6 +1400,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FileOptions& default_instance(); + void Swap(FileOptions* other); // implements Message ---------------------------------------------- @@ -1369,7 +1423,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1387,6 +1441,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { FileOptions_OptimizeMode_OptimizeMode_MIN; static const OptimizeMode OptimizeMode_MAX = FileOptions_OptimizeMode_OptimizeMode_MAX; + static const int OptimizeMode_ARRAYSIZE = + FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* OptimizeMode_descriptor() { return FileOptions_OptimizeMode_descriptor(); @@ -1435,17 +1491,41 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const; inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value); + // optional bool cc_generic_services = 16 [default = true]; + inline bool has_cc_generic_services() const; + inline void clear_cc_generic_services(); + static const int kCcGenericServicesFieldNumber = 16; + inline bool cc_generic_services() const; + inline void set_cc_generic_services(bool value); + + // optional bool java_generic_services = 17 [default = true]; + inline bool has_java_generic_services() const; + inline void clear_java_generic_services(); + static const int kJavaGenericServicesFieldNumber = 17; + inline bool java_generic_services() const; + inline void set_java_generic_services(bool value); + + // optional bool py_generic_services = 18 [default = true]; + inline bool has_py_generic_services() const; + inline void clear_py_generic_services(); + static const int kPyGenericServicesFieldNumber = 18; + inline bool py_generic_services() const; + inline void set_py_generic_services(bool value); + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1457,12 +1537,15 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::std::string _default_java_outer_classname_; bool java_multiple_files_; int optimize_for_; + bool cc_generic_services_; + bool java_generic_services_; + bool py_generic_services_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); - ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1502,6 +1585,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MessageOptions& default_instance(); + void Swap(MessageOptions* other); // implements Message ---------------------------------------------- @@ -1524,7 +1608,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1551,13 +1635,16 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1610,6 +1697,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FieldOptions& default_instance(); + void Swap(FieldOptions* other); // implements Message ---------------------------------------------- @@ -1632,7 +1720,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1640,6 +1728,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FieldOptions_CType CType; + static const CType STRING = FieldOptions_CType_STRING; static const CType CORD = FieldOptions_CType_CORD; static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { @@ -1649,6 +1738,8 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { FieldOptions_CType_CType_MIN; static const CType CType_MAX = FieldOptions_CType_CType_MAX; + static const int CType_ARRAYSIZE = + FieldOptions_CType_CType_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* CType_descriptor() { return FieldOptions_CType_descriptor(); @@ -1663,7 +1754,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // accessors ------------------------------------------------------- - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool has_ctype() const; inline void clear_ctype(); static const int kCtypeFieldNumber = 1; @@ -1698,13 +1789,16 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1760,6 +1854,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumOptions& default_instance(); + void Swap(EnumOptions* other); // implements Message ---------------------------------------------- @@ -1782,7 +1877,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1795,13 +1890,16 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1852,6 +1950,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueOptions& default_instance(); + void Swap(EnumValueOptions* other); // implements Message ---------------------------------------------- @@ -1874,7 +1973,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1887,13 +1986,16 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1944,6 +2046,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const ServiceOptions& default_instance(); + void Swap(ServiceOptions* other); // implements Message ---------------------------------------------- @@ -1966,7 +2069,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1979,13 +2082,16 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2036,6 +2142,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MethodOptions& default_instance(); + void Swap(MethodOptions* other); // implements Message ---------------------------------------------- @@ -2058,7 +2165,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2071,13 +2178,16 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2128,6 +2238,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption_NamePart& default_instance(); + void Swap(UninterpretedOption_NamePart* other); // implements Message ---------------------------------------------- @@ -2150,7 +2261,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2176,6 +2287,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline bool is_extension() const; inline void set_is_extension(bool value); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2227,6 +2339,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption& default_instance(); + void Swap(UninterpretedOption* other); // implements Message ---------------------------------------------- @@ -2249,7 +2362,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2264,11 +2377,13 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline int name_size() const; inline void clear_name(); static const int kNameFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& name() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* mutable_name(); inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); inline ::google::protobuf::UninterpretedOption_NamePart* add_name(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* + mutable_name(); // optional string identifier_value = 3; inline bool has_identifier_value() const; @@ -2311,6 +2426,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline void set_string_value(const void* value, size_t size); inline ::std::string* mutable_string_value(); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2348,9 +2464,6 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag // =================================================================== - -// =================================================================== - // FileDescriptorSet // repeated .google.protobuf.FileDescriptorProto file = 1; @@ -2360,14 +2473,6 @@ inline int FileDescriptorSet::file_size() const { inline void FileDescriptorSet::clear_file() { file_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -FileDescriptorSet::file() const { - return file_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* -FileDescriptorSet::mutable_file() { - return &file_; -} inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { return file_.Get(index); } @@ -2377,6 +2482,14 @@ inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file( inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { return file_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +FileDescriptorSet::mutable_file() { + return &file_; +} // ------------------------------------------------------------------- @@ -2473,14 +2586,6 @@ inline int FileDescriptorProto::dependency_size() const { inline void FileDescriptorProto::clear_dependency() { dependency_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -FileDescriptorProto::dependency() const { - return dependency_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -FileDescriptorProto::mutable_dependency() { - return &dependency_; -} inline const ::std::string& FileDescriptorProto::dependency(int index) const { return dependency_.Get(index); } @@ -2509,6 +2614,14 @@ inline void FileDescriptorProto::add_dependency(const char* value) { inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { dependency_.Add()->assign(reinterpret_cast<const char*>(value), size); } +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +FileDescriptorProto::dependency() const { + return dependency_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +FileDescriptorProto::mutable_dependency() { + return &dependency_; +} // repeated .google.protobuf.DescriptorProto message_type = 4; inline int FileDescriptorProto::message_type_size() const { @@ -2517,14 +2630,6 @@ inline int FileDescriptorProto::message_type_size() const { inline void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -FileDescriptorProto::message_type() const { - return message_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -FileDescriptorProto::mutable_message_type() { - return &message_type_; -} inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { return message_type_.Get(index); } @@ -2534,6 +2639,14 @@ inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { return message_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + return message_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +FileDescriptorProto::mutable_message_type() { + return &message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int FileDescriptorProto::enum_type_size() const { @@ -2542,14 +2655,6 @@ inline int FileDescriptorProto::enum_type_size() const { inline void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -FileDescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -FileDescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2559,6 +2664,14 @@ inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enu inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +FileDescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int FileDescriptorProto::service_size() const { @@ -2567,14 +2680,6 @@ inline int FileDescriptorProto::service_size() const { inline void FileDescriptorProto::clear_service() { service_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& -FileDescriptorProto::service() const { - return service_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* -FileDescriptorProto::mutable_service() { - return &service_; -} inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { return service_.Get(index); } @@ -2584,6 +2689,14 @@ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { return service_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + return service_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +FileDescriptorProto::mutable_service() { + return &service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int FileDescriptorProto::extension_size() const { @@ -2592,14 +2705,6 @@ inline int FileDescriptorProto::extension_size() const { inline void FileDescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -FileDescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -FileDescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2609,6 +2714,14 @@ inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_ex inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +FileDescriptorProto::mutable_extension() { + return &extension_; +} // optional .google.protobuf.FileOptions options = 8; inline bool FileDescriptorProto::has_options() const { @@ -2716,14 +2829,6 @@ inline int DescriptorProto::field_size() const { inline void DescriptorProto::clear_field() { field_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::field() const { - return field_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_field() { - return &field_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { return field_.Get(index); } @@ -2733,6 +2838,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field( inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { return field_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + return field_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_field() { + return &field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int DescriptorProto::extension_size() const { @@ -2741,14 +2854,6 @@ inline int DescriptorProto::extension_size() const { inline void DescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2758,6 +2863,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extens inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_extension() { + return &extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int DescriptorProto::nested_type_size() const { @@ -2766,14 +2879,6 @@ inline int DescriptorProto::nested_type_size() const { inline void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -DescriptorProto::nested_type() const { - return nested_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -DescriptorProto::mutable_nested_type() { - return &nested_type_; -} inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { return nested_type_.Get(index); } @@ -2783,6 +2888,14 @@ inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { return nested_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + return nested_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +DescriptorProto::mutable_nested_type() { + return &nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int DescriptorProto::enum_type_size() const { @@ -2791,14 +2904,6 @@ inline int DescriptorProto::enum_type_size() const { inline void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -DescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -DescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2808,6 +2913,14 @@ inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_ty inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +DescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int DescriptorProto::extension_range_size() const { @@ -2816,14 +2929,6 @@ inline int DescriptorProto::extension_range_size() const { inline void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& -DescriptorProto::extension_range() const { - return extension_range_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* -DescriptorProto::mutable_extension_range() { - return &extension_range_; -} inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { return extension_range_.Get(index); } @@ -2833,6 +2938,14 @@ inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::muta inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { return extension_range_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + return extension_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +DescriptorProto::mutable_extension_range() { + return &extension_range_; +} // optional .google.protobuf.MessageOptions options = 7; inline bool DescriptorProto::has_options() const { @@ -3143,14 +3256,6 @@ inline int EnumDescriptorProto::value_size() const { inline void EnumDescriptorProto::clear_value() { value_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& -EnumDescriptorProto::value() const { - return value_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* -EnumDescriptorProto::mutable_value() { - return &value_; -} inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { return value_.Get(index); } @@ -3160,6 +3265,14 @@ inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutabl inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { return value_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + return value_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +EnumDescriptorProto::mutable_value() { + return &value_; +} // optional .google.protobuf.EnumOptions options = 3; inline bool EnumDescriptorProto::has_options() const { @@ -3310,14 +3423,6 @@ inline int ServiceDescriptorProto::method_size() const { inline void ServiceDescriptorProto::clear_method() { method_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& -ServiceDescriptorProto::method() const { - return method_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* -ServiceDescriptorProto::mutable_method() { - return &method_; -} inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { return method_.Get(index); } @@ -3327,6 +3432,14 @@ inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutabl inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { return method_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + return method_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +ServiceDescriptorProto::mutable_method() { + return &method_; +} // optional .google.protobuf.ServiceOptions options = 3; inline bool ServiceDescriptorProto::has_options() const { @@ -3613,6 +3726,54 @@ inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_Optimi optimize_for_ = value; } +// optional bool cc_generic_services = 16 [default = true]; +inline bool FileOptions::has_cc_generic_services() const { + return _has_bit(4); +} +inline void FileOptions::clear_cc_generic_services() { + cc_generic_services_ = true; + _clear_bit(4); +} +inline bool FileOptions::cc_generic_services() const { + return cc_generic_services_; +} +inline void FileOptions::set_cc_generic_services(bool value) { + _set_bit(4); + cc_generic_services_ = value; +} + +// optional bool java_generic_services = 17 [default = true]; +inline bool FileOptions::has_java_generic_services() const { + return _has_bit(5); +} +inline void FileOptions::clear_java_generic_services() { + java_generic_services_ = true; + _clear_bit(5); +} +inline bool FileOptions::java_generic_services() const { + return java_generic_services_; +} +inline void FileOptions::set_java_generic_services(bool value) { + _set_bit(5); + java_generic_services_ = value; +} + +// optional bool py_generic_services = 18 [default = true]; +inline bool FileOptions::has_py_generic_services() const { + return _has_bit(6); +} +inline void FileOptions::clear_py_generic_services() { + py_generic_services_ = true; + _clear_bit(6); +} +inline bool FileOptions::py_generic_services() const { + return py_generic_services_; +} +inline void FileOptions::set_py_generic_services(bool value) { + _set_bit(6); + py_generic_services_ = value; +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -3620,14 +3781,6 @@ inline int FileOptions::uninterpreted_option_size() const { inline void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FileOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FileOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3637,6 +3790,14 @@ inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FileOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3681,14 +3842,6 @@ inline int MessageOptions::uninterpreted_option_size() const { inline void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MessageOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MessageOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3698,17 +3851,25 @@ inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MessageOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- // FieldOptions -// optional .google.protobuf.FieldOptions.CType ctype = 1; +// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool FieldOptions::has_ctype() const { return _has_bit(0); } inline void FieldOptions::clear_ctype() { - ctype_ = 1; + ctype_ = 0; _clear_bit(0); } inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const { @@ -3801,14 +3962,6 @@ inline int FieldOptions::uninterpreted_option_size() const { inline void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FieldOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FieldOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3818,6 +3971,14 @@ inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpre inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FieldOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3830,14 +3991,6 @@ inline int EnumOptions::uninterpreted_option_size() const { inline void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3847,6 +4000,14 @@ inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3859,14 +4020,6 @@ inline int EnumValueOptions::uninterpreted_option_size() const { inline void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumValueOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumValueOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3876,6 +4029,14 @@ inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninte inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumValueOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3888,14 +4049,6 @@ inline int ServiceOptions::uninterpreted_option_size() const { inline void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -ServiceOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -ServiceOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3905,6 +4058,14 @@ inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +ServiceOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3917,14 +4078,6 @@ inline int MethodOptions::uninterpreted_option_size() const { inline void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MethodOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MethodOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3934,6 +4087,14 @@ inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpr inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MethodOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -4008,14 +4169,6 @@ inline int UninterpretedOption::name_size() const { inline void UninterpretedOption::clear_name() { name_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& -UninterpretedOption::name() const { - return name_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* -UninterpretedOption::mutable_name() { - return &name_; -} inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { return name_.Get(index); } @@ -4025,6 +4178,14 @@ inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mu inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { return name_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + return name_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +UninterpretedOption::mutable_name() { + return &name_; +} // optional string identifier_value = 3; inline bool UninterpretedOption::has_identifier_value() const { @@ -4159,6 +4320,8 @@ inline ::std::string* UninterpretedOption::mutable_string_value() { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google @@ -4187,4 +4350,6 @@ inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions } // namespace protobuf #endif // SWIG +// @@protoc_insertion_point(global_scope) + #endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 4db88a8..cc04aa8 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -256,6 +256,22 @@ message FileOptions { + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. If you are + // using such a plugin, set these to false. In the future, we may change + // the default to false, so if you explicitly want generic services, you + // should explicitly set these to true. + optional bool cc_generic_services = 16 [default=true]; + optional bool java_generic_services = 17 [default=true]; + optional bool py_generic_services = 18 [default=true]; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -301,8 +317,11 @@ message FieldOptions { // representation of the field than it normally would. See the specific // options below. This option is not yet implemented in the open source // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1; + optional CType ctype = 1 [default = STRING]; enum CType { + // Default mode. + STRING = 0; + CORD = 1; STRING_PIECE = 2; @@ -313,6 +332,7 @@ message FieldOptions { // a single length-delimited blob. optional bool packed = 2; + // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc index 6ea674d..95708d9 100644 --- a/src/google/protobuf/descriptor_database.cc +++ b/src/google/protobuf/descriptor_database.cc @@ -37,6 +37,7 @@ #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> @@ -336,6 +337,35 @@ bool EncodedDescriptorDatabase::FindFileContainingSymbol( 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, diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h index c23ab75..f32b1db 100644 --- a/src/google/protobuf/descriptor_database.h +++ b/src/google/protobuf/descriptor_database.h @@ -280,6 +280,10 @@ class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { // 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); diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index 33de134..ac72ddc 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -480,6 +480,40 @@ INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest, #endif // GTEST_HAS_PARAM_TEST +TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) { + // Create two files, one of which is in two parts. + FileDescriptorProto file1, file2a, file2b; + file1.set_name("foo.proto"); + file1.set_package("foo"); + file1.add_message_type()->set_name("Foo"); + file2a.set_name("bar.proto"); + file2b.set_package("bar"); + file2b.add_message_type()->set_name("Bar"); + + // Normal serialization allows our optimization to kick in. + string data1 = file1.SerializeAsString(); + + // Force out-of-order serialization to test slow path. + string data2 = file2b.SerializeAsString() + file2a.SerializeAsString(); + + // Create EncodedDescriptorDatabase containing both files. + EncodedDescriptorDatabase db; + db.Add(data1.data(), data1.size()); + db.Add(data2.data(), data2.size()); + + // Test! + string filename; + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename)); + EXPECT_EQ("bar.proto", filename); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename)); +} + // =================================================================== class MergedDescriptorDatabaseTest : public testing::Test { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 8fcfba3..ec2c815 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -3948,6 +3948,9 @@ TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) { EXPECT_EQ(0, call_counter.call_count_); } +// =================================================================== + + } // namespace descriptor_unittest } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index f8b5b4e..c711a2d 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -106,7 +106,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>); case FD::CPPTYPE_STRING: - return sizeof(RepeatedPtrField<string>); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(RepeatedPtrField<string>); + } break; } } else { @@ -122,7 +126,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(Message*); case FD::CPPTYPE_STRING: - return sizeof(string*); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(string*); + } break; } } @@ -262,19 +270,24 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info) break; case FieldDescriptor::CPPTYPE_STRING: - if (!field->is_repeated()) { - if (is_prototype()) { - new(field_ptr) const string*(&field->default_value_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 { - string* default_value = - *reinterpret_cast<string* const*>( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i])); - new(field_ptr) string*(default_value); + new(field_ptr) RepeatedPtrField<string>(); } - } else { - new(field_ptr) RepeatedPtrField<string>(); - } + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: { @@ -329,8 +342,13 @@ DynamicMessage::~DynamicMessage() { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - reinterpret_cast<RepeatedPtrField<string>*>(field_ptr) - ->~RepeatedPtrField<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: @@ -340,10 +358,16 @@ DynamicMessage::~DynamicMessage() { } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - string* ptr = *reinterpret_cast<string**>(field_ptr); - if (ptr != &field->default_value_string()) { - delete ptr; + 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); @@ -373,7 +397,7 @@ void DynamicMessage::CrossLinkPrototypes() { // For singular fields, the field is just a pointer which should // point to the prototype. *reinterpret_cast<const Message**>(field_ptr) = - factory->GetPrototype(field->message_type()); + factory->GetPrototypeNoLock(field->message_type()); } } } @@ -410,11 +434,13 @@ struct DynamicMessageFactory::PrototypeMap { }; DynamicMessageFactory::DynamicMessageFactory() - : pool_(NULL), prototypes_(new PrototypeMap) { + : pool_(NULL), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool) - : pool_(pool), prototypes_(new PrototypeMap) { + : pool_(pool), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::~DynamicMessageFactory() { @@ -424,8 +450,18 @@ DynamicMessageFactory::~DynamicMessageFactory() { } } - 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. diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index f38d3b0..81dd2c6 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -73,9 +73,25 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // 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 @@ -92,14 +108,12 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // The given descriptor must outlive the returned message, and hence must // outlive the DynamicMessageFactory. // - // Note that while GetPrototype() is idempotent, it is not const. This - // implies that it is not thread-safe to call GetPrototype() on the same - // DynamicMessageFactory in two different threads simultaneously. However, - // the returned objects are just as thread-safe as any other Message. + // 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 @@ -108,6 +122,10 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // 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); }; @@ -116,4 +134,3 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { } // namespace google #endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ - diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 4d5eb6c..6084885 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -59,20 +59,6 @@ inline WireFormatLite::CppType cpp_type(FieldType type) { } // Registry stuff. -struct ExtensionInfo { - inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) - : type(type), is_repeated(is_repeated), is_packed(is_packed) {} - - FieldType type; - bool is_repeated; - bool is_packed; - - union { - ExtensionSet::EnumValidityFunc* enum_is_valid; - const MessageLite* message_prototype; - }; -}; - typedef hash_map<pair<const MessageLite*, int>, ExtensionInfo> ExtensionRegistry; ExtensionRegistry* registry_ = NULL; @@ -110,6 +96,19 @@ const ExtensionInfo* FindRegisteredExtension( } // namespace +ExtensionFinder::~ExtensionFinder() {} + +bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) { + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type_, number); + if (extension == NULL) { + return false; + } else { + *output = *extension; + return true; + } +} + void ExtensionSet::RegisterExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed) { @@ -120,13 +119,28 @@ void ExtensionSet::RegisterExtension(const MessageLite* containing_type, Register(containing_type, number, info); } +static bool CallNoArgValidityFunc(const void* arg, int number) { + // Note: Must use C-style cast here rather than reinterpret_cast because + // the C++ standard at one point did not allow casts between function and + // data pointers and some compilers enforce this for C++-style casts. No + // compiler enforces it for C-style casts since lots of C-style code has + // relied on these kinds of casts for a long time, despite being + // technically undefined. See: + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#195 + // Also note: Some compilers do not allow function pointers to be "const". + // Which makes sense, I suppose, because it's meaningless. + return ((EnumValidityFunc*)arg)(number); +} + void ExtensionSet::RegisterEnumExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed, EnumValidityFunc* is_valid) { GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM); ExtensionInfo info(type, is_repeated, is_packed); - info.enum_is_valid = is_valid; + info.enum_validity_check.func = CallNoArgValidityFunc; + // See comment in CallNoArgValidityFunc() about why we use a c-style cast. + info.enum_validity_check.arg = (void*)is_valid; Register(containing_type, number, info); } @@ -211,9 +225,10 @@ LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ } \ \ void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ - LOWERCASE value) { \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = false; \ @@ -240,9 +255,10 @@ void ExtensionSet::SetRepeated##CAMELCASE( \ } \ \ void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ - bool packed, LOWERCASE value) { \ + bool packed, LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = true; \ @@ -279,9 +295,10 @@ int ExtensionSet::GetEnum(int number, int default_value) const { } } -void ExtensionSet::SetEnum(int number, FieldType type, int value) { +void ExtensionSet::SetEnum(int number, FieldType type, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = false; @@ -307,9 +324,10 @@ void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { } void ExtensionSet::AddEnum(int number, FieldType type, - bool packed, int value) { + bool packed, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = true; @@ -337,9 +355,10 @@ const string& ExtensionSet::GetString(int number, } } -string* ExtensionSet::MutableString(int number, FieldType type) { +string* ExtensionSet::MutableString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = false; @@ -365,9 +384,10 @@ string* ExtensionSet::MutableRepeatedString(int number, int index) { return iter->second.repeated_string_value->Mutable(index); } -string* ExtensionSet::AddString(int number, FieldType type) { +string* ExtensionSet::AddString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = true; @@ -400,9 +420,10 @@ const MessageLite& ExtensionSet::GetMessage( // MessageFactory* factory) const MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; @@ -435,9 +456,10 @@ MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) { } MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = true; @@ -563,7 +585,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { if (other_extension.is_repeated) { Extension* extension; - bool is_new = MaybeNewExtension(iter->first, &extension); + bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor, + &extension); if (is_new) { // Extension did not already exist in set. extension->type = other_extension.type; @@ -622,7 +645,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ case WireFormatLite::CPPTYPE_##UPPERCASE: \ Set##CAMELCASE(iter->first, other_extension.type, \ - other_extension.LOWERCASE##_value); \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ break; HANDLE_TYPE( INT32, int32, Int32); @@ -636,11 +660,13 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #undef HANDLE_TYPE case WireFormatLite::CPPTYPE_STRING: SetString(iter->first, other_extension.type, - *other_extension.string_value); + *other_extension.string_value, + other_extension.descriptor); break; case WireFormatLite::CPPTYPE_MESSAGE: MutableMessage(iter->first, other_extension.type, - *other_extension.message_value) + *other_extension.message_value, + other_extension.descriptor) ->CheckTypeAndMergeFrom(*other_extension.message_value); break; } @@ -678,64 +704,67 @@ bool ExtensionSet::IsInitialized() const { } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { int number = WireFormatLite::GetTagFieldNumber(tag); WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); - const ExtensionInfo* extension = - FindRegisteredExtension(containing_type, number); - + ExtensionInfo extension; bool is_unknown; - if (extension == NULL) { + if (!extension_finder->Find(number, &extension)) { is_unknown = true; - } else if (extension->is_packed) { + } else if (extension.is_packed) { is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); } else { WireFormatLite::WireType expected_wire_type = - WireFormatLite::WireTypeForFieldType(real_type(extension->type)); + WireFormatLite::WireTypeForFieldType(real_type(extension.type)); is_unknown = (wire_type != expected_wire_type); } if (is_unknown) { field_skipper->SkipField(input, tag); - } else if (extension->is_packed) { + } else if (extension.is_packed) { uint32 size; if (!input->ReadVarint32(&size)) return false; io::CodedInputStream::Limit limit = input->PushLimit(size); - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: \ while (input->BytesUntilLimit() > 0) { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - true, value); \ + true, value, extension.descriptor); \ } \ break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; - if (extension->enum_is_valid(value)) { - AddEnum(number, WireFormatLite::TYPE_ENUM, true, value); + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) return false; + if (extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { + AddEnum(number, WireFormatLite::TYPE_ENUM, true, value, + extension.descriptor); } } break; @@ -750,81 +779,90 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, input->PopLimit(limit); } else { - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ - if (extension->is_repeated) { \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ + if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - false, value); \ + false, value, extension.descriptor); \ } else { \ - Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value); \ + Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ + extension.descriptor); \ } \ } break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) return false; - if (!extension->enum_is_valid(value)) { + if (!extension.enum_validity_check.func( + extension.enum_validity_check.arg, value)) { // Invalid value. Treat as unknown. field_skipper->SkipUnknownEnum(number, value); - } else if (extension->is_repeated) { - AddEnum(number, WireFormatLite::TYPE_ENUM, false, value); + } else if (extension.is_repeated) { + AddEnum(number, WireFormatLite::TYPE_ENUM, false, value, + extension.descriptor); } else { - SetEnum(number, WireFormatLite::TYPE_ENUM, value); + SetEnum(number, WireFormatLite::TYPE_ENUM, value, + extension.descriptor); } break; } case WireFormatLite::TYPE_STRING: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadString(input, value)) return false; break; } case WireFormatLite::TYPE_BYTES: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadBytes(input, value)) return false; break; } case WireFormatLite::TYPE_GROUP: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadGroup(number, input, value)) return false; break; } case WireFormatLite::TYPE_MESSAGE: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadMessage(input, value)) return false; break; } @@ -837,7 +875,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseField(tag, input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -846,7 +885,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, // UnknownFieldSet* unknown_fields) bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { while (true) { uint32 tag = input->ReadTag(); @@ -854,12 +893,12 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, case 0: return true; case WireFormatLite::kMessageSetItemStartTag: - if (!ParseMessageSetItem(input, containing_type, field_skipper)) { + if (!ParseMessageSetItem(input, extension_finder, field_skipper)) { return false; } break; default: - if (!ParseField(tag, input, containing_type, field_skipper)) { + if (!ParseField(tag, input, extension_finder, field_skipper)) { return false; } break; @@ -870,7 +909,8 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseMessageSet(input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -879,7 +919,7 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, // UnknownFieldSet* unknown_fields); bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { // TODO(kenton): It would be nice to share code between this and // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the @@ -919,7 +959,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, reinterpret_cast<const uint8*>(message_data.data()), message_data.size()); if (!ParseField(fake_tag, &sub_input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } message_data.clear(); @@ -939,7 +979,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, } else { // Already saw type_id, so we can parse this directly. if (!ParseField(fake_tag, input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } } @@ -969,26 +1009,6 @@ void ExtensionSet::SerializeWithCachedSizes( } } -uint8* ExtensionSet::SerializeWithCachedSizesToArray( - int start_field_number, int end_field_number, - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeWithCachedSizes(start_field_number, - end_field_number, - &output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - void ExtensionSet::SerializeMessageSetWithCachedSizes( io::CodedOutputStream* output) const { map<int, Extension>::const_iterator iter; @@ -997,23 +1017,6 @@ void ExtensionSet::SerializeMessageSetWithCachedSizes( } } -uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeMessageSetWithCachedSizes(&output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - int ExtensionSet::ByteSize() const { int total_size = 0; @@ -1039,10 +1042,13 @@ int ExtensionSet::MessageSetByteSize() const { // Defined in extension_set_heavy.cc. // int ExtensionSet::SpaceUsedExcludingSelf() const -bool ExtensionSet::MaybeNewExtension(int number, Extension** result) { +bool ExtensionSet::MaybeNewExtension(int number, + const FieldDescriptor* descriptor, + Extension** result) { pair<map<int, Extension>::iterator, bool> insert_result = extensions_.insert(make_pair(number, Extension())); *result = &insert_result.first->second; + (*result)->descriptor = descriptor; return insert_result.second; } @@ -1206,20 +1212,20 @@ void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes( if (is_cleared) return; // Start group. - output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); + output->WriteTag(WireFormatLite::kMessageSetItemStartTag); // Write type ID. - output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); - output->WriteVarint32(number); - + WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, + number, + output); // Write message. - output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); - - output->WriteVarint32(message_value->GetCachedSize()); - message_value->SerializeWithCachedSizes(output); + WireFormatLite::WriteMessageMaybeToArray( + WireFormatLite::kMessageSetMessageNumber, + *message_value, + output); // End group. - output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); + output->WriteTag(WireFormatLite::kMessageSetItemEndTag); } int ExtensionSet::Extension::ByteSize(int number) const { diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index e5ac277..14d5d15 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -53,6 +53,7 @@ namespace protobuf { 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 { @@ -76,6 +77,70 @@ namespace internal { // 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 @@ -92,11 +157,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet { ExtensionSet(); ~ExtensionSet(); - // 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); - // 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 @@ -117,11 +177,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // ================================================================= // Add all fields which are currently present to the given vector. This - // is useful to implement Reflection::ListFields(). The FieldDescriptors - // are looked up by number from the given pool. - // - // TODO(kenton): Looking up each field by number is somewhat unfortunate. - // Is there a better way? + // is useful to implement Reflection::ListFields(). void AppendToList(const Descriptor* containing_type, const DescriptorPool* pool, vector<const FieldDescriptor*>* output) const; @@ -176,21 +232,25 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& GetMessage(int number, const Descriptor* message_type, MessageFactory* factory) const; - void SetInt32 (int number, FieldType type, int32 value); - void SetInt64 (int number, FieldType type, int64 value); - void SetUInt32(int number, FieldType type, uint32 value); - void SetUInt64(int number, FieldType type, uint64 value); - void SetFloat (int number, FieldType type, float value); - void SetDouble(int number, FieldType type, double value); - void SetBool (int number, FieldType type, bool value); - void SetEnum (int number, FieldType type, int value); - void SetString(int number, FieldType type, const string& value); - string * MutableString (int number, FieldType type); + // |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); - MessageLite* MutableMessage(int number, FieldType type, - const Descriptor* message_type, + const MessageLite& prototype, desc); + MessageLite* MutableMessage(const FieldDescriptor* decsriptor, MessageFactory* factory); +#undef desc // repeated fields ------------------------------------------------- @@ -217,21 +277,22 @@ class LIBPROTOBUF_EXPORT ExtensionSet { string * MutableRepeatedString (int number, int index); MessageLite* MutableRepeatedMessage(int number, int index); - void AddInt32 (int number, FieldType type, bool packed, int32 value); - void AddInt64 (int number, FieldType type, bool packed, int64 value); - void AddUInt32(int number, FieldType type, bool packed, uint32 value); - void AddUInt64(int number, FieldType type, bool packed, uint64 value); - void AddFloat (int number, FieldType type, bool packed, float value); - void AddDouble(int number, FieldType type, bool packed, double value); - void AddBool (int number, FieldType type, bool packed, bool value); - void AddEnum (int number, FieldType type, bool packed, int value); - void AddString(int number, FieldType type, const string& value); - string * AddString (int number, FieldType type); - MessageLite* AddMessage(int number, FieldType type, - const MessageLite& prototype); +#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 Descriptor* message_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); @@ -257,7 +318,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // methods of ExtensionSet, this only works for generated message types -- // it looks up extensions registered using RegisterExtension(). bool ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -265,13 +326,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type); bool ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + 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, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -279,7 +340,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type); bool ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields); // Write all extension fields with field numbers in the range @@ -359,6 +420,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // 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. @@ -368,9 +434,15 @@ class LIBPROTOBUF_EXPORT ExtensionSet { 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(); @@ -381,14 +453,16 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // 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, Extension** result); + 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, - const MessageLite* containing_type, + 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 @@ -412,16 +486,18 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // These are just for convenience... inline void ExtensionSet::SetString(int number, FieldType type, - const string& value) { - MutableString(number, type)->assign(value); + 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) { - AddString(number, type)->assign(value); + const string& value, + const FieldDescriptor* descriptor) { + AddString(number, type, descriptor)->assign(value); } // =================================================================== @@ -502,7 +578,7 @@ template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get( \ } \ template<> inline void PrimitiveTypeTraits<TYPE>::Set( \ int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ - set->Set##METHOD(number, field_type, value); \ + set->Set##METHOD(number, field_type, value, NULL); \ } \ \ template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get( \ @@ -516,7 +592,7 @@ template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set( \ 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); \ + set->Add##METHOD(number, field_type, is_packed, value, NULL); \ } PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) @@ -544,11 +620,11 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { } static inline void Set(int number, FieldType field_type, const string& value, ExtensionSet* set) { - set->SetString(number, field_type, value); + set->SetString(number, field_type, value, NULL); } static inline string* Mutable(int number, FieldType field_type, ExtensionSet* set) { - return set->MutableString(number, field_type); + return set->MutableString(number, field_type, NULL); } }; @@ -571,11 +647,11 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { static inline void Add(int number, FieldType field_type, bool /*is_packed*/, const string& value, ExtensionSet* set) { - set->AddString(number, field_type, value); + set->AddString(number, field_type, value, NULL); } static inline string* Add(int number, FieldType field_type, ExtensionSet* set) { - return set->AddString(number, field_type); + return set->AddString(number, field_type, NULL); } }; @@ -596,7 +672,7 @@ class EnumTypeTraits { static inline void Set(int number, FieldType field_type, ConstType value, ExtensionSet* set) { GOOGLE_DCHECK(IsValid(value)); - set->SetEnum(number, field_type, value); + set->SetEnum(number, field_type, value, NULL); } }; @@ -616,7 +692,7 @@ class RepeatedEnumTypeTraits { 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); + set->AddEnum(number, field_type, is_packed, value, NULL); } }; @@ -640,7 +716,7 @@ class MessageTypeTraits { static inline MutableType Mutable(int number, FieldType field_type, ExtensionSet* set) { return static_cast<Type*>( - set->MutableMessage(number, field_type, Type::default_instance())); + set->MutableMessage(number, field_type, Type::default_instance(), NULL)); } }; @@ -659,7 +735,7 @@ class RepeatedMessageTypeTraits { static inline MutableType Add(int number, FieldType field_type, ExtensionSet* set) { return static_cast<Type*>( - set->AddMessage(number, field_type, Type::default_instance())); + set->AddMessage(number, field_type, Type::default_instance(), NULL)); } }; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 8555f6f..2721f15 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -40,11 +40,31 @@ #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 { @@ -58,12 +78,26 @@ void ExtensionSet::AppendToList(const Descriptor* containing_type, } if (has) { - output->push_back( - pool->FindExtensionByNumber(containing_type, iter->first)); + // 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)); @@ -88,16 +122,16 @@ const MessageLite& ExtensionSet::GetMessage(int number, } } -MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + 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(message_type); + const MessageLite* prototype = + factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); extension->message_value = prototype->New(); } else { @@ -107,12 +141,11 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, return extension->message_value; } -MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + 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 = @@ -128,7 +161,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, if (result == NULL) { const MessageLite* prototype; if (extension->repeated_message_value->size() == 0) { - prototype = factory->GetPrototype(message_type); + prototype = factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); } else { prototype = &extension->repeated_message_value->Get(0); @@ -139,18 +172,64 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, 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 MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseField(tag, input, containing_type, &skipper); + 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 MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseMessageSet(input, containing_type, &skipper); + 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 { @@ -175,7 +254,7 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { if (is_repeated) { switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ - case WireFormatLite::CPPTYPE_##UPPERCASE: \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ break @@ -189,8 +268,9 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { HANDLE_TYPE( BOOL, bool); HANDLE_TYPE( ENUM, enum); HANDLE_TYPE( STRING, string); +#undef HANDLE_TYPE - case WireFormatLite::CPPTYPE_MESSAGE: + 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 @@ -201,11 +281,11 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { } } else { switch (cpp_type(type)) { - case WireFormatLite::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); break; - case WireFormatLite::CPPTYPE_MESSAGE: + case FieldDescriptor::CPPTYPE_MESSAGE: total_size += down_cast<Message*>(message_value)->SpaceUsed(); break; default: @@ -216,6 +296,162 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { 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 diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 327aee0..000f846 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -35,10 +35,15 @@ #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> @@ -477,6 +482,160 @@ TEST(ExtensionSetTest, InvalidEnumDeath) { #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 diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index d294e58..0f065ff 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -239,8 +239,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - total_size += GetRaw<RepeatedPtrField<string> >(message, field) - .SpaceUsedExcludingSelf(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + total_size += GetRaw<RepeatedPtrField<string> >(message, field) + .SpaceUsedExcludingSelf(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -265,18 +270,24 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { break; case FieldDescriptor::CPPTYPE_STRING: { - const string* ptr = GetField<const string*>(message, field); - - // Initially, the string points to the default value stored in - // the prototype. Only count the string if it has been changed - // from the default value. - const string* default_ptr = DefaultRaw<const string*>(field); - - if (ptr != default_ptr) { - // string fields are represented by just a pointer, so also - // include sizeof(string) as well. - total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + const string* ptr = GetField<const string*>(message, field); + + // Initially, the string points to the default value stored in + // the prototype. Only count the string if it has been changed + // from the default value. + const string* default_ptr = DefaultRaw<const string*>(field); + + if (ptr != default_ptr) { + // string fields are represented by just a pointer, so also + // include sizeof(string) as well. + total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + } + break; } + } break; } @@ -324,7 +335,7 @@ void GeneratedMessageReflection::Swap( int has_bits_size = (descriptor_->field_count() + 31) / 32; for (int i = 0; i < has_bits_size; i++) { - swap(has_bits1[i], has_bits2[i]); + std::swap(has_bits1[i], has_bits2[i]); } for (int i = 0; i < descriptor_->field_count(); i++) { @@ -360,8 +371,8 @@ void GeneratedMessageReflection::Swap( switch (field->cpp_type()) { #define SWAP_VALUES(CPPTYPE, TYPE) \ case FieldDescriptor::CPPTYPE_##CPPTYPE: \ - swap(*MutableRaw<TYPE>(message1, field), \ - *MutableRaw<TYPE>(message2, field)); \ + std::swap(*MutableRaw<TYPE>(message1, field), \ + *MutableRaw<TYPE>(message2, field)); \ break; SWAP_VALUES(INT32 , int32 ); @@ -376,8 +387,13 @@ void GeneratedMessageReflection::Swap( #undef SWAP_VALUES case FieldDescriptor::CPPTYPE_STRING: - swap(*MutableRaw<string*>(message1, field), - *MutableRaw<string*>(message2, field)); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + std::swap(*MutableRaw<string*>(message1, field), + *MutableRaw<string*>(message2, field)); + break; + } break; default: @@ -473,15 +489,20 @@ void GeneratedMessageReflection::ClearField( break; case FieldDescriptor::CPPTYPE_STRING: { - const string* default_ptr = DefaultRaw<const string*>(field); - string** value = MutableRaw<string*>(message, field); - if (*value != default_ptr) { - if (field->has_default_value()) { - (*value)->assign(field->default_value_string()); - } else { - (*value)->clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + const string* default_ptr = DefaultRaw<const string*>(field); + string** value = MutableRaw<string*>(message, field); + if (*value != default_ptr) { + if (field->has_default_value()) { + (*value)->assign(field->default_value_string()); + } else { + (*value)->clear(); + } } - } + break; + } break; } @@ -508,7 +529,12 @@ void GeneratedMessageReflection::ClearField( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: { - MutableRaw<RepeatedPtrField<string> >(message, field)->Clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw<RepeatedPtrField<string> >(message, field)->Clear(); + break; + } break; } @@ -549,7 +575,12 @@ void GeneratedMessageReflection::RemoveLast( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - MutableRaw<RepeatedPtrField<string> >(message, field)->RemoveLast(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw<RepeatedPtrField<string> >(message, field)->RemoveLast(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -658,7 +689,7 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ if (field->is_extension()) { \ return MutableExtensionSet(message)->Set##TYPENAME( \ - field->number(), field->type(), value); \ + field->number(), field->type(), value, field); \ } else { \ SetField<TYPE>(message, field, value); \ } \ @@ -694,7 +725,8 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ if (field->is_extension()) { \ MutableExtensionSet(message)->Add##TYPENAME( \ - field->number(), field->type(), field->options().packed(), value); \ + field->number(), field->type(), field->options().packed(), value, \ + field); \ } else { \ AddField<TYPE>(message, field, value); \ } \ @@ -718,7 +750,14 @@ string GeneratedMessageReflection::GetString( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField<const string*>(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField<const string*>(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -730,7 +769,14 @@ const string& GeneratedMessageReflection::GetStringReference( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField<const string*>(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField<const string*>(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -741,13 +787,19 @@ void GeneratedMessageReflection::SetString( USAGE_CHECK_ALL(SetString, SINGULAR, STRING); if (field->is_extension()) { return MutableExtensionSet(message)->SetString(field->number(), - field->type(), value); + field->type(), value, field); } else { - string** ptr = MutableField<string*>(message, field); - if (*ptr == DefaultRaw<const string*>(field)) { - *ptr = new string(value); - } else { - (*ptr)->assign(value); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string** ptr = MutableField<string*>(message, field); + if (*ptr == DefaultRaw<const string*>(field)) { + *ptr = new string(value); + } else { + (*ptr)->assign(value); + } + break; + } } } } @@ -759,7 +811,14 @@ string GeneratedMessageReflection::GetRepeatedString( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField<string>(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField<string>(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -770,7 +829,14 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField<string>(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField<string>(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -783,7 +849,12 @@ void GeneratedMessageReflection::SetRepeatedString( MutableExtensionSet(message)->SetRepeatedString( field->number(), index, value); } else { - *MutableRepeatedField<string>(message, field, index) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *MutableRepeatedField<string>(message, field, index) = value; + break; + } } } @@ -794,9 +865,14 @@ void GeneratedMessageReflection::AddString( USAGE_CHECK_ALL(AddString, REPEATED, STRING); if (field->is_extension()) { MutableExtensionSet(message)->AddString(field->number(), - field->type(), value); + field->type(), value, field); } else { - *AddField<string>(message, field) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *AddField<string>(message, field) = value; + break; + } } } @@ -828,7 +904,7 @@ void GeneratedMessageReflection::SetEnum( if (field->is_extension()) { MutableExtensionSet(message)->SetEnum(field->number(), field->type(), - value->number()); + value->number(), field); } else { SetField<int>(message, field, value->number()); } @@ -874,7 +950,7 @@ void GeneratedMessageReflection::AddEnum( if (field->is_extension()) { MutableExtensionSet(message)->AddEnum(field->number(), field->type(), field->options().packed(), - value->number()); + value->number(), field); } else { AddField<int>(message, field, value->number()); } @@ -883,14 +959,15 @@ void GeneratedMessageReflection::AddEnum( // ------------------------------------------------------------------- const Message& GeneratedMessageReflection::GetMessage( - const Message& message, const FieldDescriptor* field) const { + const Message& message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast<const Message&>( - GetExtensionSet(message).GetMessage(field->number(), - field->message_type(), - message_factory_)); + GetExtensionSet(message).GetMessage( + field->number(), field->message_type(), + factory == NULL ? message_factory_ : factory)); } else { const Message* result = GetRaw<const Message*>(message, field); if (result == NULL) { @@ -901,15 +978,14 @@ const Message& GeneratedMessageReflection::GetMessage( } Message* GeneratedMessageReflection::MutableMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast<Message*>( - MutableExtensionSet(message)->MutableMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->MutableMessage(field, + factory == NULL ? message_factory_ : factory)); } else { Message** result = MutableField<Message*>(message, field); if (*result == NULL) { @@ -948,15 +1024,15 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage( } Message* GeneratedMessageReflection::AddMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); + if (factory == NULL) factory = message_factory_; + if (field->is_extension()) { return static_cast<Message*>( - MutableExtensionSet(message)->AddMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->AddMessage(field, factory)); } else { // We can't use AddField<Message>() because RepeatedPtrFieldBase doesn't // know how to allocate one. @@ -967,7 +1043,7 @@ Message* GeneratedMessageReflection::AddMessage( // We must allocate a new object. const Message* prototype; if (repeated->size() == 0) { - prototype = message_factory_->GetPrototype(field->message_type()); + prototype = factory->GetPrototype(field->message_type()); } else { prototype = &repeated->Get<GenericTypeHandler<Message> >(0); } @@ -1110,7 +1186,7 @@ inline Type* GeneratedMessageReflection::MutableField( } template <typename Type> -inline Type GeneratedMessageReflection::GetRepeatedField( +inline const Type& GeneratedMessageReflection::GetRepeatedField( const Message& message, const FieldDescriptor* field, int index) const { return GetRaw<RepeatedField<Type> >(message, field).Get(index); } @@ -1138,7 +1214,7 @@ inline Type* GeneratedMessageReflection::MutableRepeatedField( template <typename Type> inline void GeneratedMessageReflection::AddField( - Message* message, const FieldDescriptor* field, Type value) const { + Message* message, const FieldDescriptor* field, const Type& value) const { MutableRaw<RepeatedField<Type> >(message, field)->Add(value); } diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index d0b5b43..b545fa1 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -169,7 +169,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const EnumValueDescriptor* GetEnum(const Message& message, const FieldDescriptor* field) const; const Message& GetMessage(const Message& message, - const FieldDescriptor* field) const; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; void SetInt32 (Message* message, const FieldDescriptor* field, int32 value) const; @@ -190,7 +191,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const string& value) const; void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* MutableMessage(Message* message, const FieldDescriptor* field) const; + Message* MutableMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; int32 GetRepeatedInt32 (const Message& message, const FieldDescriptor* field, int index) const; @@ -262,7 +264,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { void AddEnum(Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* AddMessage(Message* message, const FieldDescriptor* field) 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; @@ -314,9 +317,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { inline Type* MutableField(Message* message, const FieldDescriptor* field) const; template <typename Type> - inline Type GetRepeatedField(const Message& message, - const FieldDescriptor* field, - int index) const; + 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, @@ -331,7 +334,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int index) const; template <typename Type> inline void AddField(Message* message, - const FieldDescriptor* field, Type value) const; + const FieldDescriptor* field, const Type& value) const; template <typename Type> inline Type* AddField(Message* message, const FieldDescriptor* field) const; diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index 9470bb0..7ac015d 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -34,10 +34,19 @@ #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(); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 80dd028..daa16f7 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -43,21 +43,33 @@ 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. +// 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 DEPRECATED_PROTOBUF_FIELD GOOGLE_ATTRIBUTE_DEPRECATED +# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED #else -# define DEPRECATED_PROTOBUF_FIELD +# define PROTOBUF_DEPRECATED #endif +// Constants for special floating point values. +LIBPROTOBUF_EXPORT double Infinity(); +LIBPROTOBUF_EXPORT double NaN(); + + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index e17a477..6a91a13 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -38,9 +38,9 @@ // will not cross the end of the buffer, since we can avoid a lot // of branching in this case. -#include <stack> +#include <google/protobuf/io/coded_stream_inl.h> +#include <algorithm> #include <limits.h> -#include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stl_util-inl.h> @@ -52,11 +52,6 @@ namespace io { namespace { -static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB - -static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB -static const int kDefaultRecursionLimit = 64; - static const int kMaxVarintBytes = 10; static const int kMaxVarint32Bytes = 5; @@ -65,72 +60,28 @@ static const int kMaxVarint32Bytes = 5; // CodedInputStream ================================================== -CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) - : input_(input), - buffer_(NULL), - buffer_size_(0), - total_bytes_read_(0), - overflow_bytes_(0), - last_tag_(0), - legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(INT_MAX), - buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), - total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), - recursion_limit_(kDefaultRecursionLimit) { - // Eagerly Refresh() so buffer space is immediately available. - Refresh(); -} - -CodedInputStream::CodedInputStream(const uint8* buffer, int size) - : input_(NULL), - buffer_(buffer), - buffer_size_(size), - total_bytes_read_(size), - overflow_bytes_(0), - last_tag_(0), - legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(size), - buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), - total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), - recursion_limit_(kDefaultRecursionLimit) { - // Note that setting current_limit_ == size is important to prevent some - // code paths from trying to access input_ and segfaulting. -} - -CodedInputStream::~CodedInputStream() { - if (input_ != NULL) { - BackUpInputToCurrentPosition(); - } -} - void CodedInputStream::BackUpInputToCurrentPosition() { - int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_; + 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_ -= buffer_size_ + buffer_size_after_limit_; - buffer_size_ = 0; + total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; + buffer_end_ = buffer_; buffer_size_after_limit_ = 0; overflow_bytes_ = 0; } } inline void CodedInputStream::RecomputeBufferLimits() { - buffer_size_ += buffer_size_after_limit_; + 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_size_ -= buffer_size_after_limit_; + buffer_end_ -= buffer_size_after_limit_; } else { buffer_size_after_limit_ = 0; } @@ -139,7 +90,7 @@ inline void CodedInputStream::RecomputeBufferLimits() { CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // Current position relative to the beginning of the stream. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); Limit old_limit = current_limit_; @@ -176,7 +127,7 @@ void CodedInputStream::PopLimit(Limit limit) { int CodedInputStream::BytesUntilLimit() { if (current_limit_ == INT_MAX) return -1; int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); return current_limit_ - current_position; } @@ -186,7 +137,7 @@ void CodedInputStream::SetTotalBytesLimit( // Make sure the limit isn't already past, since this could confuse other // code. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); total_bytes_limit_ = max(current_position, total_bytes_limit); total_bytes_warning_threshold_ = warning_threshold; RecomputeBufferLimits(); @@ -203,7 +154,9 @@ void CodedInputStream::PrintTotalBytesLimitError() { bool CodedInputStream::Skip(int count) { if (count < 0) return false; // security: count is often user-supplied - if (count <= buffer_size_) { + const int original_buffer_size = BufferSize(); + + if (count <= original_buffer_size) { // Just skipping within the current buffer. Easy. Advance(count); return true; @@ -211,13 +164,13 @@ bool CodedInputStream::Skip(int count) { if (buffer_size_after_limit_ > 0) { // We hit a limit inside this buffer. Advance to the limit and fail. - Advance(buffer_size_); + Advance(original_buffer_size); return false; } - count -= buffer_size_; + count -= original_buffer_size; buffer_ = NULL; - buffer_size_ = 0; + 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_); @@ -236,20 +189,21 @@ bool CodedInputStream::Skip(int count) { } bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { - if (buffer_size_ == 0 && !Refresh()) return false; + if (BufferSize() == 0 && !Refresh()) return false; *data = buffer_; - *size = buffer_size_; + *size = BufferSize(); return true; } bool CodedInputStream::ReadRaw(void* buffer, int size) { - while (buffer_size_ < 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_, buffer_size_); - buffer = reinterpret_cast<uint8*>(buffer) + buffer_size_; - size -= buffer_size_; - Advance(buffer_size_); + 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; } @@ -261,27 +215,25 @@ bool CodedInputStream::ReadRaw(void* buffer, int size) { 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(); } - if (size < buffer_size_) { - STLStringResizeUninitialized(buffer, size); - memcpy((uint8*)buffer->data(), buffer_, size); - Advance(size); - return true; - } - - while (buffer_size_ < size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). - if (buffer_size_ != 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_), buffer_size_); + buffer->append(reinterpret_cast<const char*>(buffer_), + current_buffer_size); } - size -= buffer_size_; - Advance(buffer_size_); + size -= current_buffer_size; + Advance(current_buffer_size); if (!Refresh()) return false; } @@ -292,11 +244,11 @@ bool CodedInputStream::ReadString(string* buffer, int size) { } -bool CodedInputStream::ReadLittleEndian32(uint32* value) { +bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -305,19 +257,15 @@ bool CodedInputStream::ReadLittleEndian32(uint32* value) { if (!ReadRaw(bytes, sizeof(*value))) return false; ptr = bytes; } - - *value = (static_cast<uint32>(ptr[0]) ) | - (static_cast<uint32>(ptr[1]) << 8) | - (static_cast<uint32>(ptr[2]) << 16) | - (static_cast<uint32>(ptr[3]) << 24); + ReadLittleEndian32FromArray(ptr, value); return true; } -bool CodedInputStream::ReadLittleEndian64(uint64* value) { +bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -326,99 +274,152 @@ bool CodedInputStream::ReadLittleEndian64(uint64* value) { 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 - uint32 part0 = (static_cast<uint32>(ptr[0]) ) | - (static_cast<uint32>(ptr[1]) << 8) | - (static_cast<uint32>(ptr[2]) << 16) | - (static_cast<uint32>(ptr[3]) << 24); - uint32 part1 = (static_cast<uint32>(ptr[4]) ) | - (static_cast<uint32>(ptr[5]) << 8) | - (static_cast<uint32>(ptr[6]) << 16) | - (static_cast<uint32>(ptr[7]) << 24); - *value = static_cast<uint64>(part0) | - (static_cast<uint64>(part1) << 32); +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 (buffer_size_ >= kMaxVarintBytes || + 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_size_ != 0 && !(buffer_[buffer_size_-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; - 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 false; - - done: - Advance(ptr - buffer_); - *value = result; + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + const uint8* end = ReadVarint32FromArray(buffer_, value); + if (end == NULL) return false; + buffer_ = end; return true; - } else { - // Optimization: If we're at a limit, detect that quickly. (This is - // common when reading tags.) - while (buffer_size_ == 0) { - // Detect cases where we definitely hit a byte limit without calling - // Refresh(). - if (// If we hit a limit, buffer_size_after_limit_ will be non-zero. - 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 false; - } + // 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); + } +} - // 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 false; +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; } + } - // Slow path: Just do a 64-bit read. - uint64 result; - if (!ReadVarint64(&result)) return false; - *value = (uint32)result; - return true; + // 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::ReadVarint64(uint64* value) { - if (buffer_size_ >= kMaxVarintBytes || +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_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) { + (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. @@ -442,7 +443,7 @@ bool CodedInputStream::ReadVarint64(uint64* value) { // We have overrun the maximum size of a varint (10 bytes). The data // must be corrupt. - return false; + return NULL; done: Advance(ptr - buffer_); @@ -450,33 +451,13 @@ bool CodedInputStream::ReadVarint64(uint64* value) { (static_cast<uint64>(part1) << 28) | (static_cast<uint64>(part2) << 56); return true; - } else { - // 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_size_ == 0) { - if (!Refresh()) return false; - } - b = *buffer_; - result |= static_cast<uint64>(b & 0x7F) << (7 * count); - Advance(1); - ++count; - } while(b & 0x80); - - *value = result; - return true; + return ReadVarint64Slow(value); } } bool CodedInputStream::Refresh() { - GOOGLE_DCHECK_EQ(buffer_size_, 0); + GOOGLE_DCHECK_EQ(0, BufferSize()); if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || total_bytes_read_ == current_limit_) { @@ -507,25 +488,27 @@ bool CodedInputStream::Refresh() { } const void* void_buffer; - if (input_->Next(&void_buffer, &buffer_size_)) { + int buffer_size; + if (input_->Next(&void_buffer, &buffer_size)) { buffer_ = reinterpret_cast<const uint8*>(void_buffer); - GOOGLE_CHECK_GE(buffer_size_, 0); + buffer_end_ = buffer_ + buffer_size; + GOOGLE_CHECK_GE(buffer_size, 0); - if (total_bytes_read_ <= INT_MAX - buffer_size_) { - total_bytes_read_ += buffer_size_; + if (total_bytes_read_ <= INT_MAX - buffer_size) { + total_bytes_read_ += buffer_size; } else { - // Overflow. Reset buffer_size_ to not include the bytes beyond INT_MAX. + // 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; + // 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_size_ -= overflow_bytes_; + overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); + buffer_end_ -= overflow_bytes_; total_bytes_read_ = INT_MAX; } @@ -533,7 +516,7 @@ bool CodedInputStream::Refresh() { return true; } else { buffer_ = NULL; - buffer_size_ = 0; + buffer_end_ = NULL; return false; } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index fa023f3..dcbb0d4 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -114,10 +114,15 @@ #include <sys/param.h> #endif // !_MSC_VER #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/common.h> // for GOOGLE_PREDICT_TRUE macro namespace google { namespace protobuf { + +class DescriptorPool; +class MessageFactory; + namespace io { // Defined in this file. @@ -166,6 +171,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // types of data not covered by the CodedInputStream interface. bool GetDirectBufferPointer(const void** data, int* size); + // Like GetDirectBufferPointer, but this method is inlined, and does not + // attempt to Refresh() if the buffer is currently empty. + inline void GetDirectBufferPointerInline(const void** data, + int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); @@ -177,6 +187,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // could claim that a string is going to be MAX_INT bytes long in order to // crash the server because it can't allocate this much space at once. bool ReadString(string* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadStringInline(string* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; // Read a 32-bit little-endian integer. @@ -184,6 +198,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Read a 64-bit little-endian integer. bool ReadLittleEndian64(uint64* value); + // These methods read from an externally provided buffer. The caller is + // responsible for ensuring that the buffer has sufficient space. + // Read a 32-bit little-endian integer. + static const uint8* ReadLittleEndian32FromArray(const uint8* buffer, + uint32* value); + // Read a 64-bit little-endian integer. + static const uint8* ReadLittleEndian64FromArray(const uint8* buffer, + uint64* value); + // Read an unsigned integer with Varint encoding, truncating to 32 bits. // Reading a 32-bit value is equivalent to reading a 64-bit one and casting // it to uint32, but may be more efficient. @@ -208,6 +231,17 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // when given a constant parameter, but GCC doesn't want to inline by default. bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Like above, except this reads from the specified buffer. The caller is + // responsible for ensuring that the buffer is large enough to read a varint + // of the expected size. For best performance, use a compile-time constant as + // the expected tag parameter. + // + // Returns a pointer beyond the expected tag if it was found, or NULL if it + // was not. + static const uint8* ExpectTagFromArray( + const uint8* buffer, + uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Usually returns true if no more bytes can be read. Always returns false // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent // call to LastTagWas() will act as if ReadTag() had been called and returned @@ -318,12 +352,90 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Decrements the recursion depth. void DecrementRecursionDepth(); + // Extension Registry ---------------------------------------------- + // ADVANCED USAGE: 99.9% of people can ignore this section. + // + // By default, when parsing extensions, the parser looks for extension + // definitions in the pool which owns the outer message's Descriptor. + // However, you may call SetExtensionRegistry() to provide an alternative + // pool instead. This makes it possible, for example, to parse a message + // using a generated class, but represent some extensions using + // DynamicMessage. + + // Set the pool used to look up extensions. Most users do not need to call + // this as the correct pool will be chosen automatically. + // + // WARNING: It is very easy to misuse this. Carefully read the requirements + // below. Do not use this unless you are sure you need it. Almost no one + // does. + // + // Let's say you are parsing a message into message object m, and you want + // to take advantage of SetExtensionRegistry(). You must follow these + // requirements: + // + // The given DescriptorPool must contain m->GetDescriptor(). It is not + // sufficient for it to simply contain a descriptor that has the same name + // and content -- it must be the *exact object*. In other words: + // assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) == + // m->GetDescriptor()); + // There are two ways to satisfy this requirement: + // 1) Use m->GetDescriptor()->pool() as the pool. This is generally useless + // because this is the pool that would be used anyway if you didn't call + // SetExtensionRegistry() at all. + // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an + // "underlay". Read the documentation for DescriptorPool for more + // information about underlays. + // + // You must also provide a MessageFactory. This factory will be used to + // construct Message objects representing extensions. The factory's + // GetPrototype() MUST return non-NULL for any Descriptor which can be found + // through the provided pool. + // + // If the provided factory might return instances of protocol-compiler- + // generated (i.e. compiled-in) types, or if the outer message object m is + // a generated type, then the given factory MUST have this property: If + // GetPrototype() is given a Descriptor which resides in + // DescriptorPool::generated_pool(), the factory MUST return the same + // prototype which MessageFactory::generated_factory() would return. That + // is, given a descriptor for a generated type, the factory must return an + // instance of the generated class (NOT DynamicMessage). However, when + // given a descriptor for a type that is NOT in generated_pool, the factory + // is free to return any implementation. + // + // The reason for this requirement is that generated sub-objects may be + // accessed via the standard (non-reflection) extension accessor methods, + // and these methods will down-cast the object to the generated class type. + // If the object is not actually of that type, the results would be undefined. + // On the other hand, if an extension is not compiled in, then there is no + // way the code could end up accessing it via the standard accessors -- the + // only way to access the extension is via reflection. When using reflection, + // DynamicMessage and generated messages are indistinguishable, so it's fine + // if these objects are represented using DynamicMessage. + // + // Using DynamicMessageFactory on which you have called + // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the + // above requirement. + // + // If either pool or factory is NULL, both must be NULL. + // + // Note that this feature is ignored when parsing "lite" messages as they do + // not have descriptors. + void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory); + + // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool + // has been provided. + const DescriptorPool* GetExtensionPool(); + + // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no + // factory has been provided. + MessageFactory* GetExtensionFactory(); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); ZeroCopyInputStream* input_; const uint8* buffer_; - int buffer_size_; // size of current buffer + const uint8* buffer_end_; // pointer to the end of the buffer. int total_bytes_read_; // total bytes read from input_, including // the current buffer @@ -334,7 +446,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // LastTagWas() stuff. uint32 last_tag_; // result of last ReadTag(). - // This is set true by ReadVarint32Fallback() if it is called when exactly + // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly // at EOF, or by ExpectAtEnd() when it returns true. This happens when we // reach the end of a message and attempt to read another tag. bool legitimate_message_end_; @@ -365,6 +477,12 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Recursion depth limit, set by SetRecursionLimit(). int recursion_limit_; + // See SetExtensionRegistry(). + const DescriptorPool* extension_pool_; + MessageFactory* extension_factory_; + + // Private member functions. + // Advance the buffer by a given number of bytes. void Advance(int amount); @@ -379,10 +497,36 @@ class LIBPROTOBUF_EXPORT CodedInputStream { void PrintTotalBytesLimitError(); // Called when the buffer runs out to request more data. Implies an - // Advance(buffer_size_). + // Advance(BufferSize()). bool Refresh(); + // When parsing varints, we optimize for the common case of small values, and + // then optimize for the case when the varint fits within the current buffer + // piece. The Fallback method is used when we can't use the one-byte + // optimization. The Slow method is yet another fallback when the buffer is + // not large enough. Making the slow path out-of-line speeds up the common + // case by 10-15%. The slow path is fairly uncommon: it only triggers when a + // message crosses multiple buffers. bool ReadVarint32Fallback(uint32* value); + bool ReadVarint64Fallback(uint64* value); + bool ReadVarint32Slow(uint32* value); + bool ReadVarint64Slow(uint64* value); + bool ReadLittleEndian32Fallback(uint32* value); + bool ReadLittleEndian64Fallback(uint64* value); + // Fallback/slow methods for reading tags. These do not update last_tag_, + // but will set legitimate_message_end_ if we are at the end of the input + // stream. + uint32 ReadTagFallback(); + uint32 ReadTagSlow(); + bool ReadStringFallback(string* buffer, int size); + + // Return the size of the buffer. + int BufferSize() const; + + static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + + static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB + static const int kDefaultRecursionLimit = 64; }; // Class which encodes and writes binary data which is composed of varint- @@ -568,7 +712,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // methods optimize for that case. inline bool CodedInputStream::ReadVarint32(uint32* value) { - if (buffer_size_ != 0 && *buffer_ < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { *value = *buffer_; Advance(1); return true; @@ -577,20 +721,93 @@ inline bool CodedInputStream::ReadVarint32(uint32* value) { } } +inline bool CodedInputStream::ReadVarint64(uint64* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint64Fallback(value); + } +} + +// static +inline const uint8* CodedInputStream::ReadLittleEndian32FromArray( + const uint8* buffer, + uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + *value = (static_cast<uint32>(buffer[0]) ) | + (static_cast<uint32>(buffer[1]) << 8) | + (static_cast<uint32>(buffer[2]) << 16) | + (static_cast<uint32>(buffer[3]) << 24); + return buffer + sizeof(*value); +#endif +} +// static +inline const uint8* CodedInputStream::ReadLittleEndian64FromArray( + const uint8* buffer, + uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + uint32 part0 = (static_cast<uint32>(buffer[0]) ) | + (static_cast<uint32>(buffer[1]) << 8) | + (static_cast<uint32>(buffer[2]) << 16) | + (static_cast<uint32>(buffer[3]) << 24); + uint32 part1 = (static_cast<uint32>(buffer[4]) ) | + (static_cast<uint32>(buffer[5]) << 8) | + (static_cast<uint32>(buffer[6]) << 16) | + (static_cast<uint32>(buffer[7]) << 24); + *value = static_cast<uint64>(part0) | + (static_cast<uint64>(part1) << 32); + return buffer + sizeof(*value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian32(uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian32Fallback(value); + } +#else + return ReadLittleEndian32Fallback(value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian64Fallback(value); + } +#else + return ReadLittleEndian64Fallback(value); +#endif +} + inline uint32 CodedInputStream::ReadTag() { - if (buffer_size_ != 0 && buffer_[0] < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { last_tag_ = buffer_[0]; Advance(1); return last_tag_; - } else if (buffer_size_ >= 2 && buffer_[1] < 0x80) { - last_tag_ = (buffer_[0] & 0x7f) + (buffer_[1] << 7); - Advance(2); - return last_tag_; - } else if (ReadVarint32Fallback(&last_tag_)) { - return last_tag_; } else { - last_tag_ = 0; - return 0; + last_tag_ = ReadTagFallback(); + return last_tag_; } } @@ -604,14 +821,14 @@ inline bool CodedInputStream::ConsumedEntireMessage() { inline bool CodedInputStream::ExpectTag(uint32 expected) { if (expected < (1 << 7)) { - if (buffer_size_ != 0 && buffer_[0] == expected) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] == expected) { Advance(1); return true; } else { return false; } } else if (expected < (1 << 14)) { - if (buffer_size_ >= 2 && + if (GOOGLE_PREDICT_TRUE(BufferSize() >= 2) && buffer_[0] == static_cast<uint8>(expected | 0x80) && buffer_[1] == static_cast<uint8>(expected >> 7)) { Advance(2); @@ -625,11 +842,32 @@ inline bool CodedInputStream::ExpectTag(uint32 expected) { } } +inline const uint8* CodedInputStream::ExpectTagFromArray( + const uint8* buffer, uint32 expected) { + if (expected < (1 << 7)) { + if (buffer[0] == expected) { + return buffer + 1; + } + } else if (expected < (1 << 14)) { + if (buffer[0] == static_cast<uint8>(expected | 0x80) && + buffer[1] == static_cast<uint8>(expected >> 7)) { + return buffer + 2; + } + } + return NULL; +} + +inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, + int* size) { + *data = buffer_; + *size = buffer_end_ - buffer_; +} + inline bool CodedInputStream::ExpectAtEnd() { // If we are at a limit we know no more bytes can be read. Otherwise, it's // hard to say without calling Refresh(), and we'd rather not do that. - if (buffer_size_ == 0 && buffer_size_after_limit_ != 0) { + if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) { last_tag_ = 0; // Pretend we called ReadTag()... legitimate_message_end_ = true; // ... and it hit EOF. return true; @@ -677,11 +915,11 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else - target[0] = static_cast<uint8>(value ); + target[0] = static_cast<uint8>(value); target[1] = static_cast<uint8>(value >> 8); target[2] = static_cast<uint8>(value >> 16); target[3] = static_cast<uint8>(value >> 24); @@ -691,18 +929,18 @@ inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else uint32 part0 = static_cast<uint32>(value); uint32 part1 = static_cast<uint32>(value >> 32); - target[0] = static_cast<uint8>(part0 ); + target[0] = static_cast<uint8>(part0); target[1] = static_cast<uint8>(part0 >> 8); target[2] = static_cast<uint8>(part0 >> 16); target[3] = static_cast<uint8>(part0 >> 24); - target[4] = static_cast<uint8>(part1 ); + target[4] = static_cast<uint8>(part1); target[5] = static_cast<uint8>(part1 >> 8); target[6] = static_cast<uint8>(part1 >> 16); target[7] = static_cast<uint8>(part1 >> 24); @@ -759,7 +997,6 @@ inline int CodedOutputStream::ByteCount() const { inline void CodedInputStream::Advance(int amount) { buffer_ += amount; - buffer_size_ -= amount; } inline void CodedOutputStream::Advance(int amount) { @@ -780,6 +1017,72 @@ inline void CodedInputStream::DecrementRecursionDepth() { if (recursion_depth_ > 0) --recursion_depth_; } +inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool, + MessageFactory* factory) { + extension_pool_ = pool; + extension_factory_ = factory; +} + +inline const DescriptorPool* CodedInputStream::GetExtensionPool() { + return extension_pool_; +} + +inline MessageFactory* CodedInputStream::GetExtensionFactory() { + return extension_factory_; +} + +inline int CodedInputStream::BufferSize() const { + return buffer_end_ - buffer_; +} + +inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) + : input_(input), + buffer_(NULL), + buffer_end_(NULL), + total_bytes_read_(0), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(INT_MAX), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); +} + +inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) + : input_(NULL), + buffer_(buffer), + buffer_end_(buffer + size), + total_bytes_read_(size), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(size), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Note that setting current_limit_ == size is important to prevent some + // code paths from trying to access input_ and segfaulting. +} + +inline CodedInputStream::~CodedInputStream() { + if (input_ != NULL) { + BackUpInputToCurrentPosition(); + } +} + } // namespace io } // namespace protobuf diff --git a/src/google/protobuf/unittest_stringutf8_micro.proto b/src/google/protobuf/io/coded_stream_inl.h index e4bbe3d..e9799d4 100644 --- a/src/google/protobuf/unittest_stringutf8_micro.proto +++ b/src/google/protobuf/io/coded_stream_inl.h @@ -28,14 +28,37 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Author: wink@google.com (Wink Saville) +// 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. -package protobuf_unittest_import; +#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ +#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ -option java_package = "com.google.protobuf.micro"; +#include <google/protobuf/io/coded_stream.h> +#include <string> +#include <google/protobuf/stubs/stl_util-inl.h> -message StringUtf8 { - optional string id = 1; - repeated string rs = 2; +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__ diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index e165fb9..7d29833 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -242,6 +242,24 @@ TEST_1D(CodedStreamTest, ExpectTag, kVarintCases) { } } +TEST_1D(CodedStreamTest, ExpectTagFromArray, kVarintCases) { + memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); + + const uint32 expected_value = static_cast<uint32>(kVarintCases_case.value); + + // If the expectation succeeds, it should return a pointer past the tag. + if (kVarintCases_case.size <= 2) { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, + expected_value + 1)); + EXPECT_TRUE(buffer_ + kVarintCases_case.size == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } else { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } +} + TEST_2D(CodedStreamTest, ReadVarint64, kVarintCases, kBlockSizes) { memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case); @@ -529,10 +547,32 @@ TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) { EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64))); } +// Tests using the static methods to read fixed-size values from raw arrays. + +TEST_1D(CodedStreamTest, ReadLittleEndian32FromArray, kFixed32Cases) { + memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes)); + + uint32 value; + const uint8* end = CodedInputStream::ReadLittleEndian32FromArray( + buffer_, &value); + EXPECT_EQ(kFixed32Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + +TEST_1D(CodedStreamTest, ReadLittleEndian64FromArray, kFixed64Cases) { + memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes)); + + uint64 value; + const uint8* end = CodedInputStream::ReadLittleEndian64FromArray( + buffer_, &value); + EXPECT_EQ(kFixed64Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + // ------------------------------------------------------------------- // Raw reads and writes -const char kRawBytes[] = "Some bytes which will be writted and read raw."; +const char kRawBytes[] = "Some bytes which will be written and read raw."; TEST_1D(CodedStreamTest, ReadRaw, kBlockSizes) { memcpy(buffer_, kRawBytes, sizeof(kRawBytes)); @@ -593,6 +633,22 @@ TEST_1D(CodedStreamTest, ReadStringImpossiblyLarge, kBlockSizes) { } } +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) { + // Same test as above, except directly use a buffer. This used to cause + // crashes while the above did not. + uint8 buffer[8]; + CodedInputStream coded_input(buffer, 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) { + scoped_array<uint8> buffer(new uint8[8]); + CodedInputStream coded_input(buffer.get(), 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + // ------------------------------------------------------------------- // Skip @@ -652,6 +708,36 @@ TEST_F(CodedStreamTest, GetDirectBufferPointerInput) { EXPECT_EQ(8, size); } +TEST_F(CodedStreamTest, GetDirectBufferPointerInlineInput) { + ArrayInputStream input(buffer_, sizeof(buffer_), 8); + CodedInputStream coded_input(&input); + + const void* ptr; + int size; + + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Peeking again should return the same pointer. + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Skip forward in the same buffer then peek again. + EXPECT_TRUE(coded_input.Skip(3)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 3, ptr); + EXPECT_EQ(5, size); + + // Skip to end of buffer and peek -- should return false and provide an empty + // buffer. It does not try to Refresh(). + EXPECT_TRUE(coded_input.Skip(5)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 8, ptr); + EXPECT_EQ(0, size); +} + TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) { ArrayOutputStream output(buffer_, sizeof(buffer_), 8); CodedOutputStream coded_output(&output); diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 937d777..c7d3074 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -65,10 +65,10 @@ void Printer::Print(const map<string, string>& variables, const char* text) { 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'. - Write(text + pos, i - pos + 1); + WriteRaw(text + pos, i - pos + 1); pos = i + 1; - // Setting this true will cause the next Write() to insert an indent + // Setting this true will cause the next WriteRaw() to insert an indent // first. at_start_of_line_ = true; @@ -76,7 +76,7 @@ void Printer::Print(const map<string, string>& variables, const char* text) { // Saw the start of a variable name. // Write what we have so far. - Write(text + pos, i - pos); + WriteRaw(text + pos, i - pos); pos = i + 1; // Find closing delimiter. @@ -90,14 +90,14 @@ void Printer::Print(const map<string, string>& variables, const char* text) { string varname(text + pos, endpos - pos); if (varname.empty()) { // Two delimiters in a row reduce to a literal delimiter character. - Write(&variable_delimiter_, 1); + 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 { - Write(iter->second.data(), iter->second.size()); + WriteRaw(iter->second.data(), iter->second.size()); } } @@ -108,7 +108,7 @@ void Printer::Print(const map<string, string>& variables, const char* text) { } // Write the rest. - Write(text + pos, size - pos); + WriteRaw(text + pos, size - pos); } void Printer::Print(const char* text) { @@ -145,14 +145,23 @@ void Printer::Outdent() { indent_.resize(indent_.size() - 2); } -void Printer::Write(const char* data, int size) { +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; - Write(indent_.data(), indent_.size()); + WriteRaw(indent_.data(), indent_.size()); if (failed_) return; } diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index b7c4cf3..de08538 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -59,8 +59,8 @@ class ZeroCopyOutputStream; // zero_copy_stream.h // 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. This helps greatly in debugging code -// which uses it. This class is not intended to be used by production servers. +// 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 @@ -94,15 +94,24 @@ class LIBPROTOBUF_EXPORT Printer { // 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: - // Write some text to the output buffer. - void Write(const char* data, int size); - const char variable_delimiter_; ZeroCopyOutputStream* const output_; diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 69c7ee3..580a53d 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -76,10 +76,38 @@ TEST(Printer, BasicPrinting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World! This is the same line.\n" - "But this is a new one.\n" - "And this is another one."); + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one.", + buffer); + } +} + +TEST(Printer, WriteRaw) { + char buffer[8192]; + + for (int block_size = 1; block_size < 512; block_size *= 2) { + ArrayOutputStream output(buffer, sizeof(buffer), block_size); + + { + string string_obj = "From an object\n"; + Printer printer(&output, '$'); + printer.WriteRaw("Hello World!", 12); + printer.PrintRaw(" This is the same line.\n"); + printer.PrintRaw("But this is a new one.\nAnd this is another one."); + printer.WriteRaw("\n", 1); + printer.PrintRaw(string_obj); + EXPECT_FALSE(printer.failed()); + } + + buffer[output.ByteCount()] = '\0'; + + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one." + "\n" + "From an object\n", + buffer); } } @@ -98,6 +126,7 @@ TEST(Printer, VariableSubstitution) { vars["abcdefg"] = "1234"; printer.Print(vars, "Hello $foo$!\nbar = $bar$\n"); + printer.PrintRaw("RawBit\n"); printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$"); vars["foo"] = "blah"; @@ -108,12 +137,13 @@ TEST(Printer, VariableSubstitution) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "bar = $foo$\n" - "1234\n" - "A literal dollar sign: $\n" - "Now foo = blah."); + EXPECT_STREQ("Hello World!\n" + "bar = $foo$\n" + "RawBit\n" + "1234\n" + "A literal dollar sign: $\n" + "Now foo = blah.", + buffer); } } @@ -125,15 +155,17 @@ TEST(Printer, InlineVariableSubstitution) { { Printer printer(&output, '$'); printer.Print("Hello $foo$!\n", "foo", "World"); + printer.PrintRaw("RawBit\n"); printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two"); EXPECT_FALSE(printer.failed()); } buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "one two\n"); + EXPECT_STREQ("Hello World!\n" + "RawBit\n" + "one two\n", + buffer); } TEST(Printer, Indenting) { @@ -156,6 +188,8 @@ TEST(Printer, Indenting) { printer.Indent(); printer.Print(" And this is still the same line.\n" "But this is indented.\n"); + printer.PrintRaw("RawBit has indent at start\n"); + printer.PrintRaw("but not after a raw newline\n"); printer.Print(vars, "Note that a newline in a variable will break " "indenting, as we see$newline$here.\n"); printer.Indent(); @@ -169,16 +203,19 @@ TEST(Printer, Indenting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, + EXPECT_STREQ( "This is not indented.\n" " This is indented\n" " And so is this\n" "But this is not. And this is still the same line.\n" " But this is indented.\n" - " Note that a newline in a variable will break indenting, as we see\n" + " RawBit has indent at start\n" + "but not after a raw newline\n" + "Note that a newline in a variable will break indenting, as we see\n" "here.\n" " And this is double-indented\n" - "Back to normal."); + "Back to normal.", + buffer); } } diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 0bda451..38fa351 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -117,9 +117,9 @@ namespace { } CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || - c == '\r' || c == '\v'); + c == '\r' || c == '\v' || c == '\f'); -CHARACTER_CLASS(Unprintable, c < ' ' && c != '\0'); +CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0'); CHARACTER_CLASS(Digit, '0' <= c && c <= '9'); CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7'); diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 98386e0..d115161 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -63,6 +63,11 @@ class LIBPROTOBUF_EXPORT ErrorCollector { // 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); }; diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index eac1455..358ec56 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -397,6 +397,19 @@ MultiTokenCase kMultiTokenCases[] = { { Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0 }, { Tokenizer::TYPE_END , "" , 1, 3 }, }}, + + // Bytes with the high-order bit set should not be seen as control characters. + { "\300", { + { Tokenizer::TYPE_SYMBOL, "\300", 0, 0 }, + { Tokenizer::TYPE_END , "" , 0, 1 }, + }}, + + // Test all whitespace chars + { "foo\n\t\r\v\fbar", { + { Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 }, + { Tokenizer::TYPE_IDENTIFIER, "bar", 1, 11 }, + { Tokenizer::TYPE_END , "" , 1, 14 }, + }}, }; TEST_2D(TokenizerTest, MultipleTokens, kMultiTokenCases, kBlockSizes) { diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h index 64e96cd..9fedb00 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.h +++ b/src/google/protobuf/io/zero_copy_stream_impl.h @@ -133,10 +133,11 @@ class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream { // A ZeroCopyOutputStream which writes to a file descriptor. // -// FileInputStream is preferred over using an ofstream with OstreamOutputStream. -// 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. +// 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. diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index c8f669a..8229ee6 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -403,7 +403,8 @@ TEST_F(IoTest, CompressionOptions) { string golden; File::ReadFileToStringOrDie( - TestSourceDir() + "/google/protobuf/testdata/golden_message", &golden); + TestSourceDir() + "/google/protobuf/testdata/golden_message", + &golden); GzipOutputStream::Options options; string gzip_compressed = Compress(golden, options); @@ -520,7 +521,7 @@ TEST_F(IoTest, GzipFileIo) { // these debug assertions while in scope. class MsvcDebugDisabler { public: -#ifdef _MSC_VER +#if defined(_MSC_VER) && _MSC_VER >= 1400 MsvcDebugDisabler() { old_handler_ = _set_invalid_parameter_handler(MyHandler); old_mode_ = _CrtSetReportMode(_CRT_ASSERT, 0); diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 4e5b662..91e6878 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -168,8 +168,11 @@ bool Message::SerializePartialToFileDescriptor(int file_descriptor) const { } bool Message::SerializeToOstream(ostream* output) const { - io::OstreamOutputStream zero_copy_output(output); - return SerializeToZeroCopyStream(&zero_copy_output); + { + io::OstreamOutputStream zero_copy_output(output); + if (!SerializeToZeroCopyStream(&zero_copy_output)) return false; + } + return output->good(); } bool Message::SerializePartialToOstream(ostream* output) const { @@ -227,7 +230,7 @@ GeneratedMessageFactory::GeneratedMessageFactory() {} GeneratedMessageFactory::~GeneratedMessageFactory() {} GeneratedMessageFactory* GeneratedMessageFactory::singleton() { - GoogleOnceInit(&generated_message_factory_once_init_, + ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, &InitGeneratedMessageFactory); return generated_message_factory_; } diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 54b596d..c0062f9 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -148,6 +148,7 @@ namespace protobuf { // Defined in this file. class Message; class Reflection; +class MessageFactory; // Defined in other files. class Descriptor; // descriptor.h @@ -238,13 +239,15 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // Reflection object's SpaceUsed() method. virtual int SpaceUsed() const; - // Debugging ------------------------------------------------------- + // 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; @@ -327,6 +330,7 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // GetReflection() wrappers. virtual Metadata GetMetadata() const = 0; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); }; @@ -453,8 +457,10 @@ class LIBPROTOBUF_EXPORT Reflection { 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) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Get a string value without copying, if possible. // @@ -499,9 +505,19 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; - // Get a mutable pointer to a field with a message type. + // 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) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Repeated field getters ------------------------------------------ @@ -603,8 +619,10 @@ class LIBPROTOBUF_EXPORT Reflection { 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) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Extensions ------------------------------------------------------ diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index a53740a..7c8f37d 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -33,9 +33,8 @@ // 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> @@ -52,6 +51,24 @@ string MessageLite::InitializationErrorString() const { 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 @@ -215,9 +232,29 @@ bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const { bool MessageLite::SerializePartialToCodedStream( io::CodedOutputStream* output) const { - ByteSize(); // Force size to be cached. - SerializeWithCachedSizes(output); - return !output->HadError(); + 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( @@ -243,7 +280,9 @@ bool MessageLite::AppendPartialToString(string* output) const { STLStringResizeUninitialized(output, old_size + byte_size); uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size); uint8* end = SerializeWithCachedSizesToArray(start); - GOOGLE_CHECK_EQ(end - start, byte_size); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } @@ -265,9 +304,11 @@ bool MessageLite::SerializeToArray(void* data, int size) const { bool MessageLite::SerializePartialToArray(void* data, int size) const { int byte_size = ByteSize(); if (size < byte_size) return false; - uint8* end = - SerializeWithCachedSizesToArray(reinterpret_cast<uint8*>(data)); - GOOGLE_CHECK_EQ(end, reinterpret_cast<uint8*>(data) + byte_size); + uint8* start = reinterpret_cast<uint8*>(data); + uint8* end = SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index 46e6844..33b9e77 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -43,6 +43,7 @@ #include <unistd.h> #endif #include <sstream> +#include <fstream> #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -77,9 +78,9 @@ TEST(MessageTest, SerializeHelpers) { string str1("foo"); string str2("bar"); - message.SerializeToString(&str1); - message.AppendToString(&str2); - message.SerializeToOstream(&stream); + EXPECT_TRUE(message.SerializeToString(&str1)); + EXPECT_TRUE(message.AppendToString(&str2)); + EXPECT_TRUE(message.SerializeToOstream(&stream)); EXPECT_EQ(str1.size() + 3, str2.size()); EXPECT_EQ("bar", str2.substr(0, 3)); @@ -95,6 +96,14 @@ TEST(MessageTest, SerializeHelpers) { } +TEST(MessageTest, SerializeToBrokenOstream) { + ofstream out; + protobuf_unittest::TestAllTypes message; + message.set_optional_int32(123); + + EXPECT_FALSE(message.SerializeToOstream(&out)); +} + TEST(MessageTest, ParseFromFileDescriptor) { string filename = TestSourceDir() + "/google/protobuf/testdata/golden_message"; diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 3230c04..f7beb11 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -39,6 +39,18 @@ 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_; diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 43c9f3f..defdefe 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -51,8 +51,8 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/message_lite.h> - namespace google { + namespace protobuf { class Message; @@ -76,10 +76,11 @@ class RepeatedField { int size() const; - Element Get(int index) const; + const Element& Get(int index) const; Element* Mutable(int index); - void Set(int index, Element value); - void Add(Element value); + void Set(int index, const Element& value); + void Add(const Element& value); + Element* Add(); // Remove the last element in the array. // 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 @@ -94,6 +95,13 @@ class RepeatedField { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + // Resize the RepeatedField to a new, smaller size. This is O(1). + void Truncate(int new_size); + + void AddAlreadyReserved(const Element& value); + Element* AddAlreadyReserved(); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element* mutable_data(); @@ -128,10 +136,19 @@ class RepeatedField { int total_size_; Element initial_space_[kInitialSize]; + + // Move the contents of |from| into |to|, possibly clobbering |from| in the + // process. For primitive types this is just a memcpy(), but it could be + // specialized for non-primitive types to, say, swap each element instead. + void MoveArray(Element to[], Element from[], int size); + + // Copy the elements of |from| into |to|. + void CopyArray(Element to[], const Element from[], int size); }; namespace internal { template <typename It> class RepeatedPtrIterator; +template <typename It> class RepeatedPtrOverPtrsIterator; } // namespace internal namespace internal { @@ -189,8 +206,11 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { void Reserve(int new_size); + int Capacity() const; + // Used for constructing iterators. void* const* raw_data() const; + void** raw_mutable_data() const; template <typename TypeHandler> typename TypeHandler::Type** mutable_data(); @@ -204,6 +224,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template <typename TypeHandler> int SpaceUsedExcludingSelf() const; + // Advanced memory management -------------------------------------- // Like Add(), but if there are no cleared objects to use, returns NULL. @@ -215,7 +236,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template <typename TypeHandler> typename TypeHandler::Type* ReleaseLast(); - int ClearedCount(); + int ClearedCount() const; template <typename TypeHandler> void AddCleared(typename TypeHandler::Type* value); template <typename TypeHandler> @@ -286,6 +307,7 @@ class StringTypeHandler : public StringTypeHandlerBase { } }; + } // namespace internal // RepeatedPtrField is like RepeatedField, but used for repeated strings or @@ -311,6 +333,8 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element** mutable_data(); @@ -331,6 +355,12 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { iterator end(); const_iterator end() const; + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator<Element> pointer_iterator; + pointer_iterator pointer_begin(); + pointer_iterator pointer_end(); + // Returns (an estimate of) the number of bytes used by the repeated field, // excluding sizeof(*this). int SpaceUsedExcludingSelf() const; @@ -363,7 +393,7 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Get the number of cleared objects that are currently being kept // around for reuse. - int ClearedCount(); + int ClearedCount() const; // Add an element to the pool of cleared objects, passing ownership to // the RepeatedPtrField. The element must be cleared prior to calling // this method. @@ -373,16 +403,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Requires: ClearedCount() > 0 Element* ReleaseCleared(); - private: + protected: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only + // subclass it in one place as a hack for compatibility with proto1. The + // subclass needs to know about TypeHandler in order to call protected + // methods on RepeatedPtrFieldBase. class TypeHandler; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); - // prototype_ is used for RepeatedPtrField<Message> and - // RepeatedPtrField<MessageLite> only (see constructor). - // TODO(kenton): Can we use some template magic to avoid wasting space on - // this field when it isn't used? - const Element* prototype_; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); }; // implementation ==================================================== @@ -406,9 +436,25 @@ inline int RepeatedField<Element>::size() const { return current_size_; } +template <typename Element> +inline int RepeatedField<Element>::Capacity() const { + return total_size_; +} + +template<typename Element> +inline void RepeatedField<Element>::AddAlreadyReserved(const Element& value) { + GOOGLE_DCHECK_LT(size(), Capacity()); + elements_[current_size_++] = value; +} + +template<typename Element> +inline Element* RepeatedField<Element>::AddAlreadyReserved() { + GOOGLE_DCHECK_LT(size(), Capacity()); + return &elements_[current_size_++]; +} template <typename Element> -inline Element RepeatedField<Element>::Get(int index) const { +inline const Element& RepeatedField<Element>::Get(int index) const { GOOGLE_DCHECK_LT(index, size()); return elements_[index]; } @@ -420,18 +466,24 @@ inline Element* RepeatedField<Element>::Mutable(int index) { } template <typename Element> -inline void RepeatedField<Element>::Set(int index, Element value) { +inline void RepeatedField<Element>::Set(int index, const Element& value) { GOOGLE_DCHECK_LT(index, size()); elements_[index] = value; } template <typename Element> -inline void RepeatedField<Element>::Add(Element value) { +inline void RepeatedField<Element>::Add(const Element& value) { if (current_size_ == total_size_) Reserve(total_size_ + 1); elements_[current_size_++] = value; } template <typename Element> +inline Element* RepeatedField<Element>::Add() { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + return &elements_[current_size_++]; +} + +template <typename Element> inline void RepeatedField<Element>::RemoveLast() { GOOGLE_DCHECK_GT(current_size_, 0); --current_size_; @@ -443,10 +495,9 @@ inline void RepeatedField<Element>::Clear() { } template <typename Element> -void RepeatedField<Element>::MergeFrom(const RepeatedField& other) { +inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) { Reserve(current_size_ + other.current_size_); - memcpy(elements_ + current_size_, other.elements_, - sizeof(Element) * other.current_size_); + CopyArray(elements_ + current_size_, other.elements_, other.current_size_); current_size_ += other.current_size_; } @@ -469,17 +520,17 @@ void RepeatedField<Element>::Swap(RepeatedField* other) { // We may not be using initial_space_ but it's not worth checking. Just // copy it anyway. Element swap_initial_space[kInitialSize]; - memcpy(swap_initial_space, initial_space_, sizeof(initial_space_)); + MoveArray(swap_initial_space, initial_space_, kInitialSize); elements_ = other->elements_; current_size_ = other->current_size_; total_size_ = other->total_size_; - memcpy(initial_space_, other->initial_space_, sizeof(initial_space_)); + MoveArray(initial_space_, other->initial_space_, kInitialSize); other->elements_ = swap_elements; other->current_size_ = swap_current_size; other->total_size_ = swap_total_size; - memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space)); + MoveArray(other->initial_space_, swap_initial_space, kInitialSize); if (elements_ == other->initial_space_) { elements_ = initial_space_; @@ -491,7 +542,7 @@ void RepeatedField<Element>::Swap(RepeatedField* other) { template <typename Element> void RepeatedField<Element>::SwapElements(int index1, int index2) { - swap(elements_[index1], elements_[index2]); + std::swap(elements_[index1], elements_[index2]); } template <typename Element> @@ -520,19 +571,40 @@ inline int RepeatedField<Element>::SpaceUsedExcludingSelf() const { return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0; } +// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant +// amount of code bloat. template <typename Element> -inline void RepeatedField<Element>::Reserve(int new_size) { +void RepeatedField<Element>::Reserve(int new_size) { if (total_size_ >= new_size) return; Element* old_elements = elements_; total_size_ = max(total_size_ * 2, new_size); elements_ = new Element[total_size_]; - memcpy(elements_, old_elements, current_size_ * sizeof(elements_[0])); + MoveArray(elements_, old_elements, current_size_); if (old_elements != initial_space_) { delete [] old_elements; } } +template <typename Element> +inline void RepeatedField<Element>::Truncate(int new_size) { + GOOGLE_DCHECK_LE(new_size, current_size_); + current_size_ = new_size; +} + +template <typename Element> +inline void RepeatedField<Element>::MoveArray( + Element to[], Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + +template <typename Element> +inline void RepeatedField<Element>::CopyArray( + Element to[], const Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + + // ------------------------------------------------------------------- namespace internal { @@ -600,17 +672,25 @@ void RepeatedPtrFieldBase::Clear() { } template <typename TypeHandler> -void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { Reserve(current_size_ + other.current_size_); for (int i = 0; i < other.current_size_; i++) { TypeHandler::Merge(other.Get<TypeHandler>(i), Add<TypeHandler>()); } } +inline int RepeatedPtrFieldBase::Capacity() const { + return total_size_; +} + inline void* const* RepeatedPtrFieldBase::raw_data() const { return elements_; } +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return elements_; +} + template <typename TypeHandler> inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this @@ -627,7 +707,7 @@ RepeatedPtrFieldBase::data() const { } inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { - swap(elements_[index1], elements_[index2]); + std::swap(elements_[index1], elements_[index2]); } template <typename TypeHandler> @@ -650,15 +730,29 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { } template <typename TypeHandler> -inline void RepeatedPtrFieldBase::AddAllocated( +void RepeatedPtrFieldBase::AddAllocated( typename TypeHandler::Type* value) { - if (allocated_size_ == total_size_) Reserve(total_size_ + 1); - // We don't care about the order of cleared elements, so if there's one - // in the way, just move it to the back of the array. - if (current_size_ < allocated_size_) { + // Make room for the new pointer. + if (current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++allocated_size_; + } else if (allocated_size_ == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast<TypeHandler>(elements_[current_size_])); + } else if (current_size_ < allocated_size_) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. elements_[allocated_size_] = elements_[current_size_]; + ++allocated_size_; + } else { + // There are no cleared objects. + ++allocated_size_; } - ++allocated_size_; + elements_[current_size_++] = value; } @@ -677,7 +771,7 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { } -inline int RepeatedPtrFieldBase::ClearedCount() { +inline int RepeatedPtrFieldBase::ClearedCount() const { return allocated_size_ - current_size_; } @@ -694,18 +788,6 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { return cast<TypeHandler>(elements_[--allocated_size_]); } -inline 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; - } -} - } // namespace internal // ------------------------------------------------------------------- @@ -720,9 +802,7 @@ class RepeatedPtrField<string>::TypeHandler template <typename Element> -inline RepeatedPtrField<Element>::RepeatedPtrField() - : prototype_(NULL) { -} +inline RepeatedPtrField<Element>::RepeatedPtrField() {} template <typename Element> RepeatedPtrField<Element>::~RepeatedPtrField() { @@ -802,7 +882,7 @@ inline Element* RepeatedPtrField<Element>::ReleaseLast() { template <typename Element> -inline int RepeatedPtrField<Element>::ClearedCount() { +inline int RepeatedPtrField<Element>::ClearedCount() const { return RepeatedPtrFieldBase::ClearedCount(); } @@ -821,6 +901,11 @@ inline void RepeatedPtrField<Element>::Reserve(int new_size) { return RepeatedPtrFieldBase::Reserve(new_size); } +template <typename Element> +inline int RepeatedPtrField<Element>::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + // ------------------------------------------------------------------- namespace internal { @@ -921,6 +1006,84 @@ class RepeatedPtrIterator void* const* it_; }; +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +template<typename Element> +class RepeatedPtrOverPtrsIterator + : public std::iterator<std::random_access_iterator_tag, Element*> { + public: + typedef RepeatedPtrOverPtrsIterator<Element> iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element*> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrOverPtrsIterator() : it_(NULL) {} + explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast<Element**>(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template<typename OtherElement> + friend class RepeatedPtrIterator; + + // The internal iterator. + void** it_; +}; + + } // namespace internal template <typename Element> @@ -944,6 +1107,18 @@ RepeatedPtrField<Element>::end() const { return iterator(raw_data() + size()); } +template <typename Element> +inline typename RepeatedPtrField<Element>::pointer_iterator +RepeatedPtrField<Element>::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template <typename Element> +inline typename RepeatedPtrField<Element>::pointer_iterator +RepeatedPtrField<Element>::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} + + // Iterators and helper functions that follow the spirit of the STL // std::back_insert_iterator and std::back_inserter but are tailor-made // for RepeatedField and RepatedPtrField. Typical usage would be: diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 50f009b..7c35f60 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -37,6 +37,7 @@ #include <algorithm> #include <list> +#include <vector> #include <google/protobuf/repeated_field.h> @@ -241,6 +242,31 @@ TEST(RepeatedField, MutableDataIsMutable) { EXPECT_EQ(2, field.Get(0)); } +TEST(RepeatedField, Truncate) { + RepeatedField<int> field; + + field.Add(12); + field.Add(34); + field.Add(56); + field.Add(78); + EXPECT_EQ(4, field.size()); + + field.Truncate(3); + EXPECT_EQ(3, field.size()); + + field.Add(90); + EXPECT_EQ(4, field.size()); + EXPECT_EQ(90, field.Get(3)); + + // Truncations that don't change the size are allowed, but growing is not + // allowed. + field.Truncate(field.size()); +#ifdef GTEST_HAS_DEATH_TEST + EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size"); +#endif +} + + // =================================================================== // RepeatedPtrField tests. These pretty much just mirror the RepeatedField // tests above. @@ -443,6 +469,52 @@ TEST(RepeatedPtrField, ClearedElements) { EXPECT_EQ(field.ClearedCount(), 0); } +// Test all code paths in AddAllocated(). +TEST(RepeatedPtrField, AddAlocated) { + RepeatedPtrField<string> field; + while (field.size() < field.Capacity()) { + field.Add()->assign("filler"); + } + + int index = field.size(); + + // First branch: Field is at capacity with no cleared objects. + string* foo = new string("foo"); + field.AddAllocated(foo); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(foo, &field.Get(index)); + + // Last branch: Field is not at capacity and there are no cleared objects. + string* bar = new string("bar"); + field.AddAllocated(bar); + ++index; + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(bar, &field.Get(index)); + + // Third branch: Field is not at capacity and there are no cleared objects. + field.RemoveLast(); + string* baz = new string("baz"); + field.AddAllocated(baz); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(1, field.ClearedCount()); + EXPECT_EQ(baz, &field.Get(index)); + + // Second branch: Field is at capacity but has some cleared objects. + while (field.size() < field.Capacity()) { + field.Add()->assign("filler2"); + } + field.RemoveLast(); + index = field.size(); + string* qux = new string("qux"); + field.AddAllocated(qux); + EXPECT_EQ(index + 1, field.size()); + // We should have discarded the cleared object. + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(qux, &field.Get(index)); +} + TEST(RepeatedPtrField, MergeFrom) { RepeatedPtrField<string> source, destination; @@ -592,7 +664,6 @@ TEST_F(RepeatedPtrFieldIteratorTest, Comparable) { } // Uninitialized iterator does not point to any of the RepeatedPtrField. -// Dereferencing an uninitialized iterator crashes the process. TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) { RepeatedPtrField<string>::iterator iter; EXPECT_TRUE(iter != proto_array_.begin()); @@ -600,9 +671,6 @@ TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) { EXPECT_TRUE(iter != proto_array_.begin() + 2); EXPECT_TRUE(iter != proto_array_.begin() + 3); EXPECT_TRUE(iter != proto_array_.end()); -#ifdef GTEST_HAS_DEATH_TEST - ASSERT_DEATH(GOOGLE_LOG(INFO) << *iter, ""); -#endif } TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) { @@ -618,6 +686,7 @@ TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) { string v = "f"; RepeatedPtrField<string>::const_iterator it = lower_bound(proto_array_.begin(), proto_array_.end(), v); + EXPECT_EQ(*it, "n"); EXPECT_TRUE(it == proto_array_.begin() + 3); } @@ -628,6 +697,149 @@ TEST_F(RepeatedPtrFieldIteratorTest, Mutation) { EXPECT_EQ("qux", proto_array_.Get(0)); } +// ------------------------------------------------------------------- + +class RepeatedPtrFieldPtrsIteratorTest : public testing::Test { + protected: + virtual void SetUp() { + proto_array_.Add()->assign("foo"); + proto_array_.Add()->assign("bar"); + proto_array_.Add()->assign("baz"); + } + + RepeatedPtrField<string> proto_array_; +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) { + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) { + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); + EXPECT_EQ("foo", **iter); + ++iter; + EXPECT_EQ("bar", **(iter++)); + EXPECT_EQ("baz", **iter); + ++iter; + EXPECT_TRUE(proto_array_.pointer_end() == iter); + EXPECT_EQ("baz", **(--proto_array_.pointer_end())); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) { + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField<string>::pointer_iterator iter2 = iter; + ++iter2; + ++iter2; + EXPECT_TRUE(iter + 2 == iter2); + EXPECT_TRUE(iter == iter2 - 2); + EXPECT_EQ("baz", *iter[2]); + EXPECT_EQ("baz", **(iter + 2)); + EXPECT_EQ(3, proto_array_.end() - proto_array_.begin()); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) { + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField<string>::pointer_iterator iter2 = iter + 1; + EXPECT_TRUE(iter == iter); + EXPECT_TRUE(iter != iter2); + EXPECT_TRUE(iter < iter2); + EXPECT_TRUE(iter <= iter2); + EXPECT_TRUE(iter <= iter); + EXPECT_TRUE(iter2 > iter); + EXPECT_TRUE(iter2 >= iter); + EXPECT_TRUE(iter >= iter); +} + +// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs. +// Dereferencing an uninitialized iterator crashes the process. +TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) { + RepeatedPtrField<string>::pointer_iterator iter; + EXPECT_TRUE(iter != proto_array_.pointer_begin()); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 1); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 2); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 3); + EXPECT_TRUE(iter != proto_array_.pointer_end()); +} + + +// This comparison functor is required by the tests for RepeatedPtrOverPtrs. +// They operate on strings and need to compare strings as strings in +// any stl algorithm, even though the iterator returns a pointer to a string +// - i.e. *iter has type string*. +struct StringLessThan { + bool operator()(const string* z, const string& y) { + return *z < y; + } + bool operator()(const string* z, const string* y) { + return *z < *y; + } +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) { + proto_array_.Clear(); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("x"); + proto_array_.Add()->assign("y"); + + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); + string v = "f"; + RepeatedPtrField<string>::pointer_iterator it = + lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(), + &v, StringLessThan()); + + GOOGLE_CHECK(*it != NULL); + + EXPECT_EQ(**it, "n"); + EXPECT_TRUE(it == proto_array_.pointer_begin() + 3); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) { + RepeatedPtrField<string>::pointer_iterator iter = + proto_array_.pointer_begin(); + **iter = "qux"; + EXPECT_EQ("qux", proto_array_.Get(0)); + + EXPECT_EQ("bar", proto_array_.Get(1)); + EXPECT_EQ("baz", proto_array_.Get(2)); + ++iter; + delete *iter; + *iter = new string("a"); + ++iter; + delete *iter; + *iter = new string("b"); + EXPECT_EQ("a", proto_array_.Get(1)); + EXPECT_EQ("b", proto_array_.Get(2)); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) { + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("y"); + proto_array_.Add()->assign("x"); + EXPECT_EQ("foo", proto_array_.Get(0)); + EXPECT_EQ("n", proto_array_.Get(5)); + EXPECT_EQ("x", proto_array_.Get(9)); + sort(proto_array_.pointer_begin(), + proto_array_.pointer_end(), + StringLessThan()); + EXPECT_EQ("a", proto_array_.Get(0)); + EXPECT_EQ("baz", proto_array_.Get(2)); + EXPECT_EQ("y", proto_array_.Get(9)); +} + + // ----------------------------------------------------------------------------- // Unit-tests for the insert iterators // google::protobuf::RepeatedFieldBackInserter, diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h index 83f5f38..a6a7d16 100644 --- a/src/google/protobuf/service.h +++ b/src/google/protobuf/service.h @@ -32,10 +32,14 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // -// This module declares the abstract interfaces underlying proto2 RPC -// services. These are intented to be independent of any particular RPC +// 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. +// 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 diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 964fb6a..551ee4a 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -83,24 +83,24 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 2002000 +#define GOOGLE_PROTOBUF_VERSION 2003000 // The minimum library version which works with the current version of the // headers. -#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2002000 +#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2003000 // The minimum header version which works with the current version of // the library. This constant should only be used by protoc's C++ code // generator. -static const int kMinHeaderVersionForLibrary = 2002000; +static const int kMinHeaderVersionForLibrary = 2003000; // The minimum protoc version which works with the current version of the // headers. -#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2002000 +#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2003000 // The minimum header version which works with the current version of // protoc. This constant should only be used in VerifyVersion(). -static const int kMinHeaderVersionForProtoc = 2002000; +static const int kMinHeaderVersionForProtoc = 2003000; // Verifies that the headers and libraries are compatible. Use the macro // below to call this. @@ -171,7 +171,13 @@ static const int64 kint64min = -kint64max - 1; static const uint32 kuint32max = 0xFFFFFFFFu; static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); -#undef GOOGLE_ATTRIBUTE_ALWAYS_INLINE +// ------------------------------------------------------------------- +// Annotations: Some parts of the code have been annotated in ways that might +// be useful to some compilers or tools, but are not supported universally. +// You can #define these annotations yourself if the default implementation +// is not right for you. + +#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE #if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) // For functions we want to force inline. // Introduced in gcc 3.1. @@ -180,14 +186,35 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); // Other compilers will have to figure it out for themselves. #define GOOGLE_ATTRIBUTE_ALWAYS_INLINE #endif +#endif -#undef GOOGLE_ATTRIBUTE_DEPRECATED +#ifndef GOOGLE_ATTRIBUTE_DEPRECATED #ifdef __GNUC__ // If the method/variable/type is used anywhere, produce a warning. #define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) #else #define GOOGLE_ATTRIBUTE_DEPRECATED #endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE +#endif +#endif + +// Delimits a block of code which may write to memory which is simultaneously +// written by other threads, but which has been determined to be thread-safe +// (e.g. because it is an idempotent write). +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN +#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN() +#endif +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END +#define GOOGLE_SAFE_CONCURRENT_WRITES_END() +#endif // =================================================================== // from google3/base/basictypes.h @@ -283,7 +310,9 @@ inline To down_cast(From* f) { // so we only accept pointers implicit_cast<From*, To>(0); } +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only! +#endif return static_cast<To>(f); } diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index c341413..822d605 100644 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -98,7 +98,7 @@ template <typename Key, class hash_set : public std::set<Key, HashFcn> { }; -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) template <typename Key> struct hash : public HASH_NAMESPACE::hash_compare<Key> { @@ -145,21 +145,30 @@ struct hash<const 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*> : public HASH_NAMESPACE::hash<const char*> { +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 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 hash_set : public HASH_NAMESPACE::HASH_SET_CLASS< Key, HashFcn, EqualKey> { }; diff --git a/src/google/protobuf/stubs/once.cc b/src/google/protobuf/stubs/once.cc index 3c53bcd..5b7af9c 100644 --- a/src/google/protobuf/stubs/once.cc +++ b/src/google/protobuf/stubs/once.cc @@ -46,33 +46,33 @@ namespace protobuf { #ifdef _WIN32 -struct GoogleOnceInternal { - GoogleOnceInternal() { +struct ProtobufOnceInternal { + ProtobufOnceInternal() { InitializeCriticalSection(&critical_section); } - ~GoogleOnceInternal() { + ~ProtobufOnceInternal() { DeleteCriticalSection(&critical_section); } CRITICAL_SECTION critical_section; }; -GoogleOnceType::~GoogleOnceType() +ProtobufOnceType::~ProtobufOnceType() { delete internal_; internal_ = NULL; } -GoogleOnceType::GoogleOnceType() { +ProtobufOnceType::ProtobufOnceType() { // internal_ may be non-NULL if Init() was already called. - if (internal_ == NULL) internal_ = new GoogleOnceInternal; + if (internal_ == NULL) internal_ = new ProtobufOnceInternal; } -void GoogleOnceType::Init(void (*init_func)()) { +void ProtobufOnceType::Init(void (*init_func)()) { // internal_ may be NULL if we're still in dynamic initialization and the // constructor has not been called yet. As mentioned in once.h, we assume // that the program is still single-threaded at this time, and therefore it // should be safe to initialize internal_ like so. - if (internal_ == NULL) internal_ = new GoogleOnceInternal; + if (internal_ == NULL) internal_ = new ProtobufOnceInternal; EnterCriticalSection(&internal_->critical_section); if (!initialized_) { diff --git a/src/google/protobuf/stubs/once.h b/src/google/protobuf/stubs/once.h index 22b0d4e..0dee407 100644 --- a/src/google/protobuf/stubs/once.h +++ b/src/google/protobuf/stubs/once.h @@ -38,13 +38,13 @@ // This is basically a portable version of pthread_once(). // // This header declares three things: -// * A type called GoogleOnceType. +// * A type called ProtobufOnceType. // * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type -// GoogleOnceType. This is the only legal way to declare such a variable. +// ProtobufOnceType. This is the only legal way to declare such a variable. // The macro may only be used at the global scope (you cannot create local // or class member variables of this type). -// * A function GogoleOnceInit(GoogleOnceType* once, void (*init_func)()). -// This function, when invoked multiple times given the same GoogleOnceType +// * A function GogoleOnceInit(ProtobufOnceType* once, void (*init_func)()). +// This function, when invoked multiple times given the same ProtobufOnceType // object, will invoke init_func on the first call only, and will make sure // none of the calls return before that first call to init_func has finished. // @@ -83,21 +83,21 @@ namespace protobuf { #ifdef _WIN32 -struct GoogleOnceInternal; +struct ProtobufOnceInternal; -struct LIBPROTOBUF_EXPORT GoogleOnceType { - GoogleOnceType(); - ~GoogleOnceType(); +struct LIBPROTOBUF_EXPORT ProtobufOnceType { + ProtobufOnceType(); + ~ProtobufOnceType(); void Init(void (*init_func)()); volatile bool initialized_; - GoogleOnceInternal* internal_; + ProtobufOnceInternal* internal_; }; #define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ - ::google::protobuf::GoogleOnceType NAME + ::google::protobuf::ProtobufOnceType NAME -inline void GoogleOnceInit(GoogleOnceType* once, void (*init_func)()) { +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { // Note: Double-checked locking is safe on x86. if (!once->initialized_) { once->Init(init_func); @@ -106,12 +106,12 @@ inline void GoogleOnceInit(GoogleOnceType* once, void (*init_func)()) { #else -typedef pthread_once_t GoogleOnceType; +typedef pthread_once_t ProtobufOnceType; #define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ pthread_once_t NAME = PTHREAD_ONCE_INIT -inline void GoogleOnceInit(GoogleOnceType* once, void (*init_func)()) { +inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { pthread_once(once, init_func); } diff --git a/src/google/protobuf/stubs/once_unittest.cc b/src/google/protobuf/stubs/once_unittest.cc index 86e0647..b8f86a0 100644 --- a/src/google/protobuf/stubs/once_unittest.cc +++ b/src/google/protobuf/stubs/once_unittest.cc @@ -52,10 +52,10 @@ class OnceInitTest : public testing::Test { current_test_ = this; } - // Since GoogleOnceType is only allowed to be allocated in static storage, - // each test must use a different pair of GoogleOnceType objects which it + // Since ProtobufOnceType is only allowed to be allocated in static storage, + // each test must use a different pair of ProtobufOnceType objects which it // must declare itself. - void SetOnces(GoogleOnceType* once, GoogleOnceType* recursive_once) { + void SetOnces(ProtobufOnceType* once, ProtobufOnceType* recursive_once) { once_ = once; recursive_once_ = recursive_once; } @@ -155,8 +155,8 @@ class OnceInitTest : public testing::Test { Mutex mutex_; Mutex init_blocker_; State state_; - GoogleOnceType* once_; - GoogleOnceType* recursive_once_; + ProtobufOnceType* once_; + ProtobufOnceType* recursive_once_; void Init() { MutexLock lock(&mutex_); diff --git a/src/google/protobuf/stubs/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc index e385a81..0f6afe6 100644 --- a/src/google/protobuf/stubs/structurally_valid.cc +++ b/src/google/protobuf/stubs/structurally_valid.cc @@ -371,36 +371,44 @@ int UTF8GenericScan(const UTF8ScanObj* st, // Do state-table scan int e = 0; uint8 c; - - // Do fast for groups of 8 identity bytes. - // This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop, - // including slowing slightly on cr/lf/ht - //---------------------------- const uint8* Tbl2 = &st->fast_state[0]; - uint32 losub = st->losub; - uint32 hiadd = st->hiadd; - while (src < srclimit8) { - uint32 s0123 = (reinterpret_cast<const uint32 *>(src))[0]; - uint32 s4567 = (reinterpret_cast<const uint32 *>(src))[1]; - src += 8; - // This is a fast range check for all bytes in [lowsub..0x80-hiadd) - uint32 temp = (s0123 - losub) | (s0123 + hiadd) | - (s4567 - losub) | (s4567 + hiadd); - if ((temp & 0x80808080) != 0) { - // We typically end up here on cr/lf/ht; src was incremented - int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) | - (Tbl2[src[-6]] | Tbl2[src[-5]]); - if (e0123 != 0) { - src -= 8; - break; - } // Exit on Non-interchange - e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) | - (Tbl2[src[-2]] | Tbl2[src[-1]]); - if (e0123 != 0) { - src -= 4; - break; - } // Exit on Non-interchange - // Else OK, go around again + const uint32 losub = st->losub; + const uint32 hiadd = st->hiadd; + // Check initial few bytes one at a time until 8-byte aligned + //---------------------------- + while ((((uintptr_t)src & 0x07) != 0) && + (src < srclimit) && + Tbl2[src[0]] == 0) { + src++; + } + if (((uintptr_t)src & 0x07) == 0) { + // Do fast for groups of 8 identity bytes. + // This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop, + // including slowing slightly on cr/lf/ht + //---------------------------- + while (src < srclimit8) { + uint32 s0123 = (reinterpret_cast<const uint32 *>(src))[0]; + uint32 s4567 = (reinterpret_cast<const uint32 *>(src))[1]; + src += 8; + // This is a fast range check for all bytes in [lowsub..0x80-hiadd) + uint32 temp = (s0123 - losub) | (s0123 + hiadd) | + (s4567 - losub) | (s4567 + hiadd); + if ((temp & 0x80808080) != 0) { + // We typically end up here on cr/lf/ht; src was incremented + int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) | + (Tbl2[src[-6]] | Tbl2[src[-5]]); + if (e0123 != 0) { + src -= 8; + break; + } // Exit on Non-interchange + e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) | + (Tbl2[src[-2]] | Tbl2[src[-1]]); + if (e0123 != 0) { + src -= 4; + break; + } // Exit on Non-interchange + // Else OK, go around again + } } } //---------------------------- @@ -470,10 +478,17 @@ int UTF8GenericScanFastAscii(const UTF8ScanObj* st, int rest_consumed; int exit_reason; do { - while ((src < srclimit8) && - (((reinterpret_cast<const uint32*>(src)[0] | - reinterpret_cast<const uint32*>(src)[1]) & 0x80808080) == 0)) { - src += 8; + // Check initial few bytes one at a time until 8-byte aligned + while ((((uintptr_t)src & 0x07) != 0) && + (src < srclimit) && (src[0] < 0x80)) { + src++; + } + if (((uintptr_t)src & 0x07) == 0) { + while ((src < srclimit8) && + (((reinterpret_cast<const uint32*>(src)[0] | + reinterpret_cast<const uint32*>(src)[1]) & 0x80808080) == 0)) { + src += 8; + } } while ((src < srclimit) && (src[0] < 0x80)) { src++; diff --git a/src/google/protobuf/stubs/structurally_valid_unittest.cc b/src/google/protobuf/stubs/structurally_valid_unittest.cc index 2282551..9088888 100644 --- a/src/google/protobuf/stubs/structurally_valid_unittest.cc +++ b/src/google/protobuf/stubs/structurally_valid_unittest.cc @@ -13,15 +13,25 @@ TEST(StructurallyValidTest, ValidUTF8String) { // On GCC, this string can be written as: // "abcd 1234 - \u2014\u2013\u2212" // MSVC seems to interpret \u differently. - string valid_str("abcd 1234 - \342\200\224\342\200\223\342\210\222"); + string valid_str("abcd 1234 - \342\200\224\342\200\223\342\210\222 - xyz789"); EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data(), valid_str.size())); + // Additional check for pointer alignment + for (int i = 1; i < 8; ++i) { + EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data() + i, + valid_str.size() - i)); + } } TEST(StructurallyValidTest, InvalidUTF8String) { - string invalid_str("\xA0\xB0"); + const string invalid_str("abcd\xA0\xB0\xA0\xB0\xA0\xB0 - xyz789"); EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data(), invalid_str.size())); + // Additional check for pointer alignment + for (int i = 1; i < 8; ++i) { + EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data() + i, + invalid_str.size() - i)); + } } } // namespace diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index a476475..bb658ba 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -36,6 +36,7 @@ #include <limits> #include <limits.h> #include <stdio.h> +#include <iterator> #ifdef _WIN32 // MSVC has only _snprintf, not snprintf. @@ -424,8 +425,8 @@ string UnescapeCEscapeString(const string& src) { // // Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. // ---------------------------------------------------------------------- -static int CEscapeInternal(const char* src, int src_len, char* dest, - int dest_len, bool use_hex) { +int CEscapeInternal(const char* src, int src_len, char* dest, + int dest_len, bool use_hex, bool utf8_safe) { const char* src_end = src + src_len; int used = 0; bool last_hex_escape = false; // true if last output char was \xNN @@ -446,7 +447,9 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, // Note that if we emit \xNN and the src character after that is a hex // digit then that digit must be escaped too to prevent it being // interpreted as part of the character code by C. - if (!isprint(*src) || (last_hex_escape && isxdigit(*src))) { + if ((!utf8_safe || static_cast<uint8>(*src) < 0x80) && + (!isprint(*src) || + (last_hex_escape && isxdigit(*src)))) { if (dest_len - used < 4) // need space for 4 letter escape return -1; sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"), @@ -468,7 +471,7 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, } int CEscapeString(const char* src, int src_len, char* dest, int dest_len) { - return CEscapeInternal(src, src_len, dest, dest_len, false); + return CEscapeInternal(src, src_len, dest, dest_len, false, false); } // ---------------------------------------------------------------------- @@ -485,11 +488,33 @@ string CEscape(const string& src) { const int dest_length = src.size() * 4 + 1; // Maximum possible expansion scoped_array<char> dest(new char[dest_length]); const int len = CEscapeInternal(src.data(), src.size(), - dest.get(), dest_length, false); + dest.get(), dest_length, false, false); GOOGLE_DCHECK_GE(len, 0); return string(dest.get(), len); } +namespace strings { + +string Utf8SafeCEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array<char> dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, false, true); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +string CHexEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array<char> dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, true, false); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +} // namespace strings + // ---------------------------------------------------------------------- // strto32_adaptor() // strtou32_adaptor() @@ -1027,7 +1052,7 @@ char* DoubleToBuffer(double value, char* buffer) { bool safe_strtof(const char* str, float* value) { char* endptr; errno = 0; // errno only gets set on errors -#ifdef _WIN32 // has no strtof() +#if defined(_WIN32) || defined (__hpux) // has no strtof() *value = strtod(str, &endptr); #else *value = strtof(str, &endptr); diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 7f6bd96..777694b 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -33,6 +33,7 @@ #ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ #define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__ +#include <stdlib.h> #include <vector> #include <google/protobuf/stubs/common.h> @@ -264,6 +265,14 @@ LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len, // ---------------------------------------------------------------------- LIBPROTOBUF_EXPORT string CEscape(const string& src); +namespace strings { +// Like CEscape() but does not escape bytes with the upper bit set. +LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src); + +// Like CEscape() but uses hex (\x) escapes instead of octals. +LIBPROTOBUF_EXPORT string CHexEscape(const string& src); +} // namespace strings + // ---------------------------------------------------------------------- // strto32() // strtou32() diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 0637c0a..af8b390 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -229,11 +229,11 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) { message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_string_piece"), - 1, "424"); + 1, "524"); message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_cord"), - 1, "425"); + 1, "525"); #endif // !PROTOBUF_TEST_NO_DESCRIPTORS } @@ -692,6 +692,40 @@ void TestUtil::SetPackedFields(unittest::TestPackedTypes* message) { message->add_packed_enum (unittest::FOREIGN_BAZ); } +void TestUtil::SetUnpackedFields(unittest::TestUnpackedTypes* message) { + // The values applied here must match those of SetPackedFields. + + message->add_unpacked_int32 (601); + message->add_unpacked_int64 (602); + message->add_unpacked_uint32 (603); + message->add_unpacked_uint64 (604); + message->add_unpacked_sint32 (605); + message->add_unpacked_sint64 (606); + message->add_unpacked_fixed32 (607); + message->add_unpacked_fixed64 (608); + message->add_unpacked_sfixed32(609); + message->add_unpacked_sfixed64(610); + message->add_unpacked_float (611); + message->add_unpacked_double (612); + message->add_unpacked_bool (true); + message->add_unpacked_enum (unittest::FOREIGN_BAR); + // add a second one of each field + message->add_unpacked_int32 (701); + message->add_unpacked_int64 (702); + message->add_unpacked_uint32 (703); + message->add_unpacked_uint64 (704); + message->add_unpacked_sint32 (705); + message->add_unpacked_sint64 (706); + message->add_unpacked_fixed32 (707); + message->add_unpacked_fixed64 (708); + message->add_unpacked_sfixed32(709); + message->add_unpacked_sfixed64(710); + message->add_unpacked_float (711); + message->add_unpacked_double (712); + message->add_unpacked_bool (false); + message->add_unpacked_enum (unittest::FOREIGN_BAZ); +} + // ------------------------------------------------------------------- void TestUtil::ModifyPackedFields(unittest::TestPackedTypes* message) { @@ -760,6 +794,56 @@ void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) { EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1)); } +void TestUtil::ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message) { + // The values expected here must match those of ExpectPackedFieldsSet. + + ASSERT_EQ(2, message.unpacked_int32_size ()); + ASSERT_EQ(2, message.unpacked_int64_size ()); + ASSERT_EQ(2, message.unpacked_uint32_size ()); + ASSERT_EQ(2, message.unpacked_uint64_size ()); + ASSERT_EQ(2, message.unpacked_sint32_size ()); + ASSERT_EQ(2, message.unpacked_sint64_size ()); + ASSERT_EQ(2, message.unpacked_fixed32_size ()); + ASSERT_EQ(2, message.unpacked_fixed64_size ()); + ASSERT_EQ(2, message.unpacked_sfixed32_size()); + ASSERT_EQ(2, message.unpacked_sfixed64_size()); + ASSERT_EQ(2, message.unpacked_float_size ()); + ASSERT_EQ(2, message.unpacked_double_size ()); + ASSERT_EQ(2, message.unpacked_bool_size ()); + ASSERT_EQ(2, message.unpacked_enum_size ()); + + EXPECT_EQ(601 , message.unpacked_int32 (0)); + EXPECT_EQ(602 , message.unpacked_int64 (0)); + EXPECT_EQ(603 , message.unpacked_uint32 (0)); + EXPECT_EQ(604 , message.unpacked_uint64 (0)); + EXPECT_EQ(605 , message.unpacked_sint32 (0)); + EXPECT_EQ(606 , message.unpacked_sint64 (0)); + EXPECT_EQ(607 , message.unpacked_fixed32 (0)); + EXPECT_EQ(608 , message.unpacked_fixed64 (0)); + EXPECT_EQ(609 , message.unpacked_sfixed32(0)); + EXPECT_EQ(610 , message.unpacked_sfixed64(0)); + EXPECT_EQ(611 , message.unpacked_float (0)); + EXPECT_EQ(612 , message.unpacked_double (0)); + EXPECT_EQ(true , message.unpacked_bool (0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.unpacked_enum(0)); + + EXPECT_EQ(701 , message.unpacked_int32 (1)); + EXPECT_EQ(702 , message.unpacked_int64 (1)); + EXPECT_EQ(703 , message.unpacked_uint32 (1)); + EXPECT_EQ(704 , message.unpacked_uint64 (1)); + EXPECT_EQ(705 , message.unpacked_sint32 (1)); + EXPECT_EQ(706 , message.unpacked_sint64 (1)); + EXPECT_EQ(707 , message.unpacked_fixed32 (1)); + EXPECT_EQ(708 , message.unpacked_fixed64 (1)); + EXPECT_EQ(709 , message.unpacked_sfixed32(1)); + EXPECT_EQ(710 , message.unpacked_sfixed64(1)); + EXPECT_EQ(711 , message.unpacked_float (1)); + EXPECT_EQ(712 , message.unpacked_double (1)); + EXPECT_EQ(false, message.unpacked_bool (1)); + EXPECT_EQ(unittest::FOREIGN_BAZ, message.unpacked_enum(1)); +} + // ------------------------------------------------------------------- void TestUtil::ExpectPackedClear( diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index 5a6ec88..25165f3 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -54,6 +54,7 @@ class TestUtil { static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message); static void SetPackedFields(unittest::TestPackedTypes* message); static void SetPackedExtensions(unittest::TestPackedExtensions* message); + static void SetUnpackedFields(unittest::TestUnpackedTypes* message); // Use the repeated versions of the set_*() accessors to modify all the // repeated fields of the messsage (which should already have been @@ -72,6 +73,8 @@ class TestUtil { static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message); static void ExpectPackedExtensionsSet( const unittest::TestPackedExtensions& message); + static void ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message); // Expect that the message is modified as would be expected from // Modify*Fields(). diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc index f813e8e..e224781 100644 --- a/src/google/protobuf/testing/file.cc +++ b/src/google/protobuf/testing/file.cc @@ -84,10 +84,13 @@ void File::ReadFileToStringOrDie(const string& name, string* output) { void File::WriteStringToFileOrDie(const string& contents, const string& name) { FILE* file = fopen(name.c_str(), "wb"); - GOOGLE_CHECK(file != NULL); + GOOGLE_CHECK(file != NULL) + << "fopen(" << name << ", \"wb\"): " << strerror(errno); GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file), - contents.size()); - GOOGLE_CHECK(fclose(file) == 0); + contents.size()) + << "fwrite(" << name << "): " << strerror(errno); + GOOGLE_CHECK(fclose(file) == 0) + << "fclose(" << name << "): " << strerror(errno); } bool File::CreateDir(const string& name, int mode) { @@ -97,8 +100,10 @@ bool File::CreateDir(const string& name, int mode) { bool File::RecursivelyCreateDir(const string& path, int mode) { if (CreateDir(path, mode)) return true; + if (Exists(path)) return false; + // Try creating the parent. - string::size_type slashpos = path.find_first_of('/'); + string::size_type slashpos = path.find_last_of('/'); if (slashpos == string::npos) { // No parent given. return false; diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc index 1339b33..cd094d0 100644 --- a/src/google/protobuf/testing/googletest.cc +++ b/src/google/protobuf/testing/googletest.cc @@ -46,6 +46,8 @@ #endif #include <stdio.h> #include <fcntl.h> +#include <iostream> +#include <fstream> namespace google { namespace protobuf { @@ -94,7 +96,8 @@ string GetTemporaryDirectoryName() { // tmpnam() is generally not considered safe but we're only using it for // testing. We cannot use tmpfile() or mkstemp() since we're creating a // directory. - string result = tmpnam(NULL); + char b[L_tmpnam + 1]; // HPUX multithread return 0 if s is 0 + string result = tmpnam(b); #ifdef _WIN32 // On Win32, tmpnam() returns a file prefixed with '\', but which is supposed // to be used in the current working directory. WTF? diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index cf75402..137cbce 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -54,21 +54,19 @@ namespace protobuf { string Message::DebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); - TextFormat::Print(*this, &output_stream); + TextFormat::PrintToString(*this, &debug_string); return debug_string; } string Message::ShortDebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); TextFormat::Printer printer; printer.SetSingleLineMode(true); - printer.Print(*this, &output_stream); + printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. if (debug_string.size() > 0 && debug_string[debug_string.size() - 1] == ' ') { @@ -78,10 +76,22 @@ string Message::ShortDebugString() const { return debug_string; } +string Message::Utf8DebugString() const { + string debug_string; + + TextFormat::Printer printer; + printer.SetUseUtf8StringEscaping(true); + + printer.PrintToString(*this, &debug_string); + + return debug_string; +} + void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); } + // =========================================================================== // Internal class for parsing an ASCII representation of a Protocol Message. // This class makes use of the Protocol Message compiler's tokenizer found @@ -170,6 +180,23 @@ class TextFormat::Parser::ParserImpl { } } + void ReportWarning(int line, int col, const string& message) { + if (error_collector_ == NULL) { + if (line >= 0) { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << (line + 1) << ":" + << (col + 1) << ": " << message; + } else { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << message; + } + } else { + error_collector_->AddWarning(line, col, message); + } + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl); @@ -180,6 +207,13 @@ class TextFormat::Parser::ParserImpl { message); } + // Reports a warning with the given message with information indicating + // the position (as derived from the current token). + void ReportWarning(const string& message) { + ReportWarning(tokenizer_.current().line, tokenizer_.current().column, + message); + } + // Consumes the specified message with the given starting delimeter. // This method checks to see that the end delimeter at the conclusion of // the consumption matches the starting delimeter passed in here. @@ -270,6 +304,11 @@ class TextFormat::Parser::ParserImpl { DO(ConsumeFieldValue(message, reflection, field)); } + if (field->options().deprecated()) { + ReportWarning("text format contains deprecated field \"" + + field_name + "\""); + } + return true; } @@ -583,6 +622,10 @@ class TextFormat::Parser::ParserImpl { parser_->ReportError(line, column, message); } + virtual void AddWarning(int line, int column, const string& message) { + parser_->ReportWarning(line, column, message); + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector); TextFormat::Parser::ParserImpl* parser_; @@ -644,12 +687,16 @@ class TextFormat::Printer::TextGenerator { // Print text to the output stream. void Print(const string& str) { - Print(str.c_str()); + Print(str.data(), str.size()); } // Print text to the output stream. void Print(const char* text) { - int size = strlen(text); + Print(text, strlen(text)); + } + + // Print text to the output stream. + void Print(const char* text, int size) { int pos = 0; // The number of bytes we've written so far. for (int i = 0; i < size; i++) { @@ -799,7 +846,9 @@ bool TextFormat::Parser::ParseFieldValueFromString( TextFormat::Printer::Printer() : initial_indent_level_(0), - single_line_mode_(false) {} + single_line_mode_(false), + use_short_repeated_primitives_(false), + utf8_string_escaping_(false) {} TextFormat::Printer::~Printer() {} @@ -876,6 +925,14 @@ void TextFormat::Printer::PrintField(const Message& message, const Reflection* reflection, const FieldDescriptor* field, TextGenerator& generator) { + if (use_short_repeated_primitives_ && + field->is_repeated() && + field->cpp_type() != FieldDescriptor::CPPTYPE_STRING && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + PrintShortRepeatedField(message, reflection, field, generator); + return; + } + int count = 0; if (field->is_repeated()) { @@ -885,26 +942,7 @@ void TextFormat::Printer::PrintField(const Message& message, } for (int j = 0; j < count; ++j) { - if (field->is_extension()) { - generator.Print("["); - // We special-case MessageSet elements for compatibility with proto1. - if (field->containing_type()->options().message_set_wire_format() - && field->type() == FieldDescriptor::TYPE_MESSAGE - && field->is_optional() - && field->extension_scope() == field->message_type()) { - generator.Print(field->message_type()->full_name()); - } else { - generator.Print(field->full_name()); - } - generator.Print("]"); - } else { - if (field->type() == FieldDescriptor::TYPE_GROUP) { - // Groups must be serialized with their original capitalization. - generator.Print(field->message_type()->name()); - } else { - generator.Print(field->name()); - } - } + PrintFieldName(message, reflection, field, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (single_line_mode_) { @@ -926,16 +964,64 @@ void TextFormat::Printer::PrintField(const Message& message, PrintFieldValue(message, reflection, field, field_index, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (!single_line_mode_) { + if (single_line_mode_) { + generator.Print("} "); + } else { generator.Outdent(); + generator.Print("}\n"); + } + } else { + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); } - generator.Print("}"); } + } +} - if (single_line_mode_) { - generator.Print(" "); +void TextFormat::Printer::PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + // Print primitive repeated field in short form. + PrintFieldName(message, reflection, field, generator); + + int size = reflection->FieldSize(message, field); + generator.Print(": ["); + for (int i = 0; i < size; i++) { + if (i > 0) generator.Print(", "); + PrintFieldValue(message, reflection, field, i, generator); + } + if (single_line_mode_) { + generator.Print("] "); + } else { + generator.Print("]\n"); + } +} + +void TextFormat::Printer::PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + if (field->is_extension()) { + generator.Print("["); + // We special-case MessageSet elements for compatibility with proto1. + if (field->containing_type()->options().message_set_wire_format() + && field->type() == FieldDescriptor::TYPE_MESSAGE + && field->is_optional() + && field->extension_scope() == field->message_type()) { + generator.Print(field->message_type()->full_name()); + } else { + generator.Print(field->full_name()); + } + generator.Print("]"); + } else { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + // Groups must be serialized with their original capitalization. + generator.Print(field->message_type()->name()); } else { - generator.Print("\n"); + generator.Print(field->name()); } } } @@ -973,7 +1059,11 @@ void TextFormat::Printer::PrintFieldValue( reflection->GetStringReference(message, field, &scratch); generator.Print("\""); - generator.Print(CEscape(value)); + if (utf8_string_escaping_) { + generator.Print(strings::Utf8SafeCEscape(value)); + } else { + generator.Print(CEscape(value)); + } generator.Print("\""); break; diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 39a039d..e78e104 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -117,6 +117,24 @@ class LIBPROTOBUF_EXPORT TextFormat { single_line_mode_ = single_line_mode; } + // Set true to print repeated primitives in a format like: + // field_name: [1, 2, 3, 4] + // instead of printing each value on its own line. Short format applies + // only to primitive values -- i.e. everything except strings and + // sub-messages/groups. Note that at present this format is not recognized + // by the parser. + void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) { + use_short_repeated_primitives_ = use_short_repeated_primitives; + } + + // Set true to output UTF-8 instead of ASCII. The only difference + // is that bytes >= 0x80 in string fields will not be escaped, + // because they are assumed to be part of UTF-8 multi-byte + // sequences. + void SetUseUtf8StringEscaping(bool as_utf8) { + utf8_string_escaping_ = as_utf8; + } + private: // Forward declaration of an internal class used to print the text // output to the OutputStream (see text_format.cc for implementation). @@ -133,6 +151,19 @@ class LIBPROTOBUF_EXPORT TextFormat { const FieldDescriptor* field, TextGenerator& generator); + // Print a repeated primitive field in short form. + void PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + + // Print the name of a field -- i.e. everything that comes before the + // ':' for a single name/value pair. + void PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + // Outputs a textual representation of the value of the field supplied on // the message supplied or the default value if not set. void PrintFieldValue(const Message& message, @@ -150,6 +181,10 @@ class LIBPROTOBUF_EXPORT TextFormat { int initial_indent_level_; bool single_line_mode_; + + bool use_short_repeated_primitives_; + + bool utf8_string_escaping_; }; // Parses a text-format protocol message from the given input stream to diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 7c31e80..ddf8ff7 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -138,12 +138,53 @@ TEST_F(TextFormatTest, ShortDebugString) { proto_.ShortDebugString()); } +TEST_F(TextFormatTest, ShortPrimitiveRepeateds) { + proto_.set_optional_int32(123); + proto_.add_repeated_int32(456); + proto_.add_repeated_int32(789); + proto_.add_repeated_string("foo"); + proto_.add_repeated_string("bar"); + proto_.add_repeated_nested_message()->set_bb(2); + proto_.add_repeated_nested_message()->set_bb(3); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::FOO); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::BAR); + + TextFormat::Printer printer; + printer.SetUseShortRepeatedPrimitives(true); + string text; + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123\n" + "repeated_int32: [456, 789]\n" + "repeated_string: \"foo\"\n" + "repeated_string: \"bar\"\n" + "repeated_nested_message {\n bb: 2\n}\n" + "repeated_nested_message {\n bb: 3\n}\n" + "repeated_nested_enum: [FOO, BAR]\n", + text); + + // Try in single-line mode. + printer.SetSingleLineMode(true); + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123 " + "repeated_int32: [456, 789] " + "repeated_string: \"foo\" " + "repeated_string: \"bar\" " + "repeated_nested_message { bb: 2 } " + "repeated_nested_message { bb: 3 } " + "repeated_nested_enum: [FOO, BAR] ", + text); +} + + TEST_F(TextFormatTest, StringEscape) { // Set the string value to test. proto_.set_optional_string(kEscapeTestString); // Get the DebugString from the proto. string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); // Hardcode a correct value to test against. string correct_string = "optional_string: " @@ -152,12 +193,36 @@ TEST_F(TextFormatTest, StringEscape) { // Compare. EXPECT_EQ(correct_string, debug_string); + // UTF-8 string is the same as non-UTF-8 because + // the protocol buffer contains no UTF-8 text. + EXPECT_EQ(correct_string, utf8_debug_string); string expected_short_debug_string = "optional_string: " + kEscapeTestStringEscaped; EXPECT_EQ(expected_short_debug_string, proto_.ShortDebugString()); } +TEST_F(TextFormatTest, Utf8DebugString) { + // Set the string value to test. + proto_.set_optional_string("\350\260\267\346\255\214"); + + // Get the DebugString from the proto. + string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); + + // Hardcode a correct value to test against. + string correct_utf8_string = "optional_string: " + "\"\350\260\267\346\255\214\"" + "\n"; + string correct_string = "optional_string: " + "\"\\350\\260\\267\\346\\255\\214\"" + "\n"; + + // Compare. + EXPECT_EQ(correct_utf8_string, utf8_debug_string); + EXPECT_EQ(correct_string, debug_string); +} + TEST_F(TextFormatTest, PrintUnknownFields) { // Test printing of unknown fields in a message. @@ -603,10 +668,15 @@ class TextFormatParserTest : public testing::Test { void ExpectFailure(const string& input, const string& message, int line, int col, Message* proto) { + ExpectMessage(input, message, line, col, proto, false); + } + + void ExpectMessage(const string& input, const string& message, int line, + int col, Message* proto, bool expected_result) { TextFormat::Parser parser; MockErrorCollector error_collector; parser.RecordErrorsTo(&error_collector); - EXPECT_FALSE(parser.ParseFromString(input, proto)); + EXPECT_EQ(parser.ParseFromString(input, proto), expected_result); EXPECT_EQ(SimpleItoa(line) + ":" + SimpleItoa(col) + ": " + message + "\n", error_collector.text_); } @@ -625,6 +695,10 @@ class TextFormatParserTest : public testing::Test { strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line + 1, column + 1, message); } + + void AddWarning(int line, int column, const string& message) { + AddError(line, column, "WARNING:" + message); + } }; }; @@ -945,6 +1019,12 @@ TEST_F(TextFormatParserTest, FailsOnTokenizationError) { errors[0]); } +TEST_F(TextFormatParserTest, ParseDeprecatedField) { + unittest::TestDeprecatedFields message; + ExpectMessage("deprecated_int32: 42", + "WARNING:text format contains deprecated field " + "\"deprecated_int32\"", 1, 21, &message, true); +} class TextFormatMessageSetTest : public testing::Test { protected: @@ -991,5 +1071,4 @@ TEST_F(TextFormatMessageSetTest, Deserialize) { } // namespace text_format_unittest } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 03811de..d51fa1e 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -155,6 +155,10 @@ message TestAllTypes { optional string default_cord = 85 [ctype=CORD,default="123"]; } +message TestDeprecatedFields { + optional int32 deprecated_int32 = 1 [deprecated=true]; +} + // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { @@ -348,6 +352,12 @@ message TestEmptyMessageWithExtensions { extensions 1 to max; } +message TestMultipleExtensionRanges { + extensions 42; + extensions 4143 to 4243; + extensions 65536 to max; +} + // Test that really large tag numbers don't break anything. message TestReallyLargeTagNumber { // The largest possible tag number is 2^28 - 1, since the wire format uses @@ -372,13 +382,14 @@ message TestMutualRecursionB { } // Test that groups have disjoint field numbers from their siblings and -// parents. This is NOT possible in proto1; only proto2. When outputting -// proto1, the dup fields should be dropped. -message TestDupFieldNumber { - optional int32 a = 1; - optional group Foo = 2 { optional int32 a = 1; } - optional group Bar = 3 { optional int32 a = 1; } -} +// parents. This is NOT possible in proto1; only proto2. When attempting +// to compile with proto1, this will emit an error; so we only include it +// in protobuf_unittest_proto. +message TestDupFieldNumber { // NO_PROTO1 + optional int32 a = 1; // NO_PROTO1 + optional group Foo = 2 { optional int32 a = 1; } // NO_PROTO1 + optional group Bar = 3 { optional int32 a = 1; } // NO_PROTO1 +} // NO_PROTO1 // Needed for a Python test. @@ -468,6 +479,14 @@ message TestExtremeDefaultValues { // Using exponents optional float large_float = 12 [default = 2E8]; optional float small_negative_float = 13 [default = -8e-28]; + + // Text for nonfinite floating-point values. + optional double inf_double = 14 [default = inf]; + optional double neg_inf_double = 15 [default = -inf]; + optional double nan_double = 16 [default = nan]; + optional float inf_float = 17 [default = inf]; + optional float neg_inf_float = 18 [default = -inf]; + optional float nan_float = 19 [default = nan]; } // Test String and Bytes: string is for valid UTF-8 strings @@ -498,6 +517,25 @@ message TestPackedTypes { repeated ForeignEnum packed_enum = 103 [packed = true]; } +// A message with the same fields as TestPackedTypes, but without packing. Used +// to test packed <-> unpacked wire compatibility. +message TestUnpackedTypes { + repeated int32 unpacked_int32 = 90 [packed = false]; + repeated int64 unpacked_int64 = 91 [packed = false]; + repeated uint32 unpacked_uint32 = 92 [packed = false]; + repeated uint64 unpacked_uint64 = 93 [packed = false]; + repeated sint32 unpacked_sint32 = 94 [packed = false]; + repeated sint64 unpacked_sint64 = 95 [packed = false]; + repeated fixed32 unpacked_fixed32 = 96 [packed = false]; + repeated fixed64 unpacked_fixed64 = 97 [packed = false]; + repeated sfixed32 unpacked_sfixed32 = 98 [packed = false]; + repeated sfixed64 unpacked_sfixed64 = 99 [packed = false]; + repeated float unpacked_float = 100 [packed = false]; + repeated double unpacked_double = 101 [packed = false]; + repeated bool unpacked_bool = 102 [packed = false]; + repeated ForeignEnum unpacked_enum = 103 [packed = false]; +} + message TestPackedExtensions { extensions 1 to max; } @@ -519,6 +557,47 @@ extend TestPackedExtensions { repeated ForeignEnum packed_enum_extension = 103 [packed = true]; } +// Used by ExtensionSetTest/DynamicExtensions. The test actually builds +// a set of extensions to TestAllExtensions dynamically, based on the fields +// of this message type. +message TestDynamicExtensions { + enum DynamicEnumType { + DYNAMIC_FOO = 2200; + DYNAMIC_BAR = 2201; + DYNAMIC_BAZ = 2202; + } + message DynamicMessageType { + optional int32 dynamic_field = 2100; + } + + optional fixed32 scalar_extension = 2000; + optional ForeignEnum enum_extension = 2001; + optional DynamicEnumType dynamic_enum_extension = 2002; + + optional ForeignMessage message_extension = 2003; + optional DynamicMessageType dynamic_message_extension = 2004; + + repeated string repeated_extension = 2005; + repeated sint32 packed_extension = 2006 [packed = true]; +} + +message TestRepeatedScalarDifferentTagSizes { + // Parsing repeated fixed size values used to fail. This message needs to be + // used in order to get a tag of the right size; all of the repeated fields + // in TestAllTypes didn't trigger the check. + repeated fixed32 repeated_fixed32 = 12; + // Check for a varint type, just for good measure. + repeated int32 repeated_int32 = 13; + + // These have two-byte tags. + repeated fixed64 repeated_fixed64 = 2046; + repeated int64 repeated_int64 = 2047; + + // Three byte tags. + repeated float repeated_float = 262142; + repeated uint64 repeated_uint64 = 262143; +} + // Test that RPC services work. message FooRequest {} message FooResponse {} diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto index 6ad2dab..bc0b7c1 100644 --- a/src/google/protobuf/unittest_enormous_descriptor.proto +++ b/src/google/protobuf/unittest_enormous_descriptor.proto @@ -35,6 +35,7 @@ // A proto file that has an extremely large descriptor. Used to test that // descriptors over 64k don't break the string literal length limit in Java. + package google.protobuf; option java_package = "com.google.protobuf"; diff --git a/src/google/protobuf/unittest_micro.proto b/src/google/protobuf/unittest_micro.proto deleted file mode 100644 index 3d7fcd2..0000000 --- a/src/google/protobuf/unittest_micro.proto +++ /dev/null @@ -1,162 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// http://code.google.com/p/protobuf/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: wink@google.com (Wink Saville) - -package protobuf_unittest; - -import "google/protobuf/unittest_import_micro.proto"; - -option java_package = "com.google.protobuf.micro"; -option java_outer_classname = "MicroOuterClass"; - -// Same as TestAllTypes but with the micro runtime. -message TestAllTypesMicro { - - message NestedMessage { - optional int32 bb = 1; - } - - enum NestedEnum { - FOO = 1; - BAR = 2; - BAZ = 3; - } - - // Singular - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional group OptionalGroup = 16 { - optional int32 a = 17; - } - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessageMicro optional_foreign_message = 19; - optional protobuf_unittest_import.ImportMessageMicro - optional_import_message = 20; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnumMicro optional_foreign_enum = 22; - optional protobuf_unittest_import.ImportEnumMicro optional_import_enum = 23; - - optional string optional_string_piece = 24 [ctype=STRING_PIECE]; - optional string optional_cord = 25 [ctype=CORD]; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - repeated group RepeatedGroup = 46 { - optional int32 a = 47; - } - - repeated NestedMessage repeated_nested_message = 48; - repeated ForeignMessageMicro repeated_foreign_message = 49; - repeated protobuf_unittest_import.ImportMessageMicro - repeated_import_message = 50; - - repeated NestedEnum repeated_nested_enum = 51; - repeated ForeignEnumMicro repeated_foreign_enum = 52; - repeated protobuf_unittest_import.ImportEnumMicro repeated_import_enum = 53; - - repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; - repeated string repeated_cord = 55 [ctype=CORD]; - - // Singular with defaults - optional int32 default_int32 = 61 [default = 41 ]; - optional int64 default_int64 = 62 [default = 42 ]; - optional uint32 default_uint32 = 63 [default = 43 ]; - optional uint64 default_uint64 = 64 [default = 44 ]; - optional sint32 default_sint32 = 65 [default = -45 ]; - optional sint64 default_sint64 = 66 [default = 46 ]; - optional fixed32 default_fixed32 = 67 [default = 47 ]; - optional fixed64 default_fixed64 = 68 [default = 48 ]; - optional sfixed32 default_sfixed32 = 69 [default = 49 ]; - optional sfixed64 default_sfixed64 = 70 [default = -50 ]; - optional float default_float = 71 [default = 51.5 ]; - optional double default_double = 72 [default = 52e3 ]; - optional bool default_bool = 73 [default = true ]; - optional string default_string = 74 [default = "hello"]; - optional bytes default_bytes = 75 [default = "world"]; - - optional NestedEnum default_nested_enum = 81 [default = BAR]; - optional ForeignEnumMicro default_foreign_enum = 82 - [default = FOREIGN_MICRO_BAR]; - optional protobuf_unittest_import.ImportEnumMicro - default_import_enum = 83 [default = IMPORT_MICRO_BAR]; - - optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"]; - optional string default_cord = 85 [ctype=CORD,default="123"]; - - required int32 id = 86; -} - -message ForeignMessageMicro { - optional int32 c = 1; -} - -enum ForeignEnumMicro { - FOREIGN_MICRO_FOO = 4; - FOREIGN_MICRO_BAR = 5; - FOREIGN_MICRO_BAZ = 6; -} - -// Test that deprecated fields work. We only verify that they compile (at one -// point this failed). -message TestDeprecatedMicro { - optional int32 deprecated_field = 1 [deprecated = true]; -} diff --git a/src/google/protobuf/unittest_import_micro.proto b/src/google/protobuf/unittest_no_generic_services.proto index adac807..fcae421 100644 --- a/src/google/protobuf/unittest_import_micro.proto +++ b/src/google/protobuf/unittest_no_generic_services.proto @@ -29,21 +29,26 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) -// -// This is like unittest_import.proto but with optimize_for = MICRO_RUNTIME. -package protobuf_unittest_import; +package google.protobuf.no_generic_services_test; + +option cc_generic_services = false; +option java_generic_services = false; +option py_generic_services = false; -// java_package and java_outer_classname are specified on the command line. -//option java_package = "com.google.protobuf.micro"; -//option java_outer_classname = "UnittestImportMicro"; +message TestMessage { + optional int32 a = 1; + extensions 1000 to max; +} + +enum TestEnum { + FOO = 1; +} -message ImportMessageMicro { - optional int32 d = 1; +extend TestMessage { + optional int32 test_extension = 1000; } -enum ImportEnumMicro { - IMPORT_MICRO_FOO = 7; - IMPORT_MICRO_BAR = 8; - IMPORT_MICRO_BAZ = 9; +service TestService { + rpc Foo(TestMessage) returns(TestMessage); } diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 318ffaf..e1f8b83 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/stubs/common.h> #include <google/protobuf/unknown_field_set.h> #include <google/protobuf/stubs/stl_util-inl.h> #include <google/protobuf/io/coded_stream.h> @@ -50,13 +51,12 @@ UnknownFieldSet::~UnknownFieldSet() { delete fields_; } -void UnknownFieldSet::Clear() { - if (fields_ != NULL) { - for (int i = 0; i < fields_->size(); i++) { - (*fields_)[i].Delete(); - } - fields_->clear(); +void UnknownFieldSet::ClearFallback() { + GOOGLE_DCHECK(fields_ != NULL); + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); } + fields_->clear(); } void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index d6ca70f..84c2e2b 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -66,7 +66,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { ~UnknownFieldSet(); // Remove all fields. - void Clear(); + inline void Clear(); // Is this set empty? inline bool empty() const; @@ -119,6 +119,8 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { } private: + void ClearFallback(); + vector<UnknownField>* fields_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); @@ -180,6 +182,12 @@ class LIBPROTOBUF_EXPORT UnknownField { // =================================================================== // inline implementations +inline void UnknownFieldSet::Clear() { + if (fields_ != NULL) { + ClearFallback(); + } +} + inline bool UnknownFieldSet::empty() const { return fields_ == NULL || fields_->empty(); } diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 5aa6772..831a579 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -391,7 +391,12 @@ bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, // If that failed, check if the field is an extension. if (field == NULL && descriptor->IsExtensionNumber(field_number)) { - field = message_reflection->FindKnownExtensionByNumber(field_number); + if (input->GetExtensionPool() == NULL) { + field = message_reflection->FindKnownExtensionByNumber(field_number); + } else { + field = input->GetExtensionPool() + ->FindExtensionByNumber(descriptor, field_number); + } } // If that failed, but we're a MessageSet, and this is the tag for a @@ -419,52 +424,67 @@ bool WireFormat::ParseAndMergeField( io::CodedInputStream* input) { const Reflection* message_reflection = message->GetReflection(); - if (field == NULL || - WireFormatLite::GetTagWireType(tag) != WireTypeForField(field)) { - // We don't recognize this field. Either the field number is unknown - // or the wire type doesn't match. Put it in our unknown field set. - return SkipField(input, tag, - message_reflection->MutableUnknownFields(message)); + enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format; + + if (field == NULL) { + value_format = UNKNOWN; + } else if (WireFormatLite::GetTagWireType(tag) == + WireTypeForFieldType(field->type())) { + value_format = NORMAL_FORMAT; + } else if (field->is_packable() && + WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + value_format = PACKED_FORMAT; + } else { + // We don't recognize this field. Either the field number is unknown + // or the wire type doesn't match. Put it in our unknown field set. + value_format = UNKNOWN; } - if (field->options().packed()) { + if (value_format == UNKNOWN) { + return SkipField(input, tag, + message_reflection->MutableUnknownFields(message)); + } else if (value_format == PACKED_FORMAT) { uint32 length; if (!input->ReadVarint32(&length)) return false; io::CodedInputStream::Limit limit = input->PushLimit(length); switch (field->type()) { -#define HANDLE_PACKED_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ while (input->BytesUntilLimit() > 0) { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } \ break; \ } - HANDLE_PACKED_TYPE( INT32, Int32, int32, Int32) - HANDLE_PACKED_TYPE( INT64, Int64, int64, Int64) - HANDLE_PACKED_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_PACKED_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_PACKED_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_PACKED_TYPE(UINT64, UInt64, uint64, UInt64) + HANDLE_PACKED_TYPE( INT32, int32, Int32) + HANDLE_PACKED_TYPE( INT64, int64, Int64) + HANDLE_PACKED_TYPE(SINT32, int32, Int32) + HANDLE_PACKED_TYPE(SINT64, int64, Int64) + HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) + HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) - HANDLE_PACKED_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_PACKED_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_PACKED_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_PACKED_TYPE(SFIXED64, SFixed64, int64, Int64) + HANDLE_PACKED_TYPE( FIXED32, uint32, UInt32) + HANDLE_PACKED_TYPE( FIXED64, uint64, UInt64) + HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) + HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) - HANDLE_PACKED_TYPE(FLOAT , Float , float , Float ) - HANDLE_PACKED_TYPE(DOUBLE, Double, double, Double) + HANDLE_PACKED_TYPE(FLOAT , float , Float ) + HANDLE_PACKED_TYPE(DOUBLE, double, Double) - HANDLE_PACKED_TYPE(BOOL, Bool, bool, Bool) + HANDLE_PACKED_TYPE(BOOL, bool, Bool) #undef HANDLE_PACKED_TYPE case FieldDescriptor::TYPE_ENUM: { while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -487,11 +507,14 @@ bool WireFormat::ParseAndMergeField( input->PopLimit(limit); } else { + // Non-packed value (value_format == NORMAL_FORMAT) switch (field->type()) { -#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ if (field->is_repeated()) { \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } else { \ @@ -500,31 +523,28 @@ bool WireFormat::ParseAndMergeField( break; \ } - HANDLE_TYPE( INT32, Int32, int32, Int32) - HANDLE_TYPE( INT64, Int64, int64, Int64) - HANDLE_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) - - HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) - - HANDLE_TYPE(FLOAT , Float , float , Float ) - HANDLE_TYPE(DOUBLE, Double, double, Double) + HANDLE_TYPE( INT32, int32, Int32) + HANDLE_TYPE( INT64, int64, Int64) + HANDLE_TYPE(SINT32, int32, Int32) + HANDLE_TYPE(SINT64, int64, Int64) + HANDLE_TYPE(UINT32, uint32, UInt32) + HANDLE_TYPE(UINT64, uint64, UInt64) - HANDLE_TYPE(BOOL, Bool, bool, Bool) + HANDLE_TYPE( FIXED32, uint32, UInt32) + HANDLE_TYPE( FIXED64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, int32, Int32) + HANDLE_TYPE(SFIXED64, int64, Int64) - HANDLE_TYPE(STRING, String, string, String) - HANDLE_TYPE(BYTES, Bytes, string, String) + HANDLE_TYPE(FLOAT , float , Float ) + HANDLE_TYPE(DOUBLE, double, Double) + HANDLE_TYPE(BOOL, bool, Bool) #undef HANDLE_TYPE case FieldDescriptor::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -544,13 +564,38 @@ bool WireFormat::ParseAndMergeField( break; } + // Handle strings separately so that we can optimize the ctype=CORD case. + case FieldDescriptor::TYPE_STRING: { + string value; + if (!WireFormatLite::ReadString(input, &value)) return false; + VerifyUTF8String(value.data(), value.length(), PARSE); + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } + + case FieldDescriptor::TYPE_BYTES: { + string value; + if (!WireFormatLite::ReadBytes(input, &value)) return false; + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } case FieldDescriptor::TYPE_GROUP: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag), @@ -562,9 +607,11 @@ bool WireFormat::ParseAndMergeField( case FieldDescriptor::TYPE_MESSAGE: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadMessage(input, sub_message)) return false; @@ -782,23 +829,23 @@ void WireFormat::SerializeFieldWithCachedSizes( // Handle strings separately so that we can get string references // instead of copying. case FieldDescriptor::TYPE_STRING: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - VerifyUTF8String(value.data(), value.length(), SERIALIZE); - WireFormatLite::WriteString(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + VerifyUTF8String(value.data(), value.length(), SERIALIZE); + WireFormatLite::WriteString(field->number(), value, output); break; } case FieldDescriptor::TYPE_BYTES: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - WireFormatLite::WriteBytes(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + WireFormatLite::WriteBytes(field->number(), value, output); break; } } @@ -961,14 +1008,14 @@ int WireFormat::FieldDataOnlyByteSize( // instead of copying. case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_BYTES: { - for (int j = 0; j < count; j++) { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - data_size += WireFormatLite::StringSize(value); - } + for (int j = 0; j < count; j++) { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + data_size += WireFormatLite::StringSize(value); + } break; } } diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 5d09803..d347d11 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -32,14 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include <google/protobuf/wire_format_lite_inl.h> + #include <stack> #include <string> #include <vector> - -#include <google/protobuf/wire_format_lite_inl.h> - #include <google/protobuf/stubs/common.h> -#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/io/coded_stream_inl.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> @@ -187,6 +186,174 @@ void FieldSkipper::SkipUnknownEnum( // Nothing. } +bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input, + bool (*is_valid)(int), + RepeatedField<int>* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + int value; + if (!google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, WireFormatLite::TYPE_ENUM>(input, &value)) { + return false; + } + if (is_valid(value)) { + values->Add(value); + } + } + input->PopLimit(limit); + return true; +} + +void WireFormatLite::WriteInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt32NoTag(value, output); +} +void WireFormatLite::WriteInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt64NoTag(value, output); +} +void WireFormatLite::WriteUInt32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt32NoTag(value, output); +} +void WireFormatLite::WriteUInt64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt64NoTag(value, output); +} +void WireFormatLite::WriteSInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt32NoTag(value, output); +} +void WireFormatLite::WriteSInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt64NoTag(value, output); +} +void WireFormatLite::WriteFixed32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFixed32NoTag(value, output); +} +void WireFormatLite::WriteFixed64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteFixed64NoTag(value, output); +} +void WireFormatLite::WriteSFixed32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteSFixed32NoTag(value, output); +} +void WireFormatLite::WriteSFixed64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteSFixed64NoTag(value, output); +} +void WireFormatLite::WriteFloat(int field_number, float value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFloatNoTag(value, output); +} +void WireFormatLite::WriteDouble(int field_number, double value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteDoubleNoTag(value, output); +} +void WireFormatLite::WriteBool(int field_number, bool value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteBoolNoTag(value, output); +} +void WireFormatLite::WriteEnum(int field_number, int value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteEnumNoTag(value, output); +} + +void WireFormatLite::WriteString(int field_number, const string& value, + io::CodedOutputStream* output) { + // String is for UTF-8 text only + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} +void WireFormatLite::WriteBytes(int field_number, const string& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} + + +void WireFormatLite::WriteGroup(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessage(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + value.SerializeWithCachedSizes(output); +} + +void WireFormatLite::WriteGroupMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + const int size = value.GetCachedSize(); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessageMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } +} + +bool WireFormatLite::ReadString(io::CodedInputStream* input, + string* value) { + // String is for UTF-8 text only + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->InternalReadStringInline(value, length)) return false; + return true; +} +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, + string* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + return input->InternalReadStringInline(value, length); +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index 9b7a401..e3d5b2d 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -46,15 +46,18 @@ namespace google { namespace protobuf { + template <typename T> class RepeatedField; // repeated_field.h namespace io { - class CodedInputStream; // coded_stream.h - class CodedOutputStream; // coded_stream.h + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h } } namespace protobuf { namespace internal { +class StringPieceField; + // This class is for internal use by the protocol buffer library and by // protocol-complier-generated message classes. It must not be called // directly by clients. @@ -183,14 +186,21 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // required string message = 3; // } // } + static const int kMessageSetItemNumber = 1; + static const int kMessageSetTypeIdNumber = 2; + static const int kMessageSetMessageNumber = 3; static const int kMessageSetItemStartTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_START_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_START_GROUP); static const int kMessageSetItemEndTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_END_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_END_GROUP); static const int kMessageSetTypeIdTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(2, WireFormatLite::WIRETYPE_VARINT); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber, + WireFormatLite::WIRETYPE_VARINT); static const int kMessageSetMessageTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(3, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); // Byte size of all tags of a MessageSet::Item combined. static const int kMessageSetItemTagsSize; @@ -227,23 +237,59 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // Read fields, not including tags. The assumption is that you already // read the tag to determine what field to read. - static inline bool ReadInt32 (input, int32* value); - static inline bool ReadInt64 (input, int64* value); - static inline bool ReadUInt32 (input, uint32* value); - static inline bool ReadUInt64 (input, uint64* value); - static inline bool ReadSInt32 (input, int32* value); - static inline bool ReadSInt64 (input, int64* value); - static inline bool ReadFixed32 (input, uint32* value); - static inline bool ReadFixed64 (input, uint64* value); - static inline bool ReadSFixed32(input, int32* value); - static inline bool ReadSFixed64(input, int64* value); - static inline bool ReadFloat (input, float* value); - static inline bool ReadDouble (input, double* value); - static inline bool ReadBool (input, bool* value); - static inline bool ReadEnum (input, int* value); - - static inline bool ReadString(input, string* value); - static inline bool ReadBytes (input, string* value); + + // For primitive fields, we just use a templatized routine parameterized by + // the represented type and the FieldType. These are specialized with the + // appropriate definition for each declared type. + template <typename CType, enum FieldType DeclaredType> + static inline bool ReadPrimitive(input, CType* value) INL; + + // Reads repeated primitive values, with optimizations for repeats. + // tag_size and tag should both be compile-time constants provided by the + // protocol compiler. + template <typename CType, enum FieldType DeclaredType> + static inline bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField<CType>* value) INL; + + // Identical to ReadRepeatedPrimitive, except will not inline the + // implementation. + template <typename CType, enum FieldType DeclaredType> + static bool ReadRepeatedPrimitiveNoInline(int tag_size, + uint32 tag, + input, + RepeatedField<CType>* value); + + // Reads a primitive value directly from the provided buffer. It returns a + // pointer past the segment of data that was read. + // + // This is only implemented for the types with fixed wire size, e.g. + // float, double, and the (s)fixed* types. + template <typename CType, enum FieldType DeclaredType> + static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, + CType* value) INL; + + // Reads a primitive packed field. + // + // This is only implemented for packable types. + template <typename CType, enum FieldType DeclaredType> + static inline bool ReadPackedPrimitive(input, + RepeatedField<CType>* value) INL; + + // Identical to ReadPackedPrimitive, except will not inline the + // implementation. + template <typename CType, enum FieldType DeclaredType> + static bool ReadPackedPrimitiveNoInline(input, RepeatedField<CType>* value); + + // Read a packed enum field. Values for which is_valid() returns false are + // dropped. + static bool ReadPackedEnumNoInline(input, + bool (*is_valid)(int), + RepeatedField<int>* value); + + static bool ReadString(input, string* value); + static bool ReadBytes (input, string* value); static inline bool ReadGroup (field_number, input, MessageLite* value); static inline bool ReadMessage(input, MessageLite* value); @@ -279,38 +325,44 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline void WriteEnumNoTag (int value, output) INL; // Write fields, including tags. - static inline void WriteInt32 (field_number, int32 value, output) INL; - static inline void WriteInt64 (field_number, int64 value, output) INL; - static inline void WriteUInt32 (field_number, uint32 value, output) INL; - static inline void WriteUInt64 (field_number, uint64 value, output) INL; - static inline void WriteSInt32 (field_number, int32 value, output) INL; - static inline void WriteSInt64 (field_number, int64 value, output) INL; - static inline void WriteFixed32 (field_number, uint32 value, output) INL; - static inline void WriteFixed64 (field_number, uint64 value, output) INL; - static inline void WriteSFixed32(field_number, int32 value, output) INL; - static inline void WriteSFixed64(field_number, int64 value, output) INL; - static inline void WriteFloat (field_number, float value, output) INL; - static inline void WriteDouble (field_number, double value, output) INL; - static inline void WriteBool (field_number, bool value, output) INL; - static inline void WriteEnum (field_number, int value, output) INL; - - static inline void WriteString(field_number, const string& value, output) INL; - static inline void WriteBytes (field_number, const string& value, output) INL; - - static inline void WriteGroup( - field_number, const MessageLite& value, output) INL; - static inline void WriteMessage( - field_number, const MessageLite& value, output) INL; + static void WriteInt32 (field_number, int32 value, output); + static void WriteInt64 (field_number, int64 value, output); + static void WriteUInt32 (field_number, uint32 value, output); + static void WriteUInt64 (field_number, uint64 value, output); + static void WriteSInt32 (field_number, int32 value, output); + static void WriteSInt64 (field_number, int64 value, output); + static void WriteFixed32 (field_number, uint32 value, output); + static void WriteFixed64 (field_number, uint64 value, output); + static void WriteSFixed32(field_number, int32 value, output); + static void WriteSFixed64(field_number, int64 value, output); + static void WriteFloat (field_number, float value, output); + static void WriteDouble (field_number, double value, output); + static void WriteBool (field_number, bool value, output); + static void WriteEnum (field_number, int value, output); + + static void WriteString(field_number, const string& value, output); + static void WriteBytes (field_number, const string& value, output); + + static void WriteGroup( + field_number, const MessageLite& value, output); + static void WriteMessage( + field_number, const MessageLite& value, output); + // Like above, but these will check if the output stream has enough + // space to write directly to a flat array. + static void WriteGroupMaybeToArray( + field_number, const MessageLite& value, output); + static void WriteMessageMaybeToArray( + field_number, const MessageLite& value, output); // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The // pointer must point at an instance of MessageType, *not* a subclass (or // the subclass must not override SerializeWithCachedSizes()). template<typename MessageType> static inline void WriteGroupNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); template<typename MessageType> static inline void WriteMessageNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); #undef output #define output uint8* target @@ -426,6 +478,16 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline int MessageSizeNoVirtual(const MessageType& value); private: + // A helper method for the repeated primitive reader. This method has + // optimizations for primitive types that have fixed size on the wire, and + // can be read using potentially faster paths. + template <typename CType, enum FieldType DeclaredType> + static inline bool ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + google::protobuf::io::CodedInputStream* input, + RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static const CppType kFieldTypeToCppTypeMap[]; static const WireFormatLite::WireType kWireTypeForFieldType[]; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index eb9155e..d7b2c30 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -39,7 +39,9 @@ #include <string> #include <google/protobuf/stubs/common.h> #include <google/protobuf/message_lite.h> +#include <google/protobuf/repeated_field.h> #include <google/protobuf/wire_format_lite.h> +#include <google/protobuf/generated_message_util.h> #include <google/protobuf/io/coded_stream.h> @@ -47,106 +49,295 @@ namespace google { namespace protobuf { namespace internal { -inline bool WireFormatLite::ReadInt32(io::CodedInputStream* input, - int32* value) { +// Implementation details of ReadPrimitive. + +template <> +inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_INT32>( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast<int32>(temp); return true; } -inline bool WireFormatLite::ReadInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_INT64>( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = static_cast<int64>(temp); return true; } -inline bool WireFormatLite::ReadUInt32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>( + io::CodedInputStream* input, + uint32* value) { return input->ReadVarint32(value); } -inline bool WireFormatLite::ReadUInt64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_UINT64>( + io::CodedInputStream* input, + uint64* value) { return input->ReadVarint64(value); } -inline bool WireFormatLite::ReadSInt32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SINT32>( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = ZigZagDecode32(temp); return true; } -inline bool WireFormatLite::ReadSInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SINT64>( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = ZigZagDecode64(temp); return true; } -inline bool WireFormatLite::ReadFixed32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_FIXED32>( + io::CodedInputStream* input, + uint32* value) { return input->ReadLittleEndian32(value); } -inline bool WireFormatLite::ReadFixed64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<uint64, WireFormatLite::TYPE_FIXED64>( + io::CodedInputStream* input, + uint64* value) { return input->ReadLittleEndian64(value); } -inline bool WireFormatLite::ReadSFixed32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int32, WireFormatLite::TYPE_SFIXED32>( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = static_cast<int32>(temp); return true; } -inline bool WireFormatLite::ReadSFixed64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int64, WireFormatLite::TYPE_SFIXED64>( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = static_cast<int64>(temp); return true; } -inline bool WireFormatLite::ReadFloat(io::CodedInputStream* input, - float* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<float, WireFormatLite::TYPE_FLOAT>( + io::CodedInputStream* input, + float* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = DecodeFloat(temp); return true; } -inline bool WireFormatLite::ReadDouble(io::CodedInputStream* input, - double* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<double, WireFormatLite::TYPE_DOUBLE>( + io::CodedInputStream* input, + double* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = DecodeDouble(temp); return true; } -inline bool WireFormatLite::ReadBool(io::CodedInputStream* input, - bool* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>( + io::CodedInputStream* input, + bool* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = temp != 0; return true; } -inline bool WireFormatLite::ReadEnum(io::CodedInputStream* input, - int* value) { +template <> +inline bool WireFormatLite::ReadPrimitive<int, WireFormatLite::TYPE_ENUM>( + io::CodedInputStream* input, + int* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast<int>(temp); return true; } -inline bool WireFormatLite::ReadString(io::CodedInputStream* input, - string* value) { - // String is for UTF-8 text only - uint32 length; - if (!input->ReadVarint32(&length)) return false; - if (!input->ReadString(value, length)) return false; +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint32, WireFormatLite::TYPE_FIXED32>( + const uint8* buffer, + uint32* value) { + return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint64, WireFormatLite::TYPE_FIXED64>( + const uint8* buffer, + uint64* value) { + return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int32, WireFormatLite::TYPE_SFIXED32>( + const uint8* buffer, + int32* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = static_cast<int32>(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int64, WireFormatLite::TYPE_SFIXED64>( + const uint8* buffer, + int64* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = static_cast<int64>(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + float, WireFormatLite::TYPE_FLOAT>( + const uint8* buffer, + float* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = DecodeFloat(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + double, WireFormatLite::TYPE_DOUBLE>( + const uint8* buffer, + double* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = DecodeDouble(temp); + return buffer; +} + +template <typename CType, enum WireFormatLite::FieldType DeclaredType> +inline bool WireFormatLite::ReadRepeatedPrimitive(int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField<CType>* values) { + CType value; + if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false; + values->Add(value); + int elements_already_reserved = values->Capacity() - values->size(); + while (elements_already_reserved > 0 && input->ExpectTag(tag)) { + if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false; + values->AddAlreadyReserved(value); + elements_already_reserved--; + } + return true; +} + +template <typename CType, enum WireFormatLite::FieldType DeclaredType> +inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField<CType>* values) { + GOOGLE_DCHECK_EQ(UInt32Size(tag), tag_size); + CType value; + if (!ReadPrimitive<CType, DeclaredType>(input, &value)) + return false; + values->Add(value); + + // For fixed size values, repeated values can be read more quickly by + // reading directly from a raw array. + // + // We can get a tight loop by only reading as many elements as can be + // added to the RepeatedField without having to do any resizing. Additionally, + // we only try to read as many elements as are available from the current + // buffer space. Doing so avoids having to perform boundary checks when + // reading the value: the maximum number of elements that can be read is + // known outside of the loop. + const void* void_pointer; + int size; + input->GetDirectBufferPointerInline(&void_pointer, &size); + if (size > 0) { + const uint8* buffer = reinterpret_cast<const uint8*>(void_pointer); + // The number of bytes each type occupies on the wire. + const int per_value_size = tag_size + sizeof(value); + + int elements_available = min(values->Capacity() - values->size(), + size / per_value_size); + int num_read = 0; + while (num_read < elements_available && + (buffer = io::CodedInputStream::ExpectTagFromArray( + buffer, tag)) != NULL) { + buffer = ReadPrimitiveFromArray<CType, DeclaredType>(buffer, &value); + values->AddAlreadyReserved(value); + ++num_read; + } + const int read_bytes = num_read * per_value_size; + if (read_bytes > 0) { + input->Skip(read_bytes); + } + } return true; } -inline bool WireFormatLite::ReadBytes(io::CodedInputStream* input, - string* value) { + +// Specializations of ReadRepeatedPrimitive for the fixed size types, which use +// the optimized code path. +#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \ +template <> \ +inline bool WireFormatLite::ReadRepeatedPrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + int tag_size, \ + uint32 tag, \ + io::CodedInputStream* input, \ + RepeatedField<CPPTYPE>* values) { \ + return ReadRepeatedFixedSizePrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + tag_size, tag, input, values); \ +} + +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE); + +#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE + +template <typename CType, enum WireFormatLite::FieldType DeclaredType> +bool WireFormatLite::ReadRepeatedPrimitiveNoInline( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField<CType>* value) { + return ReadRepeatedPrimitive<CType, DeclaredType>( + tag_size, tag, input, value); +} + +template <typename CType, enum WireFormatLite::FieldType DeclaredType> +inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input, + RepeatedField<CType>* values) { uint32 length; if (!input->ReadVarint32(&length)) return false; - return input->ReadString(value, length); + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + CType value; + if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false; + values->Add(value); + } + input->PopLimit(limit); + return true; +} + +template <typename CType, enum WireFormatLite::FieldType DeclaredType> +bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, + RepeatedField<CType>* values) { + return ReadPackedPrimitive<CType, DeclaredType>(input, values); } @@ -270,107 +461,6 @@ inline void WireFormatLite::WriteEnumNoTag(int value, output->WriteVarint32SignExtended(value); } -inline void WireFormatLite::WriteInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt32NoTag(value, output); -} -inline void WireFormatLite::WriteInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt64NoTag(value, output); -} -inline void WireFormatLite::WriteUInt32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt32NoTag(value, output); -} -inline void WireFormatLite::WriteUInt64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt64NoTag(value, output); -} -inline void WireFormatLite::WriteSInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt32NoTag(value, output); -} -inline void WireFormatLite::WriteSInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt64NoTag(value, output); -} -inline void WireFormatLite::WriteFixed32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteFixed64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteSFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteSFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteFloat(int field_number, float value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFloatNoTag(value, output); -} -inline void WireFormatLite::WriteDouble(int field_number, double value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteDoubleNoTag(value, output); -} -inline void WireFormatLite::WriteBool(int field_number, bool value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteBoolNoTag(value, output); -} -inline void WireFormatLite::WriteEnum(int field_number, int value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteEnumNoTag(value, output); -} - -inline void WireFormatLite::WriteString(int field_number, const string& value, - io::CodedOutputStream* output) { - // String is for UTF-8 text only - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} -inline void WireFormatLite::WriteBytes(int field_number, const string& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} - - -inline void WireFormatLite::WriteGroup(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_START_GROUP, output); - value.SerializeWithCachedSizes(output); - WriteTag(field_number, WIRETYPE_END_GROUP, output); -} -inline void WireFormatLite::WriteMessage(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.GetCachedSize()); - value.SerializeWithCachedSizes(output); -} - template<typename MessageType> inline void WireFormatLite::WriteGroupNoVirtual(int field_number, const MessageType& value, diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 51960ee..867970c 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -126,6 +126,38 @@ TEST(WireFormatTest, ParsePacked) { TestUtil::ExpectPackedFieldsSet(dest); } +TEST(WireFormatTest, ParsePackedFromUnpacked) { + // Serialize using the generated code. + unittest::TestUnpackedTypes source; + TestUtil::SetUnpackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestPackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectPackedFieldsSet(dest); +} + +TEST(WireFormatTest, ParseUnpackedFromPacked) { + // Serialize using the generated code. + unittest::TestPackedTypes source; + TestUtil::SetPackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestUnpackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectUnpackedFieldsSet(dest); +} + TEST(WireFormatTest, ParsePackedExtensions) { unittest::TestPackedExtensions source, dest; string data; @@ -568,6 +600,45 @@ TEST(WireFormatTest, ZigZag) { LL(-75123905439571256)))); } +TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) { + // At one point checks would trigger when parsing repeated fixed scalar + // fields. + protobuf_unittest::TestRepeatedScalarDifferentTagSizes msg1, msg2; + for (int i = 0; i < 100; ++i) { + msg1.add_repeated_fixed32(i); + msg1.add_repeated_int32(i); + msg1.add_repeated_fixed64(i); + msg1.add_repeated_int64(i); + msg1.add_repeated_float(i); + msg1.add_repeated_uint64(i); + } + + // Make sure that we have a variety of tag sizes. + const google::protobuf::Descriptor* desc = msg1.GetDescriptor(); + const google::protobuf::FieldDescriptor* field; + field = desc->FindFieldByName("repeated_fixed32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_fixed64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_float"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_uint64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + + EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString())); + EXPECT_EQ(msg1.DebugString(), msg2.DebugString()); +} + class WireFormatInvalidInputTest : public testing::Test { protected: // Make a serialized TestAllTypes in which the field optional_nested_message |