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 length] == 0)
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)typedDataWithFloat32:(NSData*)data {
166  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat32];
167 }
168 
169 + (instancetype)typedDataWithFloat64:(NSData*)data {
170  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat64];
171 }
172 
173 + (instancetype)typedDataWithData:(NSData*)data type:(FlutterStandardDataType)type {
174  return [[[FlutterStandardTypedData alloc] initWithData:data type:type] autorelease];
175 }
176 
177 - (instancetype)initWithData:(NSData*)data type:(FlutterStandardDataType)type {
179  NSAssert(data, @"Data cannot be nil");
180  NSAssert(data.length % elementSize == 0, @"Data must contain integral number of elements");
181  self = [super init];
182  NSAssert(self, @"Super init cannot be nil");
183  _data = [data retain];
184  _type = type;
185  _elementSize = elementSize;
186  _elementCount = data.length / elementSize;
187  return self;
188 }
189 
190 - (void)dealloc {
191  [_data release];
192  [super dealloc];
193 }
194 
195 - (BOOL)isEqual:(id)object {
196  if (self == object)
197  return YES;
198  if (![object isKindOfClass:[FlutterStandardTypedData class]])
199  return NO;
200  FlutterStandardTypedData* other = (FlutterStandardTypedData*)object;
201  return self.type == other.type && self.elementCount == other.elementCount &&
202  [self.data isEqual:other.data];
203 }
204 
205 - (NSUInteger)hash {
206  return [self.data hash] ^ self.type;
207 }
208 @end
209 
210 #pragma mark - Writer and reader of standard codec
211 
212 @implementation FlutterStandardWriter {
213  NSMutableData* _data;
214 }
215 
216 - (instancetype)initWithData:(NSMutableData*)data {
217  self = [super init];
218  NSAssert(self, @"Super init cannot be nil");
219  _data = [data retain];
220  return self;
221 }
222 
223 - (void)dealloc {
224  [_data release];
225  [super dealloc];
226 }
227 
228 - (void)writeByte:(UInt8)value {
229  [_data appendBytes:&value length:1];
230 }
231 
232 - (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
233  [_data appendBytes:bytes length:length];
234 }
235 
236 - (void)writeData:(NSData*)data {
237  [_data appendData:data];
238 }
239 
240 - (void)writeSize:(UInt32)size {
241  if (size < 254) {
242  [self writeByte:(UInt8)size];
243  } else if (size <= 0xffff) {
244  [self writeByte:254];
245  UInt16 value = (UInt16)size;
246  [self writeBytes:&value length:2];
247  } else {
248  [self writeByte:255];
249  [self writeBytes:&size length:4];
250  }
251 }
252 
253 - (void)writeAlignment:(UInt8)alignment {
254  UInt8 mod = _data.length % alignment;
255  if (mod) {
256  for (int i = 0; i < (alignment - mod); i++) {
257  [self writeByte:0];
258  }
259  }
260 }
261 
262 - (void)writeUTF8:(NSString*)value {
263  UInt32 length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
264  [self writeSize:length];
265  [self writeBytes:value.UTF8String length:length];
266 }
267 
268 - (void)writeValue:(id)value {
269  if (value == nil || value == [NSNull null]) {
270  [self writeByte:FlutterStandardFieldNil];
271  } else if ([value isKindOfClass:[NSNumber class]]) {
272  CFNumberRef number = (CFNumberRef)value;
273  BOOL success = NO;
274  if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
275  BOOL b = CFBooleanGetValue((CFBooleanRef)number);
276  [self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)];
277  success = YES;
278  } else if (CFNumberIsFloatType(number)) {
279  Float64 f;
280  success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
281  if (success) {
282  [self writeByte:FlutterStandardFieldFloat64];
283  [self writeAlignment:8];
284  [self writeBytes:(UInt8*)&f length:8];
285  }
286  } else if (CFNumberGetByteSize(number) <= 4) {
287  SInt32 n;
288  success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
289  if (success) {
290  [self writeByte:FlutterStandardFieldInt32];
291  [self writeBytes:(UInt8*)&n length:4];
292  }
293  } else if (CFNumberGetByteSize(number) <= 8) {
294  SInt64 n;
295  success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
296  if (success) {
297  [self writeByte:FlutterStandardFieldInt64];
298  [self writeBytes:(UInt8*)&n length:8];
299  }
300  }
301  if (!success) {
302  NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
303  NSAssert(NO, @"Unsupported value for standard codec");
304  }
305  } else if ([value isKindOfClass:[NSString class]]) {
306  NSString* string = value;
307  [self writeByte:FlutterStandardFieldString];
308  [self writeUTF8:string];
309  } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
310  FlutterStandardTypedData* typedData = value;
311  [self writeByte:FlutterStandardFieldForDataType(typedData.type)];
312  [self writeSize:typedData.elementCount];
313  [self writeAlignment:typedData.elementSize];
314  [self writeData:typedData.data];
315  } else if ([value isKindOfClass:[NSData class]]) {
317  } else if ([value isKindOfClass:[NSArray class]]) {
318  NSArray* array = value;
319  [self writeByte:FlutterStandardFieldList];
320  [self writeSize:array.count];
321  for (id object in array) {
322  [self writeValue:object];
323  }
324  } else if ([value isKindOfClass:[NSDictionary class]]) {
325  NSDictionary* dict = value;
326  [self writeByte:FlutterStandardFieldMap];
327  [self writeSize:dict.count];
328  for (id key in dict) {
329  [self writeValue:key];
330  [self writeValue:[dict objectForKey:key]];
331  }
332  } else {
333  NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
334  NSAssert(NO, @"Unsupported value for standard codec");
335  }
336 }
337 @end
338 
339 @implementation FlutterStandardReader {
340  NSData* _data;
341  NSRange _range;
342 }
343 
344 - (instancetype)initWithData:(NSData*)data {
345  self = [super init];
346  NSAssert(self, @"Super init cannot be nil");
347  _data = [data retain];
348  _range = NSMakeRange(0, 0);
349  return self;
350 }
351 
352 - (void)dealloc {
353  [_data release];
354  [super dealloc];
355 }
356 
357 - (BOOL)hasMore {
358  return _range.location < _data.length;
359 }
360 
361 - (void)readBytes:(void*)destination length:(NSUInteger)length {
362  _range.length = length;
363  [_data getBytes:destination range:_range];
364  _range.location += _range.length;
365 }
366 
367 - (UInt8)readByte {
368  UInt8 value;
369  [self readBytes:&value length:1];
370  return value;
371 }
372 
373 - (UInt32)readSize {
374  UInt8 byte = [self readByte];
375  if (byte < 254) {
376  return (UInt32)byte;
377  } else if (byte == 254) {
378  UInt16 value;
379  [self readBytes:&value length:2];
380  return value;
381  } else {
382  UInt32 value;
383  [self readBytes:&value length:4];
384  return value;
385  }
386 }
387 
388 - (NSData*)readData:(NSUInteger)length {
389  _range.length = length;
390  NSData* data = [_data subdataWithRange:_range];
391  _range.location += _range.length;
392  return data;
393 }
394 
395 - (NSString*)readUTF8 {
396  NSData* bytes = [self readData:[self readSize]];
397  return [[[NSString alloc] initWithData:bytes encoding:NSUTF8StringEncoding] autorelease];
398 }
399 
400 - (void)readAlignment:(UInt8)alignment {
401  UInt8 mod = _range.location % alignment;
402  if (mod) {
403  _range.location += (alignment - mod);
404  }
405 }
406 
407 - (FlutterStandardTypedData*)readTypedDataOfType:(FlutterStandardDataType)type {
408  UInt32 elementCount = [self readSize];
409  UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
410  [self readAlignment:elementSize];
411  NSData* data = [self readData:elementCount * elementSize];
412  return [FlutterStandardTypedData typedDataWithData:data type:type];
413 }
414 
415 - (nullable id)readValue {
416  return [self readValueOfType:[self readByte]];
417 }
418 
419 - (nullable id)readValueOfType:(UInt8)type {
420  FlutterStandardField field = (FlutterStandardField)type;
421  switch (field) {
422  case FlutterStandardFieldNil:
423  return nil;
424  case FlutterStandardFieldTrue:
425  return @YES;
426  case FlutterStandardFieldFalse:
427  return @NO;
428  case FlutterStandardFieldInt32: {
429  SInt32 value;
430  [self readBytes:&value length:4];
431  return @(value);
432  }
433  case FlutterStandardFieldInt64: {
434  SInt64 value;
435  [self readBytes:&value length:8];
436  return @(value);
437  }
438  case FlutterStandardFieldFloat64: {
439  Float64 value;
440  [self readAlignment:8];
441  [self readBytes:&value length:8];
442  return [NSNumber numberWithDouble:value];
443  }
444  case FlutterStandardFieldIntHex:
445  case FlutterStandardFieldString:
446  return [self readUTF8];
447  case FlutterStandardFieldUInt8Data:
448  case FlutterStandardFieldInt32Data:
449  case FlutterStandardFieldInt64Data:
450  case FlutterStandardFieldFloat32Data:
451  case FlutterStandardFieldFloat64Data:
452  return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
453  case FlutterStandardFieldList: {
454  UInt32 length = [self readSize];
455  NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
456  for (UInt32 i = 0; i < length; i++) {
457  id value = [self readValue];
458  [array addObject:(value == nil ? [NSNull null] : value)];
459  }
460  return array;
461  }
462  case FlutterStandardFieldMap: {
463  UInt32 size = [self readSize];
464  NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:size];
465  for (UInt32 i = 0; i < size; i++) {
466  id key = [self readValue];
467  id val = [self readValue];
468  [dict setObject:(val == nil ? [NSNull null] : val)
469  forKey:(key == nil ? [NSNull null] : key)];
470  }
471  return dict;
472  }
473  default:
474  NSAssert(NO, @"Corrupted standard message");
475  }
476 }
477 @end
478 
479 @implementation FlutterStandardReaderWriter
480 - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
481  return [[[FlutterStandardWriter alloc] initWithData:data] autorelease];
482 }
483 
484 - (FlutterStandardReader*)readerWithData:(NSData*)data {
485  return [[[FlutterStandardReader alloc] initWithData:data] autorelease];
486 }
487 @end
KeyCallType type
const uint8_t uint32_t uint32_t GError ** error
instancetype errorWithCode:message:details:(NSString *code, [message] NSString *_Nullable message, [details] id _Nullable details)
NSRange _range
void readBytes:length:(void *destination, [length] NSUInteger length)
GAsyncResult * result
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
void writeAlignment:(UInt8 alignment)
FlutterSemanticsFlag flag
size_t length
NSData * readData:(NSUInteger length)
int BOOL
Definition: windows_types.h:37
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