840 lines
36 KiB
C
840 lines
36 KiB
C
|
// Protocol Buffers - Google's data interchange format
|
||
|
// Copyright 2008 Google LLC. All rights reserved.
|
||
|
//
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file or at
|
||
|
// https://developers.google.com/open-source/licenses/bsd
|
||
|
|
||
|
// Author: jschorr@google.com (Joseph Schorr)
|
||
|
// Based on original Protocol Buffers design by
|
||
|
// Sanjay Ghemawat, Jeff Dean, and others.
|
||
|
//
|
||
|
// Utilities for printing and parsing protocol messages in a human-readable,
|
||
|
// text-based format.
|
||
|
|
||
|
#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|
||
|
#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|
||
|
|
||
|
#include <atomic>
|
||
|
#include <memory>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "absl/container/flat_hash_map.h"
|
||
|
#include "absl/container/flat_hash_set.h"
|
||
|
#include "absl/strings/cord.h"
|
||
|
#include "absl/strings/string_view.h"
|
||
|
#include "google/protobuf/descriptor.h"
|
||
|
#include "google/protobuf/message.h"
|
||
|
#include "google/protobuf/message_lite.h"
|
||
|
#include "google/protobuf/port.h"
|
||
|
|
||
|
|
||
|
// Must be included last.
|
||
|
#include "google/protobuf/port_def.inc"
|
||
|
|
||
|
#ifdef SWIG
|
||
|
#error "You cannot SWIG proto headers"
|
||
|
#endif
|
||
|
|
||
|
namespace google {
|
||
|
namespace protobuf {
|
||
|
|
||
|
namespace internal {
|
||
|
PROTOBUF_EXPORT extern const char kDebugStringSilentMarker[1];
|
||
|
PROTOBUF_EXPORT extern const char kDebugStringSilentMarkerForDetection[3];
|
||
|
|
||
|
PROTOBUF_EXPORT extern std::atomic<bool> enable_debug_string_safe_format;
|
||
|
PROTOBUF_EXPORT int64_t GetRedactedFieldCount();
|
||
|
PROTOBUF_EXPORT bool ShouldRedactField(const FieldDescriptor* field);
|
||
|
|
||
|
// This enum contains all the APIs that convert protos to human-readable
|
||
|
// formats. A higher-level API must correspond to a greater number than any
|
||
|
// lower-level APIs it calls under the hood (e.g kDebugString >
|
||
|
// kMemberPrintToString > kPrintWithStream).
|
||
|
PROTOBUF_EXPORT enum class FieldReporterLevel {
|
||
|
kNoReport = 0,
|
||
|
kPrintMessage = 1,
|
||
|
kPrintWithGenerator = 2,
|
||
|
kPrintWithStream = 3,
|
||
|
kMemberPrintToString = 4,
|
||
|
kStaticPrintToString = 5,
|
||
|
kAbslStringify = 6,
|
||
|
kShortFormat = 7,
|
||
|
kUtf8Format = 8,
|
||
|
kDebugString = 12,
|
||
|
kShortDebugString = 13,
|
||
|
kUtf8DebugString = 14,
|
||
|
kUnredactedDebugFormatForTest = 15,
|
||
|
kUnredactedShortDebugFormatForTest = 16,
|
||
|
kUnredactedUtf8DebugFormatForTest = 17
|
||
|
};
|
||
|
|
||
|
} // namespace internal
|
||
|
|
||
|
namespace io {
|
||
|
class ErrorCollector; // tokenizer.h
|
||
|
}
|
||
|
|
||
|
namespace python {
|
||
|
namespace cmessage {
|
||
|
class PythonFieldValuePrinter;
|
||
|
}
|
||
|
} // namespace python
|
||
|
|
||
|
namespace internal {
|
||
|
// Enum used to set printing options for StringifyMessage.
|
||
|
PROTOBUF_EXPORT enum class Option;
|
||
|
|
||
|
// Converts a protobuf message to a string. If enable_safe_format is true,
|
||
|
// sensitive fields are redacted, and a per-process randomized prefix is
|
||
|
// inserted.
|
||
|
PROTOBUF_EXPORT std::string StringifyMessage(const Message& message,
|
||
|
Option option,
|
||
|
FieldReporterLevel reporter_level,
|
||
|
bool enable_safe_format);
|
||
|
|
||
|
class UnsetFieldsMetadataTextFormatTestUtil;
|
||
|
class UnsetFieldsMetadataMessageDifferencerTestUtil;
|
||
|
} // namespace internal
|
||
|
|
||
|
// This class implements protocol buffer text format, colloquially known as text
|
||
|
// proto. Printing and parsing protocol messages in text format is useful for
|
||
|
// debugging and human editing of messages.
|
||
|
//
|
||
|
// This class is really a namespace that contains only static methods.
|
||
|
class PROTOBUF_EXPORT TextFormat {
|
||
|
public:
|
||
|
TextFormat(const TextFormat&) = delete;
|
||
|
TextFormat& operator=(const TextFormat&) = delete;
|
||
|
|
||
|
// Outputs a textual representation of the given message to the given
|
||
|
// output stream. Returns false if printing fails.
|
||
|
static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
|
||
|
|
||
|
// Print the fields in an UnknownFieldSet. They are printed by tag number
|
||
|
// only. Embedded messages are heuristically identified by attempting to
|
||
|
// parse them. Returns false if printing fails.
|
||
|
static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||
|
io::ZeroCopyOutputStream* output);
|
||
|
|
||
|
// Like Print(), but outputs directly to a string.
|
||
|
// Note: output will be cleared prior to printing, and will be left empty
|
||
|
// even if printing fails. Returns false if printing fails.
|
||
|
static bool PrintToString(const Message& message, std::string* output);
|
||
|
|
||
|
// Like PrintUnknownFields(), but outputs directly to a string. Returns
|
||
|
// false if printing fails.
|
||
|
static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
|
||
|
std::string* output);
|
||
|
|
||
|
// Outputs a textual representation of the value of the field supplied on
|
||
|
// the message supplied. For non-repeated fields, an index of -1 must
|
||
|
// be supplied. Note that this method will print the default value for a
|
||
|
// field if it is not set.
|
||
|
static void PrintFieldValueToString(const Message& message,
|
||
|
const FieldDescriptor* field, int index,
|
||
|
std::string* output);
|
||
|
|
||
|
// Forward declare `Printer` for `BaseTextGenerator::MarkerToken` which
|
||
|
// restricts some methods of `BaseTextGenerator` to the class `Printer`.
|
||
|
class Printer;
|
||
|
|
||
|
class PROTOBUF_EXPORT BaseTextGenerator {
|
||
|
private:
|
||
|
// Passkey (go/totw/134#what-about-stdshared-ptr) that allows `Printer`
|
||
|
// (but not derived classes) to call `PrintMaybeWithMarker` and its
|
||
|
// `Printer::TextGenerator` to overload it.
|
||
|
// This prevents users from bypassing the marker generation.
|
||
|
class MarkerToken {
|
||
|
private:
|
||
|
explicit MarkerToken() = default; // 'explicit' prevents aggregate init.
|
||
|
friend class Printer;
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
virtual ~BaseTextGenerator();
|
||
|
|
||
|
virtual void Indent() {}
|
||
|
virtual void Outdent() {}
|
||
|
// Returns the current indentation size in characters.
|
||
|
virtual size_t GetCurrentIndentationSize() const { return 0; }
|
||
|
|
||
|
// Print text to the output stream.
|
||
|
virtual void Print(const char* text, size_t size) = 0;
|
||
|
|
||
|
void PrintString(absl::string_view str) { Print(str.data(), str.size()); }
|
||
|
|
||
|
template <size_t n>
|
||
|
void PrintLiteral(const char (&text)[n]) {
|
||
|
Print(text, n - 1); // n includes the terminating zero character.
|
||
|
}
|
||
|
|
||
|
// Internal to Printer, access regulated by `MarkerToken`.
|
||
|
virtual void PrintMaybeWithMarker(MarkerToken, absl::string_view text) {
|
||
|
Print(text.data(), text.size());
|
||
|
}
|
||
|
|
||
|
// Internal to Printer, access regulated by `MarkerToken`.
|
||
|
virtual void PrintMaybeWithMarker(MarkerToken, absl::string_view text_head,
|
||
|
absl::string_view text_tail) {
|
||
|
Print(text_head.data(), text_head.size());
|
||
|
Print(text_tail.data(), text_tail.size());
|
||
|
}
|
||
|
|
||
|
friend class Printer;
|
||
|
};
|
||
|
|
||
|
// The default printer that converts scalar values from fields into their
|
||
|
// string representation.
|
||
|
// You can derive from this FastFieldValuePrinter if you want to have fields
|
||
|
// to be printed in a different way and register it at the Printer.
|
||
|
class PROTOBUF_EXPORT FastFieldValuePrinter {
|
||
|
public:
|
||
|
FastFieldValuePrinter();
|
||
|
FastFieldValuePrinter(const FastFieldValuePrinter&) = delete;
|
||
|
FastFieldValuePrinter& operator=(const FastFieldValuePrinter&) = delete;
|
||
|
virtual ~FastFieldValuePrinter();
|
||
|
virtual void PrintBool(bool val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintInt32(int32_t val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintUInt32(uint32_t val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintInt64(int64_t val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintUInt64(uint64_t val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintFloat(float val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintDouble(double val, BaseTextGenerator* generator) const;
|
||
|
virtual void PrintString(const std::string& val,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintBytes(const std::string& val,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintEnum(int32_t val, const std::string& name,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintFieldName(const Message& message, int field_index,
|
||
|
int field_count, const Reflection* reflection,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintFieldName(const Message& message,
|
||
|
const Reflection* reflection,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintMessageStart(const Message& message, int field_index,
|
||
|
int field_count, bool single_line_mode,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
// Allows to override the logic on how to print the content of a message.
|
||
|
// Return false to use the default printing logic. Note that it is legal for
|
||
|
// this function to print something and then return false to use the default
|
||
|
// content printing (although at that point it would behave similarly to
|
||
|
// PrintMessageStart).
|
||
|
virtual bool PrintMessageContent(const Message& message, int field_index,
|
||
|
int field_count, bool single_line_mode,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
virtual void PrintMessageEnd(const Message& message, int field_index,
|
||
|
int field_count, bool single_line_mode,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
};
|
||
|
|
||
|
// Deprecated: please use FastFieldValuePrinter instead.
|
||
|
class PROTOBUF_EXPORT FieldValuePrinter {
|
||
|
public:
|
||
|
FieldValuePrinter();
|
||
|
FieldValuePrinter(const FieldValuePrinter&) = delete;
|
||
|
FieldValuePrinter& operator=(const FieldValuePrinter&) = delete;
|
||
|
virtual ~FieldValuePrinter();
|
||
|
virtual std::string PrintBool(bool val) const;
|
||
|
virtual std::string PrintInt32(int32_t val) const;
|
||
|
virtual std::string PrintUInt32(uint32_t val) const;
|
||
|
virtual std::string PrintInt64(int64_t val) const;
|
||
|
virtual std::string PrintUInt64(uint64_t val) const;
|
||
|
virtual std::string PrintFloat(float val) const;
|
||
|
virtual std::string PrintDouble(double val) const;
|
||
|
virtual std::string PrintString(const std::string& val) const;
|
||
|
virtual std::string PrintBytes(const std::string& val) const;
|
||
|
virtual std::string PrintEnum(int32_t val, const std::string& name) const;
|
||
|
virtual std::string PrintFieldName(const Message& message,
|
||
|
const Reflection* reflection,
|
||
|
const FieldDescriptor* field) const;
|
||
|
virtual std::string PrintMessageStart(const Message& message,
|
||
|
int field_index, int field_count,
|
||
|
bool single_line_mode) const;
|
||
|
virtual std::string PrintMessageEnd(const Message& message, int field_index,
|
||
|
int field_count,
|
||
|
bool single_line_mode) const;
|
||
|
|
||
|
private:
|
||
|
FastFieldValuePrinter delegate_;
|
||
|
};
|
||
|
|
||
|
class PROTOBUF_EXPORT MessagePrinter {
|
||
|
public:
|
||
|
MessagePrinter() {}
|
||
|
MessagePrinter(const MessagePrinter&) = delete;
|
||
|
MessagePrinter& operator=(const MessagePrinter&) = delete;
|
||
|
virtual ~MessagePrinter() {}
|
||
|
virtual void Print(const Message& message, bool single_line_mode,
|
||
|
BaseTextGenerator* generator) const = 0;
|
||
|
};
|
||
|
|
||
|
// Interface that Printers or Parsers can use to find extensions, or types
|
||
|
// referenced in Any messages.
|
||
|
class PROTOBUF_EXPORT Finder {
|
||
|
public:
|
||
|
virtual ~Finder();
|
||
|
|
||
|
// Try to find an extension of *message by fully-qualified field
|
||
|
// name. Returns nullptr if no extension is known for this name or number.
|
||
|
// The base implementation uses the extensions already known by the message.
|
||
|
virtual const FieldDescriptor* FindExtension(Message* message,
|
||
|
const std::string& name) const;
|
||
|
|
||
|
// Similar to FindExtension, but uses a Descriptor and the extension number
|
||
|
// instead of using a Message and the name when doing the look up.
|
||
|
virtual const FieldDescriptor* FindExtensionByNumber(
|
||
|
const Descriptor* descriptor, int number) const;
|
||
|
|
||
|
// Find the message type for an Any proto.
|
||
|
// Returns nullptr if no message is known for this name.
|
||
|
// The base implementation only accepts prefixes of type.googleprod.com/ or
|
||
|
// type.googleapis.com/, and searches the DescriptorPool of the parent
|
||
|
// message.
|
||
|
virtual const Descriptor* FindAnyType(const Message& message,
|
||
|
const std::string& prefix,
|
||
|
const std::string& name) const;
|
||
|
|
||
|
// Find the message factory for the given extension field. This can be used
|
||
|
// to generalize the Parser to add extension fields to a message in the same
|
||
|
// way as the "input" message for the Parser.
|
||
|
virtual MessageFactory* FindExtensionFactory(
|
||
|
const FieldDescriptor* field) const;
|
||
|
};
|
||
|
|
||
|
// Class for those users which require more fine-grained control over how
|
||
|
// a protobuffer message is printed out.
|
||
|
class PROTOBUF_EXPORT Printer {
|
||
|
public:
|
||
|
Printer();
|
||
|
|
||
|
// Like TextFormat::Print
|
||
|
bool Print(const Message& message, io::ZeroCopyOutputStream* output) const;
|
||
|
// Like TextFormat::Printer::Print but takes an additional
|
||
|
// internal::FieldReporterLevel
|
||
|
bool Print(const Message& message, io::ZeroCopyOutputStream* output,
|
||
|
internal::FieldReporterLevel reporter) const;
|
||
|
// Like TextFormat::PrintUnknownFields
|
||
|
bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||
|
io::ZeroCopyOutputStream* output) const;
|
||
|
// Like TextFormat::PrintToString
|
||
|
bool PrintToString(const Message& message, std::string* output) const;
|
||
|
// Like TextFormat::PrintUnknownFieldsToString
|
||
|
bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
|
||
|
std::string* output) const;
|
||
|
// Like TextFormat::PrintFieldValueToString
|
||
|
void PrintFieldValueToString(const Message& message,
|
||
|
const FieldDescriptor* field, int index,
|
||
|
std::string* output) const;
|
||
|
|
||
|
// Adjust the initial indent level of all output. Each indent level is
|
||
|
// equal to two spaces.
|
||
|
void SetInitialIndentLevel(int indent_level) {
|
||
|
initial_indent_level_ = indent_level;
|
||
|
}
|
||
|
|
||
|
// If printing in single line mode, then the entire message will be output
|
||
|
// on a single line with no line breaks.
|
||
|
void SetSingleLineMode(bool single_line_mode) {
|
||
|
single_line_mode_ = single_line_mode;
|
||
|
}
|
||
|
|
||
|
bool IsInSingleLineMode() const { return single_line_mode_; }
|
||
|
|
||
|
// If use_field_number is true, uses field number instead of field name.
|
||
|
void SetUseFieldNumber(bool use_field_number) {
|
||
|
use_field_number_ = use_field_number;
|
||
|
}
|
||
|
|
||
|
// 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.
|
||
|
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. This will change the default FastFieldValuePrinter.
|
||
|
void SetUseUtf8StringEscaping(bool as_utf8);
|
||
|
|
||
|
// Set the default FastFieldValuePrinter that is used for all fields that
|
||
|
// don't have a field-specific printer registered.
|
||
|
// Takes ownership of the printer.
|
||
|
void SetDefaultFieldValuePrinter(const FastFieldValuePrinter* printer);
|
||
|
|
||
|
[[deprecated("Please use FastFieldValuePrinter")]] void
|
||
|
SetDefaultFieldValuePrinter(const FieldValuePrinter* printer);
|
||
|
|
||
|
// Sets whether we want to hide unknown fields or not.
|
||
|
// Usually unknown fields are printed in a generic way that includes the
|
||
|
// tag number of the field instead of field name. However, sometimes it
|
||
|
// is useful to be able to print the message without unknown fields (e.g.
|
||
|
// for the python protobuf version to maintain consistency between its pure
|
||
|
// python and c++ implementations).
|
||
|
void SetHideUnknownFields(bool hide) { hide_unknown_fields_ = hide; }
|
||
|
|
||
|
// If print_message_fields_in_index_order is true, fields of a proto message
|
||
|
// will be printed using the order defined in source code instead of the
|
||
|
// field number, extensions will be printed at the end of the message
|
||
|
// and their relative order is determined by the extension number.
|
||
|
// By default, use the field number order.
|
||
|
void SetPrintMessageFieldsInIndexOrder(
|
||
|
bool print_message_fields_in_index_order) {
|
||
|
print_message_fields_in_index_order_ =
|
||
|
print_message_fields_in_index_order;
|
||
|
}
|
||
|
|
||
|
// If expand==true, expand google.protobuf.Any payloads. The output
|
||
|
// will be of form
|
||
|
// [type_url] { <value_printed_in_text> }
|
||
|
//
|
||
|
// If expand==false, print Any using the default printer. The output will
|
||
|
// look like
|
||
|
// type_url: "<type_url>" value: "serialized_content"
|
||
|
void SetExpandAny(bool expand) { expand_any_ = expand; }
|
||
|
|
||
|
// Set how parser finds message for Any payloads.
|
||
|
void SetFinder(const Finder* finder) { finder_ = finder; }
|
||
|
|
||
|
// If non-zero, we truncate all string fields that are longer than
|
||
|
// this threshold. This is useful when the proto message has very long
|
||
|
// strings, e.g., dump of encoded image file.
|
||
|
//
|
||
|
// NOTE: Setting a non-zero value breaks round-trip safe
|
||
|
// property of TextFormat::Printer. That is, from the printed message, we
|
||
|
// cannot fully recover the original string field any more.
|
||
|
void SetTruncateStringFieldLongerThan(
|
||
|
const int64_t truncate_string_field_longer_than) {
|
||
|
truncate_string_field_longer_than_ = truncate_string_field_longer_than;
|
||
|
}
|
||
|
|
||
|
// Sets whether sensitive fields found in the message will be reported or
|
||
|
// not.
|
||
|
void SetReportSensitiveFields(internal::FieldReporterLevel reporter) {
|
||
|
if (report_sensitive_fields_ < reporter) {
|
||
|
report_sensitive_fields_ = reporter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Register a custom field-specific FastFieldValuePrinter for fields
|
||
|
// with a particular FieldDescriptor.
|
||
|
// Returns "true" if the registration succeeded, or "false", if there is
|
||
|
// already a printer for that FieldDescriptor.
|
||
|
// Takes ownership of the printer on successful registration.
|
||
|
bool RegisterFieldValuePrinter(const FieldDescriptor* field,
|
||
|
const FastFieldValuePrinter* printer);
|
||
|
|
||
|
[[deprecated("Please use FastFieldValuePrinter")]] bool
|
||
|
RegisterFieldValuePrinter(const FieldDescriptor* field,
|
||
|
const FieldValuePrinter* printer);
|
||
|
|
||
|
// Register a custom message-specific MessagePrinter for messages with a
|
||
|
// particular Descriptor.
|
||
|
// Returns "true" if the registration succeeded, or "false" if there is
|
||
|
// already a printer for that Descriptor.
|
||
|
// Takes ownership of the printer on successful registration.
|
||
|
bool RegisterMessagePrinter(const Descriptor* descriptor,
|
||
|
const MessagePrinter* printer);
|
||
|
|
||
|
// Default printing for messages, which allows registered message printers
|
||
|
// to fall back to default printing without losing the ability to control
|
||
|
// sub-messages or fields.
|
||
|
// NOTE: If the passed in `text_generaor` is not actually the current
|
||
|
// `TextGenerator`, then no output will be produced.
|
||
|
void PrintMessage(const Message& message,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
|
||
|
private:
|
||
|
friend std::string Message::DebugString() const;
|
||
|
friend std::string Message::ShortDebugString() const;
|
||
|
friend std::string Message::Utf8DebugString() const;
|
||
|
friend std::string internal::StringifyMessage(
|
||
|
const Message& message, internal::Option option,
|
||
|
internal::FieldReporterLevel reporter_level, bool enable_safe_format);
|
||
|
|
||
|
// Sets whether silent markers will be inserted.
|
||
|
void SetInsertSilentMarker(bool v) { insert_silent_marker_ = v; }
|
||
|
|
||
|
// Sets whether strings will be redacted and thus unparsable.
|
||
|
void SetRedactDebugString(bool redact) { redact_debug_string_ = redact; }
|
||
|
|
||
|
// Sets whether the output string should be made non-deterministic.
|
||
|
// This discourages equality checks based on serialized string comparisons.
|
||
|
void SetRandomizeDebugString(bool randomize) {
|
||
|
randomize_debug_string_ = randomize;
|
||
|
}
|
||
|
|
||
|
// Forward declaration of an internal class used to print the text
|
||
|
// output to the OutputStream (see text_format.cc for implementation).
|
||
|
class TextGenerator;
|
||
|
using MarkerToken = BaseTextGenerator::MarkerToken;
|
||
|
|
||
|
// Forward declaration of an internal class used to print field values for
|
||
|
// DebugString APIs (see text_format.cc for implementation).
|
||
|
class DebugStringFieldValuePrinter;
|
||
|
|
||
|
// Forward declaration of an internal class used to print UTF-8 escaped
|
||
|
// strings (see text_format.cc for implementation).
|
||
|
class FastFieldValuePrinterUtf8Escaping;
|
||
|
|
||
|
// Internal Print method, used for writing to the OutputStream via
|
||
|
// the TextGenerator class.
|
||
|
void Print(const Message& message, BaseTextGenerator* generator) const;
|
||
|
|
||
|
// Print a single field.
|
||
|
void PrintField(const Message& message, const Reflection* reflection,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
|
||
|
// Print a repeated primitive field in short form.
|
||
|
void PrintShortRepeatedField(const Message& message,
|
||
|
const Reflection* reflection,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
|
||
|
// Print the name of a field -- i.e. everything that comes before the
|
||
|
// ':' for a single name/value pair.
|
||
|
void PrintFieldName(const Message& message, int field_index,
|
||
|
int field_count, const Reflection* reflection,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
|
||
|
// 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, const Reflection* reflection,
|
||
|
const FieldDescriptor* field, int index,
|
||
|
BaseTextGenerator* generator) const;
|
||
|
|
||
|
// Print the fields in an UnknownFieldSet. They are printed by tag number
|
||
|
// only. Embedded messages are heuristically identified by attempting to
|
||
|
// parse them (subject to the recursion budget).
|
||
|
void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||
|
BaseTextGenerator* generator,
|
||
|
int recursion_budget) const;
|
||
|
|
||
|
bool PrintAny(const Message& message, BaseTextGenerator* generator) const;
|
||
|
|
||
|
// Try to redact a field value based on the annotations associated with
|
||
|
// the field. This function returns true if it redacts the field value.
|
||
|
bool TryRedactFieldValue(const Message& message,
|
||
|
const FieldDescriptor* field,
|
||
|
BaseTextGenerator* generator,
|
||
|
bool insert_value_separator) const;
|
||
|
|
||
|
const FastFieldValuePrinter* GetFieldPrinter(
|
||
|
const FieldDescriptor* field) const {
|
||
|
auto it = custom_printers_.find(field);
|
||
|
return it == custom_printers_.end() ? default_field_value_printer_.get()
|
||
|
: it->second.get();
|
||
|
}
|
||
|
|
||
|
friend class google::protobuf::python::cmessage::PythonFieldValuePrinter;
|
||
|
static void HardenedPrintString(absl::string_view src,
|
||
|
TextFormat::BaseTextGenerator* generator);
|
||
|
|
||
|
int initial_indent_level_;
|
||
|
bool single_line_mode_;
|
||
|
bool use_field_number_;
|
||
|
bool use_short_repeated_primitives_;
|
||
|
bool insert_silent_marker_;
|
||
|
bool redact_debug_string_;
|
||
|
bool randomize_debug_string_;
|
||
|
internal::FieldReporterLevel report_sensitive_fields_;
|
||
|
bool hide_unknown_fields_;
|
||
|
bool print_message_fields_in_index_order_;
|
||
|
bool expand_any_;
|
||
|
int64_t truncate_string_field_longer_than_;
|
||
|
|
||
|
std::unique_ptr<const FastFieldValuePrinter> default_field_value_printer_;
|
||
|
absl::flat_hash_map<const FieldDescriptor*,
|
||
|
std::unique_ptr<const FastFieldValuePrinter>>
|
||
|
custom_printers_;
|
||
|
|
||
|
absl::flat_hash_map<const Descriptor*,
|
||
|
std::unique_ptr<const MessagePrinter>>
|
||
|
custom_message_printers_;
|
||
|
|
||
|
const Finder* finder_;
|
||
|
};
|
||
|
|
||
|
// Parses a text-format protocol message from the given input stream to
|
||
|
// the given message object. This function parses the human-readable
|
||
|
// serialization format written by Print(). Returns true on success. The
|
||
|
// message is cleared first, even if the function fails -- See Merge() to
|
||
|
// avoid this behavior.
|
||
|
//
|
||
|
// Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
|
||
|
//
|
||
|
// One common use for this function is parsing handwritten strings in test
|
||
|
// code.
|
||
|
//
|
||
|
// If you would like to read a protocol buffer serialized in the
|
||
|
// (non-human-readable) binary wire format, see
|
||
|
// google::protobuf::MessageLite::ParseFromString().
|
||
|
static bool Parse(io::ZeroCopyInputStream* input, Message* output);
|
||
|
// Like Parse(), but reads directly from a string.
|
||
|
static bool ParseFromString(absl::string_view input, Message* output);
|
||
|
// Like Parse(), but reads directly from a Cord.
|
||
|
static bool ParseFromCord(const absl::Cord& input, Message* output);
|
||
|
|
||
|
// Like Parse(), but the data is merged into the given message, as if
|
||
|
// using Message::MergeFrom().
|
||
|
static bool Merge(io::ZeroCopyInputStream* input, Message* output);
|
||
|
// Like Merge(), but reads directly from a string.
|
||
|
static bool MergeFromString(absl::string_view input, Message* output);
|
||
|
|
||
|
// Parse the given text as a single field value and store it into the
|
||
|
// given field of the given message. If the field is a repeated field,
|
||
|
// the new value will be added to the end
|
||
|
static bool ParseFieldValueFromString(absl::string_view input,
|
||
|
const FieldDescriptor* field,
|
||
|
Message* message);
|
||
|
|
||
|
// A location in the parsed text.
|
||
|
struct ParseLocation {
|
||
|
int line;
|
||
|
int column;
|
||
|
|
||
|
ParseLocation() : line(-1), column(-1) {}
|
||
|
ParseLocation(int line_param, int column_param)
|
||
|
: line(line_param), column(column_param) {}
|
||
|
};
|
||
|
|
||
|
// A range of locations in the parsed text, including `start` and excluding
|
||
|
// `end`.
|
||
|
struct ParseLocationRange {
|
||
|
ParseLocation start;
|
||
|
ParseLocation end;
|
||
|
ParseLocationRange() : start(), end() {}
|
||
|
ParseLocationRange(ParseLocation start_param, ParseLocation end_param)
|
||
|
: start(start_param), end(end_param) {}
|
||
|
};
|
||
|
|
||
|
// Data structure which is populated with the locations of each field
|
||
|
// value parsed from the text.
|
||
|
class PROTOBUF_EXPORT ParseInfoTree {
|
||
|
public:
|
||
|
ParseInfoTree() = default;
|
||
|
ParseInfoTree(const ParseInfoTree&) = delete;
|
||
|
ParseInfoTree& operator=(const ParseInfoTree&) = delete;
|
||
|
|
||
|
// Returns the parse location range for index-th value of the field in
|
||
|
// the parsed text. If none exists, returns a location with start and end
|
||
|
// line -1. Index should be -1 for not-repeated fields.
|
||
|
ParseLocationRange GetLocationRange(const FieldDescriptor* field,
|
||
|
int index) const;
|
||
|
|
||
|
// Returns the starting parse location for index-th value of the field in
|
||
|
// the parsed text. If none exists, returns a location with line = -1. Index
|
||
|
// should be -1 for not-repeated fields.
|
||
|
ParseLocation GetLocation(const FieldDescriptor* field, int index) const {
|
||
|
return GetLocationRange(field, index).start;
|
||
|
}
|
||
|
|
||
|
// Returns the parse info tree for the given field, which must be a message
|
||
|
// type. The nested information tree is owned by the root tree and will be
|
||
|
// deleted when it is deleted.
|
||
|
ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
|
||
|
int index) const;
|
||
|
|
||
|
private:
|
||
|
// Allow the text format parser to record information into the tree.
|
||
|
friend class TextFormat;
|
||
|
|
||
|
// Records the starting and ending locations of a single value for a field.
|
||
|
void RecordLocation(const FieldDescriptor* field, ParseLocationRange range);
|
||
|
|
||
|
// Create and records a nested tree for a nested message field.
|
||
|
ParseInfoTree* CreateNested(const FieldDescriptor* field);
|
||
|
|
||
|
// Defines the map from the index-th field descriptor to its parse location.
|
||
|
absl::flat_hash_map<const FieldDescriptor*, std::vector<ParseLocationRange>>
|
||
|
locations_;
|
||
|
// Defines the map from the index-th field descriptor to the nested parse
|
||
|
// info tree.
|
||
|
absl::flat_hash_map<const FieldDescriptor*,
|
||
|
std::vector<std::unique_ptr<ParseInfoTree>>>
|
||
|
nested_;
|
||
|
};
|
||
|
|
||
|
// For more control over parsing, use this class.
|
||
|
class PROTOBUF_EXPORT Parser {
|
||
|
public:
|
||
|
Parser();
|
||
|
~Parser();
|
||
|
|
||
|
// Like TextFormat::Parse().
|
||
|
bool Parse(io::ZeroCopyInputStream* input, Message* output);
|
||
|
// Like TextFormat::ParseFromString().
|
||
|
bool ParseFromString(absl::string_view input, Message* output);
|
||
|
// Like TextFormat::ParseFromCord().
|
||
|
bool ParseFromCord(const absl::Cord& input, Message* output);
|
||
|
// Like TextFormat::Merge().
|
||
|
bool Merge(io::ZeroCopyInputStream* input, Message* output);
|
||
|
// Like TextFormat::MergeFromString().
|
||
|
bool MergeFromString(absl::string_view input, Message* output);
|
||
|
|
||
|
// Set where to report parse errors. If nullptr (the default), errors will
|
||
|
// be printed to stderr.
|
||
|
void RecordErrorsTo(io::ErrorCollector* error_collector) {
|
||
|
error_collector_ = error_collector;
|
||
|
}
|
||
|
|
||
|
// Set how parser finds extensions. If nullptr (the default), the
|
||
|
// parser will use the standard Reflection object associated with
|
||
|
// the message being parsed.
|
||
|
void SetFinder(const Finder* finder) { finder_ = finder; }
|
||
|
|
||
|
// Sets where location information about the parse will be written. If
|
||
|
// nullptr
|
||
|
// (the default), then no location will be written.
|
||
|
void WriteLocationsTo(ParseInfoTree* tree) { parse_info_tree_ = tree; }
|
||
|
|
||
|
// Normally parsing fails if, after parsing, output->IsInitialized()
|
||
|
// returns false. Call AllowPartialMessage(true) to skip this check.
|
||
|
void AllowPartialMessage(bool allow) { allow_partial_ = allow; }
|
||
|
|
||
|
// Allow field names to be matched case-insensitively.
|
||
|
// This is not advisable if there are fields that only differ in case, or
|
||
|
// if you want to enforce writing in the canonical form.
|
||
|
// This is 'false' by default.
|
||
|
void AllowCaseInsensitiveField(bool allow) {
|
||
|
allow_case_insensitive_field_ = allow;
|
||
|
}
|
||
|
|
||
|
// Like TextFormat::ParseFieldValueFromString
|
||
|
bool ParseFieldValueFromString(absl::string_view input,
|
||
|
const FieldDescriptor* field,
|
||
|
Message* output);
|
||
|
|
||
|
// When an unknown extension is met, parsing will fail if this option is
|
||
|
// set to false (the default). If true, unknown extensions will be ignored
|
||
|
// and a warning message will be generated.
|
||
|
// Beware! Setting this option true may hide some errors (e.g. spelling
|
||
|
// error on extension name). This allows data loss; unlike binary format,
|
||
|
// text format cannot preserve unknown extensions. Avoid using this option
|
||
|
// if possible.
|
||
|
void AllowUnknownExtension(bool allow) { allow_unknown_extension_ = allow; }
|
||
|
|
||
|
// When an unknown field is met, parsing will fail if this option is set
|
||
|
// to false (the default). If true, unknown fields will be ignored and
|
||
|
// a warning message will be generated.
|
||
|
// Beware! Setting this option true may hide some errors (e.g. spelling
|
||
|
// error on field name). This allows data loss; unlike binary format, text
|
||
|
// format cannot preserve unknown fields. Avoid using this option
|
||
|
// if possible.
|
||
|
void AllowUnknownField(bool allow) { allow_unknown_field_ = allow; }
|
||
|
|
||
|
|
||
|
void AllowFieldNumber(bool allow) { allow_field_number_ = allow; }
|
||
|
|
||
|
// Sets maximum recursion depth which parser can use. This is effectively
|
||
|
// the maximum allowed nesting of proto messages.
|
||
|
void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
|
||
|
|
||
|
// Metadata representing all the fields that were explicitly unset in
|
||
|
// textproto. Example:
|
||
|
// "some_int_field: 0"
|
||
|
// where some_int_field has implicit presence.
|
||
|
//
|
||
|
// This class should only be used to pass data between TextFormat and the
|
||
|
// MessageDifferencer.
|
||
|
class UnsetFieldsMetadata {
|
||
|
public:
|
||
|
UnsetFieldsMetadata() = default;
|
||
|
|
||
|
private:
|
||
|
using Id = std::pair<const Message*, const FieldDescriptor*>;
|
||
|
// Return an id representing the unset field in the given message.
|
||
|
static Id GetUnsetFieldId(const Message& message,
|
||
|
const FieldDescriptor& fd);
|
||
|
|
||
|
// List of ids of explicitly unset proto fields.
|
||
|
absl::flat_hash_set<Id> ids_;
|
||
|
|
||
|
friend class ::google::protobuf::internal::
|
||
|
UnsetFieldsMetadataMessageDifferencerTestUtil;
|
||
|
friend class ::google::protobuf::internal::UnsetFieldsMetadataTextFormatTestUtil;
|
||
|
friend class ::google::protobuf::util::MessageDifferencer;
|
||
|
friend class ::google::protobuf::TextFormat::Parser;
|
||
|
};
|
||
|
|
||
|
// If called, the parser will report the parsed fields that had no
|
||
|
// effect on the resulting proto (for example, fields with no presence that
|
||
|
// were set to their default value). These can be passed to the Partially()
|
||
|
// matcher as an indicator to explicitly check these fields are missing
|
||
|
// in the actual.
|
||
|
void OutputNoOpFields(UnsetFieldsMetadata* no_op_fields) {
|
||
|
no_op_fields_ = no_op_fields;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Forward declaration of an internal class used to parse text
|
||
|
// representations (see text_format.cc for implementation).
|
||
|
class ParserImpl;
|
||
|
|
||
|
// Like TextFormat::Merge(). The provided implementation is used
|
||
|
// to do the parsing.
|
||
|
bool MergeUsingImpl(io::ZeroCopyInputStream* input, Message* output,
|
||
|
ParserImpl* parser_impl);
|
||
|
|
||
|
io::ErrorCollector* error_collector_;
|
||
|
const Finder* finder_;
|
||
|
ParseInfoTree* parse_info_tree_;
|
||
|
bool allow_partial_;
|
||
|
bool allow_case_insensitive_field_;
|
||
|
bool allow_unknown_field_;
|
||
|
bool allow_unknown_extension_;
|
||
|
bool allow_unknown_enum_;
|
||
|
bool allow_field_number_;
|
||
|
bool allow_relaxed_whitespace_;
|
||
|
bool allow_singular_overwrites_;
|
||
|
int recursion_limit_;
|
||
|
UnsetFieldsMetadata* no_op_fields_ = nullptr;
|
||
|
};
|
||
|
|
||
|
|
||
|
private:
|
||
|
// Hack: ParseInfoTree declares TextFormat as a friend which should extend
|
||
|
// the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
|
||
|
// old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
|
||
|
// helpers for ParserImpl to call methods of ParseInfoTree.
|
||
|
static inline void RecordLocation(ParseInfoTree* info_tree,
|
||
|
const FieldDescriptor* field,
|
||
|
ParseLocationRange location);
|
||
|
static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
|
||
|
const FieldDescriptor* field);
|
||
|
// To reduce stack frame bloat we use an out-of-line function to print
|
||
|
// strings. This avoid local std::string temporaries.
|
||
|
template <typename... T>
|
||
|
static void OutOfLinePrintString(BaseTextGenerator* generator,
|
||
|
const T&... values);
|
||
|
};
|
||
|
|
||
|
|
||
|
inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
|
||
|
const FieldDescriptor* field,
|
||
|
ParseLocationRange location) {
|
||
|
info_tree->RecordLocation(field, location);
|
||
|
}
|
||
|
|
||
|
inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
|
||
|
ParseInfoTree* info_tree, const FieldDescriptor* field) {
|
||
|
return info_tree->CreateNested(field);
|
||
|
}
|
||
|
|
||
|
} // namespace protobuf
|
||
|
} // namespace google
|
||
|
|
||
|
#include "google/protobuf/port_undef.inc"
|
||
|
|
||
|
#endif // GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|