blob: d7567c4355d8f4bf6a7d99071503eec303555f85 [file] [log] [blame]
// Protocol Buffers for Objective C
//
// Copyright 2010 Booyah Inc.
// Copyright 2008 Cyrus Najmabadi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "ConcreteExtensionField.h"
#import "AbstractMessage.h"
#import "CodedInputStream.h"
#import "CodedOutputStream.h"
#import "ExtendableMessageBuilder.h"
#import "MessageBuilder.h"
#import "Utilities.h"
#import "WireFormat.h"
@interface PBConcreteExtensionField()
@property PBExtensionType type;
@property (assign) Class extendedClass;
@property SInt32 fieldNumber;
@property (strong) id defaultValue;
@property (assign) Class messageOrGroupClass;
@property BOOL isRepeated;
@property BOOL isPacked;
@property BOOL isMessageSetWireFormat;
@end
@implementation PBConcreteExtensionField
@synthesize type;
@synthesize extendedClass;
@synthesize fieldNumber;
@synthesize defaultValue;
@synthesize messageOrGroupClass;
@synthesize isRepeated;
@synthesize isPacked;
@synthesize isMessageSetWireFormat;
- (id) initWithType:(PBExtensionType) type_
extendedClass:(Class) extendedClass_
fieldNumber:(SInt32) fieldNumber_
defaultValue:(id) defaultValue_
messageOrGroupClass:(Class) messageOrGroupClass_
isRepeated:(BOOL) isRepeated_
isPacked:(BOOL) isPacked_
isMessageSetWireFormat:(BOOL) isMessageSetWireFormat_ {
if ((self = [super init])) {
self.type = type_;
self.extendedClass = extendedClass_;
self.fieldNumber = fieldNumber_;
self.defaultValue = defaultValue_;
self.messageOrGroupClass = messageOrGroupClass_;
self.isRepeated = isRepeated_;
self.isPacked = isPacked_;
self.isMessageSetWireFormat = isMessageSetWireFormat_;
}
return self;
}
+ (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type
extendedClass:(Class) extendedClass
fieldNumber:(SInt32) fieldNumber
defaultValue:(id) defaultValue
messageOrGroupClass:(Class) messageOrGroupClass
isRepeated:(BOOL) isRepeated
isPacked:(BOOL) isPacked
isMessageSetWireFormat:(BOOL) isMessageSetWireFormat {
return [[PBConcreteExtensionField alloc] initWithType:type
extendedClass:extendedClass
fieldNumber:fieldNumber
defaultValue:defaultValue
messageOrGroupClass:messageOrGroupClass
isRepeated:isRepeated
isPacked:isPacked
isMessageSetWireFormat:isMessageSetWireFormat];
}
- (PBWireFormat) wireType {
if (isPacked) {
return PBWireFormatLengthDelimited;
}
switch (type) {
case PBExtensionTypeBool: return PBWireFormatVarint;
case PBExtensionTypeFixed32: return PBWireFormatFixed32;
case PBExtensionTypeSFixed32: return PBWireFormatFixed32;
case PBExtensionTypeFloat: return PBWireFormatFixed32;
case PBExtensionTypeFixed64: return PBWireFormatFixed64;
case PBExtensionTypeSFixed64: return PBWireFormatFixed64;
case PBExtensionTypeDouble: return PBWireFormatFixed64;
case PBExtensionTypeInt32: return PBWireFormatVarint;
case PBExtensionTypeInt64: return PBWireFormatVarint;
case PBExtensionTypeSInt32: return PBWireFormatVarint;
case PBExtensionTypeSInt64: return PBWireFormatVarint;
case PBExtensionTypeUInt32: return PBWireFormatVarint;
case PBExtensionTypeUInt64: return PBWireFormatVarint;
case PBExtensionTypeBytes: return PBWireFormatLengthDelimited;
case PBExtensionTypeString: return PBWireFormatLengthDelimited;
case PBExtensionTypeMessage: return PBWireFormatLengthDelimited;
case PBExtensionTypeGroup: return PBWireFormatStartGroup;
case PBExtensionTypeEnum: return PBWireFormatVarint;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
BOOL typeIsFixedSize(PBExtensionType type) {
switch (type) {
case PBExtensionTypeBool:
case PBExtensionTypeFixed32:
case PBExtensionTypeSFixed32:
case PBExtensionTypeFloat:
case PBExtensionTypeFixed64:
case PBExtensionTypeSFixed64:
case PBExtensionTypeDouble:
return YES;
default:
return NO;
}
}
SInt32 typeSize(PBExtensionType type) {
switch (type) {
case PBExtensionTypeBool:
return 1;
case PBExtensionTypeFixed32:
case PBExtensionTypeSFixed32:
case PBExtensionTypeFloat:
return 4;
case PBExtensionTypeFixed64:
case PBExtensionTypeSFixed64:
case PBExtensionTypeDouble:
return 8;
default:
break;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) writeSingleValue:(id) value
includingTagToCodedOutputStream:(PBCodedOutputStream*) output {
switch (type) {
case PBExtensionTypeBool:
[output writeBool:fieldNumber value:[value boolValue]];
return;
case PBExtensionTypeFixed32:
[output writeFixed32:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeSFixed32:
[output writeSFixed32:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeFloat:
[output writeFloat:fieldNumber value:[value floatValue]];
return;
case PBExtensionTypeFixed64:
[output writeFixed64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeSFixed64:
[output writeSFixed64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeDouble:
[output writeDouble:fieldNumber value:[value doubleValue]];
return;
case PBExtensionTypeInt32:
[output writeInt32:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeInt64:
[output writeInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeSInt32:
[output writeSInt32:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeSInt64:
[output writeSInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeUInt32:
[output writeUInt32:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeUInt64:
[output writeUInt64:fieldNumber value:[value longLongValue]];
return;
case PBExtensionTypeBytes:
[output writeData:fieldNumber value:value];
return;
case PBExtensionTypeString:
[output writeString:fieldNumber value:value];
return;
case PBExtensionTypeGroup:
[output writeGroup:fieldNumber value:value];
return;
case PBExtensionTypeEnum:
[output writeEnum:fieldNumber value:(SInt32)[value integerValue]];
return;
case PBExtensionTypeMessage:
if (isMessageSetWireFormat) {
[output writeMessageSetExtension:fieldNumber value:value];
} else {
[output writeMessage:fieldNumber value:value];
}
return;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) writeSingleValue:(id) value
noTagToCodedOutputStream:(PBCodedOutputStream*) output {
switch (type) {
case PBExtensionTypeBool:
[output writeBoolNoTag:[value boolValue]];
return;
case PBExtensionTypeFixed32:
[output writeFixed32NoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeSFixed32:
[output writeSFixed32NoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeFloat:
[output writeFloatNoTag:[value floatValue]];
return;
case PBExtensionTypeFixed64:
[output writeFixed64NoTag:[value longLongValue]];
return;
case PBExtensionTypeSFixed64:
[output writeSFixed64NoTag:[value longLongValue]];
return;
case PBExtensionTypeDouble:
[output writeDoubleNoTag:[value doubleValue]];
return;
case PBExtensionTypeInt32:
[output writeInt32NoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeInt64:
[output writeInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeSInt32:
[output writeSInt32NoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeSInt64:
[output writeSInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeUInt32:
[output writeUInt32NoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeUInt64:
[output writeUInt64NoTag:[value longLongValue]];
return;
case PBExtensionTypeBytes:
[output writeDataNoTag:value];
return;
case PBExtensionTypeString:
[output writeStringNoTag:value];
return;
case PBExtensionTypeGroup:
[output writeGroupNoTag:fieldNumber value:value];
return;
case PBExtensionTypeEnum:
[output writeEnumNoTag:(SInt32)[value integerValue]];
return;
case PBExtensionTypeMessage:
[output writeMessageNoTag:value];
return;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (SInt32) computeSingleSerializedSizeNoTag:(id) value {
switch (type) {
case PBExtensionTypeBool: return computeBoolSizeNoTag([value boolValue]);
case PBExtensionTypeFixed32: return computeFixed32SizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeSFixed32: return computeSFixed32SizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeFloat: return computeFloatSizeNoTag([value floatValue]);
case PBExtensionTypeFixed64: return computeFixed64SizeNoTag([value longLongValue]);
case PBExtensionTypeSFixed64: return computeSFixed64SizeNoTag([value longLongValue]);
case PBExtensionTypeDouble: return computeDoubleSizeNoTag([value doubleValue]);
case PBExtensionTypeInt32: return computeInt32SizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeInt64: return computeInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeSInt32: return computeSInt32SizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeSInt64: return computeSInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeUInt32: return computeUInt32SizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeUInt64: return computeUInt64SizeNoTag([value longLongValue]);
case PBExtensionTypeBytes: return computeDataSizeNoTag(value);
case PBExtensionTypeString: return computeStringSizeNoTag(value);
case PBExtensionTypeGroup: return computeGroupSizeNoTag(value);
case PBExtensionTypeEnum: return computeEnumSizeNoTag((SInt32)[value integerValue]);
case PBExtensionTypeMessage: return computeMessageSizeNoTag(value);
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (SInt32) computeSingleSerializedSizeIncludingTag:(id) value {
switch (type) {
case PBExtensionTypeBool: return computeBoolSize(fieldNumber, [value boolValue]);
case PBExtensionTypeFixed32: return computeFixed32Size(fieldNumber,(SInt32) [value integerValue]);
case PBExtensionTypeSFixed32: return computeSFixed32Size(fieldNumber, (SInt32)[value integerValue]);
case PBExtensionTypeFloat: return computeFloatSize(fieldNumber, [value floatValue]);
case PBExtensionTypeFixed64: return computeFixed64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeSFixed64: return computeSFixed64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeDouble: return computeDoubleSize(fieldNumber, [value doubleValue]);
case PBExtensionTypeInt32: return computeInt32Size(fieldNumber, (SInt32)[value integerValue]);
case PBExtensionTypeInt64: return computeInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeSInt32: return computeSInt32Size(fieldNumber, (SInt32)[value integerValue]);
case PBExtensionTypeSInt64: return computeSInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeUInt32: return computeUInt32Size(fieldNumber, (SInt32)[value integerValue]);
case PBExtensionTypeUInt64: return computeUInt64Size(fieldNumber, [value longLongValue]);
case PBExtensionTypeBytes: return computeDataSize(fieldNumber, value);
case PBExtensionTypeString: return computeStringSize(fieldNumber, value);
case PBExtensionTypeGroup: return computeGroupSize(fieldNumber, value);
case PBExtensionTypeEnum: return computeEnumSize(fieldNumber, (SInt32)[value integerValue]);
case PBExtensionTypeMessage:
if (isMessageSetWireFormat) {
return computeMessageSetExtensionSize(fieldNumber, value);
} else {
return computeMessageSize(fieldNumber, value);
}
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) writeDescriptionOfSingleValue:(id) value
to:(NSMutableString*) output
withIndent:(NSString*) indent {
switch (type) {
case PBExtensionTypeBool:
case PBExtensionTypeFixed32:
case PBExtensionTypeSFixed32:
case PBExtensionTypeFloat:
case PBExtensionTypeFixed64:
case PBExtensionTypeSFixed64:
case PBExtensionTypeDouble:
case PBExtensionTypeInt32:
case PBExtensionTypeInt64:
case PBExtensionTypeSInt32:
case PBExtensionTypeSInt64:
case PBExtensionTypeUInt32:
case PBExtensionTypeUInt64:
case PBExtensionTypeBytes:
case PBExtensionTypeString:
case PBExtensionTypeEnum:
[output appendFormat:@"%@%@\n", indent, value];
return;
case PBExtensionTypeGroup:
case PBExtensionTypeMessage:
[((PBAbstractMessage *)value) writeDescriptionTo:output withIndent:indent];
return;
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void)writeRepeatedValues:(NSArray*) values includingTagsToCodedOutputStream:(PBCodedOutputStream*) output {
if (isPacked) {
[output writeTag:fieldNumber format:PBWireFormatLengthDelimited];
SInt32 dataSize = 0;
if (typeIsFixedSize(type)) {
dataSize = (SInt32)(values.count * typeSize(type));
} else {
for (id value in values) {
dataSize += [self computeSingleSerializedSizeNoTag:value];
}
}
[output writeRawVarint32:dataSize];
for (id value in values) {
[self writeSingleValue:value noTagToCodedOutputStream:output];
}
} else {
for (id value in values) {
[self writeSingleValue:value includingTagToCodedOutputStream:output];
}
}
}
- (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output {
if (isRepeated) {
[self writeRepeatedValues:value includingTagsToCodedOutputStream:output];
} else {
[self writeSingleValue:value includingTagToCodedOutputStream:output];
}
}
- (SInt32) computeRepeatedSerializedSizeIncludingTags:(NSArray*) values {
if (isPacked) {
SInt32 size = 0;
if (typeIsFixedSize(type)) {
size = (SInt32)(values.count * typeSize(type));
} else {
for (id value in values) {
size += [self computeSingleSerializedSizeNoTag:value];
}
}
return size + computeTagSize(fieldNumber) + computeRawVarint32Size(size);
} else {
SInt32 size = 0;
for (id value in values) {
size += [self computeSingleSerializedSizeIncludingTag:value];
}
return size;
}
}
- (SInt32) computeSerializedSizeIncludingTag:(id) value {
if (isRepeated) {
return [self computeRepeatedSerializedSizeIncludingTags:value];
} else {
return [self computeSingleSerializedSizeIncludingTag:value];
}
}
- (void) writeDescriptionOf:(id)value
to:(NSMutableString *)output
withIndent:(NSString *)indent {
if (isRepeated) {
NSArray* values = value;
for (id singleValue in values) {
[self writeDescriptionOfSingleValue:singleValue to:output withIndent:indent];
}
} else {
[self writeDescriptionOfSingleValue:value to:output withIndent:indent];
}
}
- (void) mergeMessageSetExtentionFromCodedInputStream:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSetBuilder*) unknownFields {
@throw [NSException exceptionWithName:@"NYI" reason:@"" userInfo:nil];
// The wire format for MessageSet is:
// message MessageSet {
// repeated group Item = 1 {
// required int32 typeId = 2;
// required bytes message = 3;
// }
// }
// "typeId" is the extension's field number. The extension can only be
// a message type, where "message" contains the encoded bytes of that
// message.
//
// In practice, we will probably never see a MessageSet item in which
// the message appears before the type ID, or where either field does not
// appear exactly once. However, in theory such cases are valid, so we
// should be prepared to accept them.
//int typeId = 0;
// ByteString rawBytes = null;
//
// while (true) {
// final int tag = input.readTag();
// if (tag == 0) {
// break;
// }
//
// if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
// typeId = input.readUInt32();
// // Zero is not a valid type ID.
// if (typeId != 0) {
// if (rawBytes != null) {
// unknownFields.mergeField(typeId,
// UnknownFieldSet.Field.newBuilder()
// .addLengthDelimited(rawBytes)
// .build());
// rawBytes = null;
// }
// }
// } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
// if (typeId == 0) {
// // We haven't seen a type ID yet, so we have to store the raw bytes
// // for now.
// rawBytes = input.readBytes();
// } else {
// unknownFields.mergeField(typeId,
// UnknownFieldSet.Field.newBuilder()
// .addLengthDelimited(input.readBytes())
// .build());
// }
// } else {
// // Unknown fieldNumber. Skip it.
// if (!input.skipField(tag)) {
// break; // end of group
// }
// }
// }
//
// input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
}
- (id) readSingleValueFromCodedInputStream:(PBCodedInputStream*) input
extensionRegistry:(PBExtensionRegistry*) extensionRegistry {
switch (type) {
case PBExtensionTypeBool: return [NSNumber numberWithBool:[input readBool]];
case PBExtensionTypeFixed32: return @([input readFixed32]);
case PBExtensionTypeSFixed32: return @([input readSFixed32]);
case PBExtensionTypeFloat: return [NSNumber numberWithFloat:[input readFloat]];
case PBExtensionTypeFixed64: return [NSNumber numberWithLongLong:[input readFixed64]];
case PBExtensionTypeSFixed64: return [NSNumber numberWithLongLong:[input readSFixed64]];
case PBExtensionTypeDouble: return [NSNumber numberWithDouble:[input readDouble]];
case PBExtensionTypeInt32: return @([input readInt32]);
case PBExtensionTypeInt64: return [NSNumber numberWithLongLong:[input readInt64]];
case PBExtensionTypeSInt32: return @([input readSInt32]);
case PBExtensionTypeSInt64: return [NSNumber numberWithLongLong:[input readSInt64]];
case PBExtensionTypeUInt32: return @([input readUInt32]);
case PBExtensionTypeUInt64: return [NSNumber numberWithLongLong:[input readUInt64]];
case PBExtensionTypeBytes: return [input readData];
case PBExtensionTypeString: return [input readString];
case PBExtensionTypeEnum: return @([input readEnum]);
case PBExtensionTypeGroup:
{
id<PBMessageBuilder> builder = [messageOrGroupClass builder];
[input readGroup:fieldNumber builder:builder extensionRegistry:extensionRegistry];
return [builder build];
}
case PBExtensionTypeMessage:
{
id<PBMessageBuilder> builder = [messageOrGroupClass builder];
[input readMessage:builder extensionRegistry:extensionRegistry];
return [builder build];
}
}
@throw [NSException exceptionWithName:@"InternalError" reason:@"" userInfo:nil];
}
- (void) mergeFromCodedInputStream:(PBCodedInputStream*) input
unknownFields:(PBUnknownFieldSetBuilder*) unknownFields
extensionRegistry:(PBExtensionRegistry*) extensionRegistry
builder:(PBExtendableMessageBuilder*) builder
tag:(SInt32) tag {
if (isPacked) {
SInt32 length = [input readRawVarint32];
SInt32 limit = [input pushLimit:length];
while ([input bytesUntilLimit] > 0) {
id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry];
[builder addExtension:self value:value];
}
[input popLimit:limit];
} else if (isMessageSetWireFormat) {
[self mergeMessageSetExtentionFromCodedInputStream:input
unknownFields:unknownFields];
} else {
id value = [self readSingleValueFromCodedInputStream:input extensionRegistry:extensionRegistry];
if (isRepeated) {
[builder addExtension:self value:value];
} else {
[builder setExtension:self value:value];
}
}
}
@end