FlutterStandardCodec.mm 14.4 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4
// FLUTTER_NOLINT
5

6
#import "flutter/shell/platform/darwin/common/framework/Source/FlutterStandardCodec_Internal.h"
7 8 9

#pragma mark - Codec for basic message channel

10 11 12
@implementation FlutterStandardMessageCodec {
  FlutterStandardReaderWriter* _readerWriter;
}
13 14 15
+ (instancetype)sharedInstance {
  static id _sharedInstance = nil;
  if (!_sharedInstance) {
16 17 18
    FlutterStandardReaderWriter* readerWriter =
        [[[FlutterStandardReaderWriter alloc] init] autorelease];
    _sharedInstance = [[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter];
19 20 21 22
  }
  return _sharedInstance;
}

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
+ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
  return [[[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter] autorelease];
}

- (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _readerWriter = [readerWriter retain];
  return self;
}

- (void)dealloc {
  [_readerWriter release];
  [super dealloc];
}

39
- (NSData*)encode:(id)message {
40 41
  if (message == nil)
    return nil;
42
  NSMutableData* data = [NSMutableData dataWithCapacity:32];
43
  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
44 45 46 47 48
  [writer writeValue:message];
  return data;
}

- (id)decode:(NSData*)message {
49
  if (message == nil)
50
    return nil;
51
  FlutterStandardReader* reader = [_readerWriter readerWithData:message];
52 53 54 55 56 57 58 59
  id value = [reader readValue];
  NSAssert(![reader hasMore], @"Corrupted standard message");
  return value;
}
@end

#pragma mark - Codec for method channel

60 61 62
@implementation FlutterStandardMethodCodec {
  FlutterStandardReaderWriter* _readerWriter;
}
63 64 65
+ (instancetype)sharedInstance {
  static id _sharedInstance = nil;
  if (!_sharedInstance) {
66 67 68
    FlutterStandardReaderWriter* readerWriter =
        [[[FlutterStandardReaderWriter alloc] init] autorelease];
    _sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter];
69 70 71 72
  }
  return _sharedInstance;
}

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
+ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
  return [[[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter] autorelease];
}

- (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _readerWriter = [readerWriter retain];
  return self;
}

- (void)dealloc {
  [_readerWriter release];
  [super dealloc];
}

89 90
- (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
  NSMutableData* data = [NSMutableData dataWithCapacity:32];
91
  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
92 93 94 95 96
  [writer writeValue:call.method];
  [writer writeValue:call.arguments];
  return data;
}

97 98
- (NSData*)encodeSuccessEnvelope:(id)result {
  NSMutableData* data = [NSMutableData dataWithCapacity:32];
99
  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
100 101 102 103 104 105 106
  [writer writeByte:0];
  [writer writeValue:result];
  return data;
}

- (NSData*)encodeErrorEnvelope:(FlutterError*)error {
  NSMutableData* data = [NSMutableData dataWithCapacity:32];
107
  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
108 109 110 111 112 113 114 115
  [writer writeByte:1];
  [writer writeValue:error.code];
  [writer writeValue:error.message];
  [writer writeValue:error.details];
  return data;
}

- (FlutterMethodCall*)decodeMethodCall:(NSData*)message {
116
  FlutterStandardReader* reader = [_readerWriter readerWithData:message];
117 118 119
  id value1 = [reader readValue];
  id value2 = [reader readValue];
  NSAssert(![reader hasMore], @"Corrupted standard method call");
120
  NSAssert([value1 isKindOfClass:[NSString class]], @"Corrupted standard method call");
121 122
  return [FlutterMethodCall methodCallWithMethodName:value1 arguments:value2];
}
123

124
- (id)decodeEnvelope:(NSData*)envelope {
125
  FlutterStandardReader* reader = [_readerWriter readerWithData:envelope];
126 127 128 129 130 131 132
  UInt8 flag = [reader readByte];
  NSAssert(flag <= 1, @"Corrupted standard envelope");
  id result;
  switch (flag) {
    case 0: {
      result = [reader readValue];
      NSAssert(![reader hasMore], @"Corrupted standard envelope");
133
    } break;
134 135 136 137 138
    case 1: {
      id code = [reader readValue];
      id message = [reader readValue];
      id details = [reader readValue];
      NSAssert(![reader hasMore], @"Corrupted standard envelope");
139
      NSAssert([code isKindOfClass:[NSString class]], @"Invalid standard envelope");
140 141
      NSAssert(message == nil || [message isKindOfClass:[NSString class]],
               @"Invalid standard envelope");
142
      result = [FlutterError errorWithCode:code message:message details:details];
143
    } break;
144 145 146
  }
  return result;
}
147 148
@end

149
using namespace flutter;
150 151 152 153 154

#pragma mark - Standard serializable types

@implementation FlutterStandardTypedData
+ (instancetype)typedDataWithBytes:(NSData*)data {
155
  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeUInt8];
156 157 158
}

+ (instancetype)typedDataWithInt32:(NSData*)data {
159
  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt32];
