• 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 #ifndef _MSC_VER
32 #include <unistd.h>
33 #endif
34 #include <climits>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fstream>
38 #include <iostream>
39 #include <sstream>
40 #include <stdlib.h>
41 #include <unordered_set>
42 #include <vector>
43 
44 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
45 #include <google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h>
46 #include <google/protobuf/descriptor.pb.h>
47 #include <google/protobuf/io/coded_stream.h>
48 #include <google/protobuf/io/printer.h>
49 #include <google/protobuf/io/zero_copy_stream_impl.h>
50 #include <google/protobuf/io/io_win32.h>
51 #include <google/protobuf/port.h>
52 #include <google/protobuf/stubs/common.h>
53 #include <google/protobuf/stubs/strutil.h>
54 
55 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
56 // error cases, so it seems to be ok to use as a back door for errors.
57 
58 namespace google {
59 namespace protobuf {
60 namespace compiler {
61 namespace objectivec {
62 
63 // <io.h> is transitively included in this file. Import the functions explicitly
64 // in this port namespace to avoid ambiguous definition.
65 namespace posix {
66 #ifdef _WIN32
67 using ::google::protobuf::io::win32::open;
68 #else
69 using ::open;
70 #endif
71 }  // namespace port
72 
Options()73 Options::Options() {
74   // Default is the value of the env for the package prefixes.
75   const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
76   if (file_path) {
77     expected_prefixes_path = file_path;
78   }
79   const char* suppressions = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES_SUPPRESSIONS");
80   if (suppressions) {
81     expected_prefixes_suppressions =
82         Split(suppressions, ";", true);
83   }
84 }
85 
86 namespace {
87 
MakeWordsMap(const char * const words[],size_t num_words)88 std::unordered_set<std::string> MakeWordsMap(const char* const words[],
89                                              size_t num_words) {
90   std::unordered_set<std::string> result;
91   for (int i = 0; i < num_words; i++) {
92     result.insert(words[i]);
93   }
94   return result;
95 }
96 
97 const char* const kUpperSegmentsList[] = {"url", "http", "https"};
98 
99 std::unordered_set<std::string> kUpperSegments =
100     MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
101 
ascii_isnewline(char c)102 bool ascii_isnewline(char c) {
103   return c == '\n' || c == '\r';
104 }
105 
106 // Internal helper for name handing.
107 // Do not expose this outside of helpers, stick to having functions for specific
108 // cases (ClassName(), FieldName()), so there is always consistent suffix rules.
UnderscoresToCamelCase(const std::string & input,bool first_capitalized)109 std::string UnderscoresToCamelCase(const std::string& input,
110                                    bool first_capitalized) {
111   std::vector<std::string> values;
112   std::string current;
113 
114   bool last_char_was_number = false;
115   bool last_char_was_lower = false;
116   bool last_char_was_upper = false;
117   for (int i = 0; i < input.size(); i++) {
118     char c = input[i];
119     if (ascii_isdigit(c)) {
120       if (!last_char_was_number) {
121         values.push_back(current);
122         current = "";
123       }
124       current += c;
125       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
126       last_char_was_number = true;
127     } else if (ascii_islower(c)) {
128       // lowercase letter can follow a lowercase or uppercase letter
129       if (!last_char_was_lower && !last_char_was_upper) {
130         values.push_back(current);
131         current = "";
132       }
133       current += c;  // already lower
134       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
135       last_char_was_lower = true;
136     } else if (ascii_isupper(c)) {
137       if (!last_char_was_upper) {
138         values.push_back(current);
139         current = "";
140       }
141       current += ascii_tolower(c);
142       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
143       last_char_was_upper = true;
144     } else {
145       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
146     }
147   }
148   values.push_back(current);
149 
150   std::string result;
151   bool first_segment_forces_upper = false;
152   for (std::vector<std::string>::iterator i = values.begin(); i != values.end();
153        ++i) {
154     std::string value = *i;
155     bool all_upper = (kUpperSegments.count(value) > 0);
156     if (all_upper && (result.length() == 0)) {
157       first_segment_forces_upper = true;
158     }
159     for (int j = 0; j < value.length(); j++) {
160       if (j == 0 || all_upper) {
161         value[j] = ascii_toupper(value[j]);
162       } else {
163         // Nothing, already in lower.
164       }
165     }
166     result += value;
167   }
168   if ((result.length() != 0) &&
169       !first_capitalized &&
170       !first_segment_forces_upper) {
171     result[0] = ascii_tolower(result[0]);
172   }
173   return result;
174 }
175 
176 const char* const kReservedWordList[] = {
177   // Note NSObject Methods:
178   // These are brought in from objectivec_nsobject_methods.h that is generated
179   // using method_dump.sh. See kNSObjectMethods below.
180 
181   // Objective C "keywords" that aren't in C
182   // From
183   // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
184   // with some others added on.
185   "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
186   "self", "instancetype", "nullable", "nonnull", "nil", "Nil",
187   "YES", "NO", "weak",
188 
189   // C/C++ keywords (Incl C++ 0x11)
190   // From http://en.cppreference.com/w/cpp/keywords
191   "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
192   "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
193   "compl", "const", "constexpr", "const_cast", "continue", "decltype",
194   "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
195   "export", "extern ", "false", "float", "for", "friend", "goto", "if",
196   "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
197   "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
198   "public", "register", "reinterpret_cast", "return", "short", "signed",
199   "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
200   "template", "this", "thread_local", "throw", "true", "try", "typedef",
201   "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
202   "volatile", "wchar_t", "while", "xor", "xor_eq",
203 
204   // C99 keywords
205   // From
206   // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
207   "restrict",
208 
209   // GCC/Clang extension
210   "typeof",
211 
212   // Not a keyword, but will break you
213   "NULL",
214 
215   // Objective-C Runtime typedefs
216   // From <obc/runtime.h>
217   "Category", "Ivar", "Method", "Protocol",
218 
219   // GPBMessage Methods
220   // Only need to add instance methods that may conflict with
221   // method declared in protos. The main cases are methods
222   // that take no arguments, or setFoo:/hasFoo: type methods.
223   "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
224   "extensionsCurrentlySet", "initialized", "isInitialized", "serializedSize",
225   "sortedExtensionsInUse", "unknownFields",
226 
227   // MacTypes.h names
228   "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
229   "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
230   "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
231   "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
232   "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
233 };
234 
235 // returns true is input starts with __ or _[A-Z] which are reserved identifiers
236 // in C/ C++. All calls should go through UnderscoresToCamelCase before getting here
237 // but this verifies and allows for future expansion if we decide to redefine what a
238 // reserved C identifier is (for example the GNU list
239 // https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html )
IsReservedCIdentifier(const std::string & input)240 bool IsReservedCIdentifier(const std::string& input) {
241   if (input.length() > 2) {
242     if (input.at(0) == '_') {
243       if (isupper(input.at(1)) || input.at(1) == '_') {
244         return true;
245       }
246     }
247   }
248   return false;
249 }
250 
SanitizeNameForObjC(const std::string & prefix,const std::string & input,const std::string & extension,std::string * out_suffix_added)251 std::string SanitizeNameForObjC(const std::string& prefix,
252                            const std::string& input,
253                            const std::string& extension,
254                            std::string* out_suffix_added) {
255   static const std::unordered_set<std::string> kReservedWords =
256       MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
257   static const std::unordered_set<std::string> kNSObjectMethods =
258       MakeWordsMap(kNSObjectMethodsList, GOOGLE_ARRAYSIZE(kNSObjectMethodsList));
259   std::string sanitized;
260   // We add the prefix in the cases where the string is missing a prefix.
261   // We define "missing a prefix" as where 'input':
262   // a) Doesn't start with the prefix or
263   // b) Isn't equivalent to the prefix or
264   // c) Has the prefix, but the letter after the prefix is lowercase
265   if (HasPrefixString(input, prefix)) {
266     if (input.length() == prefix.length() || !ascii_isupper(input[prefix.length()])) {
267       sanitized = prefix + input;
268     } else {
269       sanitized = input;
270     }
271   } else {
272     sanitized = prefix + input;
273   }
274   if (IsReservedCIdentifier(sanitized) ||
275       (kReservedWords.count(sanitized) > 0) ||
276       (kNSObjectMethods.count(sanitized) > 0)) {
277     if (out_suffix_added) *out_suffix_added = extension;
278     return sanitized + extension;
279   }
280   if (out_suffix_added) out_suffix_added->clear();
281   return sanitized;
282 }
283 
NameFromFieldDescriptor(const FieldDescriptor * field)284 std::string NameFromFieldDescriptor(const FieldDescriptor* field) {
285   if (field->type() == FieldDescriptor::TYPE_GROUP) {
286     return field->message_type()->name();
287   } else {
288     return field->name();
289   }
290 }
291 
PathSplit(const std::string & path,std::string * directory,std::string * basename)292 void PathSplit(const std::string& path, std::string* directory,
293                std::string* basename) {
294   std::string::size_type last_slash = path.rfind('/');
295   if (last_slash == std::string::npos) {
296     if (directory) {
297       *directory = "";
298     }
299     if (basename) {
300       *basename = path;
301     }
302   } else {
303     if (directory) {
304       *directory = path.substr(0, last_slash);
305     }
306     if (basename) {
307       *basename = path.substr(last_slash + 1);
308     }
309   }
310 }
311 
IsSpecialName(const std::string & name,const std::string * special_names,size_t count)312 bool IsSpecialName(const std::string& name, const std::string* special_names,
313                    size_t count) {
314   for (size_t i = 0; i < count; ++i) {
315     size_t length = special_names[i].length();
316     if (name.compare(0, length, special_names[i]) == 0) {
317       if (name.length() > length) {
318         // If name is longer than the retained_name[i] that it matches
319         // the next character must be not lower case (newton vs newTon vs
320         // new_ton).
321         return !ascii_islower(name[length]);
322       } else {
323         return true;
324       }
325     }
326   }
327   return false;
328 }
329 
GetZeroEnumNameForFlagType(const FlagType flag_type)330 std::string GetZeroEnumNameForFlagType(const FlagType flag_type) {
331   switch(flag_type) {
332     case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
333       return "GPBDescriptorInitializationFlag_None";
334     case FLAGTYPE_EXTENSION:
335       return "GPBExtensionNone";
336     case FLAGTYPE_FIELD:
337       return "GPBFieldNone";
338     default:
339       GOOGLE_LOG(FATAL) << "Can't get here.";
340       return "0";
341   }
342 }
343 
GetEnumNameForFlagType(const FlagType flag_type)344 std::string GetEnumNameForFlagType(const FlagType flag_type) {
345   switch(flag_type) {
346     case FLAGTYPE_DESCRIPTOR_INITIALIZATION:
347       return "GPBDescriptorInitializationFlags";
348     case FLAGTYPE_EXTENSION:
349       return "GPBExtensionOptions";
350     case FLAGTYPE_FIELD:
351       return "GPBFieldFlags";
352     default:
353       GOOGLE_LOG(FATAL) << "Can't get here.";
354       return std::string();
355   }
356 }
357 
358 }  // namespace
359 
360 // Escape C++ trigraphs by escaping question marks to \?
EscapeTrigraphs(const std::string & to_escape)361 std::string EscapeTrigraphs(const std::string& to_escape) {
362   return StringReplace(to_escape, "?", "\\?", true);
363 }
364 
StripProto(const std::string & filename)365 std::string StripProto(const std::string& filename) {
366   if (HasSuffixString(filename, ".protodevel")) {
367     return StripSuffixString(filename, ".protodevel");
368   } else {
369     return StripSuffixString(filename, ".proto");
370   }
371 }
372 
TrimWhitespace(StringPiece * input)373 void TrimWhitespace(StringPiece* input) {
374   while (!input->empty() && ascii_isspace(*input->data())) {
375     input->remove_prefix(1);
376   }
377   while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
378     input->remove_suffix(1);
379   }
380 }
381 
IsRetainedName(const std::string & name)382 bool IsRetainedName(const std::string& name) {
383   // List of prefixes from
384   // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
385   static const std::string retained_names[] = {"new", "alloc", "copy",
386                                                "mutableCopy"};
387   return IsSpecialName(name, retained_names,
388                        sizeof(retained_names) / sizeof(retained_names[0]));
389 }
390 
IsInitName(const std::string & name)391 bool IsInitName(const std::string& name) {
392   static const std::string init_names[] = {"init"};
393   return IsSpecialName(name, init_names,
394                        sizeof(init_names) / sizeof(init_names[0]));
395 }
396 
BaseFileName(const FileDescriptor * file)397 std::string BaseFileName(const FileDescriptor* file) {
398   std::string basename;
399   PathSplit(file->name(), NULL, &basename);
400   return basename;
401 }
402 
FileClassPrefix(const FileDescriptor * file)403 std::string FileClassPrefix(const FileDescriptor* file) {
404   // Default is empty string, no need to check has_objc_class_prefix.
405   std::string result = file->options().objc_class_prefix();
406   return result;
407 }
408 
FilePath(const FileDescriptor * file)409 std::string FilePath(const FileDescriptor* file) {
410   std::string output;
411   std::string basename;
412   std::string directory;
413   PathSplit(file->name(), &directory, &basename);
414   if (directory.length() > 0) {
415     output = directory + "/";
416   }
417   basename = StripProto(basename);
418 
419   // CamelCase to be more ObjC friendly.
420   basename = UnderscoresToCamelCase(basename, true);
421 
422   output += basename;
423   return output;
424 }
425 
FilePathBasename(const FileDescriptor * file)426 std::string FilePathBasename(const FileDescriptor* file) {
427   std::string output;
428   std::string basename;
429   std::string directory;
430   PathSplit(file->name(), &directory, &basename);
431   basename = StripProto(basename);
432 
433   // CamelCase to be more ObjC friendly.
434   output = UnderscoresToCamelCase(basename, true);
435 
436   return output;
437 }
438 
FileClassName(const FileDescriptor * file)439 std::string FileClassName(const FileDescriptor* file) {
440   const std::string prefix = FileClassPrefix(file);
441   const std::string name =
442       UnderscoresToCamelCase(StripProto(BaseFileName(file)), true) + "Root";
443   // There aren't really any reserved words that end in "Root", but playing
444   // it safe and checking.
445   return SanitizeNameForObjC(prefix, name, "_RootClass", NULL);
446 }
447 
ClassNameWorker(const Descriptor * descriptor)448 std::string ClassNameWorker(const Descriptor* descriptor) {
449   std::string name;
450   if (descriptor->containing_type() != NULL) {
451     name = ClassNameWorker(descriptor->containing_type());
452     name += "_";
453   }
454   return name + descriptor->name();
455 }
456 
ClassNameWorker(const EnumDescriptor * descriptor)457 std::string ClassNameWorker(const EnumDescriptor* descriptor) {
458   std::string name;
459   if (descriptor->containing_type() != NULL) {
460     name = ClassNameWorker(descriptor->containing_type());
461     name += "_";
462   }
463   return name + descriptor->name();
464 }
465 
ClassName(const Descriptor * descriptor)466 std::string ClassName(const Descriptor* descriptor) {
467   return ClassName(descriptor, NULL);
468 }
469 
ClassName(const Descriptor * descriptor,std::string * out_suffix_added)470 std::string ClassName(const Descriptor* descriptor,
471                       std::string* out_suffix_added) {
472   // 1. Message names are used as is (style calls for CamelCase, trust it).
473   // 2. Check for reserved word at the very end and then suffix things.
474   const std::string prefix = FileClassPrefix(descriptor->file());
475   const std::string name = ClassNameWorker(descriptor);
476   return SanitizeNameForObjC(prefix, name, "_Class", out_suffix_added);
477 }
478 
EnumName(const EnumDescriptor * descriptor)479 std::string EnumName(const EnumDescriptor* descriptor) {
480   // 1. Enum names are used as is (style calls for CamelCase, trust it).
481   // 2. Check for reserved word at the every end and then suffix things.
482   //      message Fixed {
483   //        message Size {...}
484   //        enum Mumble {...}
485   //      ...
486   //      }
487   //    yields Fixed_Class, Fixed_Size.
488   const std::string prefix = FileClassPrefix(descriptor->file());
489   const std::string name = ClassNameWorker(descriptor);
490   return SanitizeNameForObjC(prefix, name, "_Enum", NULL);
491 }
492 
EnumValueName(const EnumValueDescriptor * descriptor)493 std::string EnumValueName(const EnumValueDescriptor* descriptor) {
494   // Because of the Switch enum compatibility, the name on the enum has to have
495   // the suffix handing, so it slightly diverges from how nested classes work.
496   //   enum Fixed {
497   //     FOO = 1
498   //   }
499   // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
500   const std::string class_name = EnumName(descriptor->type());
501   const std::string value_str =
502       UnderscoresToCamelCase(descriptor->name(), true);
503   const std::string name = class_name + "_" + value_str;
504   // There aren't really any reserved words with an underscore and a leading
505   // capital letter, but playing it safe and checking.
506   return SanitizeNameForObjC("", name, "_Value", NULL);
507 }
508 
EnumValueShortName(const EnumValueDescriptor * descriptor)509 std::string EnumValueShortName(const EnumValueDescriptor* descriptor) {
510   // Enum value names (EnumValueName above) are the enum name turned into
511   // a class name and then the value name is CamelCased and concatenated; the
512   // whole thing then gets sanitized for reserved words.
513   // The "short name" is intended to be the final leaf, the value name; but
514   // you can't simply send that off to sanitize as that could result in it
515   // getting modified when the full name didn't.  For example enum
516   // "StorageModes" has a value "retain".  So the full name is
517   // "StorageModes_Retain", but if we sanitize "retain" it would become
518   // "RetainValue".
519   // So the right way to get the short name is to take the full enum name
520   // and then strip off the enum name (leaving the value name and anything
521   // done by sanitize).
522   const std::string class_name = EnumName(descriptor->type());
523   const std::string long_name_prefix = class_name + "_";
524   const std::string long_name = EnumValueName(descriptor);
525   return StripPrefixString(long_name, long_name_prefix);
526 }
527 
UnCamelCaseEnumShortName(const std::string & name)528 std::string UnCamelCaseEnumShortName(const std::string& name) {
529   std::string result;
530   for (int i = 0; i < name.size(); i++) {
531     char c = name[i];
532     if (i > 0 && ascii_isupper(c)) {
533       result += '_';
534     }
535     result += ascii_toupper(c);
536   }
537   return result;
538 }
539 
ExtensionMethodName(const FieldDescriptor * descriptor)540 std::string ExtensionMethodName(const FieldDescriptor* descriptor) {
541   const std::string name = NameFromFieldDescriptor(descriptor);
542   const std::string result = UnderscoresToCamelCase(name, false);
543   return SanitizeNameForObjC("", result, "_Extension", NULL);
544 }
545 
FieldName(const FieldDescriptor * field)546 std::string FieldName(const FieldDescriptor* field) {
547   const std::string name = NameFromFieldDescriptor(field);
548   std::string result = UnderscoresToCamelCase(name, false);
549   if (field->is_repeated() && !field->is_map()) {
550     // Add "Array" before do check for reserved worlds.
551     result += "Array";
552   } else {
553     // If it wasn't repeated, but ends in "Array", force on the _p suffix.
554     if (HasSuffixString(result, "Array")) {
555       result += "_p";
556     }
557   }
558   return SanitizeNameForObjC("", result, "_p", NULL);
559 }
560 
FieldNameCapitalized(const FieldDescriptor * field)561 std::string FieldNameCapitalized(const FieldDescriptor* field) {
562   // Want the same suffix handling, so upcase the first letter of the other
563   // name.
564   std::string result = FieldName(field);
565   if (result.length() > 0) {
566     result[0] = ascii_toupper(result[0]);
567   }
568   return result;
569 }
570 
OneofEnumName(const OneofDescriptor * descriptor)571 std::string OneofEnumName(const OneofDescriptor* descriptor) {
572   const Descriptor* fieldDescriptor = descriptor->containing_type();
573   std::string name = ClassName(fieldDescriptor);
574   name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase";
575   // No sanitize needed because the OS never has names that end in _OneOfCase.
576   return name;
577 }
578 
OneofName(const OneofDescriptor * descriptor)579 std::string OneofName(const OneofDescriptor* descriptor) {
580   std::string name = UnderscoresToCamelCase(descriptor->name(), false);
581   // No sanitize needed because it gets OneOfCase added and that shouldn't
582   // ever conflict.
583   return name;
584 }
585 
OneofNameCapitalized(const OneofDescriptor * descriptor)586 std::string OneofNameCapitalized(const OneofDescriptor* descriptor) {
587   // Use the common handling and then up-case the first letter.
588   std::string result = OneofName(descriptor);
589   if (result.length() > 0) {
590     result[0] = ascii_toupper(result[0]);
591   }
592   return result;
593 }
594 
ObjCClass(const std::string & class_name)595 std::string ObjCClass(const std::string& class_name) {
596   return std::string("GPBObjCClass(") + class_name + ")";
597 }
598 
ObjCClassDeclaration(const std::string & class_name)599 std::string ObjCClassDeclaration(const std::string& class_name) {
600   return std::string("GPBObjCClassDeclaration(") + class_name + ");";
601 }
602 
UnCamelCaseFieldName(const std::string & name,const FieldDescriptor * field)603 std::string UnCamelCaseFieldName(const std::string& name, const FieldDescriptor* field) {
604   std::string worker(name);
605   if (HasSuffixString(worker, "_p")) {
606     worker = StripSuffixString(worker, "_p");
607   }
608   if (field->is_repeated() && HasSuffixString(worker, "Array")) {
609     worker = StripSuffixString(worker, "Array");
610   }
611   if (field->type() == FieldDescriptor::TYPE_GROUP) {
612     if (worker.length() > 0) {
613       if (ascii_islower(worker[0])) {
614         worker[0] = ascii_toupper(worker[0]);
615       }
616     }
617     return worker;
618   } else {
619     std::string result;
620     for (int i = 0; i < worker.size(); i++) {
621       char c = worker[i];
622       if (ascii_isupper(c)) {
623         if (i > 0) {
624           result += '_';
625         }
626         result += ascii_tolower(c);
627       } else {
628         result += c;
629       }
630     }
631     return result;
632   }
633 }
634 
GetCapitalizedType(const FieldDescriptor * field)635 std::string GetCapitalizedType(const FieldDescriptor* field) {
636   switch (field->type()) {
637     case FieldDescriptor::TYPE_INT32:
638       return "Int32";
639     case FieldDescriptor::TYPE_UINT32:
640       return "UInt32";
641     case FieldDescriptor::TYPE_SINT32:
642       return "SInt32";
643     case FieldDescriptor::TYPE_FIXED32:
644       return "Fixed32";
645     case FieldDescriptor::TYPE_SFIXED32:
646       return "SFixed32";
647     case FieldDescriptor::TYPE_INT64:
648       return "Int64";
649     case FieldDescriptor::TYPE_UINT64:
650       return "UInt64";
651     case FieldDescriptor::TYPE_SINT64:
652       return "SInt64";
653     case FieldDescriptor::TYPE_FIXED64:
654       return "Fixed64";
655     case FieldDescriptor::TYPE_SFIXED64:
656       return "SFixed64";
657     case FieldDescriptor::TYPE_FLOAT:
658       return "Float";
659     case FieldDescriptor::TYPE_DOUBLE:
660       return "Double";
661     case FieldDescriptor::TYPE_BOOL:
662       return "Bool";
663     case FieldDescriptor::TYPE_STRING:
664       return "String";
665     case FieldDescriptor::TYPE_BYTES:
666       return "Bytes";
667     case FieldDescriptor::TYPE_ENUM:
668       return "Enum";
669     case FieldDescriptor::TYPE_GROUP:
670       return "Group";
671     case FieldDescriptor::TYPE_MESSAGE:
672       return "Message";
673   }
674 
675   // Some compilers report reaching end of function even though all cases of
676   // the enum are handed in the switch.
677   GOOGLE_LOG(FATAL) << "Can't get here.";
678   return std::string();
679 }
680 
GetObjectiveCType(FieldDescriptor::Type field_type)681 ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
682   switch (field_type) {
683     case FieldDescriptor::TYPE_INT32:
684     case FieldDescriptor::TYPE_SINT32:
685     case FieldDescriptor::TYPE_SFIXED32:
686       return OBJECTIVECTYPE_INT32;
687 
688     case FieldDescriptor::TYPE_UINT32:
689     case FieldDescriptor::TYPE_FIXED32:
690       return OBJECTIVECTYPE_UINT32;
691 
692     case FieldDescriptor::TYPE_INT64:
693     case FieldDescriptor::TYPE_SINT64:
694     case FieldDescriptor::TYPE_SFIXED64:
695       return OBJECTIVECTYPE_INT64;
696 
697     case FieldDescriptor::TYPE_UINT64:
698     case FieldDescriptor::TYPE_FIXED64:
699       return OBJECTIVECTYPE_UINT64;
700 
701     case FieldDescriptor::TYPE_FLOAT:
702       return OBJECTIVECTYPE_FLOAT;
703 
704     case FieldDescriptor::TYPE_DOUBLE:
705       return OBJECTIVECTYPE_DOUBLE;
706 
707     case FieldDescriptor::TYPE_BOOL:
708       return OBJECTIVECTYPE_BOOLEAN;
709 
710     case FieldDescriptor::TYPE_STRING:
711       return OBJECTIVECTYPE_STRING;
712 
713     case FieldDescriptor::TYPE_BYTES:
714       return OBJECTIVECTYPE_DATA;
715 
716     case FieldDescriptor::TYPE_ENUM:
717       return OBJECTIVECTYPE_ENUM;
718 
719     case FieldDescriptor::TYPE_GROUP:
720     case FieldDescriptor::TYPE_MESSAGE:
721       return OBJECTIVECTYPE_MESSAGE;
722   }
723 
724   // Some compilers report reaching end of function even though all cases of
725   // the enum are handed in the switch.
726   GOOGLE_LOG(FATAL) << "Can't get here.";
727   return OBJECTIVECTYPE_INT32;
728 }
729 
IsPrimitiveType(const FieldDescriptor * field)730 bool IsPrimitiveType(const FieldDescriptor* field) {
731   ObjectiveCType type = GetObjectiveCType(field);
732   switch (type) {
733     case OBJECTIVECTYPE_INT32:
734     case OBJECTIVECTYPE_UINT32:
735     case OBJECTIVECTYPE_INT64:
736     case OBJECTIVECTYPE_UINT64:
737     case OBJECTIVECTYPE_FLOAT:
738     case OBJECTIVECTYPE_DOUBLE:
739     case OBJECTIVECTYPE_BOOLEAN:
740     case OBJECTIVECTYPE_ENUM:
741       return true;
742       break;
743     default:
744       return false;
745   }
746 }
747 
IsReferenceType(const FieldDescriptor * field)748 bool IsReferenceType(const FieldDescriptor* field) {
749   return !IsPrimitiveType(field);
750 }
751 
HandleExtremeFloatingPoint(std::string val,bool add_float_suffix)752 static std::string HandleExtremeFloatingPoint(std::string val,
753                                               bool add_float_suffix) {
754   if (val == "nan") {
755     return "NAN";
756   } else if (val == "inf") {
757     return "INFINITY";
758   } else if (val == "-inf") {
759     return "-INFINITY";
760   } else {
761     // float strings with ., e or E need to have f appended
762     if (add_float_suffix && (val.find(".") != std::string::npos ||
763                              val.find("e") != std::string::npos ||
764                              val.find("E") != std::string::npos)) {
765       val += "f";
766     }
767     return val;
768   }
769 }
770 
GPBGenericValueFieldName(const FieldDescriptor * field)771 std::string GPBGenericValueFieldName(const FieldDescriptor* field) {
772   // Returns the field within the GPBGenericValue union to use for the given
773   // field.
774   if (field->is_repeated()) {
775       return "valueMessage";
776   }
777   switch (field->cpp_type()) {
778     case FieldDescriptor::CPPTYPE_INT32:
779       return "valueInt32";
780     case FieldDescriptor::CPPTYPE_UINT32:
781       return "valueUInt32";
782     case FieldDescriptor::CPPTYPE_INT64:
783       return "valueInt64";
784     case FieldDescriptor::CPPTYPE_UINT64:
785       return "valueUInt64";
786     case FieldDescriptor::CPPTYPE_FLOAT:
787       return "valueFloat";
788     case FieldDescriptor::CPPTYPE_DOUBLE:
789       return "valueDouble";
790     case FieldDescriptor::CPPTYPE_BOOL:
791       return "valueBool";
792     case FieldDescriptor::CPPTYPE_STRING:
793       if (field->type() == FieldDescriptor::TYPE_BYTES) {
794         return "valueData";
795       } else {
796         return "valueString";
797       }
798     case FieldDescriptor::CPPTYPE_ENUM:
799       return "valueEnum";
800     case FieldDescriptor::CPPTYPE_MESSAGE:
801       return "valueMessage";
802   }
803 
804   // Some compilers report reaching end of function even though all cases of
805   // the enum are handed in the switch.
806   GOOGLE_LOG(FATAL) << "Can't get here.";
807   return std::string();
808 }
809 
810 
DefaultValue(const FieldDescriptor * field)811 std::string DefaultValue(const FieldDescriptor* field) {
812   // Repeated fields don't have defaults.
813   if (field->is_repeated()) {
814     return "nil";
815   }
816 
817   // Switch on cpp_type since we need to know which default_value_* method
818   // of FieldDescriptor to call.
819   switch (field->cpp_type()) {
820     case FieldDescriptor::CPPTYPE_INT32:
821       // gcc and llvm reject the decimal form of kint32min and kint64min.
822       if (field->default_value_int32() == INT_MIN) {
823         return "-0x80000000";
824       }
825       return StrCat(field->default_value_int32());
826     case FieldDescriptor::CPPTYPE_UINT32:
827       return StrCat(field->default_value_uint32()) + "U";
828     case FieldDescriptor::CPPTYPE_INT64:
829       // gcc and llvm reject the decimal form of kint32min and kint64min.
830       if (field->default_value_int64() == LLONG_MIN) {
831         return "-0x8000000000000000LL";
832       }
833       return StrCat(field->default_value_int64()) + "LL";
834     case FieldDescriptor::CPPTYPE_UINT64:
835       return StrCat(field->default_value_uint64()) + "ULL";
836     case FieldDescriptor::CPPTYPE_DOUBLE:
837       return HandleExtremeFloatingPoint(
838           SimpleDtoa(field->default_value_double()), false);
839     case FieldDescriptor::CPPTYPE_FLOAT:
840       return HandleExtremeFloatingPoint(
841           SimpleFtoa(field->default_value_float()), true);
842     case FieldDescriptor::CPPTYPE_BOOL:
843       return field->default_value_bool() ? "YES" : "NO";
844     case FieldDescriptor::CPPTYPE_STRING: {
845       const bool has_default_value = field->has_default_value();
846       const std::string& default_string = field->default_value_string();
847       if (!has_default_value || default_string.length() == 0) {
848         // If the field is defined as being the empty string,
849         // then we will just assign to nil, as the empty string is the
850         // default for both strings and data.
851         return "nil";
852       }
853       if (field->type() == FieldDescriptor::TYPE_BYTES) {
854         // We want constant fields in our data structures so we can
855         // declare them as static. To achieve this we cheat and stuff
856         // a escaped c string (prefixed with a length) into the data
857         // field, and cast it to an (NSData*) so it will compile.
858         // The runtime library knows how to handle it.
859 
860         // Must convert to a standard byte order for packing length into
861         // a cstring.
862         uint32 length = ghtonl(default_string.length());
863         std::string bytes((const char*)&length, sizeof(length));
864         bytes.append(default_string);
865         return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\"";
866       } else {
867         return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\"";
868       }
869     }
870     case FieldDescriptor::CPPTYPE_ENUM:
871       return EnumValueName(field->default_value_enum());
872     case FieldDescriptor::CPPTYPE_MESSAGE:
873       return "nil";
874   }
875 
876   // Some compilers report reaching end of function even though all cases of
877   // the enum are handed in the switch.
878   GOOGLE_LOG(FATAL) << "Can't get here.";
879   return std::string();
880 }
881 
HasNonZeroDefaultValue(const FieldDescriptor * field)882 bool HasNonZeroDefaultValue(const FieldDescriptor* field) {
883   // Repeated fields don't have defaults.
884   if (field->is_repeated()) {
885     return false;
886   }
887 
888   // As much as checking field->has_default_value() seems useful, it isn't
889   // because of enums. proto2 syntax allows the first item in an enum (the
890   // default) to be non zero. So checking field->has_default_value() would
891   // result in missing this non zero default.  See MessageWithOneBasedEnum in
892   // objectivec/Tests/unittest_objc.proto for a test Message to confirm this.
893 
894   // Some proto file set the default to the zero value, so make sure the value
895   // isn't the zero case.
896   switch (field->cpp_type()) {
897     case FieldDescriptor::CPPTYPE_INT32:
898       return field->default_value_int32() != 0;
899     case FieldDescriptor::CPPTYPE_UINT32:
900       return field->default_value_uint32() != 0U;
901     case FieldDescriptor::CPPTYPE_INT64:
902       return field->default_value_int64() != 0LL;
903     case FieldDescriptor::CPPTYPE_UINT64:
904       return field->default_value_uint64() != 0ULL;
905     case FieldDescriptor::CPPTYPE_DOUBLE:
906       return field->default_value_double() != 0.0;
907     case FieldDescriptor::CPPTYPE_FLOAT:
908       return field->default_value_float() != 0.0f;
909     case FieldDescriptor::CPPTYPE_BOOL:
910       return field->default_value_bool();
911     case FieldDescriptor::CPPTYPE_STRING: {
912       const std::string& default_string = field->default_value_string();
913       return default_string.length() != 0;
914     }
915     case FieldDescriptor::CPPTYPE_ENUM:
916       return field->default_value_enum()->number() != 0;
917     case FieldDescriptor::CPPTYPE_MESSAGE:
918       return false;
919   }
920 
921   // Some compilers report reaching end of function even though all cases of
922   // the enum are handed in the switch.
923   GOOGLE_LOG(FATAL) << "Can't get here.";
924   return false;
925 }
926 
BuildFlagsString(const FlagType flag_type,const std::vector<std::string> & strings)927 std::string BuildFlagsString(const FlagType flag_type,
928                              const std::vector<std::string>& strings) {
929   if (strings.empty()) {
930     return GetZeroEnumNameForFlagType(flag_type);
931   } else if (strings.size() == 1) {
932     return strings[0];
933   }
934   std::string string("(" + GetEnumNameForFlagType(flag_type) + ")(");
935   for (size_t i = 0; i != strings.size(); ++i) {
936     if (i > 0) {
937       string.append(" | ");
938     }
939     string.append(strings[i]);
940   }
941   string.append(")");
942   return string;
943 }
944 
BuildCommentsString(const SourceLocation & location,bool prefer_single_line)945 std::string BuildCommentsString(const SourceLocation& location,
946                            bool prefer_single_line) {
947   const std::string& comments = location.leading_comments.empty()
948                                ? location.trailing_comments
949                                : location.leading_comments;
950   std::vector<std::string> lines;
951   lines = Split(comments, "\n", false);
952   while (!lines.empty() && lines.back().empty()) {
953     lines.pop_back();
954   }
955   // If there are no comments, just return an empty string.
956   if (lines.empty()) {
957     return "";
958   }
959 
960   std::string prefix;
961   std::string suffix;
962   std::string final_comments;
963   std::string epilogue;
964 
965   bool add_leading_space = false;
966 
967   if (prefer_single_line && lines.size() == 1) {
968     prefix = "/** ";
969     suffix = " */\n";
970   } else {
971     prefix = "* ";
972     suffix = "\n";
973     final_comments += "/**\n";
974     epilogue = " **/\n";
975     add_leading_space = true;
976   }
977 
978   for (int i = 0; i < lines.size(); i++) {
979     std::string line = StripPrefixString(lines[i], " ");
980     // HeaderDoc and appledoc use '\' and '@' for markers; escape them.
981     line = StringReplace(line, "\\", "\\\\", true);
982     line = StringReplace(line, "@", "\\@", true);
983     // Decouple / from * to not have inline comments inside comments.
984     line = StringReplace(line, "/*", "/\\*", true);
985     line = StringReplace(line, "*/", "*\\/", true);
986     line = prefix + line;
987     StripWhitespace(&line);
988     // If not a one line, need to add the first space before *, as
989     // StripWhitespace would have removed it.
990     line = (add_leading_space ? " " : "") + line;
991     final_comments += line + suffix;
992   }
993   final_comments += epilogue;
994   return final_comments;
995 }
996 
997 // Making these a generator option for folks that don't use CocoaPods, but do
998 // want to put the library in a framework is an interesting question. The
999 // problem is it means changing sources shipped with the library to actually
1000 // use a different value; so it isn't as simple as a option.
1001 const char* const ProtobufLibraryFrameworkName = "Protobuf";
1002 
ProtobufFrameworkImportSymbol(const std::string & framework_name)1003 std::string ProtobufFrameworkImportSymbol(const std::string& framework_name) {
1004   // GPB_USE_[framework_name]_FRAMEWORK_IMPORTS
1005   std::string result = std::string("GPB_USE_");
1006   result += ToUpper(framework_name);
1007   result += "_FRAMEWORK_IMPORTS";
1008   return result;
1009 }
1010 
IsProtobufLibraryBundledProtoFile(const FileDescriptor * file)1011 bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) {
1012   // We don't check the name prefix or proto package because some files
1013   // (descriptor.proto), aren't shipped generated by the library, so this
1014   // seems to be the safest way to only catch the ones shipped.
1015   const std::string name = file->name();
1016   if (name == "google/protobuf/any.proto" ||
1017       name == "google/protobuf/api.proto" ||
1018       name == "google/protobuf/duration.proto" ||
1019       name == "google/protobuf/empty.proto" ||
1020       name == "google/protobuf/field_mask.proto" ||
1021       name == "google/protobuf/source_context.proto" ||
1022       name == "google/protobuf/struct.proto" ||
1023       name == "google/protobuf/timestamp.proto" ||
1024       name == "google/protobuf/type.proto" ||
1025       name == "google/protobuf/wrappers.proto") {
1026     return true;
1027   }
1028   return false;
1029 }
1030 
ReadLine(StringPiece * input,StringPiece * line)1031 bool ReadLine(StringPiece* input, StringPiece* line) {
1032   for (int len = 0; len < input->size(); ++len) {
1033     if (ascii_isnewline((*input)[len])) {
1034       *line = StringPiece(input->data(), len);
1035       ++len;  // advance over the newline
1036       *input = StringPiece(input->data() + len, input->size() - len);
1037       return true;
1038     }
1039   }
1040   return false;  // Ran out of input with no newline.
1041 }
1042 
RemoveComment(StringPiece * input)1043 void RemoveComment(StringPiece* input) {
1044   int offset = input->find('#');
1045   if (offset != StringPiece::npos) {
1046     input->remove_suffix(input->length() - offset);
1047   }
1048 }
1049 
1050 namespace {
1051 
1052 class ExpectedPrefixesCollector : public LineConsumer {
1053  public:
ExpectedPrefixesCollector(std::map<std::string,std::string> * inout_package_to_prefix_map)1054   ExpectedPrefixesCollector(std::map<std::string, std::string>* inout_package_to_prefix_map)
1055       : prefix_map_(inout_package_to_prefix_map) {}
1056 
1057   virtual bool ConsumeLine(const StringPiece& line, std::string* out_error);
1058 
1059  private:
1060   std::map<std::string, std::string>* prefix_map_;
1061 };
1062 
ConsumeLine(const StringPiece & line,std::string * out_error)1063 bool ExpectedPrefixesCollector::ConsumeLine(
1064     const StringPiece& line, std::string* out_error) {
1065   int offset = line.find('=');
1066   if (offset == StringPiece::npos) {
1067     *out_error = std::string("Expected prefixes file line without equal sign: '") +
1068                  std::string(line) + "'.";
1069     return false;
1070   }
1071   StringPiece package = line.substr(0, offset);
1072   StringPiece prefix = line.substr(offset + 1);
1073   TrimWhitespace(&package);
1074   TrimWhitespace(&prefix);
1075   // Don't really worry about error checking the package/prefix for
1076   // being valid.  Assume the file is validated when it is created/edited.
1077   (*prefix_map_)[std::string(package)] = std::string(prefix);
1078   return true;
1079 }
1080 
LoadExpectedPackagePrefixes(const Options & generation_options,std::map<std::string,std::string> * prefix_map,std::string * out_error)1081 bool LoadExpectedPackagePrefixes(const Options& generation_options,
1082                                  std::map<std::string, std::string>* prefix_map,
1083                                  std::string* out_error) {
1084   if (generation_options.expected_prefixes_path.empty()) {
1085     return true;
1086   }
1087 
1088   ExpectedPrefixesCollector collector(prefix_map);
1089   return ParseSimpleFile(
1090       generation_options.expected_prefixes_path, &collector, out_error);
1091 }
1092 
ValidateObjCClassPrefix(const FileDescriptor * file,const std::string & expected_prefixes_path,const std::map<std::string,std::string> & expected_package_prefixes,std::string * out_error)1093 bool ValidateObjCClassPrefix(
1094     const FileDescriptor* file, const std::string& expected_prefixes_path,
1095     const std::map<std::string, std::string>& expected_package_prefixes,
1096     std::string* out_error) {
1097   const std::string prefix = file->options().objc_class_prefix();
1098   const std::string package = file->package();
1099 
1100   // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
1101   // error cases, so it seems to be ok to use as a back door for warnings.
1102 
1103   // Check: Error - See if there was an expected prefix for the package and
1104   // report if it doesn't match (wrong or missing).
1105   std::map<std::string, std::string>::const_iterator package_match =
1106       expected_package_prefixes.find(package);
1107   if (package_match != expected_package_prefixes.end()) {
1108     // There was an entry, and...
1109     if (package_match->second == prefix) {
1110       // ...it matches.  All good, out of here!
1111       return true;
1112     } else {
1113       // ...it didn't match!
1114       *out_error = "error: Expected 'option objc_class_prefix = \"" +
1115                    package_match->second + "\";' for package '" + package +
1116                    "' in '" + file->name() + "'";
1117       if (prefix.length()) {
1118         *out_error += "; but found '" + prefix + "' instead";
1119       }
1120       *out_error += ".";
1121       return false;
1122     }
1123   }
1124 
1125   // If there was no prefix option, we're done at this point.
1126   if (prefix.empty()) {
1127     // No prefix, nothing left to check.
1128     return true;
1129   }
1130 
1131   // Check: Warning - Make sure the prefix is is a reasonable value according
1132   // to Apple's rules (the checks above implicitly whitelist anything that
1133   // doesn't meet these rules).
1134   if (!ascii_isupper(prefix[0])) {
1135     std::cerr
1136          << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1137          << prefix << "\";' in '" << file->name() << "';"
1138          << " it should start with a capital letter." << std::endl;
1139     std::cerr.flush();
1140   }
1141   if (prefix.length() < 3) {
1142     // Apple reserves 2 character prefixes for themselves. They do use some
1143     // 3 character prefixes, but they haven't updated the rules/docs.
1144     std::cerr
1145          << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
1146          << prefix << "\";' in '" << file->name() << "';"
1147          << " Apple recommends they should be at least 3 characters long."
1148          << std::endl;
1149     std::cerr.flush();
1150   }
1151 
1152   // Look for any other package that uses the same prefix.
1153   std::string other_package_for_prefix;
1154   for (std::map<std::string, std::string>::const_iterator i =
1155            expected_package_prefixes.begin();
1156        i != expected_package_prefixes.end(); ++i) {
1157     if (i->second == prefix) {
1158       other_package_for_prefix = i->first;
1159       break;
1160     }
1161   }
1162 
1163   // Check: Warning - If the file does not have a package, check whether
1164   // the prefix declared is being used by another package or not.
1165   if (package.empty()) {
1166     // The file does not have a package and ...
1167     if (other_package_for_prefix.empty()) {
1168       // ... no other package has declared that prefix.
1169       std::cerr
1170            << "protoc:0: warning: File '" << file->name() << "' has no "
1171            << "package. Consider adding a new package to the proto and adding '"
1172            << "new.package = " << prefix << "' to the expected prefixes file ("
1173            << expected_prefixes_path << ")." << std::endl;
1174       std::cerr.flush();
1175     } else {
1176       // ... another package has declared the same prefix.
1177       std::cerr
1178            << "protoc:0: warning: File '" << file->name() << "' has no package "
1179            << "and package '" << other_package_for_prefix << "' already uses '"
1180            << prefix << "' as its prefix. Consider either adding a new package "
1181            << "to the proto, or reusing one of the packages already using this "
1182            << "prefix in the expected prefixes file ("
1183            << expected_prefixes_path << ")." << std::endl;
1184       std::cerr.flush();
1185     }
1186     return true;
1187   }
1188 
1189   // Check: Error - Make sure the prefix wasn't expected for a different
1190   // package (overlap is allowed, but it has to be listed as an expected
1191   // overlap).
1192   if (!other_package_for_prefix.empty()) {
1193     *out_error =
1194         "error: Found 'option objc_class_prefix = \"" + prefix +
1195         "\";' in '" + file->name() +
1196         "'; that prefix is already used for 'package " +
1197         other_package_for_prefix + ";'. It can only be reused by listing " +
1198         "it in the expected file (" +
1199         expected_prefixes_path + ").";
1200     return false;  // Only report first usage of the prefix.
1201   }
1202 
1203   // Check: Warning - If the given package/prefix pair wasn't expected, issue a
1204   // warning issue a warning suggesting it gets added to the file.
1205   if (!expected_package_prefixes.empty()) {
1206     std::cerr
1207          << "protoc:0: warning: Found unexpected 'option objc_class_prefix = \""
1208          << prefix << "\";' in '" << file->name() << "';"
1209          << " consider adding it to the expected prefixes file ("
1210          << expected_prefixes_path << ")." << std::endl;
1211     std::cerr.flush();
1212   }
1213 
1214   return true;
1215 }
1216 
1217 }  // namespace
1218 
ValidateObjCClassPrefixes(const std::vector<const FileDescriptor * > & files,const Options & generation_options,std::string * out_error)1219 bool ValidateObjCClassPrefixes(const std::vector<const FileDescriptor*>& files,
1220                                const Options& generation_options,
1221                                std::string* out_error) {
1222   // Load the expected package prefixes, if available, to validate against.
1223   std::map<std::string, std::string> expected_package_prefixes;
1224   if (!LoadExpectedPackagePrefixes(generation_options,
1225                                    &expected_package_prefixes,
1226                                    out_error)) {
1227     return false;
1228   }
1229 
1230   for (int i = 0; i < files.size(); i++) {
1231     bool should_skip =
1232       (std::find(generation_options.expected_prefixes_suppressions.begin(),
1233                  generation_options.expected_prefixes_suppressions.end(),
1234                  files[i]->name())
1235           != generation_options.expected_prefixes_suppressions.end());
1236     if (should_skip) {
1237       continue;
1238     }
1239 
1240     bool is_valid =
1241         ValidateObjCClassPrefix(files[i],
1242                                 generation_options.expected_prefixes_path,
1243                                 expected_package_prefixes,
1244                                 out_error);
1245     if (!is_valid) {
1246       return false;
1247     }
1248   }
1249   return true;
1250 }
1251 
TextFormatDecodeData()1252 TextFormatDecodeData::TextFormatDecodeData() { }
1253 
~TextFormatDecodeData()1254 TextFormatDecodeData::~TextFormatDecodeData() { }
1255 
AddString(int32 key,const std::string & input_for_decode,const std::string & desired_output)1256 void TextFormatDecodeData::AddString(int32 key,
1257                                      const std::string& input_for_decode,
1258                                      const std::string& desired_output) {
1259   for (std::vector<DataEntry>::const_iterator i = entries_.begin();
1260        i != entries_.end(); ++i) {
1261     if (i->first == key) {
1262       std::cerr << "error: duplicate key (" << key
1263            << ") making TextFormat data, input: \"" << input_for_decode
1264            << "\", desired: \"" << desired_output << "\"." << std::endl;
1265       std::cerr.flush();
1266       abort();
1267     }
1268   }
1269 
1270   const std::string& data = TextFormatDecodeData::DecodeDataForString(
1271       input_for_decode, desired_output);
1272   entries_.push_back(DataEntry(key, data));
1273 }
1274 
Data() const1275 std::string TextFormatDecodeData::Data() const {
1276   std::ostringstream data_stringstream;
1277 
1278   if (num_entries() > 0) {
1279     io::OstreamOutputStream data_outputstream(&data_stringstream);
1280     io::CodedOutputStream output_stream(&data_outputstream);
1281 
1282     output_stream.WriteVarint32(num_entries());
1283     for (std::vector<DataEntry>::const_iterator i = entries_.begin();
1284          i != entries_.end(); ++i) {
1285       output_stream.WriteVarint32(i->first);
1286       output_stream.WriteString(i->second);
1287     }
1288   }
1289 
1290   data_stringstream.flush();
1291   return data_stringstream.str();
1292 }
1293 
1294 namespace {
1295 
1296 // Helper to build up the decode data for a string.
1297 class DecodeDataBuilder {
1298  public:
DecodeDataBuilder()1299   DecodeDataBuilder() { Reset(); }
1300 
1301   bool AddCharacter(const char desired, const char input);
AddUnderscore()1302   void AddUnderscore() {
1303     Push();
1304     need_underscore_ = true;
1305   }
Finish()1306   std::string Finish() {
1307     Push();
1308     return decode_data_;
1309   }
1310 
1311  private:
1312   static constexpr uint8 kAddUnderscore = 0x80;
1313 
1314   static constexpr uint8 kOpAsIs = 0x00;
1315   static constexpr uint8 kOpFirstUpper = 0x40;
1316   static constexpr uint8 kOpFirstLower = 0x20;
1317   static constexpr uint8 kOpAllUpper = 0x60;
1318 
1319   static constexpr int kMaxSegmentLen = 0x1f;
1320 
AddChar(const char desired)1321   void AddChar(const char desired) {
1322     ++segment_len_;
1323     is_all_upper_ &= ascii_isupper(desired);
1324   }
1325 
Push()1326   void Push() {
1327     uint8 op = (op_ | segment_len_);
1328     if (need_underscore_) op |= kAddUnderscore;
1329     if (op != 0) {
1330       decode_data_ += (char)op;
1331     }
1332     Reset();
1333   }
1334 
AddFirst(const char desired,const char input)1335   bool AddFirst(const char desired, const char input) {
1336     if (desired == input) {
1337       op_ = kOpAsIs;
1338     } else if (desired == ascii_toupper(input)) {
1339       op_ = kOpFirstUpper;
1340     } else if (desired == ascii_tolower(input)) {
1341       op_ = kOpFirstLower;
1342     } else {
1343       // Can't be transformed to match.
1344       return false;
1345     }
1346     AddChar(desired);
1347     return true;
1348   }
1349 
Reset()1350   void Reset() {
1351     need_underscore_ = false;
1352     op_ = 0;
1353     segment_len_ = 0;
1354     is_all_upper_ = true;
1355   }
1356 
1357   bool need_underscore_;
1358   bool is_all_upper_;
1359   uint8 op_;
1360   int segment_len_;
1361 
1362   std::string decode_data_;
1363 };
1364 
AddCharacter(const char desired,const char input)1365 bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
1366   // If we've hit the max size, push to start a new segment.
1367   if (segment_len_ == kMaxSegmentLen) {
1368     Push();
1369   }
1370   if (segment_len_ == 0) {
1371     return AddFirst(desired, input);
1372   }
1373 
1374   // Desired and input match...
1375   if (desired == input) {
1376     // If we aren't transforming it, or we're upper casing it and it is
1377     // supposed to be uppercase; just add it to the segment.
1378     if ((op_ != kOpAllUpper) || ascii_isupper(desired)) {
1379       AddChar(desired);
1380       return true;
1381     }
1382 
1383     // Add the current segment, and start the next one.
1384     Push();
1385     return AddFirst(desired, input);
1386   }
1387 
1388   // If we need to uppercase, and everything so far has been uppercase,
1389   // promote op to AllUpper.
1390   if ((desired == ascii_toupper(input)) && is_all_upper_) {
1391     op_ = kOpAllUpper;
1392     AddChar(desired);
1393     return true;
1394   }
1395 
1396   // Give up, push and start a new segment.
1397   Push();
1398   return AddFirst(desired, input);
1399 }
1400 
1401 // If decode data can't be generated, a directive for the raw string
1402 // is used instead.
DirectDecodeString(const std::string & str)1403 std::string DirectDecodeString(const std::string& str) {
1404   std::string result;
1405   result += (char)'\0';  // Marker for full string.
1406   result += str;
1407   result += (char)'\0';  // End of string.
1408   return result;
1409 }
1410 
1411 }  // namespace
1412 
1413 // static
DecodeDataForString(const std::string & input_for_decode,const std::string & desired_output)1414 std::string TextFormatDecodeData::DecodeDataForString(
1415     const std::string& input_for_decode, const std::string& desired_output) {
1416   if (input_for_decode.empty() || desired_output.empty()) {
1417     std::cerr << "error: got empty string for making TextFormat data, input: \""
1418          << input_for_decode << "\", desired: \"" << desired_output << "\"."
1419          << std::endl;
1420     std::cerr.flush();
1421     abort();
1422   }
1423   if ((input_for_decode.find('\0') != std::string::npos) ||
1424       (desired_output.find('\0') != std::string::npos)) {
1425     std::cerr << "error: got a null char in a string for making TextFormat data,"
1426          << " input: \"" << CEscape(input_for_decode) << "\", desired: \""
1427          << CEscape(desired_output) << "\"." << std::endl;
1428     std::cerr.flush();
1429     abort();
1430   }
1431 
1432   DecodeDataBuilder builder;
1433 
1434   // Walk the output building it from the input.
1435   int x = 0;
1436   for (int y = 0; y < desired_output.size(); y++) {
1437     const char d = desired_output[y];
1438     if (d == '_') {
1439       builder.AddUnderscore();
1440       continue;
1441     }
1442 
1443     if (x >= input_for_decode.size()) {
1444       // Out of input, no way to encode it, just return a full decode.
1445       return DirectDecodeString(desired_output);
1446     }
1447     if (builder.AddCharacter(d, input_for_decode[x])) {
1448       ++x;  // Consumed one input
1449     } else {
1450       // Couldn't transform for the next character, just return a full decode.
1451       return DirectDecodeString(desired_output);
1452     }
1453   }
1454 
1455   if (x != input_for_decode.size()) {
1456     // Extra input (suffix from name sanitizing?), just return a full decode.
1457     return DirectDecodeString(desired_output);
1458   }
1459 
1460   // Add the end marker.
1461   return builder.Finish() + (char)'\0';
1462 }
1463 
1464 namespace {
1465 
1466 class Parser {
1467  public:
Parser(LineConsumer * line_consumer)1468   Parser(LineConsumer* line_consumer)
1469       : line_consumer_(line_consumer), line_(0) {}
1470 
1471   // Parses a check of input, returning success/failure.
1472   bool ParseChunk(StringPiece chunk);
1473 
1474   // Should be called to finish parsing (after all input has been provided via
1475   // ParseChunk()).  Returns success/failure.
1476   bool Finish();
1477 
last_line() const1478   int last_line() const { return line_; }
error_str() const1479   std::string error_str() const { return error_str_; }
1480 
1481  private:
1482   bool ParseLoop();
1483 
1484   LineConsumer* line_consumer_;
1485   int line_;
1486   std::string error_str_;
1487   StringPiece p_;
1488   std::string leftover_;
1489 };
1490 
ParseChunk(StringPiece chunk)1491 bool Parser::ParseChunk(StringPiece chunk) {
1492   if (!leftover_.empty()) {
1493     leftover_ += std::string(chunk);
1494     p_ = StringPiece(leftover_);
1495   } else {
1496     p_ = chunk;
1497   }
1498   bool result = ParseLoop();
1499   if (p_.empty()) {
1500     leftover_.clear();
1501   } else {
1502     leftover_ = std::string(p_);
1503   }
1504   return result;
1505 }
1506 
Finish()1507 bool Parser::Finish() {
1508   if (leftover_.empty()) {
1509     return true;
1510   }
1511   // Force a newline onto the end to finish parsing.
1512   leftover_ += "\n";
1513   p_ = StringPiece(leftover_);
1514   if (!ParseLoop()) {
1515     return false;
1516   }
1517   return p_.empty();  // Everything used?
1518 }
1519 
ParseLoop()1520 bool Parser::ParseLoop() {
1521   StringPiece line;
1522   while (ReadLine(&p_, &line)) {
1523     ++line_;
1524     RemoveComment(&line);
1525     TrimWhitespace(&line);
1526     if (line.empty()) {
1527       continue;  // Blank line.
1528     }
1529     if (!line_consumer_->ConsumeLine(line, &error_str_)) {
1530       return false;
1531     }
1532   }
1533   return true;
1534 }
1535 
1536 }  // namespace
1537 
LineConsumer()1538 LineConsumer::LineConsumer() {}
1539 
~LineConsumer()1540 LineConsumer::~LineConsumer() {}
1541 
ParseSimpleFile(const std::string & path,LineConsumer * line_consumer,std::string * out_error)1542 bool ParseSimpleFile(const std::string& path, LineConsumer* line_consumer,
1543                      std::string* out_error) {
1544   int fd;
1545   do {
1546     fd = posix::open(path.c_str(), O_RDONLY);
1547   } while (fd < 0 && errno == EINTR);
1548   if (fd < 0) {
1549     *out_error = std::string("error: Unable to open \"") + path + "\", " +
1550                  strerror(errno);
1551     return false;
1552   }
1553   io::FileInputStream file_stream(fd);
1554   file_stream.SetCloseOnDelete(true);
1555 
1556   Parser parser(line_consumer);
1557   const void* buf;
1558   int buf_len;
1559   while (file_stream.Next(&buf, &buf_len)) {
1560     if (buf_len == 0) {
1561       continue;
1562     }
1563 
1564     if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
1565       *out_error =
1566           std::string("error: ") + path +
1567           " Line " + StrCat(parser.last_line()) + ", " + parser.error_str();
1568       return false;
1569     }
1570   }
1571   return parser.Finish();
1572 }
1573 
ImportWriter(const std::string & generate_for_named_framework,const std::string & named_framework_to_proto_path_mappings_path,const std::string & runtime_import_prefix,bool include_wkt_imports)1574 ImportWriter::ImportWriter(
1575     const std::string& generate_for_named_framework,
1576     const std::string& named_framework_to_proto_path_mappings_path,
1577     const std::string& runtime_import_prefix, bool include_wkt_imports)
1578     : generate_for_named_framework_(generate_for_named_framework),
1579       named_framework_to_proto_path_mappings_path_(
1580           named_framework_to_proto_path_mappings_path),
1581       runtime_import_prefix_(runtime_import_prefix),
1582       include_wkt_imports_(include_wkt_imports),
1583       need_to_parse_mapping_file_(true) {}
1584 
~ImportWriter()1585 ImportWriter::~ImportWriter() {}
1586 
AddFile(const FileDescriptor * file,const std::string & header_extension)1587 void ImportWriter::AddFile(const FileDescriptor* file,
1588                            const std::string& header_extension) {
1589   if (IsProtobufLibraryBundledProtoFile(file)) {
1590     // The imports of the WKTs are only needed within the library itself,
1591     // in other cases, they get skipped because the generated code already
1592     // import GPBProtocolBuffers.h and hence proves them.
1593     if (include_wkt_imports_) {
1594       const std::string header_name =
1595           "GPB" + FilePathBasename(file) + header_extension;
1596       protobuf_imports_.push_back(header_name);
1597     }
1598     return;
1599   }
1600 
1601   // Lazy parse any mappings.
1602   if (need_to_parse_mapping_file_) {
1603     ParseFrameworkMappings();
1604   }
1605 
1606   std::map<std::string, std::string>::iterator proto_lookup =
1607       proto_file_to_framework_name_.find(file->name());
1608   if (proto_lookup != proto_file_to_framework_name_.end()) {
1609     other_framework_imports_.push_back(
1610         proto_lookup->second + "/" +
1611         FilePathBasename(file) + header_extension);
1612     return;
1613   }
1614 
1615   if (!generate_for_named_framework_.empty()) {
1616     other_framework_imports_.push_back(
1617         generate_for_named_framework_ + "/" +
1618         FilePathBasename(file) + header_extension);
1619     return;
1620   }
1621 
1622   other_imports_.push_back(FilePath(file) + header_extension);
1623 }
1624 
Print(io::Printer * printer) const1625 void ImportWriter::Print(io::Printer* printer) const {
1626   bool add_blank_line = false;
1627 
1628   if (!protobuf_imports_.empty()) {
1629     PrintRuntimeImports(printer, protobuf_imports_, runtime_import_prefix_);
1630     add_blank_line = true;
1631   }
1632 
1633   if (!other_framework_imports_.empty()) {
1634     if (add_blank_line) {
1635       printer->Print("\n");
1636     }
1637 
1638     for (std::vector<std::string>::const_iterator iter =
1639              other_framework_imports_.begin();
1640          iter != other_framework_imports_.end(); ++iter) {
1641       printer->Print(
1642           "#import <$header$>\n",
1643           "header", *iter);
1644     }
1645 
1646     add_blank_line = true;
1647   }
1648 
1649   if (!other_imports_.empty()) {
1650     if (add_blank_line) {
1651       printer->Print("\n");
1652     }
1653 
1654     for (std::vector<std::string>::const_iterator iter = other_imports_.begin();
1655          iter != other_imports_.end(); ++iter) {
1656       printer->Print(
1657           "#import \"$header$\"\n",
1658           "header", *iter);
1659     }
1660   }
1661 }
1662 
PrintRuntimeImports(io::Printer * printer,const std::vector<std::string> & header_to_import,const std::string & runtime_import_prefix,bool default_cpp_symbol)1663 void ImportWriter::PrintRuntimeImports(
1664     io::Printer* printer, const std::vector<std::string>& header_to_import,
1665     const std::string& runtime_import_prefix, bool default_cpp_symbol) {
1666   // Given an override, use that.
1667   if (!runtime_import_prefix.empty()) {
1668     for (const auto& header : header_to_import) {
1669       printer->Print(
1670           " #import \"$import_prefix$/$header$\"\n",
1671           "import_prefix", runtime_import_prefix,
1672           "header", header);
1673     }
1674     return;
1675   }
1676 
1677   const std::string framework_name(ProtobufLibraryFrameworkName);
1678   const std::string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
1679 
1680   if (default_cpp_symbol) {
1681     printer->Print(
1682         "// This CPP symbol can be defined to use imports that match up to the framework\n"
1683         "// imports needed when using CocoaPods.\n"
1684         "#if !defined($cpp_symbol$)\n"
1685         " #define $cpp_symbol$ 0\n"
1686         "#endif\n"
1687         "\n",
1688         "cpp_symbol", cpp_symbol);
1689   }
1690 
1691   printer->Print(
1692       "#if $cpp_symbol$\n",
1693       "cpp_symbol", cpp_symbol);
1694   for (const auto& header : header_to_import) {
1695     printer->Print(
1696         " #import <$framework_name$/$header$>\n",
1697         "framework_name", framework_name,
1698         "header", header);
1699   }
1700   printer->Print(
1701       "#else\n");
1702   for (const auto& header : header_to_import) {
1703     printer->Print(
1704         " #import \"$header$\"\n",
1705         "header", header);
1706   }
1707   printer->Print(
1708       "#endif\n");
1709 }
1710 
ParseFrameworkMappings()1711 void ImportWriter::ParseFrameworkMappings() {
1712   need_to_parse_mapping_file_ = false;
1713   if (named_framework_to_proto_path_mappings_path_.empty()) {
1714     return;  // Nothing to do.
1715   }
1716 
1717   ProtoFrameworkCollector collector(&proto_file_to_framework_name_);
1718   std::string parse_error;
1719   if (!ParseSimpleFile(named_framework_to_proto_path_mappings_path_,
1720                        &collector, &parse_error)) {
1721     std::cerr << "error parsing " << named_framework_to_proto_path_mappings_path_
1722          << " : " << parse_error << std::endl;
1723     std::cerr.flush();
1724   }
1725 }
1726 
ConsumeLine(const StringPiece & line,std::string * out_error)1727 bool ImportWriter::ProtoFrameworkCollector::ConsumeLine(
1728     const StringPiece& line, std::string* out_error) {
1729   int offset = line.find(':');
1730   if (offset == StringPiece::npos) {
1731     *out_error =
1732         std::string("Framework/proto file mapping line without colon sign: '") +
1733         std::string(line) + "'.";
1734     return false;
1735   }
1736   StringPiece framework_name = line.substr(0, offset);
1737   StringPiece proto_file_list = line.substr(offset + 1);
1738   TrimWhitespace(&framework_name);
1739 
1740   int start = 0;
1741   while (start < proto_file_list.length()) {
1742     offset = proto_file_list.find(',', start);
1743     if (offset == StringPiece::npos) {
1744       offset = proto_file_list.length();
1745     }
1746 
1747     StringPiece proto_file = proto_file_list.substr(start, offset - start);
1748     TrimWhitespace(&proto_file);
1749     if (!proto_file.empty()) {
1750       std::map<std::string, std::string>::iterator existing_entry =
1751           map_->find(string(proto_file));
1752       if (existing_entry != map_->end()) {
1753         std::cerr << "warning: duplicate proto file reference, replacing "
1754                      "framework entry for '"
1755                   << std::string(proto_file) << "' with '" << std::string(framework_name)
1756                   << "' (was '" << existing_entry->second << "')." << std::endl;
1757         std::cerr.flush();
1758       }
1759 
1760       if (proto_file.find(' ') != StringPiece::npos) {
1761         std::cerr << "note: framework mapping file had a proto file with a "
1762                      "space in, hopefully that isn't a missing comma: '"
1763                   << std::string(proto_file) << "'" << std::endl;
1764         std::cerr.flush();
1765       }
1766 
1767       (*map_)[std::string(proto_file)] = std::string(framework_name);
1768     }
1769 
1770     start = offset + 1;
1771   }
1772 
1773   return true;
1774 }
1775 
1776 }  // namespace objectivec
1777 }  // namespace compiler
1778 }  // namespace protobuf
1779 }  // namespace google
1780