1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * 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.
18 //
19 // 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.
30
31 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <limits>
36 #include <map>
37 #include <vector>
38 #include <google/protobuf/stubs/hash.h>
39
40 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
41 #include <google/protobuf/io/printer.h>
42 #include <google/protobuf/stubs/logging.h>
43 #include <google/protobuf/stubs/common.h>
44 #include <google/protobuf/stubs/strutil.h>
45 #include <google/protobuf/stubs/substitute.h>
46
47
48 namespace google {
49 namespace protobuf {
50 namespace compiler {
51 namespace cpp {
52
53 namespace {
54
55 static const char kAnyMessageName[] = "Any";
56 static const char kAnyProtoFile[] = "google/protobuf/any.proto";
57 static const char kGoogleProtobufPrefix[] = "google/protobuf/";
58
DotsToUnderscores(const string & name)59 string DotsToUnderscores(const string& name) {
60 return StringReplace(name, ".", "_", true);
61 }
62
DotsToColons(const string & name)63 string DotsToColons(const string& name) {
64 return StringReplace(name, ".", "::", true);
65 }
66
67 const char* const kKeywordList[] = {
68 "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
69 "bool", "break", "case", "catch", "char", "class", "compl", "const",
70 "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
71 "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern",
72 "false", "float", "for", "friend", "goto", "if", "inline", "int", "long",
73 "mutable", "namespace", "new", "noexcept", "not", "not_eq", "NULL",
74 "operator", "or", "or_eq", "private", "protected", "public", "register",
75 "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
76 "static_assert", "static_cast", "struct", "switch", "template", "this",
77 "thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
78 "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
79 "while", "xor", "xor_eq"
80 };
81
MakeKeywordsMap()82 hash_set<string> MakeKeywordsMap() {
83 hash_set<string> result;
84 for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
85 result.insert(kKeywordList[i]);
86 }
87 return result;
88 }
89
90 hash_set<string> kKeywords = MakeKeywordsMap();
91
92 // Returns whether the provided descriptor has an extension. This includes its
93 // nested types.
HasExtension(const Descriptor * descriptor)94 bool HasExtension(const Descriptor* descriptor) {
95 if (descriptor->extension_count() > 0) {
96 return true;
97 }
98 for (int i = 0; i < descriptor->nested_type_count(); ++i) {
99 if (HasExtension(descriptor->nested_type(i))) {
100 return true;
101 }
102 }
103 return false;
104 }
105
106 } // namespace
107
UnderscoresToCamelCase(const string & input,bool cap_next_letter)108 string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
109 string result;
110 // Note: I distrust ctype.h due to locales.
111 for (int i = 0; i < input.size(); i++) {
112 if ('a' <= input[i] && input[i] <= 'z') {
113 if (cap_next_letter) {
114 result += input[i] + ('A' - 'a');
115 } else {
116 result += input[i];
117 }
118 cap_next_letter = false;
119 } else if ('A' <= input[i] && input[i] <= 'Z') {
120 // Capital letters are left as-is.
121 result += input[i];
122 cap_next_letter = false;
123 } else if ('0' <= input[i] && input[i] <= '9') {
124 result += input[i];
125 cap_next_letter = true;
126 } else {
127 cap_next_letter = true;
128 }
129 }
130 return result;
131 }
132
133 const char kThickSeparator[] =
134 "// ===================================================================\n";
135 const char kThinSeparator[] =
136 "// -------------------------------------------------------------------\n";
137
ClassName(const Descriptor * descriptor,bool qualified)138 string ClassName(const Descriptor* descriptor, bool qualified) {
139
140 // Find "outer", the descriptor of the top-level message in which
141 // "descriptor" is embedded.
142 const Descriptor* outer = descriptor;
143 while (outer->containing_type() != NULL) outer = outer->containing_type();
144
145 const string& outer_name = outer->full_name();
146 string inner_name = descriptor->full_name().substr(outer_name.size());
147
148 if (qualified) {
149 return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
150 } else {
151 return outer->name() + DotsToUnderscores(inner_name);
152 }
153 }
154
ClassName(const EnumDescriptor * enum_descriptor,bool qualified)155 string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
156 if (enum_descriptor->containing_type() == NULL) {
157 if (qualified) {
158 return "::" + DotsToColons(enum_descriptor->full_name());
159 } else {
160 return enum_descriptor->name();
161 }
162 } else {
163 string result = ClassName(enum_descriptor->containing_type(), qualified);
164 result += '_';
165 result += enum_descriptor->name();
166 return result;
167 }
168 }
169
170
DependentBaseClassTemplateName(const Descriptor * descriptor)171 string DependentBaseClassTemplateName(const Descriptor* descriptor) {
172 return ClassName(descriptor, false) + "_InternalBase";
173 }
174
SuperClassName(const Descriptor * descriptor,const Options & options)175 string SuperClassName(const Descriptor* descriptor, const Options& options) {
176 return HasDescriptorMethods(descriptor->file(), options)
177 ? "::google::protobuf::Message"
178 : "::google::protobuf::MessageLite";
179 }
180
DependentBaseDownCast()181 string DependentBaseDownCast() {
182 return "reinterpret_cast<T*>(this)->";
183 }
184
DependentBaseConstDownCast()185 string DependentBaseConstDownCast() {
186 return "reinterpret_cast<const T*>(this)->";
187 }
188
FieldName(const FieldDescriptor * field)189 string FieldName(const FieldDescriptor* field) {
190 string result = field->name();
191 LowerString(&result);
192 if (kKeywords.count(result) > 0) {
193 result.append("_");
194 }
195 return result;
196 }
197
EnumValueName(const EnumValueDescriptor * enum_value)198 string EnumValueName(const EnumValueDescriptor* enum_value) {
199 string result = enum_value->name();
200 if (kKeywords.count(result) > 0) {
201 result.append("_");
202 }
203 return result;
204 }
205
FieldConstantName(const FieldDescriptor * field)206 string FieldConstantName(const FieldDescriptor *field) {
207 string field_name = UnderscoresToCamelCase(field->name(), true);
208 string result = "k" + field_name + "FieldNumber";
209
210 if (!field->is_extension() &&
211 field->containing_type()->FindFieldByCamelcaseName(
212 field->camelcase_name()) != field) {
213 // This field's camelcase name is not unique. As a hack, add the field
214 // number to the constant name. This makes the constant rather useless,
215 // but what can we do?
216 result += "_" + SimpleItoa(field->number());
217 }
218
219 return result;
220 }
221
IsFieldDependent(const FieldDescriptor * field)222 bool IsFieldDependent(const FieldDescriptor* field) {
223 if (field->containing_oneof() != NULL &&
224 field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
225 return true;
226 }
227 if (field->is_map()) {
228 const Descriptor* map_descriptor = field->message_type();
229 for (int i = 0; i < map_descriptor->field_count(); i++) {
230 if (IsFieldDependent(map_descriptor->field(i))) {
231 return true;
232 }
233 }
234 return false;
235 }
236 if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
237 return false;
238 }
239 if (field->containing_oneof() != NULL) {
240 // Oneof fields will always be dependent.
241 //
242 // This is a unique case for field codegen. Field generators are
243 // responsible for generating all the field-specific accessor
244 // functions, except for the clear_*() function; instead, field
245 // generators produce inline clearing code.
246 //
247 // For non-oneof fields, the Message class uses the inline clearing
248 // code to define the field's clear_*() function, as well as in the
249 // destructor. For oneof fields, the Message class generates a much
250 // more complicated clear_*() function, which clears only the oneof
251 // member that is set, in addition to clearing methods for each of the
252 // oneof members individually.
253 //
254 // Since oneofs do not have their own generator class, the Message code
255 // generation logic would be significantly complicated in order to
256 // split dependent and non-dependent manipulation logic based on
257 // whether the oneof truly needs to be dependent; so, for oneof fields,
258 // we just assume it (and its constituents) should be manipulated by a
259 // dependent base class function.
260 //
261 // This is less precise than how dependent message-typed fields are
262 // handled, but the cost is limited to only the generated code for the
263 // oneof field, which seems like an acceptable tradeoff.
264 return true;
265 }
266 if (field->file() == field->message_type()->file()) {
267 return false;
268 }
269 return true;
270 }
271
DependentTypeName(const FieldDescriptor * field)272 string DependentTypeName(const FieldDescriptor* field) {
273 return "InternalBase_" + field->name() + "_T";
274 }
275
FieldMessageTypeName(const FieldDescriptor * field)276 string FieldMessageTypeName(const FieldDescriptor* field) {
277 // Note: The Google-internal version of Protocol Buffers uses this function
278 // as a hook point for hacks to support legacy code.
279 return ClassName(field->message_type(), true);
280 }
281
StripProto(const string & filename)282 string StripProto(const string& filename) {
283 if (HasSuffixString(filename, ".protodevel")) {
284 return StripSuffixString(filename, ".protodevel");
285 } else {
286 return StripSuffixString(filename, ".proto");
287 }
288 }
289
PrimitiveTypeName(FieldDescriptor::CppType type)290 const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
291 switch (type) {
292 case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32";
293 case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64";
294 case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
295 case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
296 case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
297 case FieldDescriptor::CPPTYPE_FLOAT : return "float";
298 case FieldDescriptor::CPPTYPE_BOOL : return "bool";
299 case FieldDescriptor::CPPTYPE_ENUM : return "int";
300 case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
301 case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
302
303 // No default because we want the compiler to complain if any new
304 // CppTypes are added.
305 }
306
307 GOOGLE_LOG(FATAL) << "Can't get here.";
308 return NULL;
309 }
310
DeclaredTypeMethodName(FieldDescriptor::Type type)311 const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
312 switch (type) {
313 case FieldDescriptor::TYPE_INT32 : return "Int32";
314 case FieldDescriptor::TYPE_INT64 : return "Int64";
315 case FieldDescriptor::TYPE_UINT32 : return "UInt32";
316 case FieldDescriptor::TYPE_UINT64 : return "UInt64";
317 case FieldDescriptor::TYPE_SINT32 : return "SInt32";
318 case FieldDescriptor::TYPE_SINT64 : return "SInt64";
319 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
320 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
321 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
322 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
323 case FieldDescriptor::TYPE_FLOAT : return "Float";
324 case FieldDescriptor::TYPE_DOUBLE : return "Double";
325
326 case FieldDescriptor::TYPE_BOOL : return "Bool";
327 case FieldDescriptor::TYPE_ENUM : return "Enum";
328
329 case FieldDescriptor::TYPE_STRING : return "String";
330 case FieldDescriptor::TYPE_BYTES : return "Bytes";
331 case FieldDescriptor::TYPE_GROUP : return "Group";
332 case FieldDescriptor::TYPE_MESSAGE : return "Message";
333
334 // No default because we want the compiler to complain if any new
335 // types are added.
336 }
337 GOOGLE_LOG(FATAL) << "Can't get here.";
338 return "";
339 }
340
Int32ToString(int number)341 string Int32ToString(int number) {
342 // gcc rejects the decimal form of kint32min.
343 if (number == kint32min) {
344 GOOGLE_COMPILE_ASSERT(kint32min == (~0x7fffffff), kint32min_value_error);
345 return "(~0x7fffffff)";
346 } else {
347 return SimpleItoa(number);
348 }
349 }
350
Int64ToString(int64 number)351 string Int64ToString(int64 number) {
352 // gcc rejects the decimal form of kint64min
353 if (number == kint64min) {
354 // Make sure we are in a 2's complement system.
355 GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(~0x7fffffffffffffff),
356 kint64min_value_error);
357 return "GOOGLE_LONGLONG(~0x7fffffffffffffff)";
358 }
359 return "GOOGLE_LONGLONG(" + SimpleItoa(number) + ")";
360 }
361
DefaultValue(const FieldDescriptor * field)362 string DefaultValue(const FieldDescriptor* field) {
363 switch (field->cpp_type()) {
364 case FieldDescriptor::CPPTYPE_INT32:
365 return Int32ToString(field->default_value_int32());
366 case FieldDescriptor::CPPTYPE_UINT32:
367 return SimpleItoa(field->default_value_uint32()) + "u";
368 case FieldDescriptor::CPPTYPE_INT64:
369 return Int64ToString(field->default_value_int64());
370 case FieldDescriptor::CPPTYPE_UINT64:
371 return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
372 case FieldDescriptor::CPPTYPE_DOUBLE: {
373 double value = field->default_value_double();
374 if (value == numeric_limits<double>::infinity()) {
375 return "::google::protobuf::internal::Infinity()";
376 } else if (value == -numeric_limits<double>::infinity()) {
377 return "-::google::protobuf::internal::Infinity()";
378 } else if (value != value) {
379 return "::google::protobuf::internal::NaN()";
380 } else {
381 return SimpleDtoa(value);
382 }
383 }
384 case FieldDescriptor::CPPTYPE_FLOAT:
385 {
386 float value = field->default_value_float();
387 if (value == numeric_limits<float>::infinity()) {
388 return "static_cast<float>(::google::protobuf::internal::Infinity())";
389 } else if (value == -numeric_limits<float>::infinity()) {
390 return "static_cast<float>(-::google::protobuf::internal::Infinity())";
391 } else if (value != value) {
392 return "static_cast<float>(::google::protobuf::internal::NaN())";
393 } else {
394 string float_value = SimpleFtoa(value);
395 // If floating point value contains a period (.) or an exponent
396 // (either E or e), then append suffix 'f' to make it a float
397 // literal.
398 if (float_value.find_first_of(".eE") != string::npos) {
399 float_value.push_back('f');
400 }
401 return float_value;
402 }
403 }
404 case FieldDescriptor::CPPTYPE_BOOL:
405 return field->default_value_bool() ? "true" : "false";
406 case FieldDescriptor::CPPTYPE_ENUM:
407 // Lazy: Generate a static_cast because we don't have a helper function
408 // that constructs the full name of an enum value.
409 return strings::Substitute(
410 "static_cast< $0 >($1)",
411 ClassName(field->enum_type(), true),
412 Int32ToString(field->default_value_enum()->number()));
413 case FieldDescriptor::CPPTYPE_STRING:
414 return "\"" + EscapeTrigraphs(
415 CEscape(field->default_value_string())) +
416 "\"";
417 case FieldDescriptor::CPPTYPE_MESSAGE:
418 return FieldMessageTypeName(field) + "::default_instance()";
419 }
420 // Can't actually get here; make compiler happy. (We could add a default
421 // case above but then we wouldn't get the nice compiler warning when a
422 // new type is added.)
423 GOOGLE_LOG(FATAL) << "Can't get here.";
424 return "";
425 }
426
427 // Convert a file name into a valid identifier.
FilenameIdentifier(const string & filename)428 string FilenameIdentifier(const string& filename) {
429 string result;
430 for (int i = 0; i < filename.size(); i++) {
431 if (ascii_isalnum(filename[i])) {
432 result.push_back(filename[i]);
433 } else {
434 // Not alphanumeric. To avoid any possibility of name conflicts we
435 // use the hex code for the character.
436 StrAppend(&result, "_", strings::Hex(static_cast<uint8>(filename[i])));
437 }
438 }
439 return result;
440 }
441
442 // Return the name of the AddDescriptors() function for a given file.
GlobalAddDescriptorsName(const string & filename)443 string GlobalAddDescriptorsName(const string& filename) {
444 return "protobuf_AddDesc_" + FilenameIdentifier(filename);
445 }
446
447 // Return the name of the AssignDescriptors() function for a given file.
GlobalAssignDescriptorsName(const string & filename)448 string GlobalAssignDescriptorsName(const string& filename) {
449 return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
450 }
451
452 // Return the name of the ShutdownFile() function for a given file.
GlobalShutdownFileName(const string & filename)453 string GlobalShutdownFileName(const string& filename) {
454 return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
455 }
456
457 // Return the qualified C++ name for a file level symbol.
QualifiedFileLevelSymbol(const string & package,const string & name)458 string QualifiedFileLevelSymbol(const string& package, const string& name) {
459 if (package.empty()) {
460 return StrCat("::", name);
461 }
462 return StrCat("::", DotsToColons(package), "::", name);
463 }
464
465 // Escape C++ trigraphs by escaping question marks to \?
EscapeTrigraphs(const string & to_escape)466 string EscapeTrigraphs(const string& to_escape) {
467 return StringReplace(to_escape, "?", "\\?", true);
468 }
469
470 // Escaped function name to eliminate naming conflict.
SafeFunctionName(const Descriptor * descriptor,const FieldDescriptor * field,const string & prefix)471 string SafeFunctionName(const Descriptor* descriptor,
472 const FieldDescriptor* field,
473 const string& prefix) {
474 // Do not use FieldName() since it will escape keywords.
475 string name = field->name();
476 LowerString(&name);
477 string function_name = prefix + name;
478 if (descriptor->FindFieldByName(function_name)) {
479 // Single underscore will also make it conflicting with the private data
480 // member. We use double underscore to escape function names.
481 function_name.append("__");
482 } else if (kKeywords.count(name) > 0) {
483 // If the field name is a keyword, we append the underscore back to keep it
484 // consistent with other function names.
485 function_name.append("_");
486 }
487 return function_name;
488 }
489
StaticInitializersForced(const FileDescriptor * file,const Options & options)490 bool StaticInitializersForced(const FileDescriptor* file,
491 const Options& options) {
492 if (HasDescriptorMethods(file, options) || file->extension_count() > 0) {
493 return true;
494 }
495 for (int i = 0; i < file->message_type_count(); ++i) {
496 if (HasExtension(file->message_type(i))) {
497 return true;
498 }
499 }
500 return false;
501 }
502
PrintHandlingOptionalStaticInitializers(const FileDescriptor * file,const Options & options,io::Printer * printer,const char * with_static_init,const char * without_static_init,const char * var1,const string & val1,const char * var2,const string & val2)503 void PrintHandlingOptionalStaticInitializers(
504 const FileDescriptor* file, const Options& options, io::Printer* printer,
505 const char* with_static_init, const char* without_static_init,
506 const char* var1, const string& val1, const char* var2,
507 const string& val2) {
508 map<string, string> vars;
509 if (var1) {
510 vars[var1] = val1;
511 }
512 if (var2) {
513 vars[var2] = val2;
514 }
515 PrintHandlingOptionalStaticInitializers(
516 vars, file, options, printer, with_static_init, without_static_init);
517 }
518
PrintHandlingOptionalStaticInitializers(const map<string,string> & vars,const FileDescriptor * file,const Options & options,io::Printer * printer,const char * with_static_init,const char * without_static_init)519 void PrintHandlingOptionalStaticInitializers(const map<string, string>& vars,
520 const FileDescriptor* file,
521 const Options& options,
522 io::Printer* printer,
523 const char* with_static_init,
524 const char* without_static_init) {
525 if (StaticInitializersForced(file, options)) {
526 printer->Print(vars, with_static_init);
527 } else {
528 printer->Print(vars, (string(
529 "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") +
530 without_static_init +
531 "#else\n" +
532 with_static_init +
533 "#endif\n").c_str());
534 }
535 }
536
537
HasMapFields(const Descriptor * descriptor)538 static bool HasMapFields(const Descriptor* descriptor) {
539 for (int i = 0; i < descriptor->field_count(); ++i) {
540 if (descriptor->field(i)->is_map()) {
541 return true;
542 }
543 }
544 for (int i = 0; i < descriptor->nested_type_count(); ++i) {
545 if (HasMapFields(descriptor->nested_type(i))) return true;
546 }
547 return false;
548 }
549
HasMapFields(const FileDescriptor * file)550 bool HasMapFields(const FileDescriptor* file) {
551 for (int i = 0; i < file->message_type_count(); ++i) {
552 if (HasMapFields(file->message_type(i))) return true;
553 }
554 return false;
555 }
556
HasEnumDefinitions(const Descriptor * message_type)557 static bool HasEnumDefinitions(const Descriptor* message_type) {
558 if (message_type->enum_type_count() > 0) return true;
559 for (int i = 0; i < message_type->nested_type_count(); ++i) {
560 if (HasEnumDefinitions(message_type->nested_type(i))) return true;
561 }
562 return false;
563 }
564
HasEnumDefinitions(const FileDescriptor * file)565 bool HasEnumDefinitions(const FileDescriptor* file) {
566 if (file->enum_type_count() > 0) return true;
567 for (int i = 0; i < file->message_type_count(); ++i) {
568 if (HasEnumDefinitions(file->message_type(i))) return true;
569 }
570 return false;
571 }
572
IsStringOrMessage(const FieldDescriptor * field)573 bool IsStringOrMessage(const FieldDescriptor* field) {
574 switch (field->cpp_type()) {
575 case FieldDescriptor::CPPTYPE_INT32:
576 case FieldDescriptor::CPPTYPE_INT64:
577 case FieldDescriptor::CPPTYPE_UINT32:
578 case FieldDescriptor::CPPTYPE_UINT64:
579 case FieldDescriptor::CPPTYPE_DOUBLE:
580 case FieldDescriptor::CPPTYPE_FLOAT:
581 case FieldDescriptor::CPPTYPE_BOOL:
582 case FieldDescriptor::CPPTYPE_ENUM:
583 return false;
584 case FieldDescriptor::CPPTYPE_STRING:
585 case FieldDescriptor::CPPTYPE_MESSAGE:
586 return true;
587 }
588
589 GOOGLE_LOG(FATAL) << "Can't get here.";
590 return false;
591 }
592
EffectiveStringCType(const FieldDescriptor * field)593 FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field) {
594 GOOGLE_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
595 // Open-source protobuf release only supports STRING ctype.
596 return FieldOptions::STRING;
597
598 }
599
IsAnyMessage(const FileDescriptor * descriptor)600 bool IsAnyMessage(const FileDescriptor* descriptor) {
601 return descriptor->name() == kAnyProtoFile;
602 }
603
IsAnyMessage(const Descriptor * descriptor)604 bool IsAnyMessage(const Descriptor* descriptor) {
605 return descriptor->name() == kAnyMessageName &&
606 descriptor->file()->name() == kAnyProtoFile;
607 }
608
IsWellKnownMessage(const FileDescriptor * descriptor)609 bool IsWellKnownMessage(const FileDescriptor* descriptor) {
610 return !descriptor->name().compare(0, 16, kGoogleProtobufPrefix);
611 }
612
613 enum Utf8CheckMode {
614 STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields.
615 VERIFY = 1, // Only log an error but parsing will succeed.
616 NONE = 2, // No UTF-8 check.
617 };
618
619 // Which level of UTF-8 enforcemant is placed on this file.
GetUtf8CheckMode(const FieldDescriptor * field,const Options & options)620 static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field,
621 const Options& options) {
622 if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
623 return STRICT;
624 } else if (GetOptimizeFor(field->file(), options) !=
625 FileOptions::LITE_RUNTIME) {
626 return VERIFY;
627 } else {
628 return NONE;
629 }
630 }
631
GenerateUtf8CheckCode(const FieldDescriptor * field,const Options & options,bool for_parse,const map<string,string> & variables,const char * parameters,const char * strict_function,const char * verify_function,io::Printer * printer)632 static void GenerateUtf8CheckCode(const FieldDescriptor* field,
633 const Options& options, bool for_parse,
634 const map<string, string>& variables,
635 const char* parameters,
636 const char* strict_function,
637 const char* verify_function,
638 io::Printer* printer) {
639 switch (GetUtf8CheckMode(field, options)) {
640 case STRICT: {
641 if (for_parse) {
642 printer->Print("DO_(");
643 }
644 printer->Print(
645 "::google::protobuf::internal::WireFormatLite::$function$(\n",
646 "function", strict_function);
647 printer->Indent();
648 printer->Print(variables, parameters);
649 if (for_parse) {
650 printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n");
651 } else {
652 printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n");
653 }
654 printer->Print("\"$full_name$\")", "full_name", field->full_name());
655 if (for_parse) {
656 printer->Print(")");
657 }
658 printer->Print(";\n");
659 printer->Outdent();
660 break;
661 }
662 case VERIFY: {
663 printer->Print(
664 "::google::protobuf::internal::WireFormat::$function$(\n",
665 "function", verify_function);
666 printer->Indent();
667 printer->Print(variables, parameters);
668 if (for_parse) {
669 printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n");
670 } else {
671 printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n");
672 }
673 printer->Print("\"$full_name$\");\n", "full_name", field->full_name());
674 printer->Outdent();
675 break;
676 }
677 case NONE:
678 break;
679 }
680 }
681
GenerateUtf8CheckCodeForString(const FieldDescriptor * field,const Options & options,bool for_parse,const map<string,string> & variables,const char * parameters,io::Printer * printer)682 void GenerateUtf8CheckCodeForString(const FieldDescriptor* field,
683 const Options& options, bool for_parse,
684 const map<string, string>& variables,
685 const char* parameters,
686 io::Printer* printer) {
687 GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
688 "VerifyUtf8String", "VerifyUTF8StringNamedField",
689 printer);
690 }
691
GenerateUtf8CheckCodeForCord(const FieldDescriptor * field,const Options & options,bool for_parse,const map<string,string> & variables,const char * parameters,io::Printer * printer)692 void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field,
693 const Options& options, bool for_parse,
694 const map<string, string>& variables,
695 const char* parameters,
696 io::Printer* printer) {
697 GenerateUtf8CheckCode(field, options, for_parse, variables, parameters,
698 "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer);
699 }
700
701 } // namespace cpp
702 } // namespace compiler
703 } // namespace protobuf
704 } // namespace google
705