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