LCOV - code coverage report
Current view: top level - third_party/protobuf/src/google/protobuf/compiler/objectivec - objectivec_helpers.cc (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 7 498 1.4 %
Date: 2015-10-10 Functions: 3 58 5.2 %

          Line data    Source code
       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             : #ifdef _MSC_VER
      32             : #include <io.h>
      33             : #else
      34             : #include <unistd.h>
      35             : #endif
      36             : #include <climits>
      37             : #include <errno.h>
      38             : #include <fcntl.h>
      39             : #include <fstream>
      40             : #include <iostream>
      41             : #include <sstream>
      42             : #include <stdlib.h>
      43             : #include <vector>
      44             : 
      45             : #include <google/protobuf/stubs/hash.h>
      46             : #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
      47             : #include <google/protobuf/io/coded_stream.h>
      48             : #include <google/protobuf/io/zero_copy_stream_impl.h>
      49             : #include <google/protobuf/descriptor.pb.h>
      50             : #include <google/protobuf/stubs/common.h>
      51             : #include <google/protobuf/stubs/strutil.h>
      52             : 
      53             : // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
      54             : // error cases, so it seems to be ok to use as a back door for errors.
      55             : 
      56             : namespace google {
      57             : namespace protobuf {
      58             : namespace compiler {
      59             : namespace objectivec {
      60             : 
      61             : namespace {
      62             : 
      63          34 : hash_set<string> MakeWordsMap(const char* const words[], size_t num_words) {
      64             :   hash_set<string> result;
      65        2669 :   for (int i = 0; i < num_words; i++) {
      66        7905 :     result.insert(words[i]);
      67             :   }
      68          34 :   return result;
      69             : }
      70             : 
      71             : const char* const kUpperSegmentsList[] = {"url", "http", "https"};
      72             : 
      73          17 : hash_set<string> kUpperSegments =
      74             :     MakeWordsMap(kUpperSegmentsList, GOOGLE_ARRAYSIZE(kUpperSegmentsList));
      75             : 
      76             : // Internal helper for name handing.
      77             : // Do not expose this outside of helpers, stick to having functions for specific
      78             : // cases (ClassName(), FieldName()), so there is always consistent suffix rules.
      79           0 : string UnderscoresToCamelCase(const string& input, bool first_capitalized) {
      80             :   vector<string> values;
      81             :   string current;
      82             : 
      83           0 :   bool last_char_was_number = false;
      84           0 :   bool last_char_was_lower = false;
      85           0 :   bool last_char_was_upper = false;
      86           0 :   for (int i = 0; i < input.size(); i++) {
      87           0 :     char c = input[i];
      88           0 :     if (ascii_isdigit(c)) {
      89           0 :       if (!last_char_was_number) {
      90           0 :         values.push_back(current);
      91             :         current = "";
      92             :       }
      93           0 :       current += c;
      94             :       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
      95             :       last_char_was_number = true;
      96           0 :     } else if (ascii_islower(c)) {
      97             :       // lowercase letter can follow a lowercase or uppercase letter
      98           0 :       if (!last_char_was_lower && !last_char_was_upper) {
      99           0 :         values.push_back(current);
     100             :         current = "";
     101             :       }
     102           0 :       current += c;  // already lower
     103             :       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
     104             :       last_char_was_lower = true;
     105           0 :     } else if (ascii_isupper(c)) {
     106           0 :       if (!last_char_was_upper) {
     107           0 :         values.push_back(current);
     108             :         current = "";
     109             :       }
     110           0 :       current += ascii_tolower(c);
     111             :       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
     112             :       last_char_was_upper = true;
     113             :     } else {
     114             :       last_char_was_number = last_char_was_lower = last_char_was_upper = false;
     115             :     }
     116             :   }
     117           0 :   values.push_back(current);
     118             : 
     119           0 :   for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
     120           0 :     string value = *i;
     121           0 :     bool all_upper = (kUpperSegments.count(value) > 0);
     122           0 :     for (int j = 0; j < value.length(); j++) {
     123           0 :       if (j == 0 || all_upper) {
     124           0 :         value[j] = ascii_toupper(value[j]);
     125             :       } else {
     126             :         // Nothing, already in lower.
     127             :       }
     128             :     }
     129           0 :     *i = value;
     130             :   }
     131             :   string result;
     132           0 :   for (vector<string>::iterator i = values.begin(); i != values.end(); ++i) {
     133           0 :     result += *i;
     134             :   }
     135           0 :   if ((result.length() != 0) && !first_capitalized) {
     136           0 :     result[0] = ascii_tolower(result[0]);
     137             :   }
     138           0 :   return result;
     139             : }
     140             : 
     141             : const char* const kReservedWordList[] = {
     142             :     // Objective C "keywords" that aren't in C
     143             :     // From
     144             :     // http://stackoverflow.com/questions/1873630/reserved-keywords-in-objective-c
     145             :     "id", "_cmd", "super", "in", "out", "inout", "bycopy", "byref", "oneway",
     146             :     "self",
     147             : 
     148             :     // C/C++ keywords (Incl C++ 0x11)
     149             :     // From http://en.cppreference.com/w/cpp/keywords
     150             :     "and", "and_eq", "alignas", "alignof", "asm", "auto", "bitand", "bitor",
     151             :     "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class",
     152             :     "compl", "const", "constexpr", "const_cast", "continue", "decltype",
     153             :     "default", "delete", "double", "dynamic_cast", "else", "enum", "explicit",
     154             :     "export", "extern ", "false", "float", "for", "friend", "goto", "if",
     155             :     "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
     156             :     "not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected",
     157             :     "public", "register", "reinterpret_cast", "return", "short", "signed",
     158             :     "sizeof", "static", "static_assert", "static_cast", "struct", "switch",
     159             :     "template", "this", "thread_local", "throw", "true", "try", "typedef",
     160             :     "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
     161             :     "volatile", "wchar_t", "while", "xor", "xor_eq",
     162             : 
     163             :     // C99 keywords
     164             :     // From
     165             :     // http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fkeyw.htm
     166             :     "restrict",
     167             : 
     168             :     // Objective-C Runtime typedefs
     169             :     // From <obc/runtime.h>
     170             :     "Category", "Ivar", "Method", "Protocol",
     171             : 
     172             :     // NSObject Methods
     173             :     // new is covered by C++ keywords.
     174             :     "description", "debugDescription", "finalize", "hash", "dealloc", "init",
     175             :     "class", "superclass", "retain", "release", "autorelease", "retainCount",
     176             :     "zone", "isProxy", "copy", "mutableCopy", "classForCoder",
     177             : 
     178             :     // GPBMessage Methods
     179             :     // Only need to add instance methods that may conflict with
     180             :     // method declared in protos. The main cases are methods
     181             :     // that take no arguments, or setFoo:/hasFoo: type methods.
     182             :     "clear", "data", "delimitedData", "descriptor", "extensionRegistry",
     183             :     "extensionsCurrentlySet", "isInitialized", "serializedSize",
     184             :     "sortedExtensionsInUse", "unknownFields",
     185             : 
     186             :     // MacTypes.h names
     187             :     "Fixed", "Fract", "Size", "LogicalAddress", "PhysicalAddress", "ByteCount",
     188             :     "ByteOffset", "Duration", "AbsoluteTime", "OptionBits", "ItemCount",
     189             :     "PBVersion", "ScriptCode", "LangCode", "RegionCode", "OSType",
     190             :     "ProcessSerialNumber", "Point", "Rect", "FixedPoint", "FixedRect", "Style",
     191             :     "StyleParameter", "StyleField", "TimeScale", "TimeBase", "TimeRecord",
     192             : };
     193             : 
     194          17 : hash_set<string> kReservedWords =
     195             :     MakeWordsMap(kReservedWordList, GOOGLE_ARRAYSIZE(kReservedWordList));
     196             : 
     197           0 : string SanitizeNameForObjC(const string& input, const string& extension) {
     198           0 :   if (kReservedWords.count(input) > 0) {
     199           0 :     return input + extension;
     200             :   }
     201           0 :   return input;
     202             : }
     203             : 
     204           0 : string NameFromFieldDescriptor(const FieldDescriptor* field) {
     205           0 :   if (field->type() == FieldDescriptor::TYPE_GROUP) {
     206           0 :     return field->message_type()->name();
     207             :   } else {
     208           0 :     return field->name();
     209             :   }
     210             : }
     211             : 
     212             : // Escape C++ trigraphs by escaping question marks to \?
     213           0 : string EscapeTrigraphs(const string& to_escape) {
     214           0 :   return StringReplace(to_escape, "?", "\\?", true);
     215             : }
     216             : 
     217           0 : void PathSplit(const string& path, string* directory, string* basename) {
     218           0 :   string::size_type last_slash = path.rfind('/');
     219           0 :   if (last_slash == string::npos) {
     220           0 :     if (directory) {
     221             :       *directory = "";
     222             :     }
     223           0 :     if (basename) {
     224             :       *basename = path;
     225             :     }
     226             :   } else {
     227           0 :     if (directory) {
     228           0 :       *directory = path.substr(0, last_slash);
     229             :     }
     230           0 :     if (basename) {
     231           0 :       *basename = path.substr(last_slash + 1);
     232             :     }
     233             :   }
     234           0 : }
     235             : 
     236           0 : bool IsSpecialName(const string& name, const string* special_names,
     237             :                    size_t count) {
     238           0 :   for (size_t i = 0; i < count; ++i) {
     239           0 :     size_t length = special_names[i].length();
     240           0 :     if (name.compare(0, length, special_names[i]) == 0) {
     241           0 :       if (name.length() > length) {
     242             :         // If name is longer than the retained_name[i] that it matches
     243             :         // the next character must be not lower case (newton vs newTon vs
     244             :         // new_ton).
     245           0 :         return !ascii_islower(name[length]);
     246             :       } else {
     247             :         return true;
     248             :       }
     249             :     }
     250             :   }
     251             :   return false;
     252             : }
     253             : 
     254             : }  // namespace
     255             : 
     256           0 : string StripProto(const string& filename) {
     257           0 :   if (HasSuffixString(filename, ".protodevel")) {
     258           0 :     return StripSuffixString(filename, ".protodevel");
     259             :   } else {
     260           0 :     return StripSuffixString(filename, ".proto");
     261             :   }
     262             : }
     263             : 
     264           0 : bool IsRetainedName(const string& name) {
     265             :   // List of prefixes from
     266             :   // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
     267             :   static const string retained_names[] = {"new", "alloc", "copy",
     268           0 :                                           "mutableCopy"};
     269             :   return IsSpecialName(name, retained_names,
     270           0 :                        sizeof(retained_names) / sizeof(retained_names[0]));
     271             : }
     272             : 
     273           0 : bool IsInitName(const string& name) {
     274           0 :   static const string init_names[] = {"init"};
     275             :   return IsSpecialName(name, init_names,
     276           0 :                        sizeof(init_names) / sizeof(init_names[0]));
     277             : }
     278             : 
     279           0 : string BaseFileName(const FileDescriptor* file) {
     280             :   string basename;
     281           0 :   PathSplit(file->name(), NULL, &basename);
     282           0 :   return basename;
     283             : }
     284             : 
     285           0 : string FileName(const FileDescriptor* file) {
     286           0 :   string path = FilePath(file);
     287             :   string basename;
     288           0 :   PathSplit(path, NULL, &basename);
     289           0 :   return basename;
     290             : }
     291             : 
     292           0 : string FilePath(const FileDescriptor* file) {
     293             :   string output;
     294             :   string basename;
     295             :   string directory;
     296           0 :   PathSplit(file->name(), &directory, &basename);
     297           0 :   if (directory.length() > 0) {
     298           0 :     output = directory + "/";
     299             :   }
     300           0 :   basename = StripProto(basename);
     301             : 
     302             :   // CamelCase to be more ObjC friendly.
     303           0 :   basename = UnderscoresToCamelCase(basename, true);
     304             : 
     305             :   output += basename;
     306           0 :   return output;
     307             : }
     308             : 
     309           0 : string FileClassPrefix(const FileDescriptor* file) {
     310             :   // Default is empty string, no need to check has_objc_class_prefix.
     311           0 :   string result = file->options().objc_class_prefix();
     312           0 :   return result;
     313             : }
     314             : 
     315           0 : string FileClassName(const FileDescriptor* file) {
     316           0 :   string name = FileClassPrefix(file);
     317           0 :   name += UnderscoresToCamelCase(StripProto(BaseFileName(file)), true);
     318             :   name += "Root";
     319             :   // There aren't really any reserved words that end in "Root", but playing
     320             :   // it safe and checking.
     321           0 :   return SanitizeNameForObjC(name, "_RootClass");
     322             : }
     323             : 
     324           0 : string ClassNameWorker(const Descriptor* descriptor) {
     325             :   string name;
     326           0 :   if (descriptor->containing_type() != NULL) {
     327           0 :     name = ClassNameWorker(descriptor->containing_type());
     328             :     name += "_";
     329             :   }
     330           0 :   return name + descriptor->name();
     331             : }
     332             : 
     333           0 : string ClassNameWorker(const EnumDescriptor* descriptor) {
     334             :   string name;
     335           0 :   if (descriptor->containing_type() != NULL) {
     336           0 :     name = ClassNameWorker(descriptor->containing_type());
     337             :     name += "_";
     338             :   }
     339           0 :   return name + descriptor->name();
     340             : }
     341             : 
     342           0 : string ClassName(const Descriptor* descriptor) {
     343             :   // 1. Message names are used as is (style calls for CamelCase, trust it).
     344             :   // 2. Check for reserved word at the very end and then suffix things.
     345           0 :   string prefix = FileClassPrefix(descriptor->file());
     346           0 :   string name = ClassNameWorker(descriptor);
     347           0 :   return SanitizeNameForObjC(prefix + name, "_Class");
     348             : }
     349             : 
     350           0 : string EnumName(const EnumDescriptor* descriptor) {
     351             :   // 1. Enum names are used as is (style calls for CamelCase, trust it).
     352             :   // 2. Check for reserved word at the every end and then suffix things.
     353             :   //      message Fixed {
     354             :   //        message Size {...}
     355             :   //        enum Mumble {...}
     356             :   //      ...
     357             :   //      }
     358             :   //    yields Fixed_Class, Fixed_Size.
     359           0 :   string name = FileClassPrefix(descriptor->file());
     360           0 :   name += ClassNameWorker(descriptor);
     361           0 :   return SanitizeNameForObjC(name, "_Enum");
     362             : }
     363             : 
     364           0 : string EnumValueName(const EnumValueDescriptor* descriptor) {
     365             :   // Because of the Switch enum compatibility, the name on the enum has to have
     366             :   // the suffix handing, so it slightly diverges from how nested classes work.
     367             :   //   enum Fixed {
     368             :   //     FOO = 1
     369             :   //   }
     370             :   // yields Fixed_Enum and Fixed_Enum_Foo (not Fixed_Foo).
     371           0 :   const string& class_name = EnumName(descriptor->type());
     372           0 :   const string& value_str = UnderscoresToCamelCase(descriptor->name(), true);
     373           0 :   const string& name = class_name + "_" + value_str;
     374             :   // There aren't really any reserved words with an underscore and a leading
     375             :   // capital letter, but playing it safe and checking.
     376           0 :   return SanitizeNameForObjC(name, "_Value");
     377             : }
     378             : 
     379           0 : string EnumValueShortName(const EnumValueDescriptor* descriptor) {
     380             :   // Enum value names (EnumValueName above) are the enum name turned into
     381             :   // a class name and then the value name is CamelCased and concatenated; the
     382             :   // whole thing then gets sanitized for reserved words.
     383             :   // The "short name" is intended to be the final leaf, the value name; but
     384             :   // you can't simply send that off to sanitize as that could result in it
     385             :   // getting modified when the full name didn't.  For example enum
     386             :   // "StorageModes" has a value "retain".  So the full name is
     387             :   // "StorageModes_Retain", but if we sanitize "retain" it would become
     388             :   // "RetainValue".
     389             :   // So the right way to get the short name is to take the full enum name
     390             :   // and then strip off the enum name (leaving the value name and anything
     391             :   // done by sanitize).
     392           0 :   const string& class_name = EnumName(descriptor->type());
     393           0 :   const string& long_name_prefix = class_name + "_";
     394           0 :   const string& long_name = EnumValueName(descriptor);
     395           0 :   return StripPrefixString(long_name, long_name_prefix);
     396             : }
     397             : 
     398           0 : string UnCamelCaseEnumShortName(const string& name) {
     399             :   string result;
     400           0 :   for (int i = 0; i < name.size(); i++) {
     401           0 :     char c = name[i];
     402           0 :     if (i > 0 && ascii_isupper(c)) {
     403             :       result += '_';
     404             :     }
     405           0 :     result += ascii_toupper(c);
     406             :   }
     407           0 :   return result;
     408             : }
     409             : 
     410           0 : string ExtensionMethodName(const FieldDescriptor* descriptor) {
     411           0 :   const string& name = NameFromFieldDescriptor(descriptor);
     412           0 :   const string& result = UnderscoresToCamelCase(name, false);
     413           0 :   return SanitizeNameForObjC(result, "_Extension");
     414             : }
     415             : 
     416           0 : string FieldName(const FieldDescriptor* field) {
     417           0 :   const string& name = NameFromFieldDescriptor(field);
     418           0 :   string result = UnderscoresToCamelCase(name, false);
     419           0 :   if (field->is_repeated() && !field->is_map()) {
     420             :     // Add "Array" before do check for reserved worlds.
     421             :     result += "Array";
     422             :   } else {
     423             :     // If it wasn't repeated, but ends in "Array", force on the _p suffix.
     424           0 :     if (HasSuffixString(result, "Array")) {
     425             :       result += "_p";
     426             :     }
     427             :   }
     428           0 :   return SanitizeNameForObjC(result, "_p");
     429             : }
     430             : 
     431           0 : string FieldNameCapitalized(const FieldDescriptor* field) {
     432             :   // Want the same suffix handling, so upcase the first letter of the other
     433             :   // name.
     434           0 :   string result = FieldName(field);
     435           0 :   if (result.length() > 0) {
     436           0 :     result[0] = ascii_toupper(result[0]);
     437             :   }
     438           0 :   return result;
     439             : }
     440             : 
     441           0 : string OneofEnumName(const OneofDescriptor* descriptor) {
     442           0 :   const Descriptor* fieldDescriptor = descriptor->containing_type();
     443           0 :   string name = ClassName(fieldDescriptor);
     444           0 :   name += "_" + UnderscoresToCamelCase(descriptor->name(), true) + "_OneOfCase";
     445             :   // No sanitize needed because the OS never has names that end in _OneOfCase.
     446           0 :   return name;
     447             : }
     448             : 
     449           0 : string OneofName(const OneofDescriptor* descriptor) {
     450           0 :   string name = UnderscoresToCamelCase(descriptor->name(), false);
     451             :   // No sanitize needed because it gets OneOfCase added and that shouldn't
     452             :   // ever conflict.
     453           0 :   return name;
     454             : }
     455             : 
     456           0 : string OneofNameCapitalized(const OneofDescriptor* descriptor) {
     457             :   // Use the common handling and then up-case the first letter.
     458           0 :   string result = OneofName(descriptor);
     459           0 :   if (result.length() > 0) {
     460           0 :     result[0] = ascii_toupper(result[0]);
     461             :   }
     462           0 :   return result;
     463             : }
     464             : 
     465           0 : string UnCamelCaseFieldName(const string& name, const FieldDescriptor* field) {
     466           0 :   string worker(name);
     467           0 :   if (HasSuffixString(worker, "_p")) {
     468           0 :     worker = StripSuffixString(worker, "_p");
     469             :   }
     470           0 :   if (field->is_repeated() && HasSuffixString(worker, "Array")) {
     471           0 :     worker = StripSuffixString(worker, "Array");
     472             :   }
     473           0 :   if (field->type() == FieldDescriptor::TYPE_GROUP) {
     474           0 :     if (worker.length() > 0) {
     475           0 :       if (ascii_islower(worker[0])) {
     476           0 :         worker[0] = ascii_toupper(worker[0]);
     477             :       }
     478             :     }
     479           0 :     return worker;
     480             :   } else {
     481             :     string result;
     482           0 :     for (int i = 0; i < worker.size(); i++) {
     483           0 :       char c = worker[i];
     484           0 :       if (ascii_isupper(c)) {
     485           0 :         if (i > 0) {
     486             :           result += '_';
     487             :         }
     488           0 :         result += ascii_tolower(c);
     489             :       } else {
     490           0 :         result += c;
     491             :       }
     492             :     }
     493           0 :     return result;
     494             :   }
     495             : }
     496             : 
     497           0 : string GetCapitalizedType(const FieldDescriptor* field) {
     498           0 :   switch (field->type()) {
     499             :     case FieldDescriptor::TYPE_INT32:
     500           0 :       return "Int32";
     501             :     case FieldDescriptor::TYPE_UINT32:
     502           0 :       return "UInt32";
     503             :     case FieldDescriptor::TYPE_SINT32:
     504           0 :       return "SInt32";
     505             :     case FieldDescriptor::TYPE_FIXED32:
     506           0 :       return "Fixed32";
     507             :     case FieldDescriptor::TYPE_SFIXED32:
     508           0 :       return "SFixed32";
     509             :     case FieldDescriptor::TYPE_INT64:
     510           0 :       return "Int64";
     511             :     case FieldDescriptor::TYPE_UINT64:
     512           0 :       return "UInt64";
     513             :     case FieldDescriptor::TYPE_SINT64:
     514           0 :       return "SInt64";
     515             :     case FieldDescriptor::TYPE_FIXED64:
     516           0 :       return "Fixed64";
     517             :     case FieldDescriptor::TYPE_SFIXED64:
     518           0 :       return "SFixed64";
     519             :     case FieldDescriptor::TYPE_FLOAT:
     520           0 :       return "Float";
     521             :     case FieldDescriptor::TYPE_DOUBLE:
     522           0 :       return "Double";
     523             :     case FieldDescriptor::TYPE_BOOL:
     524           0 :       return "Bool";
     525             :     case FieldDescriptor::TYPE_STRING:
     526           0 :       return "String";
     527             :     case FieldDescriptor::TYPE_BYTES:
     528           0 :       return "Bytes";
     529             :     case FieldDescriptor::TYPE_ENUM:
     530           0 :       return "Enum";
     531             :     case FieldDescriptor::TYPE_GROUP:
     532           0 :       return "Group";
     533             :     case FieldDescriptor::TYPE_MESSAGE:
     534           0 :       return "Message";
     535             :   }
     536             : 
     537             :   // Some compilers report reaching end of function even though all cases of
     538             :   // the enum are handed in the switch.
     539           0 :   GOOGLE_LOG(FATAL) << "Can't get here.";
     540           0 :   return NULL;
     541             : }
     542             : 
     543           0 : ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type) {
     544           0 :   switch (field_type) {
     545             :     case FieldDescriptor::TYPE_INT32:
     546             :     case FieldDescriptor::TYPE_SINT32:
     547             :     case FieldDescriptor::TYPE_SFIXED32:
     548             :       return OBJECTIVECTYPE_INT32;
     549             : 
     550             :     case FieldDescriptor::TYPE_UINT32:
     551             :     case FieldDescriptor::TYPE_FIXED32:
     552           0 :       return OBJECTIVECTYPE_UINT32;
     553             : 
     554             :     case FieldDescriptor::TYPE_INT64:
     555             :     case FieldDescriptor::TYPE_SINT64:
     556             :     case FieldDescriptor::TYPE_SFIXED64:
     557           0 :       return OBJECTIVECTYPE_INT64;
     558             : 
     559             :     case FieldDescriptor::TYPE_UINT64:
     560             :     case FieldDescriptor::TYPE_FIXED64:
     561           0 :       return OBJECTIVECTYPE_UINT64;
     562             : 
     563             :     case FieldDescriptor::TYPE_FLOAT:
     564           0 :       return OBJECTIVECTYPE_FLOAT;
     565             : 
     566             :     case FieldDescriptor::TYPE_DOUBLE:
     567           0 :       return OBJECTIVECTYPE_DOUBLE;
     568             : 
     569             :     case FieldDescriptor::TYPE_BOOL:
     570           0 :       return OBJECTIVECTYPE_BOOLEAN;
     571             : 
     572             :     case FieldDescriptor::TYPE_STRING:
     573           0 :       return OBJECTIVECTYPE_STRING;
     574             : 
     575             :     case FieldDescriptor::TYPE_BYTES:
     576           0 :       return OBJECTIVECTYPE_DATA;
     577             : 
     578             :     case FieldDescriptor::TYPE_ENUM:
     579           0 :       return OBJECTIVECTYPE_ENUM;
     580             : 
     581             :     case FieldDescriptor::TYPE_GROUP:
     582             :     case FieldDescriptor::TYPE_MESSAGE:
     583           0 :       return OBJECTIVECTYPE_MESSAGE;
     584             :   }
     585             : 
     586             :   // Some compilers report reaching end of function even though all cases of
     587             :   // the enum are handed in the switch.
     588           0 :   GOOGLE_LOG(FATAL) << "Can't get here.";
     589           0 :   return OBJECTIVECTYPE_INT32;
     590             : }
     591             : 
     592           0 : bool IsPrimitiveType(const FieldDescriptor* field) {
     593           0 :   ObjectiveCType type = GetObjectiveCType(field);
     594           0 :   switch (type) {
     595             :     case OBJECTIVECTYPE_INT32:
     596             :     case OBJECTIVECTYPE_UINT32:
     597             :     case OBJECTIVECTYPE_INT64:
     598             :     case OBJECTIVECTYPE_UINT64:
     599             :     case OBJECTIVECTYPE_FLOAT:
     600             :     case OBJECTIVECTYPE_DOUBLE:
     601             :     case OBJECTIVECTYPE_BOOLEAN:
     602             :     case OBJECTIVECTYPE_ENUM:
     603             :       return true;
     604             :       break;
     605             :     default:
     606           0 :       return false;
     607             :   }
     608             : }
     609             : 
     610           0 : bool IsReferenceType(const FieldDescriptor* field) {
     611           0 :   return !IsPrimitiveType(field);
     612             : }
     613             : 
     614           0 : static string HandleExtremeFloatingPoint(string val, bool add_float_suffix) {
     615           0 :   if (val == "nan") {
     616           0 :     return "NAN";
     617           0 :   } else if (val == "inf") {
     618           0 :     return "INFINITY";
     619           0 :   } else if (val == "-inf") {
     620           0 :     return "-INFINITY";
     621             :   } else {
     622             :     // float strings with ., e or E need to have f appended
     623           0 :     if (add_float_suffix &&
     624           0 :         (val.find(".") != string::npos || val.find("e") != string::npos ||
     625           0 :          val.find("E") != string::npos)) {
     626             :       val += "f";
     627             :     }
     628           0 :     return val;
     629             :   }
     630             : }
     631             : 
     632           0 : string GPBGenericValueFieldName(const FieldDescriptor* field) {
     633             :   // Returns the field within the GPBGenericValue union to use for the given
     634             :   // field.
     635           0 :   if (field->is_repeated()) {
     636           0 :       return "valueMessage";
     637             :   }
     638           0 :   switch (field->cpp_type()) {
     639             :     case FieldDescriptor::CPPTYPE_INT32:
     640           0 :       return "valueInt32";
     641             :     case FieldDescriptor::CPPTYPE_UINT32:
     642           0 :       return "valueUInt32";
     643             :     case FieldDescriptor::CPPTYPE_INT64:
     644           0 :       return "valueInt64";
     645             :     case FieldDescriptor::CPPTYPE_UINT64:
     646           0 :       return "valueUInt64";
     647             :     case FieldDescriptor::CPPTYPE_FLOAT:
     648           0 :       return "valueFloat";
     649             :     case FieldDescriptor::CPPTYPE_DOUBLE:
     650           0 :       return "valueDouble";
     651             :     case FieldDescriptor::CPPTYPE_BOOL:
     652           0 :       return "valueBool";
     653             :     case FieldDescriptor::CPPTYPE_STRING:
     654           0 :       if (field->type() == FieldDescriptor::TYPE_BYTES) {
     655           0 :         return "valueData";
     656             :       } else {
     657           0 :         return "valueString";
     658             :       }
     659             :     case FieldDescriptor::CPPTYPE_ENUM:
     660           0 :       return "valueEnum";
     661             :     case FieldDescriptor::CPPTYPE_MESSAGE:
     662           0 :       return "valueMessage";
     663             :   }
     664             : 
     665             :   // Some compilers report reaching end of function even though all cases of
     666             :   // the enum are handed in the switch.
     667           0 :   GOOGLE_LOG(FATAL) << "Can't get here.";
     668           0 :   return NULL;
     669             : }
     670             : 
     671             : 
     672           0 : string DefaultValue(const FieldDescriptor* field) {
     673             :   // Repeated fields don't have defaults.
     674           0 :   if (field->is_repeated()) {
     675           0 :     return "nil";
     676             :   }
     677             : 
     678             :   // Switch on cpp_type since we need to know which default_value_* method
     679             :   // of FieldDescriptor to call.
     680           0 :   switch (field->cpp_type()) {
     681             :     case FieldDescriptor::CPPTYPE_INT32:
     682             :       // gcc and llvm reject the decimal form of kint32min and kint64min.
     683           0 :       if (field->default_value_int32() == INT_MIN) {
     684           0 :         return "-0x80000000";
     685             :       }
     686           0 :       return SimpleItoa(field->default_value_int32());
     687             :     case FieldDescriptor::CPPTYPE_UINT32:
     688           0 :       return SimpleItoa(field->default_value_uint32()) + "U";
     689             :     case FieldDescriptor::CPPTYPE_INT64:
     690             :       // gcc and llvm reject the decimal form of kint32min and kint64min.
     691           0 :       if (field->default_value_int64() == LLONG_MIN) {
     692           0 :         return "-0x8000000000000000LL";
     693             :       }
     694           0 :       return SimpleItoa(field->default_value_int64()) + "LL";
     695             :     case FieldDescriptor::CPPTYPE_UINT64:
     696           0 :       return SimpleItoa(field->default_value_uint64()) + "ULL";
     697             :     case FieldDescriptor::CPPTYPE_DOUBLE:
     698             :       return HandleExtremeFloatingPoint(
     699           0 :           SimpleDtoa(field->default_value_double()), false);
     700             :     case FieldDescriptor::CPPTYPE_FLOAT:
     701             :       return HandleExtremeFloatingPoint(
     702           0 :           SimpleFtoa(field->default_value_float()), true);
     703             :     case FieldDescriptor::CPPTYPE_BOOL:
     704           0 :       return field->default_value_bool() ? "YES" : "NO";
     705             :     case FieldDescriptor::CPPTYPE_STRING: {
     706           0 :       const bool has_default_value = field->has_default_value();
     707           0 :       const string& default_string = field->default_value_string();
     708           0 :       if (!has_default_value || default_string.length() == 0) {
     709             :         // If the field is defined as being the empty string,
     710             :         // then we will just assign to nil, as the empty string is the
     711             :         // default for both strings and data.
     712           0 :         return "nil";
     713             :       }
     714           0 :       if (field->type() == FieldDescriptor::TYPE_BYTES) {
     715             :         // We want constant fields in our data structures so we can
     716             :         // declare them as static. To achieve this we cheat and stuff
     717             :         // a escaped c string (prefixed with a length) into the data
     718             :         // field, and cast it to an (NSData*) so it will compile.
     719             :         // The runtime library knows how to handle it.
     720             : 
     721             :         // Must convert to a standard byte order for packing length into
     722             :         // a cstring.
     723           0 :         uint32 length = ghtonl(default_string.length());
     724           0 :         string bytes((const char*)&length, sizeof(length));
     725           0 :         bytes.append(default_string);
     726           0 :         return "(NSData*)\"" + CEscape(bytes) + "\"";
     727             :       } else {
     728           0 :         return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\"";
     729             :       }
     730             :     }
     731             :     case FieldDescriptor::CPPTYPE_ENUM:
     732           0 :       return EnumValueName(field->default_value_enum());
     733             :     case FieldDescriptor::CPPTYPE_MESSAGE:
     734           0 :       return "nil";
     735             :   }
     736             : 
     737             :   // Some compilers report reaching end of function even though all cases of
     738             :   // the enum are handed in the switch.
     739           0 :   GOOGLE_LOG(FATAL) << "Can't get here.";
     740           0 :   return NULL;
     741             : }
     742             : 
     743           0 : string BuildFlagsString(const vector<string>& strings) {
     744           0 :   if (strings.size() == 0) {
     745           0 :     return "0";
     746             :   }
     747             :   string string;
     748           0 :   for (size_t i = 0; i != strings.size(); ++i) {
     749           0 :     if (i > 0) {
     750           0 :       string.append(" | ");
     751             :     }
     752           0 :     string.append(strings[i]);
     753             :   }
     754           0 :   return string;
     755             : }
     756             : 
     757           0 : string BuildCommentsString(const SourceLocation& location) {
     758           0 :   const string& comments = location.leading_comments.empty()
     759             :                                ? location.trailing_comments
     760           0 :                                : location.leading_comments;
     761             :   vector<string> lines;
     762           0 :   SplitStringAllowEmpty(comments, "\n", &lines);
     763           0 :   while (!lines.empty() && lines.back().empty()) {
     764           0 :     lines.pop_back();
     765             :   }
     766           0 :   string prefix("//");
     767           0 :   string suffix("\n");
     768             :   string final_comments;
     769           0 :   for (int i = 0; i < lines.size(); i++) {
     770             :     // We use $ for delimiters, so replace comments with dollars with
     771             :     // html escaped version.
     772             :     // None of the other compilers handle this (as of this writing) but we
     773             :     // ran into it once, so just to be safe.
     774             :     final_comments +=
     775           0 :         prefix + StringReplace(lines[i], "$", "&#36;", true) + suffix;
     776             :   }
     777           0 :   return final_comments;
     778             : }
     779             : 
     780             : namespace {
     781             : 
     782             : // Internal helper class that parses the expected package to prefix mappings
     783             : // file.
     784           0 : class Parser {
     785             :  public:
     786             :   Parser(map<string, string>* inout_package_to_prefix_map)
     787           0 :       : prefix_map_(inout_package_to_prefix_map), line_(0) {}
     788             : 
     789             :   // Parses a check of input, returning success/failure.
     790             :   bool ParseChunk(StringPiece chunk);
     791             : 
     792             :   // Should be called to finish parsing (after all input has been provided via
     793             :   // ParseChunk()).  Returns success/failure.
     794             :   bool Finish();
     795             : 
     796             :   int last_line() const { return line_; }
     797           0 :   string error_str() const { return error_str_; }
     798             : 
     799             :  private:
     800             :   bool ParseLoop();
     801             : 
     802             :   map<string, string>* prefix_map_;
     803             :   int line_;
     804             :   string error_str_;
     805             :   StringPiece p_;
     806             :   string leftover_;
     807             : };
     808             : 
     809           0 : bool Parser::ParseChunk(StringPiece chunk) {
     810           0 :   if (!leftover_.empty()) {
     811           0 :     chunk.AppendToString(&leftover_);
     812           0 :     p_ = StringPiece(leftover_);
     813             :   } else {
     814           0 :     p_ = chunk;
     815             :   }
     816           0 :   bool result = ParseLoop();
     817           0 :   if (p_.empty()) {
     818           0 :     leftover_.clear();
     819             :   } else {
     820           0 :     leftover_ = p_.ToString();
     821             :   }
     822           0 :   return result;
     823             : }
     824             : 
     825           0 : bool Parser::Finish() {
     826           0 :   if (leftover_.empty()) {
     827             :     return true;
     828             :   }
     829             :   // Force a newline onto the end to finish parsing.
     830           0 :   p_ = StringPiece(leftover_ + "\n");
     831           0 :   if (!ParseLoop()) {
     832             :     return false;
     833             :   }
     834           0 :   return p_.empty();  // Everything used?
     835             : }
     836             : 
     837           0 : static bool ascii_isnewline(char c) { return c == '\n' || c == '\r'; }
     838             : 
     839           0 : bool ReadLine(StringPiece* input, StringPiece* line) {
     840           0 :   for (int len = 0; len < input->size(); ++len) {
     841           0 :     if (ascii_isnewline((*input)[len])) {
     842           0 :       *line = StringPiece(input->data(), len);
     843           0 :       ++len;  // advance over the newline
     844           0 :       *input = StringPiece(input->data() + len, input->size() - len);
     845           0 :       return true;
     846             :     }
     847             :   }
     848             :   return false;  // Ran out of input with no newline.
     849             : }
     850             : 
     851           0 : void TrimWhitespace(StringPiece* input) {
     852           0 :   while (!input->empty() && ascii_isspace(*input->data())) {
     853             :     input->remove_prefix(1);
     854             :   }
     855           0 :   while (!input->empty() && ascii_isspace((*input)[input->length() - 1])) {
     856           0 :     input->remove_suffix(1);
     857             :   }
     858           0 : }
     859             : 
     860           0 : void RemoveComment(StringPiece* input) {
     861           0 :   int offset = input->find('#');
     862           0 :   if (offset != StringPiece::npos) {
     863           0 :     input->remove_suffix(input->length() - offset);
     864             :   }
     865           0 : }
     866             : 
     867           0 : bool Parser::ParseLoop() {
     868             :   StringPiece line;
     869           0 :   while (ReadLine(&p_, &line)) {
     870           0 :     ++line_;
     871           0 :     RemoveComment(&line);
     872           0 :     TrimWhitespace(&line);
     873           0 :     if (line.size() == 0) {
     874           0 :       continue;  // Blank line.
     875             :     }
     876           0 :     int offset = line.find('=');
     877           0 :     if (offset == StringPiece::npos) {
     878           0 :       error_str_ =
     879           0 :           string("Line without equal sign: '") + line.ToString() + "'.";
     880           0 :       return false;
     881             :     }
     882           0 :     StringPiece package(line, 0, offset);
     883           0 :     StringPiece prefix(line, offset + 1, line.length() - offset - 1);
     884           0 :     TrimWhitespace(&package);
     885           0 :     TrimWhitespace(&prefix);
     886             :     // Don't really worry about error checking the the package/prefix for
     887             :     // being valid.  Assume the file is validated when it is created/edited.
     888           0 :     (*prefix_map_)[package.ToString()] = prefix.ToString();
     889             :   }
     890             :   return true;
     891             : }
     892             : 
     893           0 : bool LoadExpectedPackagePrefixes(map<string, string>* prefix_map,
     894             :                                  string* out_expect_file_path,
     895             :                                  string* out_error) {
     896           0 :   const char* file_path = getenv("GPB_OBJC_EXPECTED_PACKAGE_PREFIXES");
     897           0 :   if (file_path == NULL) {
     898             :     return true;
     899             :   }
     900             : 
     901             :   int fd;
     902           0 :   do {
     903           0 :     fd = open(file_path, O_RDONLY);
     904           0 :   } while (fd < 0 && errno == EINTR);
     905           0 :   if (fd < 0) {
     906             :     *out_error =
     907           0 :         string(file_path) + ":0:0: error: Unable to open." + strerror(errno);
     908           0 :     return false;
     909             :   }
     910           0 :   io::FileInputStream file_stream(fd);
     911             :   file_stream.SetCloseOnDelete(true);
     912             :   *out_expect_file_path = file_path;
     913             : 
     914           0 :   Parser parser(prefix_map);
     915             :   const void* buf;
     916             :   int buf_len;
     917           0 :   while (file_stream.Next(&buf, &buf_len)) {
     918           0 :     if (buf_len == 0) {
     919             :       continue;
     920             :     }
     921             : 
     922           0 :     if (!parser.ParseChunk(StringPiece(static_cast<const char*>(buf), buf_len))) {
     923           0 :       *out_error = string(file_path) + ":" + SimpleItoa(parser.last_line()) +
     924           0 :                    ":0: error: " + parser.error_str();
     925           0 :       return false;
     926             :     }
     927             :   }
     928           0 :   return parser.Finish();
     929             : }
     930             : 
     931             : }  // namespace
     932             : 
     933           0 : bool ValidateObjCClassPrefix(const FileDescriptor* file, string* out_error) {
     934           0 :   const string prefix = file->options().objc_class_prefix();
     935           0 :   const string package = file->package();
     936             : 
     937             :   // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
     938             :   // error cases, so it seems to be ok to use as a back door for warnings.
     939             : 
     940             :   // First Check: Warning - if there is a prefix, ensure it is is a reasonable
     941             :   // value according to Apple's rules.
     942           0 :   if (prefix.length()) {
     943           0 :     if (!ascii_isupper(prefix[0])) {
     944             :       cerr << endl
     945           0 :            << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
     946           0 :            << prefix << "\";' in '" << file->name() << "';"
     947           0 :            << " it should start with a capital letter." << endl;
     948           0 :       cerr.flush();
     949             :     }
     950           0 :     if (prefix.length() < 3) {
     951             :       cerr << endl
     952           0 :            << "protoc:0: warning: Invalid 'option objc_class_prefix = \""
     953           0 :            << prefix << "\";' in '" << file->name() << "';"
     954           0 :            << " Apple recommends they should be at least 3 characters long."
     955             :            << endl;
     956           0 :       cerr.flush();
     957             :     }
     958             :   }
     959             : 
     960             :   // Load any expected package prefixes to validate against those.
     961             :   map<string, string> expected_package_prefixes;
     962             :   string expect_file_path;
     963           0 :   if (!LoadExpectedPackagePrefixes(&expected_package_prefixes,
     964           0 :                                    &expect_file_path, out_error)) {
     965             :     return false;
     966             :   }
     967             : 
     968             :   // If there are no expected prefixes, out of here.
     969           0 :   if (expected_package_prefixes.size() == 0) {
     970             :     return true;
     971             :   }
     972             : 
     973             :   // Second Check: Error - See if there was an expected prefix for the package
     974             :   // and report if it doesn't match.
     975             :   map<string, string>::iterator package_match =
     976           0 :       expected_package_prefixes.find(package);
     977           0 :   if (package_match != expected_package_prefixes.end()) {
     978             :     // There was an entry, and...
     979           0 :     if (package_match->second == prefix) {
     980             :       // ...it matches.  All good, out of here!
     981             :       return true;
     982             :     } else {
     983             :       // ...it didn't match!
     984           0 :       *out_error = "protoc:0: error: Expected 'option objc_class_prefix = \"" +
     985           0 :                    package_match->second + "\";' in '" + file->name() + "'";
     986           0 :       if (prefix.length()) {
     987           0 :         *out_error += "; but found '" + prefix + "' instead";
     988             :       }
     989             :       *out_error += ".";
     990             :       return false;
     991             :     }
     992             :   }
     993             : 
     994             :   // Third Check: Error - If there was a prefix make sure it wasn't expected
     995             :   // for a different package instead (overlap is allowed, but it has to be
     996             :   // listed as an expected overlap).
     997           0 :   if (prefix.length()) {
     998           0 :     for (map<string, string>::iterator i = expected_package_prefixes.begin();
     999           0 :          i != expected_package_prefixes.end(); ++i) {
    1000           0 :       if (i->second == prefix) {
    1001             :         *out_error =
    1002           0 :             "protoc:0: error: Found 'option objc_class_prefix = \"" + prefix +
    1003           0 :             "\";' in '" + file->name() +
    1004           0 :             "'; that prefix is already used for 'package " + i->first +
    1005           0 :             ";'. It can only be reused by listing it in the expected file (" +
    1006           0 :             expect_file_path + ").";
    1007             :         return false;  // Only report first usage of the prefix.
    1008             :       }
    1009             :     }
    1010             :   }
    1011             : 
    1012             :   // Fourth Check: Warning - If there was a prefix, and it wasn't expected,
    1013             :   // issue a warning suggesting it gets added to the file.
    1014           0 :   if (prefix.length()) {
    1015             :     cerr << endl
    1016           0 :          << "protoc:0: warning: Found 'option objc_class_prefix = \"" << prefix
    1017           0 :          << "\";' in '" << file->name() << "';"
    1018           0 :          << " should you add it to the expected prefixes file ("
    1019           0 :          << expect_file_path << ")?" << endl;
    1020           0 :     cerr.flush();
    1021             :   }
    1022             : 
    1023             :   return true;
    1024             : }
    1025             : 
    1026           0 : void TextFormatDecodeData::AddString(int32 key,
    1027             :                                      const string& input_for_decode,
    1028             :                                      const string& desired_output) {
    1029           0 :   for (vector<DataEntry>::const_iterator i = entries_.begin();
    1030           0 :        i != entries_.end(); ++i) {
    1031           0 :     if (i->first == key) {
    1032           0 :       cerr << "error: duplicate key (" << key
    1033           0 :            << ") making TextFormat data, input: \"" << input_for_decode
    1034           0 :            << "\", desired: \"" << desired_output << "\"." << endl;
    1035           0 :       cerr.flush();
    1036           0 :       abort();
    1037             :     }
    1038             :   }
    1039             : 
    1040             :   const string& data = TextFormatDecodeData::DecodeDataForString(
    1041           0 :       input_for_decode, desired_output);
    1042           0 :   entries_.push_back(DataEntry(key, data));
    1043           0 : }
    1044             : 
    1045           0 : string TextFormatDecodeData::Data() const {
    1046           0 :   ostringstream data_stringstream;
    1047             : 
    1048           0 :   if (num_entries() > 0) {
    1049           0 :     io::OstreamOutputStream data_outputstream(&data_stringstream);
    1050           0 :     io::CodedOutputStream output_stream(&data_outputstream);
    1051             : 
    1052           0 :     output_stream.WriteVarint32(num_entries());
    1053           0 :     for (vector<DataEntry>::const_iterator i = entries_.begin();
    1054           0 :          i != entries_.end(); ++i) {
    1055           0 :       output_stream.WriteVarint32(i->first);
    1056           0 :       output_stream.WriteString(i->second);
    1057           0 :     }
    1058             :   }
    1059             : 
    1060           0 :   data_stringstream.flush();
    1061           0 :   return data_stringstream.str();
    1062             : }
    1063             : 
    1064             : namespace {
    1065             : 
    1066             : // Helper to build up the decode data for a string.
    1067           0 : class DecodeDataBuilder {
    1068             :  public:
    1069           0 :   DecodeDataBuilder() { Reset(); }
    1070             : 
    1071             :   bool AddCharacter(const char desired, const char input);
    1072             :   void AddUnderscore() {
    1073           0 :     Push();
    1074           0 :     need_underscore_ = true;
    1075             :   }
    1076             :   string Finish() {
    1077           0 :     Push();
    1078           0 :     return decode_data_;
    1079             :   }
    1080             : 
    1081             :  private:
    1082             :   static const uint8 kAddUnderscore = 0x80;
    1083             : 
    1084             :   static const uint8 kOpAsIs        = 0x00;
    1085             :   static const uint8 kOpFirstUpper  = 0x40;
    1086             :   static const uint8 kOpFirstLower  = 0x20;
    1087             :   static const uint8 kOpAllUpper    = 0x60;
    1088             : 
    1089             :   static const int kMaxSegmentLen     = 0x1f;
    1090             : 
    1091             :   void AddChar(const char desired) {
    1092           0 :     ++segment_len_;
    1093           0 :     is_all_upper_ &= ascii_isupper(desired);
    1094             :   }
    1095             : 
    1096           0 :   void Push() {
    1097           0 :     uint8 op = (op_ | segment_len_);
    1098           0 :     if (need_underscore_) op |= kAddUnderscore;
    1099           0 :     if (op != 0) {
    1100           0 :       decode_data_ += (char)op;
    1101             :     }
    1102             :     Reset();
    1103           0 :   }
    1104             : 
    1105           0 :   bool AddFirst(const char desired, const char input) {
    1106           0 :     if (desired == input) {
    1107           0 :       op_ = kOpAsIs;
    1108           0 :     } else if (desired == ascii_toupper(input)) {
    1109           0 :       op_ = kOpFirstUpper;
    1110           0 :     } else if (desired == ascii_tolower(input)) {
    1111           0 :       op_ = kOpFirstLower;
    1112             :     } else {
    1113             :       // Can't be transformed to match.
    1114             :       return false;
    1115             :     }
    1116           0 :     AddChar(desired);
    1117           0 :     return true;
    1118             :   }
    1119             : 
    1120             :   void Reset() {
    1121           0 :     need_underscore_ = false;
    1122           0 :     op_ = 0;
    1123           0 :     segment_len_ = 0;
    1124           0 :     is_all_upper_ = true;
    1125             :   }
    1126             : 
    1127             :   bool need_underscore_;
    1128             :   bool is_all_upper_;
    1129             :   uint8 op_;
    1130             :   int segment_len_;
    1131             : 
    1132             :   string decode_data_;
    1133             : };
    1134             : 
    1135           0 : bool DecodeDataBuilder::AddCharacter(const char desired, const char input) {
    1136             :   // If we've hit the max size, push to start a new segment.
    1137           0 :   if (segment_len_ == kMaxSegmentLen) {
    1138           0 :     Push();
    1139             :   }
    1140           0 :   if (segment_len_ == 0) {
    1141           0 :     return AddFirst(desired, input);
    1142             :   }
    1143             : 
    1144             :   // Desired and input match...
    1145           0 :   if (desired == input) {
    1146             :     // If we aren't transforming it, or we're upper casing it and it is
    1147             :     // supposed to be uppercase; just add it to the segment.
    1148           0 :     if ((op_ != kOpAllUpper) || ascii_isupper(desired)) {
    1149           0 :       AddChar(desired);
    1150           0 :       return true;
    1151             :     }
    1152             : 
    1153             :     // Add the current segment, and start the next one.
    1154           0 :     Push();
    1155           0 :     return AddFirst(desired, input);
    1156             :   }
    1157             : 
    1158             :   // If we need to uppercase, and everything so far has been uppercase,
    1159             :   // promote op to AllUpper.
    1160           0 :   if ((desired == ascii_toupper(input)) && is_all_upper_) {
    1161           0 :     op_ = kOpAllUpper;
    1162           0 :     AddChar(desired);
    1163           0 :     return true;
    1164             :   }
    1165             : 
    1166             :   // Give up, push and start a new segment.
    1167           0 :   Push();
    1168           0 :   return AddFirst(desired, input);
    1169             : }
    1170             : 
    1171             : // If decode data can't be generated, a directive for the raw string
    1172             : // is used instead.
    1173           0 : string DirectDecodeString(const string& str) {
    1174             :   string result;
    1175             :   result += (char)'\0';  // Marker for full string.
    1176             :   result += str;
    1177             :   result += (char)'\0';  // End of string.
    1178           0 :   return result;
    1179             : }
    1180             : 
    1181             : }  // namespace
    1182             : 
    1183             : // static
    1184           0 : string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode,
    1185             :                                                  const string& desired_output) {
    1186           0 :   if ((input_for_decode.size() == 0) || (desired_output.size() == 0)) {
    1187           0 :     cerr << "error: got empty string for making TextFormat data, input: \""
    1188           0 :          << input_for_decode << "\", desired: \"" << desired_output << "\"."
    1189             :          << endl;
    1190           0 :     cerr.flush();
    1191           0 :     abort();
    1192             :   }
    1193           0 :   if ((input_for_decode.find('\0') != string::npos) ||
    1194           0 :       (desired_output.find('\0') != string::npos)) {
    1195           0 :     cerr << "error: got a null char in a string for making TextFormat data,"
    1196           0 :          << " input: \"" << CEscape(input_for_decode) << "\", desired: \""
    1197           0 :          << CEscape(desired_output) << "\"." << endl;
    1198           0 :     cerr.flush();
    1199           0 :     abort();
    1200             :   }
    1201             : 
    1202             :   DecodeDataBuilder builder;
    1203             : 
    1204             :   // Walk the output building it from the input.
    1205           0 :   int x = 0;
    1206           0 :   for (int y = 0; y < desired_output.size(); y++) {
    1207           0 :     const char d = desired_output[y];
    1208           0 :     if (d == '_') {
    1209             :       builder.AddUnderscore();
    1210             :       continue;
    1211             :     }
    1212             : 
    1213           0 :     if (x >= input_for_decode.size()) {
    1214             :       // Out of input, no way to encode it, just return a full decode.
    1215           0 :       return DirectDecodeString(desired_output);
    1216             :     }
    1217           0 :     if (builder.AddCharacter(d, input_for_decode[x])) {
    1218           0 :       ++x;  // Consumed one input
    1219             :     } else {
    1220             :       // Couldn't transform for the next character, just return a full decode.
    1221           0 :       return DirectDecodeString(desired_output);
    1222             :     }
    1223             :   }
    1224             : 
    1225           0 :   if (x != input_for_decode.size()) {
    1226             :     // Extra input (suffix from name sanitizing?), just return a full decode.
    1227           0 :     return DirectDecodeString(desired_output);
    1228             :   }
    1229             : 
    1230             :   // Add the end marker.
    1231           0 :   return builder.Finish() + (char)'\0';
    1232             : }
    1233             : 
    1234             : }  // namespace objectivec
    1235             : }  // namespace compiler
    1236             : }  // namespace protobuf
    1237          51 : }  // namespace google

Generated by: LCOV version 1.10