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