160 161 162
}

+ (instancetype)typedDataWithInt64:(NSData*)data {
163
  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt64];
164 165 166
}

+ (instancetype)typedDataWithFloat64:(NSData*)data {
167
  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat64];
168 169
}

170 171
+ (instancetype)typedDataWithData:(NSData*)data type:(FlutterStandardDataType)type {
  return [[[FlutterStandardTypedData alloc] initWithData:data type:type] autorelease];
172 173 174 175
}

- (instancetype)initWithData:(NSData*)data type:(FlutterStandardDataType)type {
  UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
176
  NSAssert(data, @"Data cannot be nil");
177
  NSAssert(data.length % elementSize == 0, @"Data must contain integral number of elements");
178 179 180 181 182 183
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _data = [data retain];
  _type = type;
  _elementSize = elementSize;
  _elementCount = data.length / elementSize;
184 185 186 187 188 189 190
  return self;
}

- (void)dealloc {
  [_data release];
  [super dealloc];
}
191 192 193 194 195 196 197 198 199 200 201 202 203 204

- (BOOL)isEqual:(id)object {
  if (self == object)
    return YES;
  if (![object isKindOfClass:[FlutterStandardTypedData class]])
    return NO;
  FlutterStandardTypedData* other = (FlutterStandardTypedData*)object;
  return self.type == other.type && self.elementCount == other.elementCount &&
         [self.data isEqual:other.data];
}

- (NSUInteger)hash {
  return [self.data hash] ^ self.type;
}
205 206 207 208 209 210 211 212 213
@end

#pragma mark - Writer and reader of standard codec

@implementation FlutterStandardWriter {
  NSMutableData* _data;
}

- (instancetype)initWithData:(NSMutableData*)data {
214 215 216
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _data = [data retain];
217 218 219 220 221 222 223 224 225 226 227 228
  return self;
}

- (void)dealloc {
  [_data release];
  [super dealloc];
}

- (void)writeByte:(UInt8)value {
  [_data appendBytes:&value length:1];
}

229 230 231 232 233 234 235 236
- (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
  [_data appendBytes:bytes length:length];
}

- (void)writeData:(NSData*)data {
  [_data appendData:data];
}

237 238 239 240 241 242
- (void)writeSize:(UInt32)size {
  if (size < 254) {
    [self writeByte:(UInt8)size];
  } else if (size <= 0xffff) {
    [self writeByte:254];
    UInt16 value = (UInt16)size;
243
    [self writeBytes:&value length:2];
244 245
  } else {
    [self writeByte:255];
246
    [self writeBytes:&size length:4];
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  }
}

- (void)writeAlignment:(UInt8)alignment {
  UInt8 mod = _data.length % alignment;
  if (mod) {
    for (int i = 0; i < (alignment - mod); i++) {
      [self writeByte:0];
    }
  }
}

- (void)writeUTF8:(NSString*)value {
  UInt32 length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  [self writeSize:length];
262
  [self writeBytes:value.UTF8String length:length];
263 264 265 266 267 268
}

- (void)writeValue:(id)value {
  if (value == nil || value == [NSNull null]) {
    [self writeByte:FlutterStandardFieldNil];
  } else if ([value isKindOfClass:[NSNumber class]]) {
269 270 271 272
    CFNumberRef number = (CFNumberRef)value;
    BOOL success = NO;
    if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
      BOOL b = CFBooleanGetValue((CFBooleanRef)number);
273
      [self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)];
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
      success = YES;
    } else if (CFNumberIsFloatType(number)) {
      Float64 f;
      success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
      if (success) {
        [self writeByte:FlutterStandardFieldFloat64];
        [self writeAlignment:8];
        [self writeBytes:(UInt8*)&f length:8];
      }
    } else if (CFNumberGetByteSize(number) <= 4) {
      SInt32 n;
      success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
      if (success) {
        [self writeByte:FlutterStandardFieldInt32];
        [self writeBytes:(UInt8*)&n length:4];
      }
    } else if (CFNumberGetByteSize(number) <= 8) {
      SInt64 n;
      success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
      if (success) {
        [self writeByte:FlutterStandardFieldInt64];
        [self writeBytes:(UInt8*)&n length:8];
      }
    }
    if (!success) {
      NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
300 301 302 303 304 305 306 307 308 309 310
      NSAssert(NO, @"Unsupported value for standard codec");
    }
  } else if ([value isKindOfClass:[NSString class]]) {
    NSString* string = value;
    [self writeByte:FlutterStandardFieldString];
    [self writeUTF8:string];
  } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
    FlutterStandardTypedData* typedData = value;
    [self writeByte:FlutterStandardFieldForDataType(typedData.type)];
    [self writeSize:typedData.elementCount];
    [self writeAlignment:typedData.elementSize];
311
    [self writeData:typedData.data];
