blob: 1494ebd78d8ca00550af2afed357a9c2666ea2ee [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.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
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#include <float.h>
36#include <math.h>
kenton@google.com26bd9ee2008-11-21 00:06:27 +000037#include <stdio.h>
temporal40ee5512008-07-10 02:12:20 +000038#include <stack>
39#include <limits>
liujisi@google.com33165fe2010-11-02 13:14:58 +000040#include <vector>
temporal40ee5512008-07-10 02:12:20 +000041
42#include <google/protobuf/text_format.h>
43
44#include <google/protobuf/descriptor.h>
45#include <google/protobuf/io/coded_stream.h>
46#include <google/protobuf/io/zero_copy_stream.h>
47#include <google/protobuf/io/zero_copy_stream_impl.h>
48#include <google/protobuf/unknown_field_set.h>
49#include <google/protobuf/descriptor.pb.h>
50#include <google/protobuf/io/tokenizer.h>
51#include <google/protobuf/stubs/strutil.h>
52
53namespace google {
54namespace protobuf {
55
56string Message::DebugString() const {
57 string debug_string;
temporal40ee5512008-07-10 02:12:20 +000058
kenton@google.comfccb1462009-12-18 02:11:36 +000059 TextFormat::PrintToString(*this, &debug_string);
temporal40ee5512008-07-10 02:12:20 +000060
61 return debug_string;
62}
63
64string Message::ShortDebugString() const {
kenton@google.comd37d46d2009-04-25 02:53:47 +000065 string debug_string;
temporal40ee5512008-07-10 02:12:20 +000066
kenton@google.comd37d46d2009-04-25 02:53:47 +000067 TextFormat::Printer printer;
68 printer.SetSingleLineMode(true);
temporal40ee5512008-07-10 02:12:20 +000069
kenton@google.comfccb1462009-12-18 02:11:36 +000070 printer.PrintToString(*this, &debug_string);
kenton@google.comd37d46d2009-04-25 02:53:47 +000071 // Single line mode currently might have an extra space at the end.
72 if (debug_string.size() > 0 &&
73 debug_string[debug_string.size() - 1] == ' ') {
74 debug_string.resize(debug_string.size() - 1);
75 }
76
77 return debug_string;
temporal40ee5512008-07-10 02:12:20 +000078}
79
kenton@google.comfccb1462009-12-18 02:11:36 +000080string Message::Utf8DebugString() const {
81 string debug_string;
82
83 TextFormat::Printer printer;
84 printer.SetUseUtf8StringEscaping(true);
85
86 printer.PrintToString(*this, &debug_string);
87
88 return debug_string;
89}
90
temporal40ee5512008-07-10 02:12:20 +000091void Message::PrintDebugString() const {
92 printf("%s", DebugString().c_str());
93}
94
kenton@google.comfccb1462009-12-18 02:11:36 +000095
temporal40ee5512008-07-10 02:12:20 +000096// ===========================================================================
97// Internal class for parsing an ASCII representation of a Protocol Message.
98// This class makes use of the Protocol Message compiler's tokenizer found
99// in //google/protobuf/io/tokenizer.h. Note that class's Parse
100// method is *not* thread-safe and should only be used in a single thread at
101// a time.
102
103// Makes code slightly more readable. The meaning of "DO(foo)" is
104// "Execute foo and fail if it fails.", where failure is indicated by
105// returning false. Borrowed from parser.cc (Thanks Kenton!).
106#define DO(STATEMENT) if (STATEMENT) {} else return false
107
kenton@google.com24bf56f2008-09-24 20:31:01 +0000108class TextFormat::Parser::ParserImpl {
temporal40ee5512008-07-10 02:12:20 +0000109 public:
kenton@google.com24bf56f2008-09-24 20:31:01 +0000110
111 // Determines if repeated values for a non-repeated field are
112 // permitted, e.g., the string "foo: 1 foo: 2" for a
113 // required/optional field named "foo".
114 enum SingularOverwritePolicy {
115 ALLOW_SINGULAR_OVERWRITES = 0, // the last value is retained
116 FORBID_SINGULAR_OVERWRITES = 1, // an error is issued
117 };
118
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000119 ParserImpl(const Descriptor* root_message_type,
120 io::ZeroCopyInputStream* input_stream,
kenton@google.com24bf56f2008-09-24 20:31:01 +0000121 io::ErrorCollector* error_collector,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000122 TextFormat::Finder* finder,
kenton@google.com24bf56f2008-09-24 20:31:01 +0000123 SingularOverwritePolicy singular_overwrite_policy)
temporal40ee5512008-07-10 02:12:20 +0000124 : error_collector_(error_collector),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000125 finder_(finder),
temporal40ee5512008-07-10 02:12:20 +0000126 tokenizer_error_collector_(this),
127 tokenizer_(input_stream, &tokenizer_error_collector_),
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000128 root_message_type_(root_message_type),
129 singular_overwrite_policy_(singular_overwrite_policy),
130 had_errors_(false) {
temporal40ee5512008-07-10 02:12:20 +0000131 // For backwards-compatibility with proto1, we need to allow the 'f' suffix
132 // for floats.
133 tokenizer_.set_allow_f_after_float(true);
134
135 // '#' starts a comment.
136 tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE);
137
138 // Consume the starting token.
139 tokenizer_.Next();
140 }
141 ~ParserImpl() { }
142
143 // Parses the ASCII representation specified in input and saves the
144 // information into the output pointer (a Message). Returns
145 // false if an error occurs (an error will also be logged to
146 // GOOGLE_LOG(ERROR)).
147 bool Parse(Message* output) {
temporal40ee5512008-07-10 02:12:20 +0000148 // Consume fields until we cannot do so anymore.
149 while(true) {
150 if (LookingAtType(io::Tokenizer::TYPE_END)) {
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000151 return !had_errors_;
temporal40ee5512008-07-10 02:12:20 +0000152 }
153
temporal779f61c2008-08-13 03:15:00 +0000154 DO(ConsumeField(output));
temporal40ee5512008-07-10 02:12:20 +0000155 }
156 }
157
kenton@google.com80b1d622009-07-29 01:13:20 +0000158 bool ParseField(const FieldDescriptor* field, Message* output) {
159 bool suc;
160 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
161 suc = ConsumeFieldMessage(output, output->GetReflection(), field);
162 } else {
163 suc = ConsumeFieldValue(output, output->GetReflection(), field);
164 }
165 return suc && LookingAtType(io::Tokenizer::TYPE_END);
166 }
167
temporal40ee5512008-07-10 02:12:20 +0000168 void ReportError(int line, int col, const string& message) {
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000169 had_errors_ = true;
temporal40ee5512008-07-10 02:12:20 +0000170 if (error_collector_ == NULL) {
171 if (line >= 0) {
172 GOOGLE_LOG(ERROR) << "Error parsing text-format "
173 << root_message_type_->full_name()
174 << ": " << (line + 1) << ":"
175 << (col + 1) << ": " << message;
176 } else {
177 GOOGLE_LOG(ERROR) << "Error parsing text-format "
178 << root_message_type_->full_name()
179 << ": " << message;
180 }
181 } else {
182 error_collector_->AddError(line, col, message);
183 }
184 }
185
kenton@google.comfccb1462009-12-18 02:11:36 +0000186 void ReportWarning(int line, int col, const string& message) {
187 if (error_collector_ == NULL) {
188 if (line >= 0) {
189 GOOGLE_LOG(WARNING) << "Warning parsing text-format "
190 << root_message_type_->full_name()
191 << ": " << (line + 1) << ":"
192 << (col + 1) << ": " << message;
193 } else {
194 GOOGLE_LOG(WARNING) << "Warning parsing text-format "
195 << root_message_type_->full_name()
196 << ": " << message;
197 }
198 } else {
199 error_collector_->AddWarning(line, col, message);
200 }
201 }
202
temporal40ee5512008-07-10 02:12:20 +0000203 private:
204 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl);
205
206 // Reports an error with the given message with information indicating
207 // the position (as derived from the current token).
208 void ReportError(const string& message) {
209 ReportError(tokenizer_.current().line, tokenizer_.current().column,
210 message);
211 }
212
kenton@google.comfccb1462009-12-18 02:11:36 +0000213 // Reports a warning with the given message with information indicating
214 // the position (as derived from the current token).
215 void ReportWarning(const string& message) {
216 ReportWarning(tokenizer_.current().line, tokenizer_.current().column,
217 message);
218 }
219
temporal40ee5512008-07-10 02:12:20 +0000220 // Consumes the specified message with the given starting delimeter.
221 // This method checks to see that the end delimeter at the conclusion of
222 // the consumption matches the starting delimeter passed in here.
223 bool ConsumeMessage(Message* message, const string delimeter) {
temporal40ee5512008-07-10 02:12:20 +0000224 while (!LookingAt(">") && !LookingAt("}")) {
temporal779f61c2008-08-13 03:15:00 +0000225 DO(ConsumeField(message));
temporal40ee5512008-07-10 02:12:20 +0000226 }
227
228 // Confirm that we have a valid ending delimeter.
229 DO(Consume(delimeter));
230
231 return true;
232 }
233
234 // Consumes the current field (as returned by the tokenizer) on the
235 // passed in message.
temporal779f61c2008-08-13 03:15:00 +0000236 bool ConsumeField(Message* message) {
237 const Reflection* reflection = message->GetReflection();
238 const Descriptor* descriptor = message->GetDescriptor();
239
temporal40ee5512008-07-10 02:12:20 +0000240 string field_name;
241
242 const FieldDescriptor* field = NULL;
243
244 if (TryConsume("[")) {
245 // Extension.
246 DO(ConsumeIdentifier(&field_name));
247 while (TryConsume(".")) {
248 string part;
249 DO(ConsumeIdentifier(&part));
250 field_name += ".";
251 field_name += part;
252 }
253 DO(Consume("]"));
254
liujisi@google.com33165fe2010-11-02 13:14:58 +0000255 field = (finder_ != NULL
256 ? finder_->FindExtension(message, field_name)
257 : reflection->FindKnownExtensionByName(field_name));
temporal40ee5512008-07-10 02:12:20 +0000258
259 if (field == NULL) {
260 ReportError("Extension \"" + field_name + "\" is not defined or "
261 "is not an extension of \"" +
262 descriptor->full_name() + "\".");
263 return false;
264 }
265 } else {
266 DO(ConsumeIdentifier(&field_name));
267
268 field = descriptor->FindFieldByName(field_name);
269 // Group names are expected to be capitalized as they appear in the
270 // .proto file, which actually matches their type names, not their field
271 // names.
272 if (field == NULL) {
273 string lower_field_name = field_name;
274 LowerString(&lower_field_name);
275 field = descriptor->FindFieldByName(lower_field_name);
276 // If the case-insensitive match worked but the field is NOT a group,
277 if (field != NULL && field->type() != FieldDescriptor::TYPE_GROUP) {
278 field = NULL;
279 }
280 }
281 // Again, special-case group names as described above.
282 if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
283 && field->message_type()->name() != field_name) {
284 field = NULL;
285 }
286
287 if (field == NULL) {
288 ReportError("Message type \"" + descriptor->full_name() +
289 "\" has no field named \"" + field_name + "\".");
290 return false;
291 }
292 }
293
kenton@google.com24bf56f2008-09-24 20:31:01 +0000294 // Fail if the field is not repeated and it has already been specified.
295 if ((singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) &&
296 !field->is_repeated() && reflection->HasField(*message, field)) {
297 ReportError("Non-repeated field \"" + field_name +
298 "\" is specified multiple times.");
299 return false;
300 }
301
temporal40ee5512008-07-10 02:12:20 +0000302 // Perform special handling for embedded message types.
303 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
temporal40ee5512008-07-10 02:12:20 +0000304 // ':' is optional here.
305 TryConsume(":");
kenton@google.com80b1d622009-07-29 01:13:20 +0000306 DO(ConsumeFieldMessage(message, reflection, field));
temporal40ee5512008-07-10 02:12:20 +0000307 } else {
308 DO(Consume(":"));
liujisi@google.com33165fe2010-11-02 13:14:58 +0000309 if (field->is_repeated() && TryConsume("[")) {
310 // Short repeated format, e.g. "foo: [1, 2, 3]"
311 while (true) {
312 DO(ConsumeFieldValue(message, reflection, field));
313 if (TryConsume("]")) {
314 break;
315 }
316 DO(Consume(","));
317 }
318 } else {
319 DO(ConsumeFieldValue(message, reflection, field));
320 }
temporal40ee5512008-07-10 02:12:20 +0000321 }
322
liujisi@google.com33165fe2010-11-02 13:14:58 +0000323 // For historical reasons, fields may optionally be separated by commas or
324 // semicolons.
325 TryConsume(";") || TryConsume(",");
326
kenton@google.comfccb1462009-12-18 02:11:36 +0000327 if (field->options().deprecated()) {
328 ReportWarning("text format contains deprecated field \""
329 + field_name + "\"");
330 }
331
temporal40ee5512008-07-10 02:12:20 +0000332 return true;
333 }
334
kenton@google.com80b1d622009-07-29 01:13:20 +0000335 bool ConsumeFieldMessage(Message* message,
336 const Reflection* reflection,
337 const FieldDescriptor* field) {
338 string delimeter;
339 if (TryConsume("<")) {
340 delimeter = ">";
341 } else {
342 DO(Consume("{"));
343 delimeter = "}";
344 }
345
346 if (field->is_repeated()) {
347 DO(ConsumeMessage(reflection->AddMessage(message, field), delimeter));
348 } else {
349 DO(ConsumeMessage(reflection->MutableMessage(message, field),
350 delimeter));
351 }
352 return true;
353 }
354
temporal779f61c2008-08-13 03:15:00 +0000355 bool ConsumeFieldValue(Message* message,
356 const Reflection* reflection,
temporal40ee5512008-07-10 02:12:20 +0000357 const FieldDescriptor* field) {
358
359// Define an easy to use macro for setting fields. This macro checks
360// to see if the field is repeated (in which case we need to use the Add
361// methods or not (in which case we need to use the Set methods).
362#define SET_FIELD(CPPTYPE, VALUE) \
363 if (field->is_repeated()) { \
temporal779f61c2008-08-13 03:15:00 +0000364 reflection->Add##CPPTYPE(message, field, VALUE); \
temporal40ee5512008-07-10 02:12:20 +0000365 } else { \
temporal779f61c2008-08-13 03:15:00 +0000366 reflection->Set##CPPTYPE(message, field, VALUE); \
temporal40ee5512008-07-10 02:12:20 +0000367 } \
368
369 switch(field->cpp_type()) {
370 case FieldDescriptor::CPPTYPE_INT32: {
371 int64 value;
372 DO(ConsumeSignedInteger(&value, kint32max));
373 SET_FIELD(Int32, static_cast<int32>(value));
374 break;
375 }
376
377 case FieldDescriptor::CPPTYPE_UINT32: {
378 uint64 value;
379 DO(ConsumeUnsignedInteger(&value, kuint32max));
380 SET_FIELD(UInt32, static_cast<uint32>(value));
381 break;
382 }
383
384 case FieldDescriptor::CPPTYPE_INT64: {
385 int64 value;
386 DO(ConsumeSignedInteger(&value, kint64max));
387 SET_FIELD(Int64, value);
388 break;
389 }
390
391 case FieldDescriptor::CPPTYPE_UINT64: {
392 uint64 value;
393 DO(ConsumeUnsignedInteger(&value, kuint64max));
394 SET_FIELD(UInt64, value);
395 break;
396 }
397
398 case FieldDescriptor::CPPTYPE_FLOAT: {
399 double value;
400 DO(ConsumeDouble(&value));
401 SET_FIELD(Float, static_cast<float>(value));
402 break;
403 }
404
405 case FieldDescriptor::CPPTYPE_DOUBLE: {
406 double value;
407 DO(ConsumeDouble(&value));
408 SET_FIELD(Double, value);
409 break;
410 }
411
412 case FieldDescriptor::CPPTYPE_STRING: {
413 string value;
414 DO(ConsumeString(&value));
415 SET_FIELD(String, value);
416 break;
417 }
418
419 case FieldDescriptor::CPPTYPE_BOOL: {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000420 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
421 uint64 value;
422 DO(ConsumeUnsignedInteger(&value, 1));
423 SET_FIELD(Bool, value);
temporal40ee5512008-07-10 02:12:20 +0000424 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000425 string value;
426 DO(ConsumeIdentifier(&value));
427 if (value == "true" || value == "t") {
428 SET_FIELD(Bool, true);
429 } else if (value == "false" || value == "f") {
430 SET_FIELD(Bool, false);
431 } else {
432 ReportError("Invalid value for boolean field \"" + field->name()
433 + "\". Value: \"" + value + "\".");
434 return false;
435 }
temporal40ee5512008-07-10 02:12:20 +0000436 }
437 break;
438 }
439
440 case FieldDescriptor::CPPTYPE_ENUM: {
441 string value;
temporal40ee5512008-07-10 02:12:20 +0000442 const EnumDescriptor* enum_type = field->enum_type();
liujisi@google.com33165fe2010-11-02 13:14:58 +0000443 const EnumValueDescriptor* enum_value = NULL;
444
445 if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
446 DO(ConsumeIdentifier(&value));
447 // Find the enumeration value.
448 enum_value = enum_type->FindValueByName(value);
449
450 } else if (LookingAt("-") ||
451 LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
452 int64 int_value;
453 DO(ConsumeSignedInteger(&int_value, kint32max));
454 value = SimpleItoa(int_value); // for error reporting
455 enum_value = enum_type->FindValueByNumber(int_value);
456 } else {
457 ReportError("Expected integer or identifier.");
458 return false;
459 }
temporal40ee5512008-07-10 02:12:20 +0000460
461 if (enum_value == NULL) {
462 ReportError("Unknown enumeration value of \"" + value + "\" for "
463 "field \"" + field->name() + "\".");
464 return false;
465 }
466
467 SET_FIELD(Enum, enum_value);
468 break;
469 }
470
471 case FieldDescriptor::CPPTYPE_MESSAGE: {
472 // We should never get here. Put here instead of a default
473 // so that if new types are added, we get a nice compiler warning.
474 GOOGLE_LOG(FATAL) << "Reached an unintended state: CPPTYPE_MESSAGE";
475 break;
476 }
477 }
478#undef SET_FIELD
479 return true;
480 }
481
482 // Returns true if the current token's text is equal to that specified.
483 bool LookingAt(const string& text) {
484 return tokenizer_.current().text == text;
485 }
486
487 // Returns true if the current token's type is equal to that specified.
488 bool LookingAtType(io::Tokenizer::TokenType token_type) {
489 return tokenizer_.current().type == token_type;
490 }
491
492 // Consumes an identifier and saves its value in the identifier parameter.
493 // Returns false if the token is not of type IDENTFIER.
494 bool ConsumeIdentifier(string* identifier) {
495 if (!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
496 ReportError("Expected identifier.");
497 return false;
498 }
499
500 *identifier = tokenizer_.current().text;
501
502 tokenizer_.Next();
503 return true;
504 }
505
506 // Consumes a string and saves its value in the text parameter.
507 // Returns false if the token is not of type STRING.
508 bool ConsumeString(string* text) {
509 if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
510 ReportError("Expected string.");
511 return false;
512 }
513
kenton@google.comd37d46d2009-04-25 02:53:47 +0000514 text->clear();
515 while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
516 io::Tokenizer::ParseStringAppend(tokenizer_.current().text, text);
temporal40ee5512008-07-10 02:12:20 +0000517
kenton@google.comd37d46d2009-04-25 02:53:47 +0000518 tokenizer_.Next();
519 }
520
temporal40ee5512008-07-10 02:12:20 +0000521 return true;
522 }
523
524 // Consumes a uint64 and saves its value in the value parameter.
525 // Returns false if the token is not of type INTEGER.
526 bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
527 if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
528 ReportError("Expected integer.");
529 return false;
530 }
531
532 if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
533 max_value, value)) {
534 ReportError("Integer out of range.");
535 return false;
536 }
537
538 tokenizer_.Next();
539 return true;
540 }
541
542 // Consumes an int64 and saves its value in the value parameter.
543 // Note that since the tokenizer does not support negative numbers,
544 // we actually may consume an additional token (for the minus sign) in this
545 // method. Returns false if the token is not an integer
546 // (signed or otherwise).
547 bool ConsumeSignedInteger(int64* value, uint64 max_value) {
548 bool negative = false;
549
550 if (TryConsume("-")) {
551 negative = true;
552 // Two's complement always allows one more negative integer than
553 // positive.
554 ++max_value;
555 }
556
557 uint64 unsigned_value;
558
559 DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
560
561 *value = static_cast<int64>(unsigned_value);
562
563 if (negative) {
564 *value = -*value;
565 }
566
567 return true;
568 }
569
570 // Consumes a double and saves its value in the value parameter.
571 // Note that since the tokenizer does not support negative numbers,
572 // we actually may consume an additional token (for the minus sign) in this
573 // method. Returns false if the token is not a double
574 // (signed or otherwise).
575 bool ConsumeDouble(double* value) {
576 bool negative = false;
577
578 if (TryConsume("-")) {
579 negative = true;
580 }
581
582 // A double can actually be an integer, according to the tokenizer.
583 // Therefore, we must check both cases here.
584 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
585 // We have found an integer value for the double.
586 uint64 integer_value;
587 DO(ConsumeUnsignedInteger(&integer_value, kuint64max));
588
589 *value = static_cast<double>(integer_value);
590 } else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
591 // We have found a float value for the double.
592 *value = io::Tokenizer::ParseFloat(tokenizer_.current().text);
593
594 // Mark the current token as consumed.
595 tokenizer_.Next();
596 } else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
597 string text = tokenizer_.current().text;
598 LowerString(&text);
599 if (text == "inf" || text == "infinity") {
600 *value = std::numeric_limits<double>::infinity();
601 tokenizer_.Next();
602 } else if (text == "nan") {
603 *value = std::numeric_limits<double>::quiet_NaN();
604 tokenizer_.Next();
605 } else {
606 ReportError("Expected double.");
607 return false;
608 }
609 } else {
610 ReportError("Expected double.");
611 return false;
612 }
613
614 if (negative) {
615 *value = -*value;
616 }
617
618 return true;
619 }
620
621 // Consumes a token and confirms that it matches that specified in the
622 // value parameter. Returns false if the token found does not match that
623 // which was specified.
624 bool Consume(const string& value) {
625 const string& current_value = tokenizer_.current().text;
626
627 if (current_value != value) {
628 ReportError("Expected \"" + value + "\", found \"" + current_value
629 + "\".");
630 return false;
631 }
632
633 tokenizer_.Next();
634
635 return true;
636 }
637
638 // Attempts to consume the supplied value. Returns false if a the
639 // token found does not match the value specified.
640 bool TryConsume(const string& value) {
641 if (tokenizer_.current().text == value) {
642 tokenizer_.Next();
643 return true;
644 } else {
645 return false;
646 }
647 }
648
649 // An internal instance of the Tokenizer's error collector, used to
650 // collect any base-level parse errors and feed them to the ParserImpl.
651 class ParserErrorCollector : public io::ErrorCollector {
652 public:
kenton@google.com24bf56f2008-09-24 20:31:01 +0000653 explicit ParserErrorCollector(TextFormat::Parser::ParserImpl* parser) :
temporal40ee5512008-07-10 02:12:20 +0000654 parser_(parser) { }
655
656 virtual ~ParserErrorCollector() { };
657
658 virtual void AddError(int line, int column, const string& message) {
659 parser_->ReportError(line, column, message);
660 }
661
kenton@google.comfccb1462009-12-18 02:11:36 +0000662 virtual void AddWarning(int line, int column, const string& message) {
663 parser_->ReportWarning(line, column, message);
664 }
665
temporal40ee5512008-07-10 02:12:20 +0000666 private:
667 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000668 TextFormat::Parser::ParserImpl* parser_;
temporal40ee5512008-07-10 02:12:20 +0000669 };
670
671 io::ErrorCollector* error_collector_;
liujisi@google.com33165fe2010-11-02 13:14:58 +0000672 TextFormat::Finder* finder_;
temporal40ee5512008-07-10 02:12:20 +0000673 ParserErrorCollector tokenizer_error_collector_;
674 io::Tokenizer tokenizer_;
675 const Descriptor* root_message_type_;
kenton@google.com24bf56f2008-09-24 20:31:01 +0000676 SingularOverwritePolicy singular_overwrite_policy_;
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000677 bool had_errors_;
temporal40ee5512008-07-10 02:12:20 +0000678};
679
680#undef DO
681
682// ===========================================================================
683// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
684// from the Printer found in //google/protobuf/io/printer.h
kenton@google.comd37d46d2009-04-25 02:53:47 +0000685class TextFormat::Printer::TextGenerator {
temporal40ee5512008-07-10 02:12:20 +0000686 public:
kenton@google.comd37d46d2009-04-25 02:53:47 +0000687 explicit TextGenerator(io::ZeroCopyOutputStream* output,
688 int initial_indent_level)
temporal40ee5512008-07-10 02:12:20 +0000689 : output_(output),
690 buffer_(NULL),
691 buffer_size_(0),
692 at_start_of_line_(true),
693 failed_(false),
kenton@google.comd37d46d2009-04-25 02:53:47 +0000694 indent_(""),
695 initial_indent_level_(initial_indent_level) {
696 indent_.resize(initial_indent_level_ * 2, ' ');
temporal40ee5512008-07-10 02:12:20 +0000697 }
698
699 ~TextGenerator() {
700 // Only BackUp() if we're sure we've successfully called Next() at least
701 // once.
702 if (buffer_size_ > 0) {
703 output_->BackUp(buffer_size_);
704 }
705 }
706
707 // Indent text by two spaces. After calling Indent(), two spaces will be
708 // inserted at the beginning of each line of text. Indent() may be called
709 // multiple times to produce deeper indents.
710 void Indent() {
711 indent_ += " ";
712 }
713
714 // Reduces the current indent level by two spaces, or crashes if the indent
715 // level is zero.
716 void Outdent() {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000717 if (indent_.empty() ||
718 indent_.size() < initial_indent_level_ * 2) {
temporal40ee5512008-07-10 02:12:20 +0000719 GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
720 return;
721 }
722
723 indent_.resize(indent_.size() - 2);
724 }
725
726 // Print text to the output stream.
727 void Print(const string& str) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000728 Print(str.data(), str.size());
temporal40ee5512008-07-10 02:12:20 +0000729 }
730
731 // Print text to the output stream.
732 void Print(const char* text) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000733 Print(text, strlen(text));
734 }
735
736 // Print text to the output stream.
737 void Print(const char* text, int size) {
temporal40ee5512008-07-10 02:12:20 +0000738 int pos = 0; // The number of bytes we've written so far.
739
740 for (int i = 0; i < size; i++) {
741 if (text[i] == '\n') {
742 // Saw newline. If there is more text, we may need to insert an indent
743 // here. So, write what we have so far, including the '\n'.
744 Write(text + pos, i - pos + 1);
745 pos = i + 1;
746
747 // Setting this true will cause the next Write() to insert an indent
748 // first.
749 at_start_of_line_ = true;
750 }
751 }
752
753 // Write the rest.
754 Write(text + pos, size - pos);
755 }
756
757 // True if any write to the underlying stream failed. (We don't just
758 // crash in this case because this is an I/O failure, not a programming
759 // error.)
760 bool failed() const { return failed_; }
761
762 private:
763 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
764
765 void Write(const char* data, int size) {
766 if (failed_) return;
767 if (size == 0) return;
768
769 if (at_start_of_line_) {
770 // Insert an indent.
771 at_start_of_line_ = false;
772 Write(indent_.data(), indent_.size());
773 if (failed_) return;
774 }
775
776 while (size > buffer_size_) {
777 // Data exceeds space in the buffer. Copy what we can and request a
778 // new buffer.
779 memcpy(buffer_, data, buffer_size_);
780 data += buffer_size_;
781 size -= buffer_size_;
782 void* void_buffer;
783 failed_ = !output_->Next(&void_buffer, &buffer_size_);
784 if (failed_) return;
785 buffer_ = reinterpret_cast<char*>(void_buffer);
786 }
787
788 // Buffer is big enough to receive the data; copy it.
789 memcpy(buffer_, data, size);
790 buffer_ += size;
791 buffer_size_ -= size;
792 }
793
794 io::ZeroCopyOutputStream* const output_;
795 char* buffer_;
796 int buffer_size_;
797 bool at_start_of_line_;
798 bool failed_;
799
800 string indent_;
kenton@google.comd37d46d2009-04-25 02:53:47 +0000801 int initial_indent_level_;
temporal40ee5512008-07-10 02:12:20 +0000802};
803
804// ===========================================================================
805
liujisi@google.com33165fe2010-11-02 13:14:58 +0000806TextFormat::Finder::~Finder() {
807}
808
temporal40ee5512008-07-10 02:12:20 +0000809TextFormat::Parser::Parser()
810 : error_collector_(NULL),
liujisi@google.com33165fe2010-11-02 13:14:58 +0000811 finder_(NULL),
812 allow_partial_(false) {
813}
temporal40ee5512008-07-10 02:12:20 +0000814
815TextFormat::Parser::~Parser() {}
816
817bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
818 Message* output) {
819 output->Clear();
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000820 ParserImpl parser(output->GetDescriptor(), input, error_collector_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000821 finder_, ParserImpl::FORBID_SINGULAR_OVERWRITES);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000822 return MergeUsingImpl(input, output, &parser);
temporal40ee5512008-07-10 02:12:20 +0000823}
824
825bool TextFormat::Parser::ParseFromString(const string& input,
826 Message* output) {
827 io::ArrayInputStream input_stream(input.data(), input.size());
828 return Parse(&input_stream, output);
829}
830
831bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
832 Message* output) {
kenton@google.com26bd9ee2008-11-21 00:06:27 +0000833 ParserImpl parser(output->GetDescriptor(), input, error_collector_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000834 finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
kenton@google.com24bf56f2008-09-24 20:31:01 +0000835 return MergeUsingImpl(input, output, &parser);
temporal40ee5512008-07-10 02:12:20 +0000836}
837
838bool TextFormat::Parser::MergeFromString(const string& input,
839 Message* output) {
840 io::ArrayInputStream input_stream(input.data(), input.size());
841 return Merge(&input_stream, output);
842}
843
kenton@google.com24bf56f2008-09-24 20:31:01 +0000844bool TextFormat::Parser::MergeUsingImpl(io::ZeroCopyInputStream* input,
845 Message* output,
846 ParserImpl* parser_impl) {
847 if (!parser_impl->Parse(output)) return false;
848 if (!allow_partial_ && !output->IsInitialized()) {
849 vector<string> missing_fields;
850 output->FindInitializationErrors(&missing_fields);
851 parser_impl->ReportError(-1, 0, "Message missing required fields: " +
852 JoinStrings(missing_fields, ", "));
853 return false;
854 }
855 return true;
856}
temporal40ee5512008-07-10 02:12:20 +0000857
kenton@google.com80b1d622009-07-29 01:13:20 +0000858bool TextFormat::Parser::ParseFieldValueFromString(
859 const string& input,
860 const FieldDescriptor* field,
861 Message* output) {
862 io::ArrayInputStream input_stream(input.data(), input.size());
863 ParserImpl parser(output->GetDescriptor(), &input_stream, error_collector_,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000864 finder_, ParserImpl::ALLOW_SINGULAR_OVERWRITES);
kenton@google.com80b1d622009-07-29 01:13:20 +0000865 return parser.ParseField(field, output);
866}
867
temporal40ee5512008-07-10 02:12:20 +0000868/* static */ bool TextFormat::Parse(io::ZeroCopyInputStream* input,
869 Message* output) {
870 return Parser().Parse(input, output);
871}
872
873/* static */ bool TextFormat::Merge(io::ZeroCopyInputStream* input,
874 Message* output) {
875 return Parser().Merge(input, output);
876}
877
878/* static */ bool TextFormat::ParseFromString(const string& input,
879 Message* output) {
880 return Parser().ParseFromString(input, output);
881}
882
883/* static */ bool TextFormat::MergeFromString(const string& input,
884 Message* output) {
885 return Parser().MergeFromString(input, output);
886}
887
kenton@google.comd37d46d2009-04-25 02:53:47 +0000888// ===========================================================================
889
890TextFormat::Printer::Printer()
891 : initial_indent_level_(0),
kenton@google.comfccb1462009-12-18 02:11:36 +0000892 single_line_mode_(false),
893 use_short_repeated_primitives_(false),
894 utf8_string_escaping_(false) {}
kenton@google.comd37d46d2009-04-25 02:53:47 +0000895
896TextFormat::Printer::~Printer() {}
897
898bool TextFormat::Printer::PrintToString(const Message& message,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000899 string* output) const {
temporal40ee5512008-07-10 02:12:20 +0000900 GOOGLE_DCHECK(output) << "output specified is NULL";
901
902 output->clear();
903 io::StringOutputStream output_stream(output);
904
905 bool result = Print(message, &output_stream);
906
907 return result;
908}
909
kenton@google.comd37d46d2009-04-25 02:53:47 +0000910bool TextFormat::Printer::PrintUnknownFieldsToString(
temporala0f27fc2008-08-06 01:12:21 +0000911 const UnknownFieldSet& unknown_fields,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000912 string* output) const {
temporala0f27fc2008-08-06 01:12:21 +0000913 GOOGLE_DCHECK(output) << "output specified is NULL";
914
915 output->clear();
916 io::StringOutputStream output_stream(output);
917 return PrintUnknownFields(unknown_fields, &output_stream);
918}
919
kenton@google.comd37d46d2009-04-25 02:53:47 +0000920bool TextFormat::Printer::Print(const Message& message,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000921 io::ZeroCopyOutputStream* output) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000922 TextGenerator generator(output, initial_indent_level_);
temporal40ee5512008-07-10 02:12:20 +0000923
temporal779f61c2008-08-13 03:15:00 +0000924 Print(message, generator);
temporal40ee5512008-07-10 02:12:20 +0000925
926 // Output false if the generator failed internally.
927 return !generator.failed();
928}
929
kenton@google.comd37d46d2009-04-25 02:53:47 +0000930bool TextFormat::Printer::PrintUnknownFields(
temporala0f27fc2008-08-06 01:12:21 +0000931 const UnknownFieldSet& unknown_fields,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000932 io::ZeroCopyOutputStream* output) const {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000933 TextGenerator generator(output, initial_indent_level_);
temporala0f27fc2008-08-06 01:12:21 +0000934
935 PrintUnknownFields(unknown_fields, generator);
936
937 // Output false if the generator failed internally.
938 return !generator.failed();
939}
940
kenton@google.comd37d46d2009-04-25 02:53:47 +0000941void TextFormat::Printer::Print(const Message& message,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000942 TextGenerator& generator) const {
temporal779f61c2008-08-13 03:15:00 +0000943 const Reflection* reflection = message.GetReflection();
temporal40ee5512008-07-10 02:12:20 +0000944 vector<const FieldDescriptor*> fields;
temporal779f61c2008-08-13 03:15:00 +0000945 reflection->ListFields(message, &fields);
temporal40ee5512008-07-10 02:12:20 +0000946 for (int i = 0; i < fields.size(); i++) {
temporal779f61c2008-08-13 03:15:00 +0000947 PrintField(message, reflection, fields[i], generator);
temporal40ee5512008-07-10 02:12:20 +0000948 }
temporal779f61c2008-08-13 03:15:00 +0000949 PrintUnknownFields(reflection->GetUnknownFields(message), generator);
temporal40ee5512008-07-10 02:12:20 +0000950}
951
kenton@google.comd37d46d2009-04-25 02:53:47 +0000952void TextFormat::Printer::PrintFieldValueToString(
temporal40ee5512008-07-10 02:12:20 +0000953 const Message& message,
954 const FieldDescriptor* field,
955 int index,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000956 string* output) const {
temporal40ee5512008-07-10 02:12:20 +0000957
958 GOOGLE_DCHECK(output) << "output specified is NULL";
959
960 output->clear();
961 io::StringOutputStream output_stream(output);
kenton@google.comd37d46d2009-04-25 02:53:47 +0000962 TextGenerator generator(&output_stream, initial_indent_level_);
temporal40ee5512008-07-10 02:12:20 +0000963
temporal779f61c2008-08-13 03:15:00 +0000964 PrintFieldValue(message, message.GetReflection(), field, index, generator);
temporal40ee5512008-07-10 02:12:20 +0000965}
966
kenton@google.comd37d46d2009-04-25 02:53:47 +0000967void TextFormat::Printer::PrintField(const Message& message,
968 const Reflection* reflection,
969 const FieldDescriptor* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +0000970 TextGenerator& generator) const {
kenton@google.comfccb1462009-12-18 02:11:36 +0000971 if (use_short_repeated_primitives_ &&
972 field->is_repeated() &&
973 field->cpp_type() != FieldDescriptor::CPPTYPE_STRING &&
974 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
975 PrintShortRepeatedField(message, reflection, field, generator);
976 return;
977 }
978
temporal40ee5512008-07-10 02:12:20 +0000979 int count = 0;
980
981 if (field->is_repeated()) {
temporal779f61c2008-08-13 03:15:00 +0000982 count = reflection->FieldSize(message, field);
983 } else if (reflection->HasField(message, field)) {
temporal40ee5512008-07-10 02:12:20 +0000984 count = 1;
985 }
986
987 for (int j = 0; j < count; ++j) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000988 PrintFieldName(message, reflection, field, generator);
temporal40ee5512008-07-10 02:12:20 +0000989
990 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
kenton@google.comd37d46d2009-04-25 02:53:47 +0000991 if (single_line_mode_) {
992 generator.Print(" { ");
993 } else {
temporal40ee5512008-07-10 02:12:20 +0000994 generator.Print(" {\n");
995 generator.Indent();
kenton@google.comd37d46d2009-04-25 02:53:47 +0000996 }
temporal40ee5512008-07-10 02:12:20 +0000997 } else {
998 generator.Print(": ");
999 }
1000
1001 // Write the field value.
1002 int field_index = j;
1003 if (!field->is_repeated()) {
1004 field_index = -1;
1005 }
1006
temporal779f61c2008-08-13 03:15:00 +00001007 PrintFieldValue(message, reflection, field, field_index, generator);
temporal40ee5512008-07-10 02:12:20 +00001008
1009 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
kenton@google.comfccb1462009-12-18 02:11:36 +00001010 if (single_line_mode_) {
1011 generator.Print("} ");
1012 } else {
temporal40ee5512008-07-10 02:12:20 +00001013 generator.Outdent();
kenton@google.comfccb1462009-12-18 02:11:36 +00001014 generator.Print("}\n");
kenton@google.comd37d46d2009-04-25 02:53:47 +00001015 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00001016 } else {
kenton@google.comfccb1462009-12-18 02:11:36 +00001017 if (single_line_mode_) {
1018 generator.Print(" ");
1019 } else {
1020 generator.Print("\n");
1021 }
1022 }
1023 }
1024}
1025
liujisi@google.com33165fe2010-11-02 13:14:58 +00001026void TextFormat::Printer::PrintShortRepeatedField(
1027 const Message& message,
1028 const Reflection* reflection,
1029 const FieldDescriptor* field,
1030 TextGenerator& generator) const {
kenton@google.comfccb1462009-12-18 02:11:36 +00001031 // Print primitive repeated field in short form.
1032 PrintFieldName(message, reflection, field, generator);
1033
1034 int size = reflection->FieldSize(message, field);
1035 generator.Print(": [");
1036 for (int i = 0; i < size; i++) {
1037 if (i > 0) generator.Print(", ");
1038 PrintFieldValue(message, reflection, field, i, generator);
1039 }
1040 if (single_line_mode_) {
1041 generator.Print("] ");
1042 } else {
1043 generator.Print("]\n");
1044 }
1045}
1046
1047void TextFormat::Printer::PrintFieldName(const Message& message,
1048 const Reflection* reflection,
1049 const FieldDescriptor* field,
liujisi@google.com33165fe2010-11-02 13:14:58 +00001050 TextGenerator& generator) const {
kenton@google.comfccb1462009-12-18 02:11:36 +00001051 if (field->is_extension()) {
1052 generator.Print("[");
1053 // We special-case MessageSet elements for compatibility with proto1.
1054 if (field->containing_type()->options().message_set_wire_format()
1055 && field->type() == FieldDescriptor::TYPE_MESSAGE
1056 && field->is_optional()
1057 && field->extension_scope() == field->message_type()) {
1058 generator.Print(field->message_type()->full_name());
1059 } else {
1060 generator.Print(field->full_name());
1061 }
1062 generator.Print("]");
1063 } else {
1064 if (field->type() == FieldDescriptor::TYPE_GROUP) {
1065 // Groups must be serialized with their original capitalization.
1066 generator.Print(field->message_type()->name());
1067 } else {
1068 generator.Print(field->name());
kenton@google.comd37d46d2009-04-25 02:53:47 +00001069 }
temporal40ee5512008-07-10 02:12:20 +00001070 }
1071}
1072
kenton@google.comd37d46d2009-04-25 02:53:47 +00001073void TextFormat::Printer::PrintFieldValue(
temporal779f61c2008-08-13 03:15:00 +00001074 const Message& message,
1075 const Reflection* reflection,
temporal40ee5512008-07-10 02:12:20 +00001076 const FieldDescriptor* field,
1077 int index,
liujisi@google.com33165fe2010-11-02 13:14:58 +00001078 TextGenerator& generator) const {
temporal40ee5512008-07-10 02:12:20 +00001079 GOOGLE_DCHECK(field->is_repeated() || (index == -1))
1080 << "Index must be -1 for non-repeated fields";
1081
1082 switch (field->cpp_type()) {
1083#define OUTPUT_FIELD(CPPTYPE, METHOD, TO_STRING) \
1084 case FieldDescriptor::CPPTYPE_##CPPTYPE: \
1085 generator.Print(TO_STRING(field->is_repeated() ? \
temporal779f61c2008-08-13 03:15:00 +00001086 reflection->GetRepeated##METHOD(message, field, index) : \
1087 reflection->Get##METHOD(message, field))); \
temporal40ee5512008-07-10 02:12:20 +00001088 break; \
1089
1090 OUTPUT_FIELD( INT32, Int32, SimpleItoa);
1091 OUTPUT_FIELD( INT64, Int64, SimpleItoa);
1092 OUTPUT_FIELD(UINT32, UInt32, SimpleItoa);
1093 OUTPUT_FIELD(UINT64, UInt64, SimpleItoa);
1094 OUTPUT_FIELD( FLOAT, Float, SimpleFtoa);
1095 OUTPUT_FIELD(DOUBLE, Double, SimpleDtoa);
1096#undef OUTPUT_FIELD
1097
1098 case FieldDescriptor::CPPTYPE_STRING: {
1099 string scratch;
1100 const string& value = field->is_repeated() ?
temporal779f61c2008-08-13 03:15:00 +00001101 reflection->GetRepeatedStringReference(
1102 message, field, index, &scratch) :
1103 reflection->GetStringReference(message, field, &scratch);
temporal40ee5512008-07-10 02:12:20 +00001104
1105 generator.Print("\"");
kenton@google.comfccb1462009-12-18 02:11:36 +00001106 if (utf8_string_escaping_) {
1107 generator.Print(strings::Utf8SafeCEscape(value));
1108 } else {
1109 generator.Print(CEscape(value));
1110 }
temporal40ee5512008-07-10 02:12:20 +00001111 generator.Print("\"");
1112
1113 break;
1114 }
1115
1116 case FieldDescriptor::CPPTYPE_BOOL:
1117 if (field->is_repeated()) {
temporal779f61c2008-08-13 03:15:00 +00001118 generator.Print(reflection->GetRepeatedBool(message, field, index)
temporal40ee5512008-07-10 02:12:20 +00001119 ? "true" : "false");
1120 } else {
temporal779f61c2008-08-13 03:15:00 +00001121 generator.Print(reflection->GetBool(message, field)
1122 ? "true" : "false");
temporal40ee5512008-07-10 02:12:20 +00001123 }
1124 break;
1125
1126 case FieldDescriptor::CPPTYPE_ENUM:
1127 generator.Print(field->is_repeated() ?
temporal779f61c2008-08-13 03:15:00 +00001128 reflection->GetRepeatedEnum(message, field, index)->name() :
1129 reflection->GetEnum(message, field)->name());
temporal40ee5512008-07-10 02:12:20 +00001130 break;
1131
1132 case FieldDescriptor::CPPTYPE_MESSAGE:
temporal779f61c2008-08-13 03:15:00 +00001133 Print(field->is_repeated() ?
1134 reflection->GetRepeatedMessage(message, field, index) :
1135 reflection->GetMessage(message, field),
1136 generator);
temporal40ee5512008-07-10 02:12:20 +00001137 break;
1138 }
1139}
1140
kenton@google.comd37d46d2009-04-25 02:53:47 +00001141/* static */ bool TextFormat::Print(const Message& message,
1142 io::ZeroCopyOutputStream* output) {
1143 return Printer().Print(message, output);
1144}
1145
1146/* static */ bool TextFormat::PrintUnknownFields(
1147 const UnknownFieldSet& unknown_fields,
1148 io::ZeroCopyOutputStream* output) {
1149 return Printer().PrintUnknownFields(unknown_fields, output);
1150}
1151
1152/* static */ bool TextFormat::PrintToString(
1153 const Message& message, string* output) {
1154 return Printer().PrintToString(message, output);
1155}
1156
1157/* static */ bool TextFormat::PrintUnknownFieldsToString(
1158 const UnknownFieldSet& unknown_fields, string* output) {
1159 return Printer().PrintUnknownFieldsToString(unknown_fields, output);
1160}
1161
1162/* static */ void TextFormat::PrintFieldValueToString(
1163 const Message& message,
1164 const FieldDescriptor* field,
1165 int index,
1166 string* output) {
1167 return Printer().PrintFieldValueToString(message, field, index, output);
1168}
1169
kenton@google.com80b1d622009-07-29 01:13:20 +00001170/* static */ bool TextFormat::ParseFieldValueFromString(
1171 const string& input,
1172 const FieldDescriptor* field,
1173 Message* message) {
1174 return Parser().ParseFieldValueFromString(input, field, message);
1175}
1176
temporal40ee5512008-07-10 02:12:20 +00001177// Prints an integer as hex with a fixed number of digits dependent on the
1178// integer type.
1179template<typename IntType>
1180static string PaddedHex(IntType value) {
1181 string result;
1182 result.reserve(sizeof(value) * 2);
1183 for (int i = sizeof(value) * 2 - 1; i >= 0; i--) {
1184 result.push_back(int_to_hex_digit(value >> (i*4) & 0x0F));
1185 }
1186 return result;
1187}
1188
kenton@google.comd37d46d2009-04-25 02:53:47 +00001189void TextFormat::Printer::PrintUnknownFields(
liujisi@google.com33165fe2010-11-02 13:14:58 +00001190 const UnknownFieldSet& unknown_fields, TextGenerator& generator) const {
temporal40ee5512008-07-10 02:12:20 +00001191 for (int i = 0; i < unknown_fields.field_count(); i++) {
1192 const UnknownField& field = unknown_fields.field(i);
1193 string field_number = SimpleItoa(field.number());
1194
kenton@google.comd37d46d2009-04-25 02:53:47 +00001195 switch (field.type()) {
1196 case UnknownField::TYPE_VARINT:
1197 generator.Print(field_number);
1198 generator.Print(": ");
1199 generator.Print(SimpleItoa(field.varint()));
1200 if (single_line_mode_) {
1201 generator.Print(" ");
1202 } else {
1203 generator.Print("\n");
1204 }
1205 break;
1206 case UnknownField::TYPE_FIXED32: {
1207 generator.Print(field_number);
1208 generator.Print(": 0x");
1209 char buffer[kFastToBufferSize];
1210 generator.Print(FastHex32ToBuffer(field.fixed32(), buffer));
1211 if (single_line_mode_) {
1212 generator.Print(" ");
1213 } else {
1214 generator.Print("\n");
1215 }
1216 break;
temporala0f27fc2008-08-06 01:12:21 +00001217 }
kenton@google.comd37d46d2009-04-25 02:53:47 +00001218 case UnknownField::TYPE_FIXED64: {
1219 generator.Print(field_number);
1220 generator.Print(": 0x");
1221 char buffer[kFastToBufferSize];
1222 generator.Print(FastHex64ToBuffer(field.fixed64(), buffer));
1223 if (single_line_mode_) {
1224 generator.Print(" ");
1225 } else {
1226 generator.Print("\n");
1227 }
1228 break;
1229 }
1230 case UnknownField::TYPE_LENGTH_DELIMITED: {
1231 generator.Print(field_number);
1232 const string& value = field.length_delimited();
1233 UnknownFieldSet embedded_unknown_fields;
1234 if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) {
1235 // This field is parseable as a Message.
1236 // So it is probably an embedded message.
1237 if (single_line_mode_) {
1238 generator.Print(" { ");
1239 } else {
1240 generator.Print(" {\n");
1241 generator.Indent();
1242 }
1243 PrintUnknownFields(embedded_unknown_fields, generator);
1244 if (single_line_mode_) {
1245 generator.Print("} ");
1246 } else {
1247 generator.Outdent();
1248 generator.Print("}\n");
1249 }
1250 } else {
1251 // This field is not parseable as a Message.
1252 // So it is probably just a plain string.
1253 generator.Print(": \"");
1254 generator.Print(CEscape(value));
1255 generator.Print("\"");
1256 if (single_line_mode_) {
1257 generator.Print(" ");
1258 } else {
1259 generator.Print("\n");
1260 }
1261 }
1262 break;
1263 }
1264 case UnknownField::TYPE_GROUP:
1265 generator.Print(field_number);
1266 if (single_line_mode_) {
1267 generator.Print(" { ");
1268 } else {
1269 generator.Print(" {\n");
1270 generator.Indent();
1271 }
1272 PrintUnknownFields(field.group(), generator);
1273 if (single_line_mode_) {
1274 generator.Print("} ");
1275 } else {
1276 generator.Outdent();
1277 generator.Print("}\n");
1278 }
1279 break;
temporal40ee5512008-07-10 02:12:20 +00001280 }
1281 }
1282}
1283
1284} // namespace protobuf
1285} // namespace google