Home | History | Annotate | Download | only in cpp
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // http://code.google.com/p/protobuf/
      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 <vector>
     37 #include <google/protobuf/stubs/hash.h>
     38 
     39 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
     40 #include <google/protobuf/stubs/common.h>
     41 #include <google/protobuf/stubs/strutil.h>
     42 #include <google/protobuf/stubs/substitute.h>
     43 
     44 
     45 namespace google {
     46 namespace protobuf {
     47 namespace compiler {
     48 namespace cpp {
     49 
     50 namespace {
     51 
     52 string DotsToUnderscores(const string& name) {
     53   return StringReplace(name, ".", "_", true);
     54 }
     55 
     56 string DotsToColons(const string& name) {
     57   return StringReplace(name, ".", "::", true);
     58 }
     59 
     60 const char* const kKeywordList[] = {
     61   "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
     62   "catch", "char", "class", "compl", "const", "const_cast", "continue",
     63   "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
     64   "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
     65   "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
     66   "operator", "or", "or_eq", "private", "protected", "public", "register",
     67   "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
     68   "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
     69   "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
     70   "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
     71 };
     72 
     73 hash_set<string> MakeKeywordsMap() {
     74   hash_set<string> result;
     75   for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
     76     result.insert(kKeywordList[i]);
     77   }
     78   return result;
     79 }
     80 
     81 hash_set<string> kKeywords = MakeKeywordsMap();
     82 
     83 string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
     84   string result;
     85   // Note:  I distrust ctype.h due to locales.
     86   for (int i = 0; i < input.size(); i++) {
     87     if ('a' <= input[i] && input[i] <= 'z') {
     88       if (cap_next_letter) {
     89         result += input[i] + ('A' - 'a');
     90       } else {
     91         result += input[i];
     92       }
     93       cap_next_letter = false;
     94     } else if ('A' <= input[i] && input[i] <= 'Z') {
     95       // Capital letters are left as-is.
     96       result += input[i];
     97       cap_next_letter = false;
     98     } else if ('0' <= input[i] && input[i] <= '9') {
     99       result += input[i];
    100       cap_next_letter = true;
    101     } else {
    102       cap_next_letter = true;
    103     }
    104   }
    105   return result;
    106 }
    107 
    108 }  // namespace
    109 
    110 const char kThickSeparator[] =
    111   "// ===================================================================\n";
    112 const char kThinSeparator[] =
    113   "// -------------------------------------------------------------------\n";
    114 
    115 string ClassName(const Descriptor* descriptor, bool qualified) {
    116 
    117   // Find "outer", the descriptor of the top-level message in which
    118   // "descriptor" is embedded.
    119   const Descriptor* outer = descriptor;
    120   while (outer->containing_type() != NULL) outer = outer->containing_type();
    121 
    122   const string& outer_name = outer->full_name();
    123   string inner_name = descriptor->full_name().substr(outer_name.size());
    124 
    125   if (qualified) {
    126     return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name);
    127   } else {
    128     return outer->name() + DotsToUnderscores(inner_name);
    129   }
    130 }
    131 
    132 string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) {
    133   if (enum_descriptor->containing_type() == NULL) {
    134     if (qualified) {
    135       return DotsToColons(enum_descriptor->full_name());
    136     } else {
    137       return enum_descriptor->name();
    138     }
    139   } else {
    140     string result = ClassName(enum_descriptor->containing_type(), qualified);
    141     result += '_';
    142     result += enum_descriptor->name();
    143     return result;
    144   }
    145 }
    146 
    147 
    148 string SuperClassName(const Descriptor* descriptor) {
    149   return HasDescriptorMethods(descriptor->file()) ?
    150       "::google::protobuf::Message" : "::google::protobuf::MessageLite";
    151 }
    152 
    153 string FieldName(const FieldDescriptor* field) {
    154   string result = field->name();
    155   LowerString(&result);
    156   if (kKeywords.count(result) > 0) {
    157     result.append("_");
    158   }
    159   return result;
    160 }
    161 
    162 string FieldConstantName(const FieldDescriptor *field) {
    163   string field_name = UnderscoresToCamelCase(field->name(), true);
    164   string result = "k" + field_name + "FieldNumber";
    165 
    166   if (!field->is_extension() &&
    167       field->containing_type()->FindFieldByCamelcaseName(
    168         field->camelcase_name()) != field) {
    169     // This field's camelcase name is not unique.  As a hack, add the field
    170     // number to the constant name.  This makes the constant rather useless,
    171     // but what can we do?
    172     result += "_" + SimpleItoa(field->number());
    173   }
    174 
    175   return result;
    176 }
    177 
    178 string FieldMessageTypeName(const FieldDescriptor* field) {
    179   // Note:  The Google-internal version of Protocol Buffers uses this function
    180   //   as a hook point for hacks to support legacy code.
    181   return ClassName(field->message_type(), true);
    182 }
    183 
    184 string StripProto(const string& filename) {
    185   if (HasSuffixString(filename, ".protodevel")) {
    186     return StripSuffixString(filename, ".protodevel");
    187   } else {
    188     return StripSuffixString(filename, ".proto");
    189   }
    190 }
    191 
    192 const char* PrimitiveTypeName(FieldDescriptor::CppType type) {
    193   switch (type) {
    194     case FieldDescriptor::CPPTYPE_INT32  : return "::google::protobuf::int32";
    195     case FieldDescriptor::CPPTYPE_INT64  : return "::google::protobuf::int64";
    196     case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32";
    197     case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64";
    198     case FieldDescriptor::CPPTYPE_DOUBLE : return "double";
    199     case FieldDescriptor::CPPTYPE_FLOAT  : return "float";
    200     case FieldDescriptor::CPPTYPE_BOOL   : return "bool";
    201     case FieldDescriptor::CPPTYPE_ENUM   : return "int";
    202     case FieldDescriptor::CPPTYPE_STRING : return "::std::string";
    203     case FieldDescriptor::CPPTYPE_MESSAGE: return NULL;
    204 
    205     // No default because we want the compiler to complain if any new
    206     // CppTypes are added.
    207   }
    208 
    209   GOOGLE_LOG(FATAL) << "Can't get here.";
    210   return NULL;
    211 }
    212 
    213 const char* DeclaredTypeMethodName(FieldDescriptor::Type type) {
    214   switch (type) {
    215     case FieldDescriptor::TYPE_INT32   : return "Int32";
    216     case FieldDescriptor::TYPE_INT64   : return "Int64";
    217     case FieldDescriptor::TYPE_UINT32  : return "UInt32";
    218     case FieldDescriptor::TYPE_UINT64  : return "UInt64";
    219     case FieldDescriptor::TYPE_SINT32  : return "SInt32";
    220     case FieldDescriptor::TYPE_SINT64  : return "SInt64";
    221     case FieldDescriptor::TYPE_FIXED32 : return "Fixed32";
    222     case FieldDescriptor::TYPE_FIXED64 : return "Fixed64";
    223     case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
    224     case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
    225     case FieldDescriptor::TYPE_FLOAT   : return "Float";
    226     case FieldDescriptor::TYPE_DOUBLE  : return "Double";
    227 
    228     case FieldDescriptor::TYPE_BOOL    : return "Bool";
    229     case FieldDescriptor::TYPE_ENUM    : return "Enum";
    230 
    231     case FieldDescriptor::TYPE_STRING  : return "String";
    232     case FieldDescriptor::TYPE_BYTES   : return "Bytes";
    233     case FieldDescriptor::TYPE_GROUP   : return "Group";
    234     case FieldDescriptor::TYPE_MESSAGE : return "Message";
    235 
    236     // No default because we want the compiler to complain if any new
    237     // types are added.
    238   }
    239   GOOGLE_LOG(FATAL) << "Can't get here.";
    240   return "";
    241 }
    242 
    243 string DefaultValue(const FieldDescriptor* field) {
    244   switch (field->cpp_type()) {
    245     case FieldDescriptor::CPPTYPE_INT32:
    246       return SimpleItoa(field->default_value_int32());
    247     case FieldDescriptor::CPPTYPE_UINT32:
    248       return SimpleItoa(field->default_value_uint32()) + "u";
    249     case FieldDescriptor::CPPTYPE_INT64:
    250       return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")";
    251     case FieldDescriptor::CPPTYPE_UINT64:
    252       return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")";
    253     case FieldDescriptor::CPPTYPE_DOUBLE: {
    254       double value = field->default_value_double();
    255       if (value == numeric_limits<double>::infinity()) {
    256         return "::google::protobuf::internal::Infinity()";
    257       } else if (value == -numeric_limits<double>::infinity()) {
    258         return "-::google::protobuf::internal::Infinity()";
    259       } else if (value != value) {
    260         return "::google::protobuf::internal::NaN()";
    261       } else {
    262         return SimpleDtoa(value);
    263       }
    264     }
    265     case FieldDescriptor::CPPTYPE_FLOAT:
    266       {
    267         float value = field->default_value_float();
    268         if (value == numeric_limits<float>::infinity()) {
    269           return "static_cast<float>(::google::protobuf::internal::Infinity())";
    270         } else if (value == -numeric_limits<float>::infinity()) {
    271           return "static_cast<float>(-::google::protobuf::internal::Infinity())";
    272         } else if (value != value) {
    273           return "static_cast<float>(::google::protobuf::internal::NaN())";
    274         } else {
    275           string float_value = SimpleFtoa(value);
    276           // If floating point value contains a period (.) or an exponent
    277           // (either E or e), then append suffix 'f' to make it a float
    278           // literal.
    279           if (float_value.find_first_of(".eE") != string::npos) {
    280             float_value.push_back('f');
    281           }
    282           return float_value;
    283         }
    284       }
    285     case FieldDescriptor::CPPTYPE_BOOL:
    286       return field->default_value_bool() ? "true" : "false";
    287     case FieldDescriptor::CPPTYPE_ENUM:
    288       // Lazy:  Generate a static_cast because we don't have a helper function
    289       //   that constructs the full name of an enum value.
    290       return strings::Substitute(
    291           "static_cast< $0 >($1)",
    292           ClassName(field->enum_type(), true),
    293           field->default_value_enum()->number());
    294     case FieldDescriptor::CPPTYPE_STRING:
    295       return "\"" + CEscape(field->default_value_string()) + "\"";
    296     case FieldDescriptor::CPPTYPE_MESSAGE:
    297       return FieldMessageTypeName(field) + "::default_instance()";
    298   }
    299   // Can't actually get here; make compiler happy.  (We could add a default
    300   // case above but then we wouldn't get the nice compiler warning when a
    301   // new type is added.)
    302   GOOGLE_LOG(FATAL) << "Can't get here.";
    303   return "";
    304 }
    305 
    306 // Convert a file name into a valid identifier.
    307 string FilenameIdentifier(const string& filename) {
    308   string result;
    309   for (int i = 0; i < filename.size(); i++) {
    310     if (ascii_isalnum(filename[i])) {
    311       result.push_back(filename[i]);
    312     } else {
    313       // Not alphanumeric.  To avoid any possibility of name conflicts we
    314       // use the hex code for the character.
    315       result.push_back('_');
    316       char buffer[kFastToBufferSize];
    317       result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer));
    318     }
    319   }
    320   return result;
    321 }
    322 
    323 // Return the name of the AddDescriptors() function for a given file.
    324 string GlobalAddDescriptorsName(const string& filename) {
    325   return "protobuf_AddDesc_" + FilenameIdentifier(filename);
    326 }
    327 
    328 // Return the name of the AssignDescriptors() function for a given file.
    329 string GlobalAssignDescriptorsName(const string& filename) {
    330   return "protobuf_AssignDesc_" + FilenameIdentifier(filename);
    331 }
    332 
    333 // Return the name of the ShutdownFile() function for a given file.
    334 string GlobalShutdownFileName(const string& filename) {
    335   return "protobuf_ShutdownFile_" + FilenameIdentifier(filename);
    336 }
    337 
    338 }  // namespace cpp
    339 }  // namespace compiler
    340 }  // namespace protobuf
    341 }  // namespace google
    342