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 (at) 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 59 string DotsToUnderscores(const string& name) { 60 return StringReplace(name, ".", "_", true); 61 } 62 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 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. 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 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 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 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 171 string DependentBaseClassTemplateName(const Descriptor* descriptor) { 172 return ClassName(descriptor, false) + "_InternalBase"; 173 } 174 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 181 string DependentBaseDownCast() { 182 return "reinterpret_cast<T*>(this)->"; 183 } 184 185 string DependentBaseConstDownCast() { 186 return "reinterpret_cast<const T*>(this)->"; 187 } 188 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 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 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 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 272 string DependentTypeName(const FieldDescriptor* field) { 273 return "InternalBase_" + field->name() + "_T"; 274 } 275 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 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 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 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 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 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 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. 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. 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. 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. 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. 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 \? 466 string EscapeTrigraphs(const string& to_escape) { 467 return StringReplace(to_escape, "?", "\\?", true); 468 } 469 470 // Escaped function name to eliminate naming conflict. 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 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 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 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 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 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 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 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 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 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 600 bool IsAnyMessage(const FileDescriptor* descriptor) { 601 return descriptor->name() == kAnyProtoFile; 602 } 603 604 bool IsAnyMessage(const Descriptor* descriptor) { 605 return descriptor->name() == kAnyMessageName && 606 descriptor->file()->name() == kAnyProtoFile; 607 } 608 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. 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 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 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 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