• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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