Flutter Engine
FlutterStandardCodec.mm
Go to the documentation of this file.
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 #import "flutter/shell/platform/darwin/common/framework/Source/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");
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 
148 using 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 {
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]]) {
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
instancetype errorWithCode:message:details:(NSString *code, [message] NSString *_Nullable message, [details] id _Nullable details)
NSRange _range
FlMethodResponse GError ** error
void readBytes:length:(void *destination, [length] NSUInteger length)
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
void readAlignment:(UInt8 alignment)
instancetype sharedInstance()
instancetype typedDataWithBytes:(NSData *data)
FlutterStandardDataType type
uint8_t value
size_t length
void writeAlignment:(UInt8 alignment)
NSData * readData:(NSUInteger length)
instancetype methodCallWithMethodName:arguments:(NSString *method, [arguments] id _Nullable arguments)
UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type)
nullable id readValueOfType:(UInt8 type)
void writeBytes:length:(const void *bytes, [length] NSUInteger length)
void writeUTF8:(NSString *value)
int32_t id