• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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