aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/text_format.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/text_format.cc')
-rw-r--r--src/google/protobuf/text_format.cc996
1 files changed, 642 insertions, 354 deletions
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index b0a5ce63..0965fd7a 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -42,20 +42,22 @@
#include <google/protobuf/text_format.h>
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/dynamic_message.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/wire_format_lite.h>
+#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/any.h>
#include <google/protobuf/io/strtod.h>
#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/tokenizer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/io/tokenizer.h>
-#include <google/protobuf/any.h>
-#include <google/protobuf/stubs/stringprintf.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/dynamic_message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/unknown_field_set.h>
+#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/stubs/strutil.h>
+
+
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/stl_util.h>
@@ -74,24 +76,15 @@ inline bool IsOctNumber(const string& str) {
(str[1] >= '0' && str[1] < '8'));
}
-inline bool GetAnyFieldDescriptors(const Message& message,
- const FieldDescriptor** type_url_field,
- const FieldDescriptor** value_field) {
- const Descriptor* descriptor = message.GetDescriptor();
- *type_url_field = descriptor->FindFieldByNumber(1);
- *value_field = descriptor->FindFieldByNumber(2);
- return (*type_url_field != NULL &&
- (*type_url_field)->type() == FieldDescriptor::TYPE_STRING &&
- *value_field != NULL &&
- (*value_field)->type() == FieldDescriptor::TYPE_BYTES);
-}
-
} // namespace
string Message::DebugString() const {
string debug_string;
- TextFormat::PrintToString(*this, &debug_string);
+ TextFormat::Printer printer;
+ printer.SetExpandAny(true);
+
+ printer.PrintToString(*this, &debug_string);
return debug_string;
}
@@ -101,6 +94,7 @@ string Message::ShortDebugString() const {
TextFormat::Printer printer;
printer.SetSingleLineMode(true);
+ printer.SetExpandAny(true);
printer.PrintToString(*this, &debug_string);
// Single line mode currently might have an extra space at the end.
@@ -117,6 +111,7 @@ string Message::Utf8DebugString() const {
TextFormat::Printer printer;
printer.SetUseUtf8StringEscaping(true);
+ printer.SetExpandAny(true);
printer.PrintToString(*this, &debug_string);
@@ -149,7 +144,7 @@ TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::CreateNested(
const FieldDescriptor* field) {
// Owned by us in the map.
TextFormat::ParseInfoTree* instance = new TextFormat::ParseInfoTree();
- vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
+ std::vector<TextFormat::ParseInfoTree*>* trees = &nested_[field];
GOOGLE_CHECK(trees);
trees->push_back(instance);
return instance;
@@ -172,7 +167,7 @@ TextFormat::ParseLocation TextFormat::ParseInfoTree::GetLocation(
CheckFieldIndex(field, index);
if (index == -1) { index = 0; }
- const vector<TextFormat::ParseLocation>* locations =
+ const std::vector<TextFormat::ParseLocation>* locations =
FindOrNull(locations_, field);
if (locations == NULL || index >= locations->size()) {
return TextFormat::ParseLocation();
@@ -186,7 +181,8 @@ TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
CheckFieldIndex(field, index);
if (index == -1) { index = 0; }
- const vector<TextFormat::ParseInfoTree*>* trees = FindOrNull(nested_, field);
+ const std::vector<TextFormat::ParseInfoTree*>* trees =
+ FindOrNull(nested_, field);
if (trees == NULL || index >= trees->size()) {
return NULL;
}
@@ -194,6 +190,24 @@ TextFormat::ParseInfoTree* TextFormat::ParseInfoTree::GetTreeForNested(
return (*trees)[index];
}
+namespace {
+// These functions implement the behavior of the "default" TextFormat::Finder,
+// they are defined as standalone to be called when finder_ is NULL.
+const FieldDescriptor* DefaultFinderFindExtension(Message* message,
+ const string& name) {
+ return message->GetReflection()->FindKnownExtensionByName(name);
+}
+
+const Descriptor* DefaultFinderFindAnyType(const Message& message,
+ const string& prefix,
+ const string& name) {
+ if (prefix != internal::kTypeGoogleApisComPrefix &&
+ prefix != internal::kTypeGoogleProdComPrefix) {
+ return NULL;
+ }
+ return message.GetDescriptor()->file()->pool()->FindMessageTypeByName(name);
+}
+} // namespace
// ===========================================================================
// Internal class for parsing an ASCII representation of a Protocol Message.
@@ -222,14 +236,15 @@ class TextFormat::Parser::ParserImpl {
ParserImpl(const Descriptor* root_message_type,
io::ZeroCopyInputStream* input_stream,
io::ErrorCollector* error_collector,
- TextFormat::Finder* finder,
+ const TextFormat::Finder* finder,
ParseInfoTree* parse_info_tree,
SingularOverwritePolicy singular_overwrite_policy,
bool allow_case_insensitive_field,
bool allow_unknown_field,
bool allow_unknown_enum,
bool allow_field_number,
- bool allow_relaxed_whitespace)
+ bool allow_relaxed_whitespace,
+ bool allow_partial)
: error_collector_(error_collector),
finder_(finder),
parse_info_tree_(parse_info_tree),
@@ -241,6 +256,7 @@ class TextFormat::Parser::ParserImpl {
allow_unknown_field_(allow_unknown_field),
allow_unknown_enum_(allow_unknown_enum),
allow_field_number_(allow_field_number),
+ allow_partial_(allow_partial),
had_errors_(false) {
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats.
@@ -368,7 +384,7 @@ class TextFormat::Parser::ParserImpl {
const Descriptor* descriptor = message->GetDescriptor();
string field_name;
-
+ bool reserved_field = false;
const FieldDescriptor* field = NULL;
int start_line = tokenizer_.current().line;
int start_column = tokenizer_.current().column;
@@ -383,9 +399,25 @@ class TextFormat::Parser::ParserImpl {
DO(Consume("]"));
TryConsume(":"); // ':' is optional between message labels and values.
string serialized_value;
- DO(ConsumeAnyValue(full_type_name,
- message->GetDescriptor()->file()->pool(),
- &serialized_value));
+ const Descriptor* value_descriptor =
+ finder_ ? finder_->FindAnyType(*message, prefix, full_type_name)
+ : DefaultFinderFindAnyType(*message, prefix, full_type_name);
+ if (value_descriptor == NULL) {
+ ReportError("Could not find type \"" + prefix + full_type_name +
+ "\" stored in google.protobuf.Any.");
+ return false;
+ }
+ DO(ConsumeAnyValue(value_descriptor, &serialized_value));
+ if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) {
+ // Fail if any_type_url_field has already been specified.
+ if ((!any_type_url_field->is_repeated() &&
+ reflection->HasField(*message, any_type_url_field)) ||
+ (!any_value_field->is_repeated() &&
+ reflection->HasField(*message, any_value_field))) {
+ ReportError("Non-repeated Any specified multiple times.");
+ return false;
+ }
+ }
reflection->SetString(
message, any_type_url_field,
string(prefix + full_type_name));
@@ -397,9 +429,8 @@ class TextFormat::Parser::ParserImpl {
DO(ConsumeFullTypeName(&field_name));
DO(Consume("]"));
- field = (finder_ != NULL
- ? finder_->FindExtension(message, field_name)
- : reflection->FindKnownExtensionByName(field_name));
+ field = finder_ ? finder_->FindExtension(message, field_name)
+ : DefaultFinderFindExtension(message, field_name);
if (field == NULL) {
if (!allow_unknown_field_) {
@@ -420,6 +451,8 @@ class TextFormat::Parser::ParserImpl {
if (allow_field_number_ && safe_strto32(field_name, &field_number)) {
if (descriptor->IsExtensionNumber(field_number)) {
field = reflection->FindKnownExtensionByNumber(field_number);
+ } else if (descriptor->IsReservedNumber(field_number)) {
+ reserved_field = true;
} else {
field = descriptor->FindFieldByNumber(field_number);
}
@@ -448,9 +481,13 @@ class TextFormat::Parser::ParserImpl {
LowerString(&lower_field_name);
field = descriptor->FindFieldByLowercaseName(lower_field_name);
}
+
+ if (field == NULL) {
+ reserved_field = descriptor->IsReservedName(field_name);
+ }
}
- if (field == NULL) {
+ if (field == NULL && !reserved_field) {
if (!allow_unknown_field_) {
ReportError("Message type \"" + descriptor->full_name() +
"\" has no field named \"" + field_name + "\".");
@@ -462,9 +499,10 @@ class TextFormat::Parser::ParserImpl {
}
}
- // Skips unknown field.
+ // Skips unknown or reserved fields.
if (field == NULL) {
- GOOGLE_CHECK(allow_unknown_field_);
+ GOOGLE_CHECK(allow_unknown_field_ || reserved_field);
+
// Try to guess the type of this field.
// If this field is not a message, there should be a ":" between the
// field name and the field value and also the field value should not
@@ -501,32 +539,42 @@ class TextFormat::Parser::ParserImpl {
// Perform special handling for embedded message types.
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
// ':' is optional here.
- TryConsume(":");
+ bool consumed_semicolon = TryConsume(":");
+ if (consumed_semicolon && field->options().weak() && LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ // we are getting a bytes string for a weak field.
+ string tmp;
+ DO(ConsumeString(&tmp));
+ reflection->MutableMessage(message, field)->ParseFromString(tmp);
+ goto label_skip_parsing;
+ }
} else {
// ':' is required here.
DO(Consume(":"));
}
if (field->is_repeated() && TryConsume("[")) {
- // Short repeated format, e.g. "foo: [1, 2, 3]"
- while (true) {
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- // Perform special handling for embedded message types.
- DO(ConsumeFieldMessage(message, reflection, field));
- } else {
- DO(ConsumeFieldValue(message, reflection, field));
- }
- if (TryConsume("]")) {
- break;
+ // Short repeated format, e.g. "foo: [1, 2, 3]".
+ if (!TryConsume("]")) {
+ // "foo: []" is treated as empty.
+ while (true) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Perform special handling for embedded message types.
+ DO(ConsumeFieldMessage(message, reflection, field));
+ } else {
+ DO(ConsumeFieldValue(message, reflection, field));
+ }
+ if (TryConsume("]")) {
+ break;
+ }
+ DO(Consume(","));
}
- DO(Consume(","));
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
DO(ConsumeFieldMessage(message, reflection, field));
} else {
DO(ConsumeFieldValue(message, reflection, field));
}
-
+label_skip_parsing:
// For historical reasons, fields may optionally be separated by commas or
// semicolons.
TryConsume(";") || TryConsume(",");
@@ -548,12 +596,12 @@ class TextFormat::Parser::ParserImpl {
// Skips the next field including the field's name and value.
bool SkipField() {
- string field_name;
if (TryConsume("[")) {
- // Extension name.
- DO(ConsumeFullTypeName(&field_name));
+ // Extension name or type URL.
+ DO(ConsumeTypeUrlOrFullTypeName());
DO(Consume("]"));
} else {
+ string field_name;
DO(ConsumeIdentifier(&field_name));
}
@@ -713,7 +761,8 @@ class TextFormat::Parser::ParserImpl {
value = SimpleItoa(int_value); // for error reporting
enum_value = enum_type->FindValueByNumber(int_value);
} else {
- ReportError("Expected integer or identifier.");
+ ReportError("Expected integer or identifier, got: " +
+ tokenizer_.current().text);
return false;
}
@@ -751,6 +800,20 @@ class TextFormat::Parser::ParserImpl {
}
return true;
}
+ if (TryConsume("[")) {
+ while (true) {
+ if (!LookingAt("{") && !LookingAt("<")) {
+ DO(SkipFieldValue());
+ } else {
+ DO(SkipFieldMessage());
+ }
+ if (TryConsume("]")) {
+ break;
+ }
+ DO(Consume(","));
+ }
+ return true;
+ }
// Possible field values other than string:
// 12345 => TYPE_INTEGER
// -12345 => TYPE_SYMBOL + TYPE_INTEGER
@@ -826,7 +889,7 @@ class TextFormat::Parser::ParserImpl {
return true;
}
- ReportError("Expected identifier.");
+ ReportError("Expected identifier, got: " + tokenizer_.current().text);
return false;
}
@@ -842,11 +905,20 @@ class TextFormat::Parser::ParserImpl {
return true;
}
+ bool ConsumeTypeUrlOrFullTypeName() {
+ string discarded;
+ DO(ConsumeIdentifier(&discarded));
+ while (TryConsume(".") || TryConsume("/")) {
+ DO(ConsumeIdentifier(&discarded));
+ }
+ return true;
+ }
+
// Consumes a string and saves its value in the text parameter.
// Returns false if the token is not of type STRING.
bool ConsumeString(string* text) {
if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
- ReportError("Expected string.");
+ ReportError("Expected string, got: " + tokenizer_.current().text);
return false;
}
@@ -864,13 +936,13 @@ class TextFormat::Parser::ParserImpl {
// Returns false if the token is not of type INTEGER.
bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
- ReportError("Expected integer.");
+ ReportError("Expected integer, got: " + tokenizer_.current().text);
return false;
}
if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
max_value, value)) {
- ReportError("Integer out of range.");
+ ReportError("Integer out of range (" + tokenizer_.current().text + ")");
return false;
}
@@ -897,10 +969,14 @@ class TextFormat::Parser::ParserImpl {
DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
- *value = static_cast<int64>(unsigned_value);
-
if (negative) {
- *value = -*value;
+ if ((static_cast<uint64>(kint64max) + 1) == unsigned_value) {
+ *value = kint64min;
+ } else {
+ *value = -static_cast<int64>(unsigned_value);
+ }
+ } else {
+ *value = static_cast<int64>(unsigned_value);
}
return true;
@@ -910,18 +986,18 @@ class TextFormat::Parser::ParserImpl {
// Accepts decimal numbers only, rejects hex or oct numbers.
bool ConsumeUnsignedDecimalInteger(uint64* value, uint64 max_value) {
if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
- ReportError("Expected integer.");
+ ReportError("Expected integer, got: " + tokenizer_.current().text);
return false;
}
const string& text = tokenizer_.current().text;
if (IsHexNumber(text) || IsOctNumber(text)) {
- ReportError("Expect a decimal number.");
+ ReportError("Expect a decimal number, got: " + text);
return false;
}
if (!io::Tokenizer::ParseInteger(text, max_value, value)) {
- ReportError("Integer out of range.");
+ ReportError("Integer out of range (" + text + ")");
return false;
}
@@ -966,11 +1042,11 @@ class TextFormat::Parser::ParserImpl {
*value = std::numeric_limits<double>::quiet_NaN();
tokenizer_.Next();
} else {
- ReportError("Expected double.");
+ ReportError("Expected double, got: " + text);
return false;
}
} else {
- ReportError("Expected double.");
+ ReportError("Expected double, got: " + tokenizer_.current().text);
return false;
}
@@ -986,49 +1062,44 @@ class TextFormat::Parser::ParserImpl {
bool ConsumeAnyTypeUrl(string* full_type_name, string* prefix) {
// TODO(saito) Extend Consume() to consume multiple tokens at once, so that
// this code can be written as just DO(Consume(kGoogleApisTypePrefix)).
- string url1, url2, url3;
- DO(ConsumeIdentifier(&url1)); // type
- DO(Consume("."));
- DO(ConsumeIdentifier(&url2)); // googleapis
- DO(Consume("."));
- DO(ConsumeIdentifier(&url3)); // com
+ DO(ConsumeIdentifier(prefix));
+ while (TryConsume(".")) {
+ string url;
+ DO(ConsumeIdentifier(&url));
+ *prefix += "." + url;
+ }
DO(Consume("/"));
+ *prefix += "/";
DO(ConsumeFullTypeName(full_type_name));
- *prefix = url1 + "." + url2 + "." + url3 + "/";
- if (*prefix != internal::kTypeGoogleApisComPrefix &&
- *prefix != internal::kTypeGoogleProdComPrefix) {
- ReportError("TextFormat::Parser for Any supports only "
- "type.googleapis.com and type.googleprod.com, "
- "but found \"" + *prefix + "\"");
- return false;
- }
return true;
}
// A helper function for reconstructing Any::value. Consumes a text of
- // full_type_name, then serializes it into serialized_value. "pool" is used to
- // look up and create a temporary object with full_type_name.
- bool ConsumeAnyValue(const string& full_type_name, const DescriptorPool* pool,
+ // full_type_name, then serializes it into serialized_value.
+ bool ConsumeAnyValue(const Descriptor* value_descriptor,
string* serialized_value) {
- const Descriptor* value_descriptor =
- pool->FindMessageTypeByName(full_type_name);
- if (value_descriptor == NULL) {
- ReportError("Could not find type \"" + full_type_name +
- "\" stored in google.protobuf.Any.");
- return false;
- }
DynamicMessageFactory factory;
const Message* value_prototype = factory.GetPrototype(value_descriptor);
if (value_prototype == NULL) {
return false;
}
- google::protobuf::scoped_ptr<Message> value(value_prototype->New());
+ std::unique_ptr<Message> value(value_prototype->New());
string sub_delimiter;
DO(ConsumeMessageDelimiter(&sub_delimiter));
DO(ConsumeMessage(value.get(), sub_delimiter));
- value->AppendToString(serialized_value);
+ if (allow_partial_) {
+ value->AppendPartialToString(serialized_value);
+ } else {
+ if (!value->IsInitialized()) {
+ ReportError(
+ "Value of type \"" + value_descriptor->full_name() +
+ "\" stored in google.protobuf.Any has missing required fields");
+ return false;
+ }
+ value->AppendToString(serialized_value);
+ }
return true;
}
@@ -1083,7 +1154,7 @@ class TextFormat::Parser::ParserImpl {
};
io::ErrorCollector* error_collector_;
- TextFormat::Finder* finder_;
+ const TextFormat::Finder* finder_;
ParseInfoTree* parse_info_tree_;
ParserErrorCollector tokenizer_error_collector_;
io::Tokenizer tokenizer_;
@@ -1093,6 +1164,7 @@ class TextFormat::Parser::ParserImpl {
const bool allow_unknown_field_;
const bool allow_unknown_enum_;
const bool allow_field_number_;
+ const bool allow_partial_;
bool had_errors_;
};
@@ -1101,7 +1173,8 @@ class TextFormat::Parser::ParserImpl {
// ===========================================================================
// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
// from the Printer found in //google/protobuf/io/printer.h
-class TextFormat::Printer::TextGenerator {
+class TextFormat::Printer::TextGenerator
+ : public TextFormat::BaseTextGenerator {
public:
explicit TextGenerator(io::ZeroCopyOutputStream* output,
int initial_indent_level)
@@ -1110,9 +1183,8 @@ class TextFormat::Printer::TextGenerator {
buffer_size_(0),
at_start_of_line_(true),
failed_(false),
- indent_(""),
+ indent_level_(initial_indent_level),
initial_indent_level_(initial_indent_level) {
- indent_.resize(initial_indent_level_ * 2, ' ');
}
~TextGenerator() {
@@ -1126,51 +1198,44 @@ class TextFormat::Printer::TextGenerator {
// Indent text by two spaces. After calling Indent(), two spaces will be
// inserted at the beginning of each line of text. Indent() may be called
// multiple times to produce deeper indents.
- void Indent() {
- indent_ += " ";
- }
+ void Indent() override { ++indent_level_; }
// Reduces the current indent level by two spaces, or crashes if the indent
// level is zero.
- void Outdent() {
- if (indent_.empty() ||
- indent_.size() < initial_indent_level_ * 2) {
+ void Outdent() override {
+ if (indent_level_ == 0 ||
+ indent_level_ < initial_indent_level_) {
GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
return;
}
- indent_.resize(indent_.size() - 2);
- }
-
- // Print text to the output stream.
- void Print(const string& str) {
- Print(str.data(), str.size());
- }
-
- // Print text to the output stream.
- void Print(const char* text) {
- Print(text, strlen(text));
+ --indent_level_;
}
// 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++) {
- 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);
- pos = i + 1;
-
- // Setting this true will cause the next Write() to insert an indent
- // first.
+ void Print(const char* text, size_t size) override {
+ if (indent_level_ > 0) {
+ size_t pos = 0; // The number of bytes we've written so far.
+ for (size_t i = 0; i < size; i++) {
+ if (text[i] == '\n') {
+ // Saw newline. If there is more text, we may need to insert an
+ // indent here. So, write what we have so far, including the '\n'.
+ Write(text + pos, i - pos + 1);
+ pos = i + 1;
+
+ // Setting this true will cause the next Write() to insert an indent
+ // first.
+ at_start_of_line_ = true;
+ }
+ }
+ // Write the rest.
+ Write(text + pos, size - pos);
+ } else {
+ Write(text, size);
+ if (size > 0 && text[size - 1] == '\n') {
at_start_of_line_ = true;
}
}
-
- // Write the rest.
- Write(text + pos, size - pos);
}
// True if any write to the underlying stream failed. (We don't just
@@ -1181,22 +1246,46 @@ class TextFormat::Printer::TextGenerator {
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
- void Write(const char* data, int size) {
+ void Write(const char* data, size_t 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());
+ WriteIndent();
if (failed_) return;
}
while (size > buffer_size_) {
// Data exceeds space in the buffer. Copy what we can and request a
// new buffer.
- memcpy(buffer_, data, buffer_size_);
- data += buffer_size_;
+ if (buffer_size_ > 0) {
+ memcpy(buffer_, data, buffer_size_);
+ data += buffer_size_;
+ size -= buffer_size_;
+ }
+ void* void_buffer = NULL;
+ failed_ = !output_->Next(&void_buffer, &buffer_size_);
+ if (failed_) return;
+ buffer_ = reinterpret_cast<char*>(void_buffer);
+ }
+
+ // Buffer is big enough to receive the data; copy it.
+ memcpy(buffer_, data, size);
+ buffer_ += size;
+ buffer_size_ -= size;
+ }
+
+ void WriteIndent() {
+ if (indent_level_ == 0) { return; }
+ GOOGLE_DCHECK(!failed_);
+ int size = 2 * indent_level_;
+
+ while (size > buffer_size_) {
+ // Data exceeds space in the buffer. Write what we can and request a new
+ // buffer.
+ memset(buffer_, ' ', buffer_size_);
size -= buffer_size_;
void* void_buffer;
failed_ = !output_->Next(&void_buffer, &buffer_size_);
@@ -1205,7 +1294,7 @@ class TextFormat::Printer::TextGenerator {
}
// Buffer is big enough to receive the data; copy it.
- memcpy(buffer_, data, size);
+ memset(buffer_, ' ', size);
buffer_ += size;
buffer_size_ -= size;
}
@@ -1216,15 +1305,28 @@ class TextFormat::Printer::TextGenerator {
bool at_start_of_line_;
bool failed_;
- string indent_;
+ int indent_level_;
int initial_indent_level_;
};
// ===========================================================================
-
+// Implementation of the default Finder for extensions.
TextFormat::Finder::~Finder() {
}
+const FieldDescriptor* TextFormat::Finder::FindExtension(
+ Message* message, const string& name) const {
+ return DefaultFinderFindExtension(message, name);
+}
+
+const Descriptor* TextFormat::Finder::FindAnyType(const Message& message,
+ const string& prefix,
+ const string& name) const {
+ return DefaultFinderFindAnyType(message, prefix, name);
+}
+
+// ===========================================================================
+
TextFormat::Parser::Parser()
: error_collector_(NULL),
finder_(NULL),
@@ -1254,7 +1356,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
overwrites_policy,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return MergeUsingImpl(input, output, &parser);
}
@@ -1264,6 +1366,7 @@ bool TextFormat::Parser::ParseFromString(const string& input,
return Parse(&input_stream, output);
}
+
bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
Message* output) {
ParserImpl parser(output->GetDescriptor(), input, error_collector_,
@@ -1271,7 +1374,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return MergeUsingImpl(input, output, &parser);
}
@@ -1281,15 +1384,17 @@ bool TextFormat::Parser::MergeFromString(const string& input,
return Merge(&input_stream, output);
}
+
bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* /* input */,
Message* output,
ParserImpl* parser_impl) {
if (!parser_impl->Parse(output)) return false;
if (!allow_partial_ && !output->IsInitialized()) {
- vector<string> missing_fields;
+ std::vector<string> missing_fields;
output->FindInitializationErrors(&missing_fields);
- parser_impl->ReportError(-1, 0, "Message missing required fields: " +
- Join(missing_fields, ", "));
+ parser_impl->ReportError(-1, 0,
+ "Message missing required fields: " +
+ Join(missing_fields, ", "));
return false;
}
return true;
@@ -1305,7 +1410,7 @@ bool TextFormat::Parser::ParseFieldValueFromString(
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
- allow_relaxed_whitespace_);
+ allow_relaxed_whitespace_, allow_partial_);
return parser.ParseField(field, output);
}
@@ -1329,92 +1434,290 @@ bool TextFormat::Parser::ParseFieldValueFromString(
return Parser().MergeFromString(input, output);
}
+
// ===========================================================================
-// The default implementation for FieldValuePrinter. The base class just
-// does simple formatting. That way, deriving classes could decide to fallback
-// to that behavior.
+TextFormat::BaseTextGenerator::~BaseTextGenerator() {}
+
+namespace {
+
+// A BaseTextGenerator that writes to a string.
+class StringBaseTextGenerator : public TextFormat::BaseTextGenerator {
+ public:
+ void Print(const char* text, size_t size) { output_.append(text, size); }
+
+// Some compilers do not support ref-qualifiers even in C++11 mode.
+// Disable the optimization for now and revisit it later.
+#if 0 // LANG_CXX11
+ string Consume() && { return std::move(output_); }
+#else // !LANG_CXX11
+ const string& Get() { return output_; }
+#endif // LANG_CXX11
+
+ private:
+ string output_;
+};
+
+} // namespace
+
+// The default implementation for FieldValuePrinter. We just delegate the
+// implementation to the default FastFieldValuePrinter to avoid duplicating the
+// logic.
TextFormat::FieldValuePrinter::FieldValuePrinter() {}
TextFormat::FieldValuePrinter::~FieldValuePrinter() {}
+
+#if 0 // LANG_CXX11
+#define FORWARD_IMPL(fn, ...) \
+ StringBaseTextGenerator generator; \
+ delegate_.fn(__VA_ARGS__, &generator); \
+ return std::move(generator).Consume()
+#else // !LANG_CXX11
+#define FORWARD_IMPL(fn, ...) \
+ StringBaseTextGenerator generator; \
+ delegate_.fn(__VA_ARGS__, &generator); \
+ return generator.Get()
+#endif // LANG_CXX11
+
string TextFormat::FieldValuePrinter::PrintBool(bool val) const {
- return val ? "true" : "false";
+ FORWARD_IMPL(PrintBool, val);
}
string TextFormat::FieldValuePrinter::PrintInt32(int32 val) const {
- return SimpleItoa(val);
+ FORWARD_IMPL(PrintInt32, val);
}
string TextFormat::FieldValuePrinter::PrintUInt32(uint32 val) const {
- return SimpleItoa(val);
+ FORWARD_IMPL(PrintUInt32, val);
}
string TextFormat::FieldValuePrinter::PrintInt64(int64 val) const {
- return SimpleItoa(val);
+ FORWARD_IMPL(PrintInt64, val);
}
string TextFormat::FieldValuePrinter::PrintUInt64(uint64 val) const {
- return SimpleItoa(val);
+ FORWARD_IMPL(PrintUInt64, val);
}
string TextFormat::FieldValuePrinter::PrintFloat(float val) const {
- return SimpleFtoa(val);
+ FORWARD_IMPL(PrintFloat, val);
}
string TextFormat::FieldValuePrinter::PrintDouble(double val) const {
- return SimpleDtoa(val);
+ FORWARD_IMPL(PrintDouble, val);
}
string TextFormat::FieldValuePrinter::PrintString(const string& val) const {
- string printed("\"");
- CEscapeAndAppend(val, &printed);
- printed.push_back('\"');
- return printed;
+ FORWARD_IMPL(PrintString, val);
}
string TextFormat::FieldValuePrinter::PrintBytes(const string& val) const {
return PrintString(val);
}
string TextFormat::FieldValuePrinter::PrintEnum(int32 val,
const string& name) const {
- return name;
+ FORWARD_IMPL(PrintEnum, val, name);
}
string TextFormat::FieldValuePrinter::PrintFieldName(
const Message& message,
const Reflection* reflection,
const FieldDescriptor* field) const {
- if (field->is_extension()) {
- // 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()) {
- return StrCat("[", field->message_type()->full_name(), "]");
- } else {
- return StrCat("[", field->full_name(), "]");
- }
- } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
- // Groups must be serialized with their original capitalization.
- return field->message_type()->name();
- } else {
- return field->name();
- }
+ FORWARD_IMPL(PrintFieldName, message, reflection, field);
}
string TextFormat::FieldValuePrinter::PrintMessageStart(
const Message& message,
int field_index,
int field_count,
bool single_line_mode) const {
- return single_line_mode ? " { " : " {\n";
+ FORWARD_IMPL(PrintMessageStart, message, field_index, field_count,
+ single_line_mode);
}
string TextFormat::FieldValuePrinter::PrintMessageEnd(
const Message& message,
int field_index,
int field_count,
bool single_line_mode) const {
- return single_line_mode ? "} " : "}\n";
+ FORWARD_IMPL(PrintMessageEnd, message, field_index, field_count,
+ single_line_mode);
+}
+#undef FORWARD_IMPL
+
+TextFormat::FastFieldValuePrinter::FastFieldValuePrinter() {}
+TextFormat::FastFieldValuePrinter::~FastFieldValuePrinter() {}
+void TextFormat::FastFieldValuePrinter::PrintBool(
+ bool val, BaseTextGenerator* generator) const {
+ if (val) {
+ generator->PrintLiteral("true");
+ } else {
+ generator->PrintLiteral("false");
+ }
+}
+void TextFormat::FastFieldValuePrinter::PrintInt32(
+ int32 val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleItoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt32(
+ uint32 val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleItoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintInt64(
+ int64 val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleItoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintUInt64(
+ uint64 val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleItoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintFloat(
+ float val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleFtoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintDouble(
+ double val, BaseTextGenerator* generator) const {
+ generator->PrintString(SimpleDtoa(val));
+}
+void TextFormat::FastFieldValuePrinter::PrintEnum(
+ int32 val, const string& name, BaseTextGenerator* generator) const {
+ generator->PrintString(name);
+}
+
+void TextFormat::FastFieldValuePrinter::PrintString(
+ const string& val, BaseTextGenerator* generator) const {
+ generator->PrintLiteral("\"");
+ generator->PrintString(CEscape(val));
+ generator->PrintLiteral("\"");
+}
+void TextFormat::FastFieldValuePrinter::PrintBytes(
+ const string& val, BaseTextGenerator* generator) const {
+ PrintString(val, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+ const Message& message, int field_index, int field_count,
+ const Reflection* reflection, const FieldDescriptor* field,
+ BaseTextGenerator* generator) const {
+ PrintFieldName(message, reflection, field, generator);
+}
+void TextFormat::FastFieldValuePrinter::PrintFieldName(
+ const Message& message, const Reflection* reflection,
+ const FieldDescriptor* field, BaseTextGenerator* generator) const {
+ if (field->is_extension()) {
+ generator->PrintLiteral("[");
+ // 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->PrintString(field->message_type()->full_name());
+ } else {
+ generator->PrintString(field->full_name());
+ }
+ generator->PrintLiteral("]");
+ } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+ // Groups must be serialized with their original capitalization.
+ generator->PrintString(field->message_type()->name());
+ } else {
+ generator->PrintString(field->name());
+ }
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageStart(
+ const Message& message, int field_index, int field_count,
+ bool single_line_mode, BaseTextGenerator* generator) const {
+ if (single_line_mode) {
+ generator->PrintLiteral(" { ");
+ } else {
+ generator->PrintLiteral(" {\n");
+ }
+}
+void TextFormat::FastFieldValuePrinter::PrintMessageEnd(
+ const Message& message, int field_index, int field_count,
+ bool single_line_mode, BaseTextGenerator* generator) const {
+ if (single_line_mode) {
+ generator->PrintLiteral("} ");
+ } else {
+ generator->PrintLiteral("}\n");
+ }
}
namespace {
+
+// A legacy compatibility wrapper. Takes ownership of the delegate.
+class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter {
+ public:
+ explicit FieldValuePrinterWrapper(
+ const TextFormat::FieldValuePrinter* delegate)
+ : delegate_(delegate) {}
+
+ void SetDelegate(const TextFormat::FieldValuePrinter* delegate) {
+ delegate_.reset(delegate);
+ }
+
+ void PrintBool(bool val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintBool(val));
+ }
+ void PrintInt32(int32 val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintInt32(val));
+ }
+ void PrintUInt32(uint32 val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintUInt32(val));
+ }
+ void PrintInt64(int64 val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintInt64(val));
+ }
+ void PrintUInt64(uint64 val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintUInt64(val));
+ }
+ void PrintFloat(float val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintFloat(val));
+ }
+ void PrintDouble(double val, TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintDouble(val));
+ }
+ void PrintString(const string& val,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintString(val));
+ }
+ void PrintBytes(const string& val,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintBytes(val));
+ }
+ void PrintEnum(int32 val, const string& name,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintEnum(val, name));
+ }
+ void PrintFieldName(const Message& message, int field_index, int field_count,
+ const Reflection* reflection,
+ const FieldDescriptor* field,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintFieldName(
+ message, reflection, field));
+ }
+ void PrintFieldName(const Message& message, const Reflection* reflection,
+ const FieldDescriptor* field,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(
+ delegate_->PrintFieldName(message, reflection, field));
+ }
+ void PrintMessageStart(const Message& message, int field_index,
+ int field_count, bool single_line_mode,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintMessageStart(
+ message, field_index, field_count, single_line_mode));
+ }
+ void PrintMessageEnd(const Message& message, int field_index, int field_count,
+ bool single_line_mode,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintString(delegate_->PrintMessageEnd(
+ message, field_index, field_count, single_line_mode));
+ }
+
+ private:
+ std::unique_ptr<const TextFormat::FieldValuePrinter> delegate_;
+};
+
// Our own specialization: for UTF8 escaped strings.
-class FieldValuePrinterUtf8Escaping : public TextFormat::FieldValuePrinter {
+class FastFieldValuePrinterUtf8Escaping
+ : public TextFormat::FastFieldValuePrinter {
public:
- virtual string PrintString(const string& val) const {
- return StrCat("\"", strings::Utf8SafeCEscape(val), "\"");
+ void PrintString(const string& val,
+ TextFormat::BaseTextGenerator* generator) const {
+ generator->PrintLiteral("\"");
+ generator->PrintString(strings::Utf8SafeCEscape(val));
+ generator->PrintLiteral("\"");
}
- virtual string PrintBytes(const string& val) const {
- return TextFormat::FieldValuePrinter::PrintString(val);
+ void PrintBytes(const string& val,
+ TextFormat::BaseTextGenerator* generator) const {
+ return FastFieldValuePrinter::PrintString(val, generator);
}
};
@@ -1428,32 +1731,61 @@ TextFormat::Printer::Printer()
hide_unknown_fields_(false),
print_message_fields_in_index_order_(false),
expand_any_(false),
- truncate_string_field_longer_than_(0LL) {
+ truncate_string_field_longer_than_(0LL),
+ finder_(NULL) {
SetUseUtf8StringEscaping(false);
}
TextFormat::Printer::~Printer() {
STLDeleteValues(&custom_printers_);
+ STLDeleteValues(&custom_message_printers_);
}
void TextFormat::Printer::SetUseUtf8StringEscaping(bool as_utf8) {
- SetDefaultFieldValuePrinter(as_utf8
- ? new FieldValuePrinterUtf8Escaping()
- : new FieldValuePrinter());
+ SetDefaultFieldValuePrinter(as_utf8 ? new FastFieldValuePrinterUtf8Escaping()
+ : new FastFieldValuePrinter());
}
void TextFormat::Printer::SetDefaultFieldValuePrinter(
const FieldValuePrinter* printer) {
+ default_field_value_printer_.reset(new FieldValuePrinterWrapper(printer));
+}
+
+void TextFormat::Printer::SetDefaultFieldValuePrinter(
+ const FastFieldValuePrinter* printer) {
default_field_value_printer_.reset(printer);
}
bool TextFormat::Printer::RegisterFieldValuePrinter(
const FieldDescriptor* field,
const FieldValuePrinter* printer) {
+ if (field == NULL || printer == NULL) {
+ return false;
+ }
+ FieldValuePrinterWrapper* const wrapper =
+ new FieldValuePrinterWrapper(nullptr);
+ if (custom_printers_.insert(std::make_pair(field, wrapper)).second) {
+ wrapper->SetDelegate(printer);
+ return true;
+ } else {
+ delete wrapper;
+ return false;
+ }
+}
+
+bool TextFormat::Printer::RegisterFieldValuePrinter(
+ const FieldDescriptor* field, const FastFieldValuePrinter* printer) {
return field != NULL && printer != NULL &&
custom_printers_.insert(std::make_pair(field, printer)).second;
}
+bool TextFormat::Printer::RegisterMessagePrinter(
+ const Descriptor* descriptor, const MessagePrinter* printer) {
+ return descriptor != nullptr && printer != nullptr &&
+ custom_message_printers_.insert(std::make_pair(descriptor, printer))
+ .second;
+}
+
bool TextFormat::Printer::PrintToString(const Message& message,
string* output) const {
GOOGLE_DCHECK(output) << "output specified is NULL";
@@ -1478,7 +1810,7 @@ bool TextFormat::Printer::Print(const Message& message,
io::ZeroCopyOutputStream* output) const {
TextGenerator generator(output, initial_indent_level_);
- Print(message, generator);
+ Print(message, &generator);
// Output false if the generator failed internally.
return !generator.failed();
@@ -1489,7 +1821,7 @@ bool TextFormat::Printer::PrintUnknownFields(
io::ZeroCopyOutputStream* output) const {
TextGenerator generator(output, initial_indent_level_);
- PrintUnknownFields(unknown_fields, generator);
+ PrintUnknownFields(unknown_fields, &generator);
// Output false if the generator failed internally.
return !generator.failed();
@@ -1497,17 +1829,26 @@ bool TextFormat::Printer::PrintUnknownFields(
namespace {
// Comparison functor for sorting FieldDescriptors by field index.
+// Normal fields have higher precedence than extensions.
struct FieldIndexSorter {
bool operator()(const FieldDescriptor* left,
const FieldDescriptor* right) const {
- return left->index() < right->index();
+ if (left->is_extension() && right->is_extension()) {
+ return left->number() < right->number();
+ } else if (left->is_extension()) {
+ return false;
+ } else if (right->is_extension()) {
+ return true;
+ } else {
+ return left->index() < right->index();
+ }
}
};
} // namespace
bool TextFormat::Printer::PrintAny(const Message& message,
- TextGenerator& generator) const {
+ TextGenerator* generator) const {
const FieldDescriptor* type_url_field;
const FieldDescriptor* value_field;
if (!internal::GetAnyFieldDescriptors(message, &type_url_field,
@@ -1519,48 +1860,55 @@ bool TextFormat::Printer::PrintAny(const Message& message,
// Extract the full type name from the type_url field.
const string& type_url = reflection->GetString(message, type_url_field);
+ string url_prefix;
string full_type_name;
- if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
+ if (!internal::ParseAnyTypeUrl(type_url, &url_prefix, &full_type_name)) {
return false;
}
// Print the "value" in text.
const google::protobuf::Descriptor* value_descriptor =
- message.GetDescriptor()->file()->pool()->FindMessageTypeByName(
- full_type_name);
+ finder_ ? finder_->FindAnyType(message, url_prefix, full_type_name)
+ : DefaultFinderFindAnyType(message, url_prefix, full_type_name);
if (value_descriptor == NULL) {
GOOGLE_LOG(WARNING) << "Proto type " << type_url << " not found";
return false;
}
DynamicMessageFactory factory;
- google::protobuf::scoped_ptr<google::protobuf::Message> value_message(
+ std::unique_ptr<google::protobuf::Message> value_message(
factory.GetPrototype(value_descriptor)->New());
string serialized_value = reflection->GetString(message, value_field);
if (!value_message->ParseFromString(serialized_value)) {
GOOGLE_LOG(WARNING) << type_url << ": failed to parse contents";
return false;
}
- generator.Print(StrCat("[", type_url, "]"));
- const FieldValuePrinter* printer = FindWithDefault(
+ generator->PrintLiteral("[");
+ generator->PrintString(type_url);
+ generator->PrintLiteral("]");
+ const FastFieldValuePrinter* printer = FindWithDefault(
custom_printers_, value_field, default_field_value_printer_.get());
- generator.Print(
- printer->PrintMessageStart(message, -1, 0, single_line_mode_));
- generator.Indent();
+ printer->PrintMessageStart(message, -1, 0, single_line_mode_, generator);
+ generator->Indent();
Print(*value_message, generator);
- generator.Outdent();
- generator.Print(printer->PrintMessageEnd(message, -1, 0, single_line_mode_));
+ generator->Outdent();
+ printer->PrintMessageEnd(message, -1, 0, single_line_mode_, generator);
return true;
}
void TextFormat::Printer::Print(const Message& message,
- TextGenerator& generator) const {
+ TextGenerator* generator) const {
const Descriptor* descriptor = message.GetDescriptor();
+ auto itr = custom_message_printers_.find(descriptor);
+ if (itr != custom_message_printers_.end()) {
+ itr->second->Print(message, single_line_mode_, generator);
+ return;
+ }
const Reflection* reflection = message.GetReflection();
if (descriptor->full_name() == internal::kAnyFullTypeName && expand_any_ &&
PrintAny(message, generator)) {
return;
}
- vector<const FieldDescriptor*> fields;
+ std::vector<const FieldDescriptor*> fields;
reflection->ListFields(message, &fields);
if (print_message_fields_in_index_order_) {
std::sort(fields.begin(), fields.end(), FieldIndexSorter());
@@ -1578,68 +1926,19 @@ void TextFormat::Printer::PrintFieldValueToString(
const FieldDescriptor* field,
int index,
string* output) const {
-
GOOGLE_DCHECK(output) << "output specified is NULL";
output->clear();
io::StringOutputStream output_stream(output);
TextGenerator generator(&output_stream, initial_indent_level_);
- PrintFieldValue(message, message.GetReflection(), field, index, generator);
+ PrintFieldValue(message, message.GetReflection(), field, index, &generator);
}
-class MapEntryMessageComparator {
- public:
- explicit MapEntryMessageComparator(const Descriptor* descriptor)
- : field_(descriptor->field(0)) {}
-
- bool operator()(const Message* a, const Message* b) {
- const Reflection* reflection = a->GetReflection();
- switch (field_->cpp_type()) {
- case FieldDescriptor::CPPTYPE_BOOL: {
- bool first = reflection->GetBool(*a, field_);
- bool second = reflection->GetBool(*b, field_);
- return first < second;
- }
- case FieldDescriptor::CPPTYPE_INT32: {
- int32 first = reflection->GetInt32(*a, field_);
- int32 second = reflection->GetInt32(*b, field_);
- return first < second;
- }
- case FieldDescriptor::CPPTYPE_INT64: {
- int64 first = reflection->GetInt64(*a, field_);
- int64 second = reflection->GetInt64(*b, field_);
- return first < second;
- }
- case FieldDescriptor::CPPTYPE_UINT32: {
- uint32 first = reflection->GetUInt32(*a, field_);
- uint32 second = reflection->GetUInt32(*b, field_);
- return first < second;
- }
- case FieldDescriptor::CPPTYPE_UINT64: {
- uint64 first = reflection->GetUInt64(*a, field_);
- uint64 second = reflection->GetUInt64(*b, field_);
- return first < second;
- }
- case FieldDescriptor::CPPTYPE_STRING: {
- string first = reflection->GetString(*a, field_);
- string second = reflection->GetString(*b, field_);
- return first < second;
- }
- default:
- GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
- return true;
- }
- }
-
- private:
- const FieldDescriptor* field_;
-};
-
void TextFormat::Printer::PrintField(const Message& message,
const Reflection* reflection,
const FieldDescriptor* field,
- TextGenerator& generator) const {
+ TextGenerator* generator) const {
if (use_short_repeated_primitives_ &&
field->is_repeated() &&
field->cpp_type() != FieldDescriptor::CPPTYPE_STRING &&
@@ -1656,114 +1955,102 @@ void TextFormat::Printer::PrintField(const Message& message,
count = 1;
}
- std::vector<const Message*> sorted_map_field;
- if (field->is_map()) {
- const RepeatedPtrField<Message>& map_field =
- reflection->GetRepeatedPtrField<Message>(message, field);
- for (RepeatedPtrField<Message>::const_pointer_iterator it =
- map_field.pointer_begin();
- it != map_field.pointer_end(); ++it) {
- sorted_map_field.push_back(*it);
- }
-
- MapEntryMessageComparator comparator(field->message_type());
- std::stable_sort(sorted_map_field.begin(), sorted_map_field.end(),
- comparator);
+ std::vector<const Message*> map_entries;
+ const bool is_map = field->is_map();
+ if (is_map) {
+ map_entries = DynamicMapSorter::Sort(message, count, reflection, field);
}
for (int j = 0; j < count; ++j) {
const int field_index = field->is_repeated() ? j : -1;
- PrintFieldName(message, reflection, field, generator);
+ PrintFieldName(message, field_index, count, reflection, field, generator);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- const FieldValuePrinter* printer = FindWithDefault(
+ const FastFieldValuePrinter* printer = FindWithDefault(
custom_printers_, field, default_field_value_printer_.get());
const Message& sub_message =
field->is_repeated()
- ? (field->is_map()
- ? *sorted_map_field[j]
- : reflection->GetRepeatedMessage(message, field, j))
+ ? (is_map ? *map_entries[j]
+ : reflection->GetRepeatedMessage(message, field, j))
: reflection->GetMessage(message, field);
- generator.Print(
- printer->PrintMessageStart(
- sub_message, field_index, count, single_line_mode_));
- generator.Indent();
+ printer->PrintMessageStart(sub_message, field_index, count,
+ single_line_mode_, generator);
+ generator->Indent();
Print(sub_message, generator);
- generator.Outdent();
- generator.Print(
- printer->PrintMessageEnd(
- sub_message, field_index, count, single_line_mode_));
+ generator->Outdent();
+ printer->PrintMessageEnd(sub_message, field_index, count,
+ single_line_mode_, generator);
} else {
- generator.Print(": ");
+ generator->PrintLiteral(": ");
// Write the field value.
PrintFieldValue(message, reflection, field, field_index, generator);
if (single_line_mode_) {
- generator.Print(" ");
+ generator->PrintLiteral(" ");
} else {
- generator.Print("\n");
+ generator->PrintLiteral("\n");
}
}
}
}
void TextFormat::Printer::PrintShortRepeatedField(
- const Message& message,
- const Reflection* reflection,
- const FieldDescriptor* field,
- TextGenerator& generator) const {
+ const Message& message, const Reflection* reflection,
+ const FieldDescriptor* field, TextGenerator* generator) const {
// Print primitive repeated field in short form.
- PrintFieldName(message, reflection, field, generator);
-
int size = reflection->FieldSize(message, field);
- generator.Print(": [");
+ PrintFieldName(message, /*field_index=*/-1, /*field_count=*/size, reflection,
+ field, generator);
+ generator->PrintLiteral(": [");
for (int i = 0; i < size; i++) {
- if (i > 0) generator.Print(", ");
+ if (i > 0) generator->PrintLiteral(", ");
PrintFieldValue(message, reflection, field, i, generator);
}
if (single_line_mode_) {
- generator.Print("] ");
+ generator->PrintLiteral("] ");
} else {
- generator.Print("]\n");
+ generator->PrintLiteral("]\n");
}
}
void TextFormat::Printer::PrintFieldName(const Message& message,
+ int field_index, int field_count,
const Reflection* reflection,
const FieldDescriptor* field,
- TextGenerator& generator) const {
+ TextGenerator* generator) const {
// if use_field_number_ is true, prints field number instead
// of field name.
if (use_field_number_) {
- generator.Print(SimpleItoa(field->number()));
+ generator->PrintString(SimpleItoa(field->number()));
return;
}
- const FieldValuePrinter* printer = FindWithDefault(
+ const FastFieldValuePrinter* printer = FindWithDefault(
custom_printers_, field, default_field_value_printer_.get());
- generator.Print(printer->PrintFieldName(message, reflection, field));
+ printer->PrintFieldName(message, field_index, field_count, reflection, field,
+ generator);
}
-void TextFormat::Printer::PrintFieldValue(
- const Message& message,
- const Reflection* reflection,
- const FieldDescriptor* field,
- int index,
- TextGenerator& generator) const {
+void TextFormat::Printer::PrintFieldValue(const Message& message,
+ const Reflection* reflection,
+ const FieldDescriptor* field,
+ int index,
+ TextGenerator* generator) const {
GOOGLE_DCHECK(field->is_repeated() || (index == -1))
<< "Index must be -1 for non-repeated fields";
- const FieldValuePrinter* printer
- = FindWithDefault(custom_printers_, field,
- default_field_value_printer_.get());
+ const FastFieldValuePrinter* printer = FindWithDefault(
+ custom_printers_, field, default_field_value_printer_.get());
switch (field->cpp_type()) {
-#define OUTPUT_FIELD(CPPTYPE, METHOD) \
- case FieldDescriptor::CPPTYPE_##CPPTYPE: \
- generator.Print(printer->Print##METHOD(field->is_repeated() \
- ? reflection->GetRepeated##METHOD(message, field, index) \
- : reflection->Get##METHOD(message, field))); \
- break
+#define OUTPUT_FIELD(CPPTYPE, METHOD) \
+ case FieldDescriptor::CPPTYPE_##CPPTYPE: \
+ printer->Print##METHOD( \
+ field->is_repeated() \
+ ? reflection->GetRepeated##METHOD(message, field, index) \
+ : reflection->Get##METHOD(message, field), \
+ generator); \
+ break
OUTPUT_FIELD( INT32, Int32);
OUTPUT_FIELD( INT64, Int64);
@@ -1780,21 +2067,19 @@ void TextFormat::Printer::PrintFieldValue(
? reflection->GetRepeatedStringReference(
message, field, index, &scratch)
: reflection->GetStringReference(message, field, &scratch);
- int64 size = value.size();
- if (truncate_string_field_longer_than_ > 0) {
- size = std::min(truncate_string_field_longer_than_,
- static_cast<int64>(value.size()));
- }
- string truncated_value(value.substr(0, size) + "...<truncated>...");
const string* value_to_print = &value;
- if (size < value.size()) {
+ string truncated_value;
+ if (truncate_string_field_longer_than_ > 0 &&
+ truncate_string_field_longer_than_ < value.size()) {
+ truncated_value = value.substr(0, truncate_string_field_longer_than_) +
+ "...<truncated>...";
value_to_print = &truncated_value;
}
if (field->type() == FieldDescriptor::TYPE_STRING) {
- generator.Print(printer->PrintString(*value_to_print));
+ printer->PrintString(*value_to_print, generator);
} else {
GOOGLE_DCHECK_EQ(field->type(), FieldDescriptor::TYPE_BYTES);
- generator.Print(printer->PrintBytes(*value_to_print));
+ printer->PrintBytes(*value_to_print, generator);
}
break;
}
@@ -1806,7 +2091,7 @@ void TextFormat::Printer::PrintFieldValue(
const EnumValueDescriptor* enum_desc =
field->enum_type()->FindValueByNumber(enum_value);
if (enum_desc != NULL) {
- generator.Print(printer->PrintEnum(enum_value, enum_desc->name()));
+ printer->PrintEnum(enum_value, enum_desc->name(), generator);
} else {
// Ordinarily, enum_desc should not be null, because proto2 has the
// invariant that set enum field values must be in-range, but with the
@@ -1814,8 +2099,8 @@ void TextFormat::Printer::PrintFieldValue(
// it is possible for the user to force an unknown integer value. So we
// simply use the integer value itself as the enum value name in this
// case.
- generator.Print(printer->PrintEnum(enum_value,
- StringPrintf("%d", enum_value)));
+ printer->PrintEnum(enum_value, StringPrintf("%d", enum_value),
+ generator);
}
break;
}
@@ -1878,90 +2163,93 @@ static string PaddedHex(IntType value) {
}
void TextFormat::Printer::PrintUnknownFields(
- const UnknownFieldSet& unknown_fields, TextGenerator& generator) const {
+ const UnknownFieldSet& unknown_fields, TextGenerator* generator) const {
for (int i = 0; i < unknown_fields.field_count(); i++) {
const UnknownField& field = unknown_fields.field(i);
string field_number = SimpleItoa(field.number());
switch (field.type()) {
case UnknownField::TYPE_VARINT:
- generator.Print(field_number);
- generator.Print(": ");
- generator.Print(SimpleItoa(field.varint()));
+ generator->PrintString(field_number);
+ generator->PrintLiteral(": ");
+ generator->PrintString(SimpleItoa(field.varint()));
if (single_line_mode_) {
- generator.Print(" ");
+ generator->PrintLiteral(" ");
} else {
- generator.Print("\n");
+ generator->PrintLiteral("\n");
}
break;
case UnknownField::TYPE_FIXED32: {
- generator.Print(field_number);
- generator.Print(": 0x");
- generator.Print(
+ generator->PrintString(field_number);
+ generator->PrintLiteral(": 0x");
+ generator->PrintString(
StrCat(strings::Hex(field.fixed32(), strings::ZERO_PAD_8)));
if (single_line_mode_) {
- generator.Print(" ");
+ generator->PrintLiteral(" ");
} else {
- generator.Print("\n");
+ generator->PrintLiteral("\n");
}
break;
}
case UnknownField::TYPE_FIXED64: {
- generator.Print(field_number);
- generator.Print(": 0x");
- generator.Print(
+ generator->PrintString(field_number);
+ generator->PrintLiteral(": 0x");
+ generator->PrintString(
StrCat(strings::Hex(field.fixed64(), strings::ZERO_PAD_16)));
if (single_line_mode_) {
- generator.Print(" ");
+ generator->PrintLiteral(" ");
} else {
- generator.Print("\n");
+ generator->PrintLiteral("\n");
}
break;
}
case UnknownField::TYPE_LENGTH_DELIMITED: {
- generator.Print(field_number);
+ generator->PrintString(field_number);
const string& value = field.length_delimited();
UnknownFieldSet embedded_unknown_fields;
if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) {
// This field is parseable as a Message.
// So it is probably an embedded message.
if (single_line_mode_) {
- generator.Print(" { ");
+ generator->PrintLiteral(" { ");
} else {
- generator.Print(" {\n");
- generator.Indent();
+ generator->PrintLiteral(" {\n");
+ generator->Indent();
}
PrintUnknownFields(embedded_unknown_fields, generator);
if (single_line_mode_) {
- generator.Print("} ");
+ generator->PrintLiteral("} ");
} else {
- generator.Outdent();
- generator.Print("}\n");
+ generator->Outdent();
+ generator->PrintLiteral("}\n");
}
} else {
// This field is not parseable as a Message.
// So it is probably just a plain string.
- string printed(": \"");
- CEscapeAndAppend(value, &printed);
- printed.append(single_line_mode_ ? "\" " : "\"\n");
- generator.Print(printed);
+ generator->PrintLiteral(": \"");
+ generator->PrintString(CEscape(value));
+ if (single_line_mode_) {
+ generator->PrintLiteral("\" ");
+ } else {
+ generator->PrintLiteral("\"\n");
+ }
}
break;
}
case UnknownField::TYPE_GROUP:
- generator.Print(field_number);
+ generator->PrintString(field_number);
if (single_line_mode_) {
- generator.Print(" { ");
+ generator->PrintLiteral(" { ");
} else {
- generator.Print(" {\n");
- generator.Indent();
+ generator->PrintLiteral(" {\n");
+ generator->Indent();
}
PrintUnknownFields(field.group(), generator);
if (single_line_mode_) {
- generator.Print("} ");
+ generator->PrintLiteral("} ");
} else {
- generator.Outdent();
- generator.Print("}\n");
+ generator->Outdent();
+ generator->PrintLiteral("}\n");
}
break;
}