1// Copyright 2013 The Flutter Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "FlutterStandardCodec_Internal.h" 6 7#pragma mark - Codec for basic message channel 8 9@implementation FlutterStandardMessageCodec { 10 FlutterStandardReaderWriter* _readerWriter; 11} 12+ (instancetype)sharedInstance { 13 static id _sharedInstance = nil; 14 if (!_sharedInstance) { 15 FlutterStandardReaderWriter* readerWriter = 16 [[[FlutterStandardReaderWriter alloc] init] autorelease]; 17 _sharedInstance = [[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter]; 18 } 19 return _sharedInstance; 20} 21 22+ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter { 23 return [[[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter] autorelease]; 24} 25 26- (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter { 27 self = [super init]; 28 NSAssert(self, @"Super init cannot be nil"); 29 _readerWriter = [readerWriter retain]; 30 return self; 31} 32 33- (void)dealloc { 34 [_readerWriter release]; 35 [super dealloc]; 36} 37 38- (NSData*)encode:(id)message { 39 if (message == nil) 40 return nil; 41 NSMutableData* data = [NSMutableData dataWithCapacity:32]; 42 FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; 43 [writer writeValue:message]; 44 return data; 45} 46 47- (id)decode:(NSData*)message { 48 if (message == nil) 49 return nil; 50 FlutterStandardReader* reader = [_readerWriter readerWithData:message]; 51 id value = [reader readValue]; 52 NSAssert(![reader hasMore], @"Corrupted standard message"); 53 return value; 54} 55@end 56 57#pragma mark - Codec for method channel 58 59@implementation FlutterStandardMethodCodec { 60 FlutterStandardReaderWriter* _readerWriter; 61} 62+ (instancetype)sharedInstance { 63 static id _sharedInstance = nil; 64 if (!_sharedInstance) { 65 FlutterStandardReaderWriter* readerWriter = 66 [[[FlutterStandardReaderWriter alloc] init] autorelease]; 67 _sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter]; 68 } 69 return _sharedInstance; 70} 71 72+ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter { 73 return [[[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter] autorelease]; 74} 75 76- (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter { 77 self = [super init]; 78 NSAssert(self, @"Super init cannot be nil"); 79 _readerWriter = [readerWriter retain]; 80 return self; 81} 82 83- (void)dealloc { 84 [_readerWriter release]; 85 [super dealloc]; 86} 87 88- (NSData*)encodeMethodCall:(FlutterMethodCall*)call { 89 NSMutableData* data = [NSMutableData dataWithCapacity:32]; 90 FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; 91 [writer writeValue:call.method]; 92 [writer writeValue:call.arguments]; 93 return data; 94} 95 96- (NSData*)encodeSuccessEnvelope:(id)result { 97 NSMutableData* data = [NSMutableData dataWithCapacity:32]; 98 FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; 99 [writer writeByte:0]; 100 [writer writeValue:result]; 101 return data; 102} 103 104- (NSData*)encodeErrorEnvelope:(FlutterError*)error { 105 NSMutableData* data = [NSMutableData dataWithCapacity:32]; 106 FlutterStandardWriter* writer = [_readerWriter writerWithData:data]; 107 [writer writeByte:1]; 108 [writer writeValue:error.code]; 109 [writer writeValue:error.message]; 110 [writer writeValue:error.details]; 111 return data; 112} 113 114- (FlutterMethodCall*)decodeMethodCall:(NSData*)message { 115 FlutterStandardReader* reader = [_readerWriter readerWithData:message]; 116 id value1 = [reader readValue]; 117 id value2 = [reader readValue]; 118 NSAssert(![reader hasMore], @"Corrupted standard method call"); 119 NSAssert([value1 isKindOfClass:[NSString class]], @"Corrupted standard method call"); 120 return [FlutterMethodCall methodCallWithMethodName:value1 arguments:value2]; 121} 122 123- (id)decodeEnvelope:(NSData*)envelope { 124 FlutterStandardReader* reader = [_readerWriter readerWithData:envelope]; 125 UInt8 flag = [reader readByte]; 126 NSAssert(flag <= 1, @"Corrupted standard envelope"); 127 id result; 128 switch (flag) { 129 case 0: { 130 result = [reader readValue]; 131 NSAssert(![reader hasMore], @"Corrupted standard envelope"); 132 } break; 133 case 1: { 134 id code = [reader readValue]; 135 id message = [reader readValue]; 136 id details = [reader readValue]; 137 NSAssert(![reader hasMore], @"Corrupted standard envelope"); 138 NSAssert([code isKindOfClass:[NSString class]], @"Invalid standard envelope"); 139 NSAssert(message == nil || [message isKindOfClass:[NSString class]], 140 @"Invalid standard envelope"); 141 result = [FlutterError errorWithCode:code message:message details:details]; 142 } break; 143 } 144 return result; 145} 146@end 147 148using namespace flutter; 149 150#pragma mark - Standard serializable types 151 152@implementation FlutterStandardTypedData 153+ (instancetype)typedDataWithBytes:(NSData*)data { 154 return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeUInt8]; 155} 156 157+ (instancetype)typedDataWithInt32:(NSData*)data { 158 return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt32]; 159} 160 161+ (instancetype)typedDataWithInt64:(NSData*)data { 162 return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt64]; 163} 164 165+ (instancetype)typedDataWithFloat64:(NSData*)data { 166 return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat64]; 167} 168 169+ (instancetype)typedDataWithData:(NSData*)data type:(FlutterStandardDataType)type { 170 return [[[FlutterStandardTypedData alloc] initWithData:data type:type] autorelease]; 171} 172 173- (instancetype)initWithData:(NSData*)data type:(FlutterStandardDataType)type { 174 UInt8 elementSize = elementSizeForFlutterStandardDataType(type); 175 NSAssert(data, @"Data cannot be nil"); 176 NSAssert(data.length % elementSize == 0, @"Data must contain integral number of elements"); 177 self = [super init]; 178 NSAssert(self, @"Super init cannot be nil"); 179 _data = [data retain]; 180 _type = type; 181 _elementSize = elementSize; 182 _elementCount = data.length / elementSize; 183 return self; 184} 185 186- (void)dealloc { 187 [_data release]; 188 [super dealloc]; 189} 190 191- (BOOL)isEqual:(id)object { 192 if (self == object) 193 return YES; 194 if (![object isKindOfClass:[FlutterStandardTypedData class]]) 195 return NO; 196 FlutterStandardTypedData* other = (FlutterStandardTypedData*)object; 197 return self.type == other.type && self.elementCount == other.elementCount && 198 [self.data isEqual:other.data]; 199} 200 201- (NSUInteger)hash { 202 return [self.data hash] ^ self.type; 203} 204@end 205 206#pragma mark - Writer and reader of standard codec 207 208@implementation FlutterStandardWriter { 209 NSMutableData* _data; 210} 211 212- (instancetype)initWithData:(NSMutableData*)data { 213 self = [super init]; 214 NSAssert(self, @"Super init cannot be nil"); 215 _data = [data retain]; 216 return self; 217} 218 219- (void)dealloc { 220 [_data release]; 221 [super dealloc]; 222} 223 224- (void)writeByte:(UInt8)value { 225 [_data appendBytes:&value length:1]; 226} 227 228- (void)writeBytes:(const void*)bytes length:(NSUInteger)length { 229 [_data appendBytes:bytes length:length]; 230} 231 232- (void)writeData:(NSData*)data { 233 [_data appendData:data]; 234} 235 236- (void)writeSize:(UInt32)size { 237 if (size < 254) { 238 [self writeByte:(UInt8)size]; 239 } else if (size <= 0xffff) { 240 [self writeByte:254]; 241 UInt16 value = (UInt16)size; 242 [self writeBytes:&value length:2]; 243 } else { 244 [self writeByte:255]; 245 [self writeBytes:&size length:4]; 246 } 247} 248 249- (void)writeAlignment:(UInt8)alignment { 250 UInt8 mod = _data.length % alignment; 251 if (mod) { 252 for (int i = 0; i < (alignment - mod); i++) { 253 [self writeByte:0]; 254 } 255 } 256} 257 258- (void)writeUTF8:(NSString*)value { 259 UInt32 length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 260 [self writeSize:length]; 261 [self writeBytes:value.UTF8String length:length]; 262} 263 264- (void)writeValue:(id)value { 265 if (value == nil || value == [NSNull null]) { 266 [self writeByte:FlutterStandardFieldNil]; 267 } else if ([value isKindOfClass:[NSNumber class]]) { 268 CFNumberRef number = (CFNumberRef)value; 269 BOOL success = NO; 270 if (CFGetTypeID(number) == CFBooleanGetTypeID()) { 271 BOOL b = CFBooleanGetValue((CFBooleanRef)number); 272 [self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)]; 273 success = YES; 274 } else if (CFNumberIsFloatType(number)) { 275 Float64 f; 276 success = CFNumberGetValue(number, kCFNumberFloat64Type, &f); 277 if (success) { 278 [self writeByte:FlutterStandardFieldFloat64]; 279 [self writeAlignment:8]; 280 [self writeBytes:(UInt8*)&f length:8]; 281 } 282 } else if (CFNumberGetByteSize(number) <= 4) { 283 SInt32 n; 284 success = CFNumberGetValue(number, kCFNumberSInt32Type, &n); 285 if (success) { 286 [self writeByte:FlutterStandardFieldInt32]; 287 [self writeBytes:(UInt8*)&n length:4]; 288 } 289 } else if (CFNumberGetByteSize(number) <= 8) { 290 SInt64 n; 291 success = CFNumberGetValue(number, kCFNumberSInt64Type, &n); 292 if (success) { 293 [self writeByte:FlutterStandardFieldInt64]; 294 [self writeBytes:(UInt8*)&n length:8]; 295 } 296 } 297 if (!success) { 298 NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number)); 299 NSAssert(NO, @"Unsupported value for standard codec"); 300 } 301 } else if ([value isKindOfClass:[NSString class]]) { 302 NSString* string = value; 303 [self writeByte:FlutterStandardFieldString]; 304 [self writeUTF8:string]; 305 } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) { 306 FlutterStandardTypedData* typedData = value; 307 [self writeByte:FlutterStandardFieldForDataType(typedData.type)]; 308 [self writeSize:typedData.elementCount]; 309 [self writeAlignment:typedData.elementSize]; 310 [self writeData:typedData.data]; 311 } else if ([value isKindOfClass:[NSData class]]) { 312 [self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]]; 313 } else if ([value isKindOfClass:[NSArray class]]) { 314 NSArray* array = value; 315 [self writeByte:FlutterStandardFieldList]; 316 [self writeSize:array.count]; 317 for (id object in array) { 318 [self writeValue:object]; 319 } 320 } else if ([value isKindOfClass:[NSDictionary class]]) { 321 NSDictionary* dict = value; 322 [self writeByte:FlutterStandardFieldMap]; 323 [self writeSize:dict.count]; 324 for (id key in dict) { 325 [self writeValue:key]; 326 [self writeValue:[dict objectForKey:key]]; 327 } 328 } else { 329 NSLog(@"Unsupported value: %@ of type %@", value, [value class]); 330 NSAssert(NO, @"Unsupported value for standard codec"); 331 } 332} 333@end 334 335@implementation FlutterStandardReader { 336 NSData* _data; 337 NSRange _range; 338} 339 340- (instancetype)initWithData:(NSData*)data { 341 self = [super init]; 342 NSAssert(self, @"Super init cannot be nil"); 343 _data = [data retain]; 344 _range = NSMakeRange(0, 0); 345 return self; 346} 347 348- (void)dealloc { 349 [_data release]; 350 [super dealloc]; 351} 352 353- (BOOL)hasMore { 354 return _range.location < _data.length; 355} 356 357- (void)readBytes:(void*)destination length:(NSUInteger)length { 358 _range.length = length; 359 [_data getBytes:destination range:_range]; 360 _range.location += _range.length; 361} 362 363- (UInt8)readByte { 364 UInt8 value; 365 [self readBytes:&value length:1]; 366 return value; 367} 368 369- (UInt32)readSize { 370 UInt8 byte = [self readByte]; 371 if (byte < 254) { 372 return (UInt32)byte; 373 } else if (byte == 254) { 374 UInt16 value; 375 [self readBytes:&value length:2]; 376 return value; 377 } else { 378 UInt32 value; 379 [self readBytes:&value length:4]; 380 return value; 381 } 382} 383 384- (NSData*)readData:(NSUInteger)length { 385 _range.length = length; 386 NSData* data = [_data subdataWithRange:_range]; 387 _range.location += _range.length; 388 return data; 389} 390 391- (NSString*)readUTF8 { 392 NSData* bytes = [self readData:[self readSize]]; 393 return [[[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding] autorelease]; 394} 395 396- (void)readAlignment:(UInt8)alignment { 397 UInt8 mod = _range.location % alignment; 398 if (mod) { 399 _range.location += (alignment - mod); 400 } 401} 402 403- (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type { 404 UInt32 elementCount = [self readSize]; 405 UInt8 elementSize = elementSizeForFlutterStandardDataType(type); 406 [self readAlignment:elementSize]; 407 NSData* data = [self readData:elementCount * elementSize]; 408 return [FlutterStandardTypedData typedDataWithData:data type:type]; 409} 410 411- (nullable id)readValue { 412 return [self readValueOfType:[self readByte]]; 413} 414 415- (nullable id)readValueOfType:(UInt8)type { 416 FlutterStandardField field = (FlutterStandardField)type; 417 switch (field) { 418 case FlutterStandardFieldNil: 419 return nil; 420 case FlutterStandardFieldTrue: 421 return @YES; 422 case FlutterStandardFieldFalse: 423 return @NO; 424 case FlutterStandardFieldInt32: { 425 SInt32 value; 426 [self readBytes:&value length:4]; 427 return @(value); 428 } 429 case FlutterStandardFieldInt64: { 430 SInt64 value; 431 [self readBytes:&value length:8]; 432 return @(value); 433 } 434 case FlutterStandardFieldFloat64: { 435 Float64 value; 436 [self readAlignment:8]; 437 [self readBytes:&value length:8]; 438 return [NSNumber numberWithDouble:value]; 439 } 440 case FlutterStandardFieldIntHex: 441 case FlutterStandardFieldString: 442 return [self readUTF8]; 443 case FlutterStandardFieldUInt8Data: 444 case FlutterStandardFieldInt32Data: 445 case FlutterStandardFieldInt64Data: 446 case FlutterStandardFieldFloat64Data: 447 return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)]; 448 case FlutterStandardFieldList: { 449 UInt32 length = [self readSize]; 450 NSMutableArray* array = [NSMutableArray arrayWithCapacity:length]; 451 for (UInt32 i = 0; i < length; i++) { 452 id value = [self readValue]; 453 [array addObject:(value == nil ? [NSNull null] : value)]; 454 } 455 return array; 456 } 457 case FlutterStandardFieldMap: { 458 UInt32 size = [self readSize]; 459 NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size]; 460 for (UInt32 i = 0; i < size; i++) { 461 id key = [self readValue]; 462 id val = [self readValue]; 463 [dict setObject:(val == nil ? [NSNull null] : val) 464 forKey:(key == nil ? [NSNull null] : key)]; 465 } 466 return dict; 467 } 468 default: 469 NSAssert(NO, @"Corrupted standard message"); 470 } 471} 472@end 473 474@implementation FlutterStandardReaderWriter 475- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data { 476 return [[[FlutterStandardWriter alloc] initWithData:data] autorelease]; 477} 478 479- (FlutterStandardReader*)readerWithData:(NSData*)data { 480 return [[[FlutterStandardReader alloc] initWithData:data] autorelease]; 481} 482@end 483