312 313
  } else if ([value isKindOfClass:[NSData class]]) {
    [self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]];
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
  } else if ([value isKindOfClass:[NSArray class]]) {
    NSArray* array = value;
    [self writeByte:FlutterStandardFieldList];
    [self writeSize:array.count];
    for (id object in array) {
      [self writeValue:object];
    }
  } else if ([value isKindOfClass:[NSDictionary class]]) {
    NSDictionary* dict = value;
    [self writeByte:FlutterStandardFieldMap];
    [self writeSize:dict.count];
    for (id key in dict) {
      [self writeValue:key];
      [self writeValue:[dict objectForKey:key]];
    }
  } else {
330
    NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
331 332 333 334 335 336 337 338 339 340 341
    NSAssert(NO, @"Unsupported value for standard codec");
  }
}
@end

@implementation FlutterStandardReader {
  NSData* _data;
  NSRange _range;
}

- (instancetype)initWithData:(NSData*)data {
342 343 344 345
  self = [super init];
  NSAssert(self, @"Super init cannot be nil");
  _data = [data retain];
  _range = NSMakeRange(0, 0);
346 347 348 349 350 351 352 353 354 355 356 357
  return self;
}

- (void)dealloc {
  [_data release];
  [super dealloc];
}

- (BOOL)hasMore {
  return _range.location < _data.length;
}

358
- (void)readBytes:(void*)destination length:(NSUInteger)length {
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
  _range.length = length;
  [_data getBytes:destination range:_range];
  _range.location += _range.length;
}

- (UInt8)readByte {
  UInt8 value;
  [self readBytes:&value length:1];
  return value;
}

- (UInt32)readSize {
  UInt8 byte = [self readByte];
  if (byte < 254) {
    return (UInt32)byte;
  } else if (byte == 254) {
    UInt16 value;
    [self readBytes:&value length:2];
    return value;
  } else {
    UInt32 value;
    [self readBytes:&value length:4];
    return value;
  }
}

385
- (NSData*)readData:(NSUInteger)length {
386 387 388 389 390 391 392 393
  _range.length = length;
  NSData* data = [_data subdataWithRange:_range];
  _range.location += _range.length;
  return data;
}

- (NSString*)readUTF8 {
  NSData* bytes = [self readData:[self readSize]];
394
  return [[[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding] autorelease];
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
}

- (void)readAlignment:(UInt8)alignment {
  UInt8 mod = _range.location % alignment;
  if (mod) {
    _range.location += (alignment - mod);
  }
}

- (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type {
  UInt32 elementCount = [self readSize];
  UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
  [self readAlignment:elementSize];
  NSData* data = [self readData:elementCount * elementSize];
  return [FlutterStandardTypedData typedDataWithData:data type:type];
}

412
- (nullable id)readValue {
413 414 415
  return [self readValueOfType:[self readByte]];
}

416
- (nullable id)readValueOfType:(UInt8)type {
417
  FlutterStandardField field = (FlutterStandardField)type;
418 419 420 421 422 423 424 425 426 427
  switch (field) {
    case FlutterStandardFieldNil:
      return nil;
    case FlutterStandardFieldTrue:
      return @YES;
    case FlutterStandardFieldFalse:
      return @NO;
    case FlutterStandardFieldInt32: {
      SInt32 value;
      [self readBytes:&value length:4];
428
      return @(value);
429 430 431 432
    }
    case FlutterStandardFieldInt64: {
      SInt64 value;
      [self readBytes:&value length:8];
433
      return @(value);
434 435 436
    }
    case FlutterStandardFieldFloat64: {
      Float64 value;
437
      [self readAlignment:8];
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
      [self readBytes:&value length:8];
      return [NSNumber numberWithDouble:value];
    }
    case FlutterStandardFieldIntHex:
    case FlutterStandardFieldString:
      return [self readUTF8];
    case FlutterStandardFieldUInt8Data:
    case FlutterStandardFieldInt32Data:
    case FlutterStandardFieldInt64Data:
    case FlutterStandardFieldFloat64Data:
      return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
    case FlutterStandardFieldList: {
      UInt32 length = [self readSize];
      NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
      for (UInt32 i = 0; i < length; i++) {
        id value = [self readValue];
        [array addObject:(value == nil ? [NSNull null] : value)];
      }
      return array;
    }
    case FlutterStandardFieldMap: {
      UInt32 size = [self readSize];
460
      NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
461 462 463 464 465 466 467 468 469 470 471 472 473
      for (UInt32 i = 0; i < size; i++) {
        id key = [self readValue];
        id val = [self readValue];
        [dict setObject:(val == nil ? [NSNull null] : val)
                 forKey:(key == nil ? [NSNull null] : key)];
      }
      return dict;
    }
    default:
      NSAssert(NO, @"Corrupted standard message");
  }
}
@end
474 475 476 477 478 479 480 481 482 483

@implementation FlutterStandardReaderWriter
- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
  return [[[FlutterStandardWriter alloc] initWithData:data] autorelease];
}

- (FlutterStandardReader*)readerWithData:(NSData*)data {
  return [[[FlutterStandardReader alloc] initWithData:data] autorelease];
}
@end