blob: d698681c23cdd770754a0c5a4f25f6290d371f2b [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.
3// http://code.google.com/p/protobuf/
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17// Author: jschorr@google.com (Joseph Schorr)
18// Based on original Protocol Buffers design by
19// Sanjay Ghemawat, Jeff Dean, and others.
20
21#include <float.h>
22#include <math.h>
23#include <stack>
24#include <limits>
25
26#include <google/protobuf/text_format.h>
27
28#include <google/protobuf/descriptor.h>
29#include <google/protobuf/io/coded_stream.h>
30#include <google/protobuf/io/zero_copy_stream.h>
31#include <google/protobuf/io/zero_copy_stream_impl.h>
32#include <google/protobuf/unknown_field_set.h>
33#include <google/protobuf/descriptor.pb.h>
34#include <google/protobuf/io/tokenizer.h>
35#include <google/protobuf/stubs/strutil.h>
36
37namespace google {
38namespace protobuf {
39
40string Message::DebugString() const {
41 string debug_string;
42 io::StringOutputStream output_stream(&debug_string);
43
44 TextFormat::Print(*this, &output_stream);
45
46 return debug_string;
47}
48
49string Message::ShortDebugString() const {
50 // TODO(kenton): Make TextFormat support this natively instead of using
51 // DebugString() and munging the result.
52 string result = DebugString();
53
54 // Replace each contiguous range of whitespace (including newlines) with a
55 // single space.
56 for (int i = 0; i < result.size(); i++) {
57 int pos = i;
58 while (isspace(result[pos])) ++pos;
59 if (pos > i) result.replace(i, pos - i, " ");
60 }
61
62 return result;
63}
64
65void Message::PrintDebugString() const {
66 printf("%s", DebugString().c_str());
67}
68
69// ===========================================================================
70// Internal class for parsing an ASCII representation of a Protocol Message.
71// This class makes use of the Protocol Message compiler's tokenizer found
72// in //google/protobuf/io/tokenizer.h. Note that class's Parse
73// method is *not* thread-safe and should only be used in a single thread at
74// a time.
75
76// Makes code slightly more readable. The meaning of "DO(foo)" is
77// "Execute foo and fail if it fails.", where failure is indicated by
78// returning false. Borrowed from parser.cc (Thanks Kenton!).
79#define DO(STATEMENT) if (STATEMENT) {} else return false
80
81class TextFormat::ParserImpl {
82 public:
83 ParserImpl(io::ZeroCopyInputStream* input_stream,
84 io::ErrorCollector* error_collector)
85 : error_collector_(error_collector),
86 tokenizer_error_collector_(this),
87 tokenizer_(input_stream, &tokenizer_error_collector_),
88 root_message_type_(NULL) {
89 // For backwards-compatibility with proto1, we need to allow the 'f' suffix
90 // for floats.
91 tokenizer_.set_allow_f_after_float(true);
92
93 // '#' starts a comment.
94 tokenizer_.set_comment_style(io::Tokenizer::SH_COMMENT_STYLE);
95
96 // Consume the starting token.
97 tokenizer_.Next();
98 }
99 ~ParserImpl() { }
100
101 // Parses the ASCII representation specified in input and saves the
102 // information into the output pointer (a Message). Returns
103 // false if an error occurs (an error will also be logged to
104 // GOOGLE_LOG(ERROR)).
105 bool Parse(Message* output) {
106 Message::Reflection* reflection = output->GetReflection();
107 const Descriptor* descriptor = output->GetDescriptor();
108 root_message_type_ = descriptor;
109
110 // Consume fields until we cannot do so anymore.
111 while(true) {
112 if (LookingAtType(io::Tokenizer::TYPE_END)) {
113 return true;
114 }
115
116 DO(ConsumeField(reflection, descriptor));
117 }
118 }
119
120 void ReportError(int line, int col, const string& message) {
121 if (error_collector_ == NULL) {
122 if (line >= 0) {
123 GOOGLE_LOG(ERROR) << "Error parsing text-format "
124 << root_message_type_->full_name()
125 << ": " << (line + 1) << ":"
126 << (col + 1) << ": " << message;
127 } else {
128 GOOGLE_LOG(ERROR) << "Error parsing text-format "
129 << root_message_type_->full_name()
130 << ": " << message;
131 }
132 } else {
133 error_collector_->AddError(line, col, message);
134 }
135 }
136
137 private:
138 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl);
139
140 // Reports an error with the given message with information indicating
141 // the position (as derived from the current token).
142 void ReportError(const string& message) {
143 ReportError(tokenizer_.current().line, tokenizer_.current().column,
144 message);
145 }
146
147 // Consumes the specified message with the given starting delimeter.
148 // This method checks to see that the end delimeter at the conclusion of
149 // the consumption matches the starting delimeter passed in here.
150 bool ConsumeMessage(Message* message, const string delimeter) {
151 Message::Reflection* reflection = message->GetReflection();
152 const Descriptor* descriptor = message->GetDescriptor();
153
154 while (!LookingAt(">") && !LookingAt("}")) {
155 DO(ConsumeField(reflection, descriptor));
156 }
157
158 // Confirm that we have a valid ending delimeter.
159 DO(Consume(delimeter));
160
161 return true;
162 }
163
164 // Consumes the current field (as returned by the tokenizer) on the
165 // passed in message.
166 bool ConsumeField(Message::Reflection* reflection,
167 const Descriptor* descriptor) {
168 string field_name;
169
170 const FieldDescriptor* field = NULL;
171
172 if (TryConsume("[")) {
173 // Extension.
174 DO(ConsumeIdentifier(&field_name));
175 while (TryConsume(".")) {
176 string part;
177 DO(ConsumeIdentifier(&part));
178 field_name += ".";
179 field_name += part;
180 }
181 DO(Consume("]"));
182
183 field = reflection->FindKnownExtensionByName(field_name);
184
185 if (field == NULL) {
186 ReportError("Extension \"" + field_name + "\" is not defined or "
187 "is not an extension of \"" +
188 descriptor->full_name() + "\".");
189 return false;
190 }
191 } else {
192 DO(ConsumeIdentifier(&field_name));
193
194 field = descriptor->FindFieldByName(field_name);
195 // Group names are expected to be capitalized as they appear in the
196 // .proto file, which actually matches their type names, not their field
197 // names.
198 if (field == NULL) {
199 string lower_field_name = field_name;
200 LowerString(&lower_field_name);
201 field = descriptor->FindFieldByName(lower_field_name);
202 // If the case-insensitive match worked but the field is NOT a group,
203 if (field != NULL && field->type() != FieldDescriptor::TYPE_GROUP) {
204 field = NULL;
205 }
206 }
207 // Again, special-case group names as described above.
208 if (field != NULL && field->type() == FieldDescriptor::TYPE_GROUP
209 && field->message_type()->name() != field_name) {
210 field = NULL;
211 }
212
213 if (field == NULL) {
214 ReportError("Message type \"" + descriptor->full_name() +
215 "\" has no field named \"" + field_name + "\".");
216 return false;
217 }
218 }
219
220 // Perform special handling for embedded message types.
221 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
222 string delimeter;
223
224 // ':' is optional here.
225 TryConsume(":");
226
227 if (TryConsume("<")) {
228 delimeter = ">";
229 } else {
230 DO(Consume("{"));
231 delimeter = "}";
232 }
233
234 if (field->is_repeated()) {
235 DO(ConsumeMessage(reflection->AddMessage(field), delimeter));
236 } else {
237 DO(ConsumeMessage(reflection->MutableMessage(field), delimeter));
238 }
239 } else {
240 DO(Consume(":"));
241 DO(ConsumeFieldValue(reflection, field));
242 }
243
244 return true;
245 }
246
247 bool ConsumeFieldValue(Message::Reflection* reflection,
248 const FieldDescriptor* field) {
249
250// Define an easy to use macro for setting fields. This macro checks
251// to see if the field is repeated (in which case we need to use the Add
252// methods or not (in which case we need to use the Set methods).
253#define SET_FIELD(CPPTYPE, VALUE) \
254 if (field->is_repeated()) { \
255 reflection->Add##CPPTYPE(field, VALUE); \
256 } else { \
257 reflection->Set##CPPTYPE(field, VALUE); \
258 } \
259
260 switch(field->cpp_type()) {
261 case FieldDescriptor::CPPTYPE_INT32: {
262 int64 value;
263 DO(ConsumeSignedInteger(&value, kint32max));
264 SET_FIELD(Int32, static_cast<int32>(value));
265 break;
266 }
267
268 case FieldDescriptor::CPPTYPE_UINT32: {
269 uint64 value;
270 DO(ConsumeUnsignedInteger(&value, kuint32max));
271 SET_FIELD(UInt32, static_cast<uint32>(value));
272 break;
273 }
274
275 case FieldDescriptor::CPPTYPE_INT64: {
276 int64 value;
277 DO(ConsumeSignedInteger(&value, kint64max));
278 SET_FIELD(Int64, value);
279 break;
280 }
281
282 case FieldDescriptor::CPPTYPE_UINT64: {
283 uint64 value;
284 DO(ConsumeUnsignedInteger(&value, kuint64max));
285 SET_FIELD(UInt64, value);
286 break;
287 }
288
289 case FieldDescriptor::CPPTYPE_FLOAT: {
290 double value;
291 DO(ConsumeDouble(&value));
292 SET_FIELD(Float, static_cast<float>(value));
293 break;
294 }
295
296 case FieldDescriptor::CPPTYPE_DOUBLE: {
297 double value;
298 DO(ConsumeDouble(&value));
299 SET_FIELD(Double, value);
300 break;
301 }
302
303 case FieldDescriptor::CPPTYPE_STRING: {
304 string value;
305 DO(ConsumeString(&value));
306 SET_FIELD(String, value);
307 break;
308 }
309
310 case FieldDescriptor::CPPTYPE_BOOL: {
311 string value;
312 DO(ConsumeIdentifier(&value));
313
314 if (value == "true") {
315 SET_FIELD(Bool, true);
316 } else if (value == "false") {
317 SET_FIELD(Bool, false);
318 } else {
319 ReportError("Invalid value for boolean field \"" + field->name()
320 + "\". Value: \"" + value + "\".");
321 return false;
322 }
323 break;
324 }
325
326 case FieldDescriptor::CPPTYPE_ENUM: {
327 string value;
328 DO(ConsumeIdentifier(&value));
329
330 // Find the enumeration value.
331 const EnumDescriptor* enum_type = field->enum_type();
332 const EnumValueDescriptor* enum_value
333 = enum_type->FindValueByName(value);
334
335 if (enum_value == NULL) {
336 ReportError("Unknown enumeration value of \"" + value + "\" for "
337 "field \"" + field->name() + "\".");
338 return false;
339 }
340
341 SET_FIELD(Enum, enum_value);
342 break;
343 }
344
345 case FieldDescriptor::CPPTYPE_MESSAGE: {
346 // We should never get here. Put here instead of a default
347 // so that if new types are added, we get a nice compiler warning.
348 GOOGLE_LOG(FATAL) << "Reached an unintended state: CPPTYPE_MESSAGE";
349 break;
350 }
351 }
352#undef SET_FIELD
353 return true;
354 }
355
356 // Returns true if the current token's text is equal to that specified.
357 bool LookingAt(const string& text) {
358 return tokenizer_.current().text == text;
359 }
360
361 // Returns true if the current token's type is equal to that specified.
362 bool LookingAtType(io::Tokenizer::TokenType token_type) {
363 return tokenizer_.current().type == token_type;
364 }
365
366 // Consumes an identifier and saves its value in the identifier parameter.
367 // Returns false if the token is not of type IDENTFIER.
368 bool ConsumeIdentifier(string* identifier) {
369 if (!LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
370 ReportError("Expected identifier.");
371 return false;
372 }
373
374 *identifier = tokenizer_.current().text;
375
376 tokenizer_.Next();
377 return true;
378 }
379
380 // Consumes a string and saves its value in the text parameter.
381 // Returns false if the token is not of type STRING.
382 bool ConsumeString(string* text) {
383 if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
384 ReportError("Expected string.");
385 return false;
386 }
387
388 io::Tokenizer::ParseString(tokenizer_.current().text, text);
389
390 tokenizer_.Next();
391 return true;
392 }
393
394 // Consumes a uint64 and saves its value in the value parameter.
395 // Returns false if the token is not of type INTEGER.
396 bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
397 if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
398 ReportError("Expected integer.");
399 return false;
400 }
401
402 if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
403 max_value, value)) {
404 ReportError("Integer out of range.");
405 return false;
406 }
407
408 tokenizer_.Next();
409 return true;
410 }
411
412 // Consumes an int64 and saves its value in the value parameter.
413 // Note that since the tokenizer does not support negative numbers,
414 // we actually may consume an additional token (for the minus sign) in this
415 // method. Returns false if the token is not an integer
416 // (signed or otherwise).
417 bool ConsumeSignedInteger(int64* value, uint64 max_value) {
418 bool negative = false;
419
420 if (TryConsume("-")) {
421 negative = true;
422 // Two's complement always allows one more negative integer than
423 // positive.
424 ++max_value;
425 }
426
427 uint64 unsigned_value;
428
429 DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
430
431 *value = static_cast<int64>(unsigned_value);
432
433 if (negative) {
434 *value = -*value;
435 }
436
437 return true;
438 }
439
440 // Consumes a double and saves its value in the value parameter.
441 // Note that since the tokenizer does not support negative numbers,
442 // we actually may consume an additional token (for the minus sign) in this
443 // method. Returns false if the token is not a double
444 // (signed or otherwise).
445 bool ConsumeDouble(double* value) {
446 bool negative = false;
447
448 if (TryConsume("-")) {
449 negative = true;
450 }
451
452 // A double can actually be an integer, according to the tokenizer.
453 // Therefore, we must check both cases here.
454 if (LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
455 // We have found an integer value for the double.
456 uint64 integer_value;
457 DO(ConsumeUnsignedInteger(&integer_value, kuint64max));
458
459 *value = static_cast<double>(integer_value);
460 } else if (LookingAtType(io::Tokenizer::TYPE_FLOAT)) {
461 // We have found a float value for the double.
462 *value = io::Tokenizer::ParseFloat(tokenizer_.current().text);
463
464 // Mark the current token as consumed.
465 tokenizer_.Next();
466 } else if (LookingAtType(io::Tokenizer::TYPE_IDENTIFIER)) {
467 string text = tokenizer_.current().text;
468 LowerString(&text);
469 if (text == "inf" || text == "infinity") {
470 *value = std::numeric_limits<double>::infinity();
471 tokenizer_.Next();
472 } else if (text == "nan") {
473 *value = std::numeric_limits<double>::quiet_NaN();
474 tokenizer_.Next();
475 } else {
476 ReportError("Expected double.");
477 return false;
478 }
479 } else {
480 ReportError("Expected double.");
481 return false;
482 }
483
484 if (negative) {
485 *value = -*value;
486 }
487
488 return true;
489 }
490
491 // Consumes a token and confirms that it matches that specified in the
492 // value parameter. Returns false if the token found does not match that
493 // which was specified.
494 bool Consume(const string& value) {
495 const string& current_value = tokenizer_.current().text;
496
497 if (current_value != value) {
498 ReportError("Expected \"" + value + "\", found \"" + current_value
499 + "\".");
500 return false;
501 }
502
503 tokenizer_.Next();
504
505 return true;
506 }
507
508 // Attempts to consume the supplied value. Returns false if a the
509 // token found does not match the value specified.
510 bool TryConsume(const string& value) {
511 if (tokenizer_.current().text == value) {
512 tokenizer_.Next();
513 return true;
514 } else {
515 return false;
516 }
517 }
518
519 // An internal instance of the Tokenizer's error collector, used to
520 // collect any base-level parse errors and feed them to the ParserImpl.
521 class ParserErrorCollector : public io::ErrorCollector {
522 public:
523 explicit ParserErrorCollector(TextFormat::ParserImpl* parser) :
524 parser_(parser) { }
525
526 virtual ~ParserErrorCollector() { };
527
528 virtual void AddError(int line, int column, const string& message) {
529 parser_->ReportError(line, column, message);
530 }
531
532 private:
533 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector);
534 TextFormat::ParserImpl* parser_;
535 };
536
537 io::ErrorCollector* error_collector_;
538 ParserErrorCollector tokenizer_error_collector_;
539 io::Tokenizer tokenizer_;
540 const Descriptor* root_message_type_;
541};
542
543#undef DO
544
545// ===========================================================================
546// Internal class for writing text to the io::ZeroCopyOutputStream. Adapted
547// from the Printer found in //google/protobuf/io/printer.h
548class TextFormat::TextGenerator {
549 public:
550 explicit TextGenerator(io::ZeroCopyOutputStream* output)
551 : output_(output),
552 buffer_(NULL),
553 buffer_size_(0),
554 at_start_of_line_(true),
555 failed_(false),
556 indent_("") {
557 }
558
559 ~TextGenerator() {
560 // Only BackUp() if we're sure we've successfully called Next() at least
561 // once.
562 if (buffer_size_ > 0) {
563 output_->BackUp(buffer_size_);
564 }
565 }
566
567 // Indent text by two spaces. After calling Indent(), two spaces will be
568 // inserted at the beginning of each line of text. Indent() may be called
569 // multiple times to produce deeper indents.
570 void Indent() {
571 indent_ += " ";
572 }
573
574 // Reduces the current indent level by two spaces, or crashes if the indent
575 // level is zero.
576 void Outdent() {
577 if (indent_.empty()) {
578 GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
579 return;
580 }
581
582 indent_.resize(indent_.size() - 2);
583 }
584
585 // Print text to the output stream.
586 void Print(const string& str) {
587 Print(str.c_str());
588 }
589
590 // Print text to the output stream.
591 void Print(const char* text) {
592 int size = strlen(text);
593 int pos = 0; // The number of bytes we've written so far.
594
595 for (int i = 0; i < size; i++) {
596 if (text[i] == '\n') {
597 // Saw newline. If there is more text, we may need to insert an indent
598 // here. So, write what we have so far, including the '\n'.
599 Write(text + pos, i - pos + 1);
600 pos = i + 1;
601
602 // Setting this true will cause the next Write() to insert an indent
603 // first.
604 at_start_of_line_ = true;
605 }
606 }
607
608 // Write the rest.
609 Write(text + pos, size - pos);
610 }
611
612 // True if any write to the underlying stream failed. (We don't just
613 // crash in this case because this is an I/O failure, not a programming
614 // error.)
615 bool failed() const { return failed_; }
616
617 private:
618 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator);
619
620 void Write(const char* data, int size) {
621 if (failed_) return;
622 if (size == 0) return;
623
624 if (at_start_of_line_) {
625 // Insert an indent.
626 at_start_of_line_ = false;
627 Write(indent_.data(), indent_.size());
628 if (failed_) return;
629 }
630
631 while (size > buffer_size_) {
632 // Data exceeds space in the buffer. Copy what we can and request a
633 // new buffer.
634 memcpy(buffer_, data, buffer_size_);
635 data += buffer_size_;
636 size -= buffer_size_;
637 void* void_buffer;
638 failed_ = !output_->Next(&void_buffer, &buffer_size_);
639 if (failed_) return;
640 buffer_ = reinterpret_cast<char*>(void_buffer);
641 }
642
643 // Buffer is big enough to receive the data; copy it.
644 memcpy(buffer_, data, size);
645 buffer_ += size;
646 buffer_size_ -= size;
647 }
648
649 io::ZeroCopyOutputStream* const output_;
650 char* buffer_;
651 int buffer_size_;
652 bool at_start_of_line_;
653 bool failed_;
654
655 string indent_;
656};
657
658// ===========================================================================
659
660TextFormat::Parser::Parser()
661 : error_collector_(NULL),
662 allow_partial_(false) {}
663
664TextFormat::Parser::~Parser() {}
665
666bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
667 Message* output) {
668 output->Clear();
669 return Merge(input, output);
670}
671
672bool TextFormat::Parser::ParseFromString(const string& input,
673 Message* output) {
674 io::ArrayInputStream input_stream(input.data(), input.size());
675 return Parse(&input_stream, output);
676}
677
678bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
679 Message* output) {
680 ParserImpl parser(input, error_collector_);
681 if (!parser.Parse(output)) return false;
682 if (!allow_partial_ && !output->IsInitialized()) {
683 vector<string> missing_fields;
684 output->FindInitializationErrors(&missing_fields);
685 parser.ReportError(-1, 0, "Message missing required fields: " +
686 JoinStrings(missing_fields, ", "));
687 return false;
688 }
689 return true;
690}
691
692bool TextFormat::Parser::MergeFromString(const string& input,
693 Message* output) {
694 io::ArrayInputStream input_stream(input.data(), input.size());
695 return Merge(&input_stream, output);
696}
697
698
699/* static */ bool TextFormat::Parse(io::ZeroCopyInputStream* input,
700 Message* output) {
701 return Parser().Parse(input, output);
702}
703
704/* static */ bool TextFormat::Merge(io::ZeroCopyInputStream* input,
705 Message* output) {
706 return Parser().Merge(input, output);
707}
708
709/* static */ bool TextFormat::ParseFromString(const string& input,
710 Message* output) {
711 return Parser().ParseFromString(input, output);
712}
713
714/* static */ bool TextFormat::MergeFromString(const string& input,
715 Message* output) {
716 return Parser().MergeFromString(input, output);
717}
718
719/* static */ bool TextFormat::PrintToString(const Message& message,
720 string* output) {
721 GOOGLE_DCHECK(output) << "output specified is NULL";
722
723 output->clear();
724 io::StringOutputStream output_stream(output);
725
726 bool result = Print(message, &output_stream);
727
728 return result;
729}
730
temporala0f27fc2008-08-06 01:12:21 +0000731/* static */ bool TextFormat::PrintUnknownFieldsToString(
732 const UnknownFieldSet& unknown_fields,
733 string* output) {
734 GOOGLE_DCHECK(output) << "output specified is NULL";
735
736 output->clear();
737 io::StringOutputStream output_stream(output);
738 return PrintUnknownFields(unknown_fields, &output_stream);
739}
740
temporal40ee5512008-07-10 02:12:20 +0000741/* static */ bool TextFormat::Print(const Message& message,
742 io::ZeroCopyOutputStream* output) {
743 TextGenerator generator(output);
744
745 Print(message.GetDescriptor(), message.GetReflection(), generator);
746
747 // Output false if the generator failed internally.
748 return !generator.failed();
749}
750
temporala0f27fc2008-08-06 01:12:21 +0000751/* static */ bool TextFormat::PrintUnknownFields(
752 const UnknownFieldSet& unknown_fields,
753 io::ZeroCopyOutputStream* output) {
754 TextGenerator generator(output);
755
756 PrintUnknownFields(unknown_fields, generator);
757
758 // Output false if the generator failed internally.
759 return !generator.failed();
760}
761
temporal40ee5512008-07-10 02:12:20 +0000762/* static */ void TextFormat::Print(const Descriptor* descriptor,
763 const Message::Reflection* message,
764 TextGenerator& generator) {
765 vector<const FieldDescriptor*> fields;
766 message->ListFields(&fields);
767 for (int i = 0; i < fields.size(); i++) {
768 PrintField(fields[i], message, generator);
769 }
770 PrintUnknownFields(message->GetUnknownFields(), generator);
771}
772
773/* static */ void TextFormat::PrintFieldValueToString(
774 const Message& message,
775 const FieldDescriptor* field,
776 int index,
777 string* output) {
778
779 GOOGLE_DCHECK(output) << "output specified is NULL";
780
781 output->clear();
782 io::StringOutputStream output_stream(output);
783 TextGenerator generator(&output_stream);
784
785 PrintFieldValue(message.GetReflection(), field, index, generator);
786}
787
788/* static */ void TextFormat::PrintField(const FieldDescriptor* field,
789 const Message::Reflection* message,
790 TextGenerator& generator) {
791 int count = 0;
792
793 if (field->is_repeated()) {
794 count = message->FieldSize(field);
795 } else if (message->HasField(field)) {
796 count = 1;
797 }
798
799 for (int j = 0; j < count; ++j) {
800 if (field->is_extension()) {
801 generator.Print("[");
802 // We special-case MessageSet elements for compatibility with proto1.
803 if (field->containing_type()->options().message_set_wire_format()
804 && field->type() == FieldDescriptor::TYPE_MESSAGE
805 && field->is_optional()
806 && field->extension_scope() == field->message_type()) {
807 generator.Print(field->message_type()->full_name());
808 } else {
809 generator.Print(field->full_name());
810 }
811 generator.Print("]");
812 } else {
813 if (field->type() == FieldDescriptor::TYPE_GROUP) {
814 // Groups must be serialized with their original capitalization.
815 generator.Print(field->message_type()->name());
816 } else {
817 generator.Print(field->name());
818 }
819 }
820
821 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
822 generator.Print(" {\n");
823 generator.Indent();
824 } else {
825 generator.Print(": ");
826 }
827
828 // Write the field value.
829 int field_index = j;
830 if (!field->is_repeated()) {
831 field_index = -1;
832 }
833
834 PrintFieldValue(message, field, field_index, generator);
835
836 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
837 generator.Outdent();
838 generator.Print("}");
839 }
840
841 generator.Print("\n");
842 }
843}
844
845/* static */ void TextFormat::PrintFieldValue(
846 const Message::Reflection* reflection,
847 const FieldDescriptor* field,
848 int index,
849 TextGenerator& generator) {
850 GOOGLE_DCHECK(field->is_repeated() || (index == -1))
851 << "Index must be -1 for non-repeated fields";
852
853 switch (field->cpp_type()) {
854#define OUTPUT_FIELD(CPPTYPE, METHOD, TO_STRING) \
855 case FieldDescriptor::CPPTYPE_##CPPTYPE: \
856 generator.Print(TO_STRING(field->is_repeated() ? \
857 reflection->GetRepeated##METHOD(field, index) : \
858 reflection->Get##METHOD(field))); \
859 break; \
860
861 OUTPUT_FIELD( INT32, Int32, SimpleItoa);
862 OUTPUT_FIELD( INT64, Int64, SimpleItoa);
863 OUTPUT_FIELD(UINT32, UInt32, SimpleItoa);
864 OUTPUT_FIELD(UINT64, UInt64, SimpleItoa);
865 OUTPUT_FIELD( FLOAT, Float, SimpleFtoa);
866 OUTPUT_FIELD(DOUBLE, Double, SimpleDtoa);
867#undef OUTPUT_FIELD
868
869 case FieldDescriptor::CPPTYPE_STRING: {
870 string scratch;
871 const string& value = field->is_repeated() ?
872 reflection->GetRepeatedStringReference(field, index, &scratch) :
873 reflection->GetStringReference(field, &scratch);
874
875 generator.Print("\"");
876 generator.Print(CEscape(value));
877 generator.Print("\"");
878
879 break;
880 }
881
882 case FieldDescriptor::CPPTYPE_BOOL:
883 if (field->is_repeated()) {
884 generator.Print(reflection->GetRepeatedBool(field, index)
885 ? "true" : "false");
886 } else {
887 generator.Print(reflection->GetBool(field) ? "true" : "false");
888 }
889 break;
890
891 case FieldDescriptor::CPPTYPE_ENUM:
892 generator.Print(field->is_repeated() ?
893 reflection->GetRepeatedEnum(field, index)->name()
894 : reflection->GetEnum(field)->name());
895 break;
896
897 case FieldDescriptor::CPPTYPE_MESSAGE:
898 Print(field->message_type(),
899 field->is_repeated() ?
900 reflection->GetRepeatedMessage(field, index).GetReflection()
901 : reflection->GetMessage(field).GetReflection(), generator);
902 break;
903 }
904}
905
906// Prints an integer as hex with a fixed number of digits dependent on the
907// integer type.
908template<typename IntType>
909static string PaddedHex(IntType value) {
910 string result;
911 result.reserve(sizeof(value) * 2);
912 for (int i = sizeof(value) * 2 - 1; i >= 0; i--) {
913 result.push_back(int_to_hex_digit(value >> (i*4) & 0x0F));
914 }
915 return result;
916}
917
918/* static */ void TextFormat::PrintUnknownFields(
919 const UnknownFieldSet& unknown_fields, TextGenerator& generator) {
920 for (int i = 0; i < unknown_fields.field_count(); i++) {
921 const UnknownField& field = unknown_fields.field(i);
922 string field_number = SimpleItoa(field.number());
923
924 for (int j = 0; j < field.varint_size(); j++) {
925 generator.Print(field_number);
926 generator.Print(": ");
927 generator.Print(SimpleItoa(field.varint(j)));
928 generator.Print("\n");
929 }
930 for (int j = 0; j < field.fixed32_size(); j++) {
931 generator.Print(field_number);
932 generator.Print(": 0x");
933 char buffer[kFastToBufferSize];
934 generator.Print(FastHex32ToBuffer(field.fixed32(j), buffer));
935 generator.Print("\n");
936 }
937 for (int j = 0; j < field.fixed64_size(); j++) {
938 generator.Print(field_number);
939 generator.Print(": 0x");
940 char buffer[kFastToBufferSize];
941 generator.Print(FastHex64ToBuffer(field.fixed64(j), buffer));
942 generator.Print("\n");
943 }
944 for (int j = 0; j < field.length_delimited_size(); j++) {
945 generator.Print(field_number);
temporala0f27fc2008-08-06 01:12:21 +0000946 const string& value = field.length_delimited(j);
947 UnknownFieldSet embedded_unknown_fields;
948 if (!value.empty() && embedded_unknown_fields.ParseFromString(value)) {
949 // This field is parseable as a Message.
950 // So it is probably an embedded message.
951 generator.Print(" {\n");
952 generator.Indent();
953 PrintUnknownFields(embedded_unknown_fields, generator);
954 generator.Outdent();
955 generator.Print("}\n");
956 } else {
957 // This field is not parseable as a Message.
958 // So it is probably just a plain string.
959 generator.Print(": \"");
960 generator.Print(CEscape(value));
961 generator.Print("\"\n");
962 }
temporal40ee5512008-07-10 02:12:20 +0000963 }
964 for (int j = 0; j < field.group_size(); j++) {
965 generator.Print(field_number);
966 generator.Print(" {\n");
967 generator.Indent();
968 PrintUnknownFields(field.group(j), generator);
969 generator.Outdent();
970 generator.Print("}\n");
971 }
972 }
973}
974
975} // namespace protobuf
976} // namespace google