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