• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
DotsToUnderscores(const string & name)52 string DotsToUnderscores(const string& name) {
53   return StringReplace(name, ".", "_", true);
54 }
55 
DotsToColons(const string & name)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 
MakeKeywordsMap()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 
UnderscoresToCamelCase(const string & input,bool cap_next_letter)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 
ClassName(const Descriptor * descriptor,bool qualified)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 
ClassName(const EnumDescriptor * enum_descriptor,bool qualified)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 
SuperClassName(const Descriptor * descriptor)148 string SuperClassName(const Descriptor* descriptor) {
149   return HasDescriptorMethods(descriptor->file()) ?
150       "::google::protobuf::Message" : "::google::protobuf::MessageLite";
151 }
152 
FieldName(const FieldDescriptor * field)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 
FieldConstantName(const FieldDescriptor * field)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 
FieldMessageTypeName(const FieldDescriptor * field)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 
StripProto(const string & filename)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 
PrimitiveTypeName(FieldDescriptor::CppType type)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 
DeclaredTypeMethodName(FieldDescriptor::Type type)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 
DefaultValue(const FieldDescriptor * field)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.
FilenameIdentifier(const string & filename)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.
GlobalAddDescriptorsName(const string & filename)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.
GlobalAssignDescriptorsName(const string & filename)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.
GlobalShutdownFileName(const string & filename)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