Index: third_party/protobuf/objectivec/GPBUtilities.m |
diff --git a/third_party/protobuf/objectivec/GPBUtilities.m b/third_party/protobuf/objectivec/GPBUtilities.m |
index 447c749aa76779877e6f754a69f248ba414cf1db..d4538598f72c61fa2153feed1099017ac6a4db5d 100644 |
--- a/third_party/protobuf/objectivec/GPBUtilities.m |
+++ b/third_party/protobuf/objectivec/GPBUtilities.m |
@@ -39,6 +39,12 @@ |
#import "GPBUnknownField.h" |
#import "GPBUnknownFieldSet.h" |
+// Direct access is use for speed, to avoid even internally declaring things |
+// read/write, etc. The warning is enabled in the project to ensure code calling |
+// protos can turn on -Wdirect-ivar-access without issues. |
+#pragma clang diagnostic push |
+#pragma clang diagnostic ignored "-Wdirect-ivar-access" |
+ |
static void AppendTextFormatForMessage(GPBMessage *message, |
NSMutableString *toStr, |
NSString *lineIndent); |
@@ -52,8 +58,50 @@ NSData *GPBEmptyNSData(void) { |
return defaultNSData; |
} |
+// -- About Version Checks -- |
+// There's actually 3 places these checks all come into play: |
+// 1. When the generated source is compile into .o files, the header check |
+// happens. This is checking the protoc used matches the library being used |
+// when making the .o. |
+// 2. Every place a generated proto header is included in a developer's code, |
+// the header check comes into play again. But this time it is checking that |
+// the current library headers being used still support/match the ones for |
+// the generated code. |
+// 3. At runtime the final check here (GPBCheckRuntimeVersionsInternal), is |
+// called from the generated code passing in values captured when the |
+// generated code's .o was made. This checks that at runtime the generated |
+// code and runtime library match. |
+ |
+void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) { |
+ // NOTE: This is passing the value captured in the compiled code to check |
+ // against the values captured when the runtime support was compiled. This |
+ // ensures the library code isn't in a different framework/library that |
+ // was generated with a non matching version. |
+ if (GOOGLE_PROTOBUF_OBJC_VERSION < objcRuntimeVersion) { |
+ // Library is too old for headers. |
+ [NSException raise:NSInternalInconsistencyException |
+ format:@"Linked to ProtocolBuffer runtime version %d," |
+ @" but code compiled needing atleast %d!", |
+ GOOGLE_PROTOBUF_OBJC_VERSION, objcRuntimeVersion]; |
+ } |
+ if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) { |
+ // Headers are too old for library. |
+ [NSException raise:NSInternalInconsistencyException |
+ format:@"Proto generation source compiled against runtime" |
+ @" version %d, but this version of the runtime only" |
+ @" supports back to %d!", |
+ objcRuntimeVersion, |
+ GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION]; |
+ } |
+} |
+ |
+// This api is no longer used for version checks. 30001 is the last version |
+// using this old versioning model. When that support is removed, this function |
+// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h). |
void GPBCheckRuntimeVersionInternal(int32_t version) { |
- if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) { |
+ GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION == 30001, |
+ time_to_remove_this_old_version_shim); |
+ if (version != GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) { |
[NSException raise:NSInternalInconsistencyException |
format:@"Linked to ProtocolBuffer runtime version %d," |
@" but code compiled with version %d!", |
@@ -212,9 +260,10 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, |
//% TYPE *typePtr = (TYPE *)&storage[field->description_->offset]; |
//% *typePtr = value; |
//% // proto2: any value counts as having been set; proto3, it |
-//% // has to be a non zero value. |
-//% BOOL hasValue = |
-//% (syntax == GPBFileSyntaxProto2) || (value != (TYPE)0); |
+//% // has to be a non zero value or be in a oneof. |
+//% BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+//% || (value != (TYPE)0) |
+//% || (field->containingOneof_ != NULL)); |
//% GPBSetHasIvarField(self, field, hasValue); |
//% GPBBecomeVisibleToAutocreator(self); |
//%} |
@@ -331,8 +380,19 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, |
// zero, they are being cleared. |
if ((syntax == GPBFileSyntaxProto3) && !fieldIsMessage && |
([value length] == 0)) { |
- setHasValue = NO; |
- value = nil; |
+ // Except, if the field was in a oneof, then it still gets recorded as |
+ // having been set so the state of the oneof can be serialized back out. |
+ if (!oneof) { |
+ setHasValue = NO; |
+ } |
+ if (setHasValue) { |
+ NSCAssert(value != nil, @"Should never be setting has for nil"); |
+ } else { |
+ // The value passed in was retained, it must be released since we |
+ // aren't saving anything in the field. |
+ [value release]; |
+ value = nil; |
+ } |
} |
GPBSetHasIvarField(self, field, setHasValue); |
} |
@@ -518,9 +578,10 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self, |
GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value); |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (BOOL)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (BOOL)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -567,9 +628,10 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, |
int32_t *typePtr = (int32_t *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (int32_t)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (int32_t)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -616,9 +678,10 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self, |
uint32_t *typePtr = (uint32_t *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (uint32_t)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (uint32_t)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -665,9 +728,10 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self, |
int64_t *typePtr = (int64_t *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (int64_t)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (int64_t)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -714,9 +778,10 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self, |
uint64_t *typePtr = (uint64_t *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (uint64_t)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (uint64_t)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -763,9 +828,10 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self, |
float *typePtr = (float *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (float)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (float)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -812,9 +878,10 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, |
double *typePtr = (double *)&storage[field->description_->offset]; |
*typePtr = value; |
// proto2: any value counts as having been set; proto3, it |
- // has to be a non zero value. |
- BOOL hasValue = |
- (syntax == GPBFileSyntaxProto2) || (value != (double)0); |
+ // has to be a non zero value or be in a oneof. |
+ BOOL hasValue = ((syntax == GPBFileSyntaxProto2) |
+ || (value != (double)0) |
+ || (field->containingOneof_ != NULL)); |
GPBSetHasIvarField(self, field, hasValue); |
GPBBecomeVisibleToAutocreator(self); |
} |
@@ -889,21 +956,11 @@ void GPBSetMessageGroupField(GPBMessage *self, |
//%PDDM-EXPAND-END (4 expansions) |
-// Only exists for public api, no core code should use this. |
-id GPBGetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field) { |
-#if DEBUG |
- if (field.fieldType != GPBFieldTypeRepeated) { |
- [NSException raise:NSInvalidArgumentException |
- format:@"%@.%@ is not a repeated field.", |
- [self class], field.name]; |
- } |
-#endif |
- return GPBGetObjectIvarWithField(self, field); |
-} |
+// GPBGetMessageRepeatedField is defined in GPBMessage.m |
// Only exists for public api, no core code should use this. |
void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id array) { |
-#if DEBUG |
+#if defined(DEBUG) && DEBUG |
if (field.fieldType != GPBFieldTypeRepeated) { |
[NSException raise:NSInvalidArgumentException |
format:@"%@.%@ is not a repeated field.", |
@@ -942,10 +999,10 @@ void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id |
case GPBDataTypeString: |
case GPBDataTypeMessage: |
case GPBDataTypeGroup: |
- expectedClass = [NSMutableDictionary class]; |
+ expectedClass = [NSMutableArray class]; |
break; |
case GPBDataTypeEnum: |
- expectedClass = [GPBBoolArray class]; |
+ expectedClass = [GPBEnumArray class]; |
break; |
} |
if (array && ![array isKindOfClass:expectedClass]) { |
@@ -957,7 +1014,7 @@ void GPBSetMessageRepeatedField(GPBMessage *self, GPBFieldDescriptor *field, id |
GPBSetObjectIvarWithField(self, field, array); |
} |
-#if DEBUG |
+#if defined(DEBUG) && DEBUG |
static NSString *TypeToStr(GPBDataType dataType) { |
switch (dataType) { |
case GPBDataTypeBool: |
@@ -991,22 +1048,12 @@ static NSString *TypeToStr(GPBDataType dataType) { |
} |
#endif |
-// Only exists for public api, no core code should use this. |
-id GPBGetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field) { |
-#if DEBUG |
- if (field.fieldType != GPBFieldTypeMap) { |
- [NSException raise:NSInvalidArgumentException |
- format:@"%@.%@ is not a map<> field.", |
- [self class], field.name]; |
- } |
-#endif |
- return GPBGetObjectIvarWithField(self, field); |
-} |
+// GPBGetMessageMapField is defined in GPBMessage.m |
// Only exists for public api, no core code should use this. |
void GPBSetMessageMapField(GPBMessage *self, GPBFieldDescriptor *field, |
id dictionary) { |
-#if DEBUG |
+#if defined(DEBUG) && DEBUG |
if (field.fieldType != GPBFieldTypeMap) { |
[NSException raise:NSInvalidArgumentException |
format:@"%@.%@ is not a map<> field.", |
@@ -1066,7 +1113,15 @@ static void AppendStringEscaped(NSString *toPrint, NSMutableString *destStr) { |
case '\'': [destStr appendString:@"\\\'"]; break; |
case '\\': [destStr appendString:@"\\\\"]; break; |
default: |
- [destStr appendFormat:@"%C", aChar]; |
+ // This differs slightly from the C++ code in that the C++ doesn't |
+ // generate UTF8; it looks at the string in UTF8, but escapes every |
+ // byte > 0x7E. |
+ if (aChar < 0x20) { |
+ [destStr appendFormat:@"\\%d%d%d", |
+ (aChar / 64), ((aChar % 64) / 8), (aChar % 8)]; |
+ } else { |
+ [destStr appendFormat:@"%C", aChar]; |
+ } |
break; |
} |
} |
@@ -1133,6 +1188,8 @@ static void AppendTextFormatForMapMessageField( |
[toStr appendString:@"\n"]; |
[toStr appendString:valueLine]; |
+#pragma clang diagnostic push |
+#pragma clang diagnostic ignored "-Wswitch-enum" |
switch (valueDataType) { |
case GPBDataTypeString: |
AppendStringEscaped(value, toStr); |
@@ -1153,6 +1210,7 @@ static void AppendTextFormatForMapMessageField( |
NSCAssert(NO, @"Can't happen"); |
break; |
} |
+#pragma clang diagnostic pop |
[toStr appendString:@"\n"]; |
[toStr appendString:msgEnd]; |
@@ -1174,6 +1232,8 @@ static void AppendTextFormatForMapMessageField( |
} |
[toStr appendString:valueLine]; |
+#pragma clang diagnostic push |
+#pragma clang diagnostic ignored "-Wswitch-enum" |
switch (valueDataType) { |
case GPBDataTypeString: |
AppendStringEscaped(valueObj, toStr); |
@@ -1211,6 +1271,7 @@ static void AppendTextFormatForMapMessageField( |
[toStr appendString:valueObj]; |
break; |
} |
+#pragma clang diagnostic pop |
[toStr appendString:@"\n"]; |
[toStr appendString:msgEnd]; |
@@ -1480,7 +1541,8 @@ static void AppendTextFormatForMessage(GPBMessage *message, |
NSUInteger fieldCount = fieldsArray.count; |
const GPBExtensionRange *extensionRanges = descriptor.extensionRanges; |
NSUInteger extensionRangesCount = descriptor.extensionRangesCount; |
- NSArray *activeExtensions = [message sortedExtensionsInUse]; |
+ NSArray *activeExtensions = [[message extensionsCurrentlySet] |
+ sortedArrayUsingSelector:@selector(compareByFieldNumber:)]; |
for (NSUInteger i = 0, j = 0; i < fieldCount || j < extensionRangesCount;) { |
if (i == fieldCount) { |
AppendTextFormatForMessageExtensionRange( |
@@ -1706,6 +1768,8 @@ NSString *GPBDecodeTextFormatName(const uint8_t *decodeData, int32_t key, |
return result; |
} |
+#pragma clang diagnostic pop |
+ |
#pragma mark - GPBMessageSignatureProtocol |
// A series of selectors that are used solely to get @encoding values |