|
|
|
@ -108,6 +108,7 @@ static id GetOrCreateMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *fiel |
|
|
|
|
static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field); |
|
|
|
|
static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, NSZone *zone) |
|
|
|
|
__attribute__((ns_returns_retained)); |
|
|
|
|
static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self); |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
static NSError *MessageError(NSInteger code, NSDictionary *userInfo) { |
|
|
|
@ -637,6 +638,135 @@ static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { |
|
|
|
|
|
|
|
|
|
#endif // !defined(__clang_analyzer__) |
|
|
|
|
|
|
|
|
|
static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension, |
|
|
|
|
GPBMessage *messageToGetExtension, |
|
|
|
|
GPBCodedInputStream *input, |
|
|
|
|
id<GPBExtensionRegistry> extensionRegistry, |
|
|
|
|
GPBMessage *existingValue) |
|
|
|
|
__attribute__((ns_returns_retained)); |
|
|
|
|
|
|
|
|
|
// Note that this returns a retained value intentionally. |
|
|
|
|
static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension, |
|
|
|
|
GPBMessage *messageToGetExtension, |
|
|
|
|
GPBCodedInputStream *input, |
|
|
|
|
id<GPBExtensionRegistry> extensionRegistry, |
|
|
|
|
GPBMessage *existingValue) { |
|
|
|
|
GPBExtensionDescription *description = extension->description_; |
|
|
|
|
GPBCodedInputStreamState *state = &input->state_; |
|
|
|
|
switch (description->dataType) { |
|
|
|
|
case GPBDataTypeBool: |
|
|
|
|
return [[NSNumber alloc] initWithBool:GPBCodedInputStreamReadBool(state)]; |
|
|
|
|
case GPBDataTypeFixed32: |
|
|
|
|
return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadFixed32(state)]; |
|
|
|
|
case GPBDataTypeSFixed32: |
|
|
|
|
return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSFixed32(state)]; |
|
|
|
|
case GPBDataTypeFloat: |
|
|
|
|
return [[NSNumber alloc] initWithFloat:GPBCodedInputStreamReadFloat(state)]; |
|
|
|
|
case GPBDataTypeFixed64: |
|
|
|
|
return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadFixed64(state)]; |
|
|
|
|
case GPBDataTypeSFixed64: |
|
|
|
|
return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSFixed64(state)]; |
|
|
|
|
case GPBDataTypeDouble: |
|
|
|
|
return [[NSNumber alloc] initWithDouble:GPBCodedInputStreamReadDouble(state)]; |
|
|
|
|
case GPBDataTypeInt32: |
|
|
|
|
return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadInt32(state)]; |
|
|
|
|
case GPBDataTypeInt64: |
|
|
|
|
return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadInt64(state)]; |
|
|
|
|
case GPBDataTypeSInt32: |
|
|
|
|
return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSInt32(state)]; |
|
|
|
|
case GPBDataTypeSInt64: |
|
|
|
|
return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSInt64(state)]; |
|
|
|
|
case GPBDataTypeUInt32: |
|
|
|
|
return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadUInt32(state)]; |
|
|
|
|
case GPBDataTypeUInt64: |
|
|
|
|
return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadUInt64(state)]; |
|
|
|
|
case GPBDataTypeBytes: |
|
|
|
|
return GPBCodedInputStreamReadRetainedBytes(state); |
|
|
|
|
case GPBDataTypeString: |
|
|
|
|
return GPBCodedInputStreamReadRetainedString(state); |
|
|
|
|
case GPBDataTypeEnum: { |
|
|
|
|
int32_t val = GPBCodedInputStreamReadEnum(&input->state_); |
|
|
|
|
GPBEnumDescriptor *enumDescriptor = extension.enumDescriptor; |
|
|
|
|
// If run with source generated before the closed enum support, all enums |
|
|
|
|
// will be considers not closed, so casing to the enum type for a switch |
|
|
|
|
// could cause things to fall off the end of a switch. |
|
|
|
|
if (!enumDescriptor.isClosed || enumDescriptor.enumVerifier(val)) { |
|
|
|
|
return [[NSNumber alloc] initWithInt:val]; |
|
|
|
|
} else { |
|
|
|
|
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(messageToGetExtension); |
|
|
|
|
[unknownFields mergeVarintField:extension->description_->fieldNumber value:val]; |
|
|
|
|
return nil; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
case GPBDataTypeGroup: |
|
|
|
|
case GPBDataTypeMessage: { |
|
|
|
|
GPBMessage *message; |
|
|
|
|
if (existingValue) { |
|
|
|
|
message = [existingValue retain]; |
|
|
|
|
} else { |
|
|
|
|
GPBDescriptor *descriptor = [extension.msgClass descriptor]; |
|
|
|
|
message = [[descriptor.messageClass alloc] init]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (description->dataType == GPBDataTypeGroup) { |
|
|
|
|
[input readGroup:description->fieldNumber |
|
|
|
|
message:message |
|
|
|
|
extensionRegistry:extensionRegistry]; |
|
|
|
|
} else { |
|
|
|
|
// description->dataType == GPBDataTypeMessage |
|
|
|
|
if (GPBExtensionIsWireFormat(description)) { |
|
|
|
|
// For MessageSet fields the message length will have already been |
|
|
|
|
// read. |
|
|
|
|
[message mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; |
|
|
|
|
} else { |
|
|
|
|
[input readMessage:message extensionRegistry:extensionRegistry]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return message; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ExtensionMergeFromInputStream(GPBExtensionDescriptor *extension, BOOL isPackedOnStream, |
|
|
|
|
GPBCodedInputStream *input, |
|
|
|
|
id<GPBExtensionRegistry> extensionRegistry, |
|
|
|
|
GPBMessage *message) { |
|
|
|
|
GPBExtensionDescription *description = extension->description_; |
|
|
|
|
GPBCodedInputStreamState *state = &input->state_; |
|
|
|
|
if (isPackedOnStream) { |
|
|
|
|
NSCAssert(GPBExtensionIsRepeated(description), @"How was it packed if it isn't repeated?"); |
|
|
|
|
int32_t length = GPBCodedInputStreamReadInt32(state); |
|
|
|
|
size_t limit = GPBCodedInputStreamPushLimit(state, length); |
|
|
|
|
while (GPBCodedInputStreamBytesUntilLimit(state) > 0) { |
|
|
|
|
id value = NewSingleValueFromInputStream(extension, message, input, extensionRegistry, nil); |
|
|
|
|
if (value) { |
|
|
|
|
[message addExtension:extension value:value]; |
|
|
|
|
[value release]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
GPBCodedInputStreamPopLimit(state, limit); |
|
|
|
|
} else { |
|
|
|
|
id existingValue = nil; |
|
|
|
|
BOOL isRepeated = GPBExtensionIsRepeated(description); |
|
|
|
|
if (!isRepeated && GPBDataTypeIsMessage(description->dataType)) { |
|
|
|
|
existingValue = [message getExistingExtension:extension]; |
|
|
|
|
} |
|
|
|
|
id value = |
|
|
|
|
NewSingleValueFromInputStream(extension, message, input, extensionRegistry, existingValue); |
|
|
|
|
if (value) { |
|
|
|
|
if (isRepeated) { |
|
|
|
|
[message addExtension:extension value:value]; |
|
|
|
|
} else { |
|
|
|
|
[message setExtension:extension value:value]; |
|
|
|
|
} |
|
|
|
|
[value release]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator, |
|
|
|
|
GPBFieldDescriptor *field) { |
|
|
|
|
GPBMessage *message = [[msgClass alloc] init]; |
|
|
|
@ -1987,11 +2117,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { |
|
|
|
|
if (extension != nil) { |
|
|
|
|
GPBCodedInputStream *newInput = |
|
|
|
|
[[GPBCodedInputStream alloc] initWithData:rawBytes]; |
|
|
|
|
GPBExtensionMergeFromInputStream(extension, |
|
|
|
|
extension.packable, |
|
|
|
|
newInput, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
ExtensionMergeFromInputStream(extension, |
|
|
|
|
extension.packable, |
|
|
|
|
newInput, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
[newInput release]; |
|
|
|
|
} else { |
|
|
|
|
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); |
|
|
|
@ -2022,11 +2152,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (extension.wireType == wireType) { |
|
|
|
|
GPBExtensionMergeFromInputStream(extension, |
|
|
|
|
extension.packable, |
|
|
|
|
input, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
ExtensionMergeFromInputStream(extension, |
|
|
|
|
extension.packable, |
|
|
|
|
input, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
return YES; |
|
|
|
|
} |
|
|
|
|
// Primitive, repeated types can be packed on unpacked on the wire, and are |
|
|
|
@ -2034,11 +2164,11 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { |
|
|
|
|
if ([extension isRepeated] && |
|
|
|
|
!GPBDataTypeIsObject(extension->description_->dataType) && |
|
|
|
|
(extension.alternateWireType == wireType)) { |
|
|
|
|
GPBExtensionMergeFromInputStream(extension, |
|
|
|
|
!extension.packable, |
|
|
|
|
input, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
ExtensionMergeFromInputStream(extension, |
|
|
|
|
!extension.packable, |
|
|
|
|
input, |
|
|
|
|
extensionRegistry, |
|
|
|
|
self); |
|
|
|
|
return YES; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -2058,7 +2188,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { |
|
|
|
|
#pragma mark - MergeFromCodedInputStream Support |
|
|
|
|
|
|
|
|
|
static void MergeSingleFieldFromCodedInputStream( |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, |
|
|
|
|
GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) { |
|
|
|
|
GPBDataType fieldDataType = GPBGetFieldDataType(field); |
|
|
|
|
switch (fieldDataType) { |
|
|
|
@ -2128,8 +2258,7 @@ static void MergeSingleFieldFromCodedInputStream( |
|
|
|
|
|
|
|
|
|
case GPBDataTypeEnum: { |
|
|
|
|
int32_t val = GPBCodedInputStreamReadEnum(&input->state_); |
|
|
|
|
if (GPBHasPreservingUnknownEnumSemantics(syntax) || |
|
|
|
|
[field isValidEnumValue:val]) { |
|
|
|
|
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) { |
|
|
|
|
GPBSetInt32IvarWithFieldPrivate(self, field, val); |
|
|
|
|
} else { |
|
|
|
|
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); |
|
|
|
@ -2140,7 +2269,7 @@ static void MergeSingleFieldFromCodedInputStream( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void MergeRepeatedPackedFieldFromCodedInputStream( |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, |
|
|
|
|
GPBCodedInputStream *input) { |
|
|
|
|
GPBDataType fieldDataType = GPBGetFieldDataType(field); |
|
|
|
|
GPBCodedInputStreamState *state = &input->state_; |
|
|
|
@ -2179,8 +2308,7 @@ static void MergeRepeatedPackedFieldFromCodedInputStream( |
|
|
|
|
|
|
|
|
|
case GPBDataTypeEnum: { |
|
|
|
|
int32_t val = GPBCodedInputStreamReadEnum(state); |
|
|
|
|
if (GPBHasPreservingUnknownEnumSemantics(syntax) || |
|
|
|
|
[field isValidEnumValue:val]) { |
|
|
|
|
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) { |
|
|
|
|
[(GPBEnumArray*)genericArray addRawValue:val]; |
|
|
|
|
} else { |
|
|
|
|
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); |
|
|
|
@ -2194,7 +2322,7 @@ static void MergeRepeatedPackedFieldFromCodedInputStream( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, GPBFileSyntax syntax, |
|
|
|
|
GPBMessage *self, GPBFieldDescriptor *field, |
|
|
|
|
GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) { |
|
|
|
|
GPBCodedInputStreamState *state = &input->state_; |
|
|
|
|
id genericArray = GetOrCreateArrayIvarWithField(self, field); |
|
|
|
@ -2247,8 +2375,7 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
} |
|
|
|
|
case GPBDataTypeEnum: { |
|
|
|
|
int32_t val = GPBCodedInputStreamReadEnum(state); |
|
|
|
|
if (GPBHasPreservingUnknownEnumSemantics(syntax) || |
|
|
|
|
[field isValidEnumValue:val]) { |
|
|
|
|
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) { |
|
|
|
|
[(GPBEnumArray*)genericArray addRawValue:val]; |
|
|
|
|
} else { |
|
|
|
|
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self); |
|
|
|
@ -2262,7 +2389,6 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input |
|
|
|
|
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry { |
|
|
|
|
GPBDescriptor *descriptor = [self descriptor]; |
|
|
|
|
GPBFileSyntax syntax = descriptor.file.syntax; |
|
|
|
|
GPBCodedInputStreamState *state = &input->state_; |
|
|
|
|
uint32_t tag = 0; |
|
|
|
|
NSUInteger startingIndex = 0; |
|
|
|
@ -2280,7 +2406,7 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
if (GPBFieldTag(fieldDescriptor) == tag) { |
|
|
|
|
GPBFieldType fieldType = fieldDescriptor.fieldType; |
|
|
|
|
if (fieldType == GPBFieldTypeSingle) { |
|
|
|
|
MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, syntax, |
|
|
|
|
MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, |
|
|
|
|
input, extensionRegistry); |
|
|
|
|
// Well formed protos will only have a single field once, advance |
|
|
|
|
// the starting index to the next field. |
|
|
|
@ -2288,13 +2414,13 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
} else if (fieldType == GPBFieldTypeRepeated) { |
|
|
|
|
if (fieldDescriptor.isPackable) { |
|
|
|
|
MergeRepeatedPackedFieldFromCodedInputStream( |
|
|
|
|
self, fieldDescriptor, syntax, input); |
|
|
|
|
self, fieldDescriptor, input); |
|
|
|
|
// Well formed protos will only have a repeated field that is |
|
|
|
|
// packed once, advance the starting index to the next field. |
|
|
|
|
startingIndex += 1; |
|
|
|
|
} else { |
|
|
|
|
MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
self, fieldDescriptor, syntax, input, extensionRegistry); |
|
|
|
|
self, fieldDescriptor, input, extensionRegistry); |
|
|
|
|
} |
|
|
|
|
} else { // fieldType == GPBFieldTypeMap |
|
|
|
|
// GPB*Dictionary or NSDictionary, exact type doesn't matter at this |
|
|
|
@ -2325,13 +2451,13 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
BOOL alternateIsPacked = !fieldDescriptor.isPackable; |
|
|
|
|
if (alternateIsPacked) { |
|
|
|
|
MergeRepeatedPackedFieldFromCodedInputStream( |
|
|
|
|
self, fieldDescriptor, syntax, input); |
|
|
|
|
self, fieldDescriptor, input); |
|
|
|
|
// Well formed protos will only have a repeated field that is |
|
|
|
|
// packed once, advance the starting index to the next field. |
|
|
|
|
startingIndex += 1; |
|
|
|
|
} else { |
|
|
|
|
MergeRepeatedNotPackedFieldFromCodedInputStream( |
|
|
|
|
self, fieldDescriptor, syntax, input, extensionRegistry); |
|
|
|
|
self, fieldDescriptor, input, extensionRegistry); |
|
|
|
|
} |
|
|
|
|
merged = YES; |
|
|
|
|
break; |
|
|
|
|