objectivec_helpers.cc 54 KB

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