blob: 9e2cb070c69dc2349829fa98d1037c387e74edfd [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: jschorr@google.com (Joseph Schorr)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34//
35// Utilities for printing and parsing protocol messages in a human-readable,
36// text-based format.
37
38#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
39#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
40
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000041#include <map>
jieluo@google.com4de8f552014-07-18 00:47:59 +000042#include <memory>
Feng Xiao6ef984a2014-11-10 17:34:54 -080043#ifndef _SHARED_PTR_H
44#include <google/protobuf/stubs/shared_ptr.h>
45#endif
temporal40ee5512008-07-10 02:12:20 +000046#include <string>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000047#include <vector>
jieluo@google.com4de8f552014-07-18 00:47:59 +000048
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000049#include <google/protobuf/stubs/common.h>
temporal40ee5512008-07-10 02:12:20 +000050#include <google/protobuf/descriptor.h>
jieluo@google.com4de8f552014-07-18 00:47:59 +000051#include <google/protobuf/message.h>
temporal40ee5512008-07-10 02:12:20 +000052
53namespace google {
54namespace protobuf {
55
56namespace io {
57 class ErrorCollector; // tokenizer.h
58}
59
60// This class implements protocol buffer text format. Printing and parsing
61// protocol messages in text format is useful for debugging and human editing
62// of messages.
63//
64// This class is really a namespace that contains only static methods.
65class LIBPROTOBUF_EXPORT TextFormat {
66 public:
67 // Outputs a textual representation of the given message to the given
68 // output stream.
69 static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
temporala0f27fc2008-08-06 01:12:21 +000070
71 // Print the fields in an UnknownFieldSet. They are printed by tag number
72 // only. Embedded messages are heuristically identified by attempting to
73 // parse them.
74 static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
75 io::ZeroCopyOutputStream* output);
76
temporal40ee5512008-07-10 02:12:20 +000077 // Like Print(), but outputs directly to a string.
78 static bool PrintToString(const Message& message, string* output);
79
temporala0f27fc2008-08-06 01:12:21 +000080 // Like PrintUnknownFields(), but outputs directly to a string.
81 static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
82 string* output);
83
temporal40ee5512008-07-10 02:12:20 +000084 // Outputs a textual representation of the value of the field supplied on
85 // the message supplied. For non-repeated fields, an index of -1 must
86 // be supplied. Note that this method will print the default value for a
87 // field if it is not set.
88 static void PrintFieldValueToString(const Message& message,
89 const FieldDescriptor* field,
90 int index,
91 string* output);
92
jieluo@google.com4de8f552014-07-18 00:47:59 +000093 // The default printer that converts scalar values from fields into
94 // their string representation.
95 // You can derive from this FieldValuePrinter if you want to have
96 // fields to be printed in a different way and register it at the
97 // Printer.
98 class LIBPROTOBUF_EXPORT FieldValuePrinter {
99 public:
100 FieldValuePrinter();
101 virtual ~FieldValuePrinter();
102 virtual string PrintBool(bool val) const;
103 virtual string PrintInt32(int32 val) const;
104 virtual string PrintUInt32(uint32 val) const;
105 virtual string PrintInt64(int64 val) const;
106 virtual string PrintUInt64(uint64 val) const;
107 virtual string PrintFloat(float val) const;
108 virtual string PrintDouble(double val) const;
109 virtual string PrintString(const string& val) const;
110 virtual string PrintBytes(const string& val) const;
111 virtual string PrintEnum(int32 val, const string& name) const;
112 virtual string PrintFieldName(const Message& message,
113 const Reflection* reflection,
114 const FieldDescriptor* field) const;
115 virtual string PrintMessageStart(const Message& message,
116 int field_index,
117 int field_count,
118 bool single_line_mode) const;
119 virtual string PrintMessageEnd(const Message& message,
120 int field_index,
121 int field_count,
122 bool single_line_mode) const;
123
124 private:
125 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldValuePrinter);
126 };
127
kenton@google.comd37d46d2009-04-25 02:53:47 +0000128 // Class for those users which require more fine-grained control over how
129 // a protobuffer message is printed out.
130 class LIBPROTOBUF_EXPORT Printer {
131 public:
132 Printer();
133 ~Printer();
134
135 // Like TextFormat::Print
liujisi@google.com33165fe2010-11-02 13:14:58 +0000136 bool Print(const Message& message, io::ZeroCopyOutputStream* output) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000137 // Like TextFormat::PrintUnknownFields
138 bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000139 io::ZeroCopyOutputStream* output) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000140 // Like TextFormat::PrintToString
liujisi@google.com33165fe2010-11-02 13:14:58 +0000141 bool PrintToString(const Message& message, string* output) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000142 // Like TextFormat::PrintUnknownFieldsToString
143 bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000144 string* output) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000145 // Like TextFormat::PrintFieldValueToString
146 void PrintFieldValueToString(const Message& message,
147 const FieldDescriptor* field,
148 int index,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000149 string* output) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000150
151 // Adjust the initial indent level of all output. Each indent level is
152 // equal to two spaces.
153 void SetInitialIndentLevel(int indent_level) {
154 initial_indent_level_ = indent_level;
155 }
156
157 // If printing in single line mode, then the entire message will be output
158 // on a single line with no line breaks.
159 void SetSingleLineMode(bool single_line_mode) {
160 single_line_mode_ = single_line_mode;
161 }
162
jieluo@google.com4de8f552014-07-18 00:47:59 +0000163 bool IsInSingleLineMode() {
164 return single_line_mode_;
165 }
166
167 // If use_field_number is true, uses field number instead of field name.
168 void SetUseFieldNumber(bool use_field_number) {
169 use_field_number_ = use_field_number;
170 }
171
kenton@google.comfccb1462009-12-18 02:11:36 +0000172 // Set true to print repeated primitives in a format like:
173 // field_name: [1, 2, 3, 4]
174 // instead of printing each value on its own line. Short format applies
175 // only to primitive values -- i.e. everything except strings and
liujisi@google.com33165fe2010-11-02 13:14:58 +0000176 // sub-messages/groups.
kenton@google.comfccb1462009-12-18 02:11:36 +0000177 void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) {
178 use_short_repeated_primitives_ = use_short_repeated_primitives;
179 }
180
181 // Set true to output UTF-8 instead of ASCII. The only difference
182 // is that bytes >= 0x80 in string fields will not be escaped,
183 // because they are assumed to be part of UTF-8 multi-byte
jieluo@google.com4de8f552014-07-18 00:47:59 +0000184 // sequences. This will change the default FieldValuePrinter.
185 void SetUseUtf8StringEscaping(bool as_utf8);
186
187 // Set the default FieldValuePrinter that is used for all fields that
188 // don't have a field-specific printer registered.
189 // Takes ownership of the printer.
190 void SetDefaultFieldValuePrinter(const FieldValuePrinter* printer);
191
192 // Sets whether we want to hide unknown fields or not.
193 // Usually unknown fields are printed in a generic way that includes the
194 // tag number of the field instead of field name. However, sometimes it
195 // is useful to be able to print the message without unknown fields (e.g.
196 // for the python protobuf version to maintain consistency between its pure
197 // python and c++ implementations).
198 void SetHideUnknownFields(bool hide) {
199 hide_unknown_fields_ = hide;
kenton@google.comfccb1462009-12-18 02:11:36 +0000200 }
201
jieluo@google.com4de8f552014-07-18 00:47:59 +0000202 // If print_message_fields_in_index_order is true, print fields of a proto
203 // message using the order defined in source code instead of the field
204 // number. By default, use the field number order.
205 void SetPrintMessageFieldsInIndexOrder(
206 bool print_message_fields_in_index_order) {
207 print_message_fields_in_index_order_ =
208 print_message_fields_in_index_order;
209 }
210
211 // Register a custom field-specific FieldValuePrinter for fields
212 // with a particular FieldDescriptor.
213 // Returns "true" if the registration succeeded, or "false", if there is
214 // already a printer for that FieldDescriptor.
215 // Takes ownership of the printer on successful registration.
216 bool RegisterFieldValuePrinter(const FieldDescriptor* field,
217 const FieldValuePrinter* printer);
218
kenton@google.comd37d46d2009-04-25 02:53:47 +0000219 private:
220 // Forward declaration of an internal class used to print the text
221 // output to the OutputStream (see text_format.cc for implementation).
222 class TextGenerator;
223
224 // Internal Print method, used for writing to the OutputStream via
225 // the TextGenerator class.
226 void Print(const Message& message,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000227 TextGenerator& generator) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000228
229 // Print a single field.
230 void PrintField(const Message& message,
231 const Reflection* reflection,
232 const FieldDescriptor* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000233 TextGenerator& generator) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000234
kenton@google.comfccb1462009-12-18 02:11:36 +0000235 // Print a repeated primitive field in short form.
236 void PrintShortRepeatedField(const Message& message,
237 const Reflection* reflection,
238 const FieldDescriptor* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000239 TextGenerator& generator) const;
kenton@google.comfccb1462009-12-18 02:11:36 +0000240
241 // Print the name of a field -- i.e. everything that comes before the
242 // ':' for a single name/value pair.
243 void PrintFieldName(const Message& message,
244 const Reflection* reflection,
245 const FieldDescriptor* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000246 TextGenerator& generator) const;
kenton@google.comfccb1462009-12-18 02:11:36 +0000247
kenton@google.comd37d46d2009-04-25 02:53:47 +0000248 // Outputs a textual representation of the value of the field supplied on
249 // the message supplied or the default value if not set.
250 void PrintFieldValue(const Message& message,
251 const Reflection* reflection,
252 const FieldDescriptor* field,
253 int index,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000254 TextGenerator& generator) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000255
256 // Print the fields in an UnknownFieldSet. They are printed by tag number
257 // only. Embedded messages are heuristically identified by attempting to
258 // parse them.
259 void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000260 TextGenerator& generator) const;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000261
262 int initial_indent_level_;
263
264 bool single_line_mode_;
kenton@google.comfccb1462009-12-18 02:11:36 +0000265
jieluo@google.com4de8f552014-07-18 00:47:59 +0000266 bool use_field_number_;
267
kenton@google.comfccb1462009-12-18 02:11:36 +0000268 bool use_short_repeated_primitives_;
269
jieluo@google.com4de8f552014-07-18 00:47:59 +0000270 bool hide_unknown_fields_;
271
272 bool print_message_fields_in_index_order_;
273
Feng Xiaof157a562014-11-14 11:50:31 -0800274 google::protobuf::scoped_ptr<const FieldValuePrinter> default_field_value_printer_;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000275 typedef map<const FieldDescriptor*,
276 const FieldValuePrinter*> CustomPrinterMap;
277 CustomPrinterMap custom_printers_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000278 };
279
temporal40ee5512008-07-10 02:12:20 +0000280 // Parses a text-format protocol message from the given input stream to
Jisi Liu885b6122015-02-28 14:51:22 -0800281 // the given message object. This function parses the human-readable format
282 // written by Print(). Returns true on success. The message is cleared first,
283 // even if the function fails -- See Merge() to avoid this behavior.
284 //
285 // Example input: "user {\n id: 123 extra { gender: MALE language: 'en' }\n}"
286 //
287 // One use for this function is parsing handwritten strings in test code.
288 // Another use is to parse the output from google::protobuf::Message::DebugString()
289 // (or ShortDebugString()), because these functions output using
290 // google::protobuf::TextFormat::Print().
291 //
292 // If you would like to read a protocol buffer serialized in the
293 // (non-human-readable) binary wire format, see
294 // google::protobuf::MessageLite::ParseFromString().
temporal40ee5512008-07-10 02:12:20 +0000295 static bool Parse(io::ZeroCopyInputStream* input, Message* output);
296 // Like Parse(), but reads directly from a string.
297 static bool ParseFromString(const string& input, Message* output);
298
299 // Like Parse(), but the data is merged into the given message, as if
300 // using Message::MergeFrom().
301 static bool Merge(io::ZeroCopyInputStream* input, Message* output);
302 // Like Merge(), but reads directly from a string.
303 static bool MergeFromString(const string& input, Message* output);
304
kenton@google.com80b1d622009-07-29 01:13:20 +0000305 // Parse the given text as a single field value and store it into the
306 // given field of the given message. If the field is a repeated field,
307 // the new value will be added to the end
308 static bool ParseFieldValueFromString(const string& input,
309 const FieldDescriptor* field,
310 Message* message);
311
liujisi@google.com33165fe2010-11-02 13:14:58 +0000312 // Interface that TextFormat::Parser can use to find extensions.
313 // This class may be extended in the future to find more information
314 // like fields, etc.
315 class LIBPROTOBUF_EXPORT Finder {
316 public:
317 virtual ~Finder();
318
319 // Try to find an extension of *message by fully-qualified field
320 // name. Returns NULL if no extension is known for this name or number.
321 virtual const FieldDescriptor* FindExtension(
322 Message* message,
323 const string& name) const = 0;
324 };
325
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000326 // A location in the parsed text.
327 struct ParseLocation {
328 int line;
329 int column;
330
331 ParseLocation() : line(-1), column(-1) {}
332 ParseLocation(int line_param, int column_param)
333 : line(line_param), column(column_param) {}
334 };
335
336 // Data structure which is populated with the locations of each field
337 // value parsed from the text.
338 class LIBPROTOBUF_EXPORT ParseInfoTree {
339 public:
340 ParseInfoTree();
341 ~ParseInfoTree();
342
343 // Returns the parse location for index-th value of the field in the parsed
344 // text. If none exists, returns a location with line = -1. Index should be
345 // -1 for not-repeated fields.
346 ParseLocation GetLocation(const FieldDescriptor* field, int index) const;
347
348 // Returns the parse info tree for the given field, which must be a message
349 // type. The nested information tree is owned by the root tree and will be
350 // deleted when it is deleted.
351 ParseInfoTree* GetTreeForNested(const FieldDescriptor* field,
352 int index) const;
353
354 private:
355 // Allow the text format parser to record information into the tree.
356 friend class TextFormat;
357
358 // Records the starting location of a single value for a field.
359 void RecordLocation(const FieldDescriptor* field, ParseLocation location);
360
361 // Create and records a nested tree for a nested message field.
362 ParseInfoTree* CreateNested(const FieldDescriptor* field);
363
364 // Defines the map from the index-th field descriptor to its parse location.
365 typedef map<const FieldDescriptor*, vector<ParseLocation> > LocationMap;
366
367 // Defines the map from the index-th field descriptor to the nested parse
368 // info tree.
369 typedef map<const FieldDescriptor*, vector<ParseInfoTree*> > NestedMap;
370
371 LocationMap locations_;
372 NestedMap nested_;
373
374 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParseInfoTree);
375 };
376
temporal40ee5512008-07-10 02:12:20 +0000377 // For more control over parsing, use this class.
378 class LIBPROTOBUF_EXPORT Parser {
379 public:
380 Parser();
381 ~Parser();
382
383 // Like TextFormat::Parse().
384 bool Parse(io::ZeroCopyInputStream* input, Message* output);
385 // Like TextFormat::ParseFromString().
386 bool ParseFromString(const string& input, Message* output);
387 // Like TextFormat::Merge().
388 bool Merge(io::ZeroCopyInputStream* input, Message* output);
389 // Like TextFormat::MergeFromString().
390 bool MergeFromString(const string& input, Message* output);
391
392 // Set where to report parse errors. If NULL (the default), errors will
393 // be printed to stderr.
394 void RecordErrorsTo(io::ErrorCollector* error_collector) {
395 error_collector_ = error_collector;
396 }
397
liujisi@google.com33165fe2010-11-02 13:14:58 +0000398 // Set how parser finds extensions. If NULL (the default), the
399 // parser will use the standard Reflection object associated with
400 // the message being parsed.
401 void SetFinder(Finder* finder) {
402 finder_ = finder;
403 }
404
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000405 // Sets where location information about the parse will be written. If NULL
406 // (the default), then no location will be written.
407 void WriteLocationsTo(ParseInfoTree* tree) {
408 parse_info_tree_ = tree;
409 }
410
temporal40ee5512008-07-10 02:12:20 +0000411 // Normally parsing fails if, after parsing, output->IsInitialized()
412 // returns false. Call AllowPartialMessage(true) to skip this check.
413 void AllowPartialMessage(bool allow) {
414 allow_partial_ = allow;
415 }
416
jieluo@google.com4de8f552014-07-18 00:47:59 +0000417 // Allow field names to be matched case-insensitively.
418 // This is not advisable if there are fields that only differ in case, or
419 // if you want to enforce writing in the canonical form.
420 // This is 'false' by default.
421 void AllowCaseInsensitiveField(bool allow) {
422 allow_case_insensitive_field_ = allow;
423 }
424
kenton@google.com80b1d622009-07-29 01:13:20 +0000425 // Like TextFormat::ParseFieldValueFromString
426 bool ParseFieldValueFromString(const string& input,
427 const FieldDescriptor* field,
428 Message* output);
429
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000430
jieluo@google.com4de8f552014-07-18 00:47:59 +0000431 void AllowFieldNumber(bool allow) {
432 allow_field_number_ = allow;
433 }
434
temporal40ee5512008-07-10 02:12:20 +0000435 private:
kenton@google.com24bf56f2008-09-24 20:31:01 +0000436 // Forward declaration of an internal class used to parse text
437 // representations (see text_format.cc for implementation).
438 class ParserImpl;
439
440 // Like TextFormat::Merge(). The provided implementation is used
441 // to do the parsing.
442 bool MergeUsingImpl(io::ZeroCopyInputStream* input,
443 Message* output,
444 ParserImpl* parser_impl);
445
temporal40ee5512008-07-10 02:12:20 +0000446 io::ErrorCollector* error_collector_;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000447 Finder* finder_;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000448 ParseInfoTree* parse_info_tree_;
temporal40ee5512008-07-10 02:12:20 +0000449 bool allow_partial_;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000450 bool allow_case_insensitive_field_;
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000451 bool allow_unknown_field_;
jieluo@google.com4de8f552014-07-18 00:47:59 +0000452 bool allow_unknown_enum_;
453 bool allow_field_number_;
454 bool allow_relaxed_whitespace_;
455 bool allow_singular_overwrites_;
temporal40ee5512008-07-10 02:12:20 +0000456 };
457
jieluo@google.com4de8f552014-07-18 00:47:59 +0000458
temporal40ee5512008-07-10 02:12:20 +0000459 private:
xiaofeng@google.com9c1c31f2012-11-30 16:29:03 +0000460 // Hack: ParseInfoTree declares TextFormat as a friend which should extend
461 // the friendship to TextFormat::Parser::ParserImpl, but unfortunately some
462 // old compilers (e.g. GCC 3.4.6) don't implement this correctly. We provide
463 // helpers for ParserImpl to call methods of ParseInfoTree.
464 static inline void RecordLocation(ParseInfoTree* info_tree,
465 const FieldDescriptor* field,
466 ParseLocation location);
467 static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
468 const FieldDescriptor* field);
469
temporal40ee5512008-07-10 02:12:20 +0000470 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
471};
472
xiaofeng@google.com9c1c31f2012-11-30 16:29:03 +0000473inline void TextFormat::RecordLocation(ParseInfoTree* info_tree,
474 const FieldDescriptor* field,
475 ParseLocation location) {
476 info_tree->RecordLocation(field, location);
477}
478
jieluo@google.com4de8f552014-07-18 00:47:59 +0000479
xiaofeng@google.com9c1c31f2012-11-30 16:29:03 +0000480inline TextFormat::ParseInfoTree* TextFormat::CreateNested(
481 ParseInfoTree* info_tree, const FieldDescriptor* field) {
482 return info_tree->CreateNested(field);
483}
484
temporal40ee5512008-07-10 02:12:20 +0000485} // namespace protobuf
486
487} // namespace google
488#endif // GOOGLE_PROTOBUF_TEXT_FORMAT_H__