Flutter macOS Embedder
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 
7 
9 
10 #pragma mark - Codec for basic message channel
11 
12 @implementation FlutterStandardMessageCodec {
13  FlutterStandardReaderWriter* _readerWriter;
14 }
15 + (instancetype)sharedInstance {
16  static id _sharedInstance = nil;
17  if (!_sharedInstance) {
18  FlutterStandardReaderWriter* readerWriter = [[FlutterStandardReaderWriter alloc] init];
19  _sharedInstance = [[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter];
20  }
21  return _sharedInstance;
22 }
23 
24 + (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
25  return [[FlutterStandardMessageCodec alloc] initWithReaderWriter:readerWriter];
26 }
27 
28 - (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
29  self = [super init];
30  NSAssert(self, @"Super init cannot be nil");
31  _readerWriter = readerWriter;
32  return self;
33 }
34 
35 - (NSData*)encode:(id)message {
36  if (message == nil) {
37  return nil;
38  }
39  NSMutableData* data = [NSMutableData dataWithCapacity:32];
40  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
41  [writer writeValue:message];
42  return data;
43 }
44 
45 - (id)decode:(NSData*)message {
46  if ([message length] == 0) {
47  return nil;
48  }
49  FlutterStandardReader* reader = [_readerWriter readerWithData:message];
50  id value = [reader readValue];
51  NSAssert(![reader hasMore], @"Corrupted standard message");
52  return value;
53 }
54 @end
55 
56 #pragma mark - Codec for method channel
57 
58 @implementation FlutterStandardMethodCodec {
59  FlutterStandardReaderWriter* _readerWriter;
60 }
61 + (instancetype)sharedInstance {
62  static id _sharedInstance = nil;
63  if (!_sharedInstance) {
64  FlutterStandardReaderWriter* readerWriter = [[FlutterStandardReaderWriter alloc] init];
65  _sharedInstance = [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter];
66  }
67  return _sharedInstance;
68 }
69 
70 + (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
71  return [[FlutterStandardMethodCodec alloc] initWithReaderWriter:readerWriter];
72 }
73 
74 - (instancetype)initWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter {
75  self = [super init];
76  NSAssert(self, @"Super init cannot be nil");
77  _readerWriter = readerWriter;
78  return self;
79 }
80 
81 - (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
82  NSMutableData* data = [NSMutableData dataWithCapacity:32];
83  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
84  [writer writeValue:call.method];
85  [writer writeValue:call.arguments];
86  return data;
87 }
88 
89 - (NSData*)encodeSuccessEnvelope:(id)result {
90  NSMutableData* data = [NSMutableData dataWithCapacity:32];
91  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
92  [writer writeByte:0];
93  [writer writeValue:result];
94  return data;
95 }
96 
97 - (NSData*)encodeErrorEnvelope:(FlutterError*)error {
98  NSMutableData* data = [NSMutableData dataWithCapacity:32];
99  FlutterStandardWriter* writer = [_readerWriter writerWithData:data];
100  [writer writeByte:1];
101  [writer writeValue:error.code];
102  [writer writeValue:error.message];
103  [writer writeValue:error.details];
104  return data;
105 }
106 
107 - (FlutterMethodCall*)decodeMethodCall:(NSData*)message {
108  FlutterStandardReader* reader = [_readerWriter readerWithData:message];
109  id value1 = [reader readValue];
110  id value2 = [reader readValue];
111  NSAssert(![reader hasMore], @"Corrupted standard method call");
112  NSAssert([value1 isKindOfClass:[NSString class]], @"Corrupted standard method call");
114 }
115 
116 - (id)decodeEnvelope:(NSData*)envelope {
117  FlutterStandardReader* reader = [_readerWriter readerWithData:envelope];
118  UInt8 flag = [reader readByte];
119  NSAssert(flag <= 1, @"Corrupted standard envelope");
120  id result;
121  switch (flag) {
122  case 0: {
123  result = [reader readValue];
124  NSAssert(![reader hasMore], @"Corrupted standard envelope");
125  } break;
126  case 1: {
127  id code = [reader readValue];
128  id message = [reader readValue];
129  id details = [reader readValue];
130  NSAssert(![reader hasMore], @"Corrupted standard envelope");
131  NSAssert([code isKindOfClass:[NSString class]], @"Invalid standard envelope");
132  NSAssert(message == nil || [message isKindOfClass:[NSString class]],
133  @"Invalid standard envelope");
134  result = [FlutterError errorWithCode:code message:message details:details];
135  } break;
136  }
137  return result;
138 }
139 @end
140 
141 using namespace flutter;
142 
143 #pragma mark - Standard serializable types
144 
145 @implementation FlutterStandardTypedData
146 + (instancetype)typedDataWithBytes:(NSData*)data {
147  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeUInt8];
148 }
149 
150 + (instancetype)typedDataWithInt32:(NSData*)data {
151  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt32];
152 }
153 
154 + (instancetype)typedDataWithInt64:(NSData*)data {
155  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt64];
156 }
157 
158 + (instancetype)typedDataWithFloat32:(NSData*)data {
159  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat32];
160 }
161 
162 + (instancetype)typedDataWithFloat64:(NSData*)data {
163  return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat64];
164 }
165 
166 + (instancetype)typedDataWithData:(NSData*)data type:(FlutterStandardDataType)type {
167  return [[FlutterStandardTypedData alloc] initWithData:data type:type];
168 }
169 
170 - (instancetype)initWithData:(NSData*)data type:(FlutterStandardDataType)type {
172  NSAssert(data, @"Data cannot be nil");
173  NSAssert(data.length % elementSize == 0, @"Data must contain integral number of elements");
174  self = [super init];
175  NSAssert(self, @"Super init cannot be nil");
176  _data = [data copy];
177  _type = type;
178  _elementSize = elementSize;
179  _elementCount = data.length / elementSize;
180  return self;
181 }
182 
183 - (BOOL)isEqual:(id)object {
184  if (self == object) {
185  return YES;
186  }
187  if (![object isKindOfClass:[FlutterStandardTypedData class]]) {
188  return NO;
189  }
191  return self.type == other.type && self.elementCount == other.elementCount &&
192  [self.data isEqual:other.data];
193 }
194 
195 - (NSUInteger)hash {
196  return [self.data hash] ^ self.type;
197 }
198 @end
199 
200 #pragma mark - Writer and reader of standard codec
201 
202 @implementation FlutterStandardWriter {
203  NSMutableData* _data;
204 }
205 
206 - (instancetype)initWithData:(NSMutableData*)data {
207  self = [super init];
208  NSAssert(self, @"Super init cannot be nil");
209  _data = data;
210  return self;
211 }
212 
213 - (void)writeByte:(UInt8)value {
214  FlutterStandardCodecHelperWriteByte((__bridge CFMutableDataRef)_data, value);
215 }
216 
217 - (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
218  FlutterStandardCodecHelperWriteBytes((__bridge CFMutableDataRef)_data, bytes, length);
219 }
220 
221 - (void)writeData:(NSData*)data {
222  FlutterStandardCodecHelperWriteData((__bridge CFMutableDataRef)_data, (__bridge CFDataRef)data);
223 }
224 
225 - (void)writeSize:(UInt32)size {
226  FlutterStandardCodecHelperWriteSize((__bridge CFMutableDataRef)_data, size);
227 }
228 
229 - (void)writeAlignment:(UInt8)alignment {
230  FlutterStandardCodecHelperWriteAlignment((__bridge CFMutableDataRef)_data, alignment);
231 }
232 
233 - (void)writeUTF8:(NSString*)value {
234  FlutterStandardCodecHelperWriteUTF8((__bridge CFMutableDataRef)_data,
235  (__bridge CFStringRef)value);
236 }
237 
238 static FlutterStandardCodecObjcType GetWriteType(id value) {
239  if (value == nil || (__bridge CFNullRef)value == kCFNull) {
241  } else if ([value isKindOfClass:[NSNumber class]]) {
243  } else if ([value isKindOfClass:[NSString class]]) {
245  } else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
247  } else if ([value isKindOfClass:[NSData class]]) {
249  } else if ([value isKindOfClass:[NSArray class]]) {
251  } else if ([value isKindOfClass:[NSDictionary class]]) {
253  } else {
255  }
256 }
257 
259  CFTypeRef writer;
260  CFMutableDataRef data;
261 };
262 
263 static void WriteKeyValues(CFTypeRef key, CFTypeRef value, void* context) {
264  WriteKeyValuesInfo* info = (WriteKeyValuesInfo*)context;
265  FastWriteValueOfType(info->writer, info->data, key);
266  FastWriteValueOfType(info->writer, info->data, value);
267 }
268 
269 // Recurses into WriteValueOfType directly if it is writing a known type,
270 // otherwise recurses with objc_msgSend.
271 static void FastWriteValueOfType(CFTypeRef writer, CFMutableDataRef data, CFTypeRef value) {
272  FlutterStandardCodecObjcType type = GetWriteType((__bridge id)value);
274  WriteValueOfType(writer, data, type, value);
275  } else {
276  [(__bridge FlutterStandardWriter*)writer writeValue:(__bridge id)value];
277  }
278 }
279 
280 static void WriteValueOfType(CFTypeRef writer,
281  CFMutableDataRef data,
283  CFTypeRef value) {
284  switch (type) {
287  break;
289  CFNumberRef number = (CFNumberRef)value;
290  BOOL success = FlutterStandardCodecHelperWriteNumber(data, number);
291  if (!success) {
292  NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
293  NSCAssert(NO, @"Unsupported value for standard codec");
294  }
295  break;
296  }
298  CFStringRef string = (CFStringRef)value;
301  break;
302  }
304  FlutterStandardTypedData* typedData = (__bridge FlutterStandardTypedData*)value;
308  FlutterStandardCodecHelperWriteData(data, (__bridge CFDataRef)typedData.data);
309  break;
310  }
312  WriteValueOfType(writer, data, FlutterStandardCodecObjcTypeFlutterStandardTypedData,
313  (__bridge CFTypeRef)
314  [FlutterStandardTypedData typedDataWithBytes:(__bridge NSData*)value]);
315  break;
317  CFArrayRef array = (CFArrayRef)value;
319  CFIndex count = CFArrayGetCount(array);
321  for (CFIndex i = 0; i < count; ++i) {
322  FastWriteValueOfType(writer, data, CFArrayGetValueAtIndex(array, i));
323  }
324  break;
325  }
327  CFDictionaryRef dict = (CFDictionaryRef)value;
329  CFIndex count = CFDictionaryGetCount(dict);
331  WriteKeyValuesInfo info = {
332  .writer = writer,
333  .data = data,
334  };
335  CFDictionaryApplyFunction(dict, WriteKeyValues, (void*)&info);
336  break;
337  }
339  id objc_value = (__bridge id)value;
340  NSLog(@"Unsupported value: %@ of type %@", objc_value, [objc_value class]);
341  NSCAssert(NO, @"Unsupported value for standard codec");
342  break;
343  }
344  }
345 }
346 
347 - (void)writeValue:(id)value {
348  FlutterStandardCodecObjcType type = GetWriteType(value);
349  WriteValueOfType((__bridge CFTypeRef)self, (__bridge CFMutableDataRef)self->_data, type,
350  (__bridge CFTypeRef)value);
351 }
352 @end
353 
354 @implementation FlutterStandardReader {
355  NSData* _data;
356  NSRange _range;
357 }
358 
359 - (instancetype)initWithData:(NSData*)data {
360  self = [super init];
361  NSAssert(self, @"Super init cannot be nil");
362  _data = [data copy];
363  _range = NSMakeRange(0, 0);
364  return self;
365 }
366 
367 - (BOOL)hasMore {
368  return _range.location < _data.length;
369 }
370 
371 - (void)readBytes:(void*)destination length:(NSUInteger)length {
372  FlutterStandardCodecHelperReadBytes(&_range.location, length, destination,
373  (__bridge CFDataRef)_data);
374 }
375 
376 - (UInt8)readByte {
377  return FlutterStandardCodecHelperReadByte(&_range.location, (__bridge CFDataRef)_data);
378 }
379 
380 - (UInt32)readSize {
381  return FlutterStandardCodecHelperReadSize(&_range.location, (__bridge CFDataRef)_data);
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  return (__bridge NSString*)FlutterStandardCodecHelperReadUTF8(&_range.location,
393  (__bridge CFDataRef)_data);
394 }
395 
396 - (void)readAlignment:(UInt8)alignment {
397  FlutterStandardCodecHelperReadAlignment(&_range.location, alignment);
398 }
399 
400 - (nullable id)readValue {
401  return (__bridge id)ReadValue((__bridge CFTypeRef)self);
402 }
403 
404 static CFTypeRef ReadValue(CFTypeRef user_data) {
406  uint8_t type = FlutterStandardCodecHelperReadByte(&reader->_range.location,
407  (__bridge CFDataRef)reader->_data);
408  return (__bridge CFTypeRef)[reader readValueOfType:type];
409 }
410 
411 static CFTypeRef ReadTypedDataOfType(FlutterStandardField field, CFTypeRef user_data) {
413  unsigned long* location = &reader->_range.location;
414  CFDataRef data = (__bridge CFDataRef)reader->_data;
415  FlutterStandardDataType type = FlutterStandardDataTypeForField(field);
416 
417  UInt64 elementCount = FlutterStandardCodecHelperReadSize(location, data);
418  UInt64 elementSize = elementSizeForFlutterStandardDataType(type);
419  FlutterStandardCodecHelperReadAlignment(location, elementSize);
420  UInt64 length = elementCount * elementSize;
421  NSRange range = NSMakeRange(*location, length);
422  // Note: subdataWithRange performs better than CFDataCreate and
423  // CFDataCreateBytesNoCopy crashes.
424  NSData* bytes = [(__bridge NSData*)data subdataWithRange:range];
425  *location += length;
426  return (__bridge CFTypeRef)[FlutterStandardTypedData typedDataWithData:bytes type:type];
427 }
428 
429 - (nullable id)readValueOfType:(UInt8)type {
430  return (__bridge id)FlutterStandardCodecHelperReadValueOfType(
431  &_range.location, (__bridge CFDataRef)_data, type, ReadValue, ReadTypedDataOfType,
432  (__bridge CFTypeRef)self);
433 }
434 @end
435 
436 @implementation FlutterStandardReaderWriter
437 - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
438  return [[FlutterStandardWriter alloc] initWithData:data];
439 }
440 
441 - (FlutterStandardReader*)readerWithData:(NSData*)data {
442  return [[FlutterStandardReader alloc] initWithData:data];
443 }
444 @end
flutter::FlutterStandardFieldForDataType
FlutterStandardField FlutterStandardFieldForDataType(FlutterStandardDataType type)
Definition: FlutterStandardCodec_Internal.h:12
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
FlutterStandardCodecHelperReadUTF8
CFStringRef FlutterStandardCodecHelperReadUTF8(unsigned long *location, CFDataRef data)
Definition: FlutterStandardCodecHelper.cc:75
-[FlutterStandardWriter writeValue:]
void writeValue:(id value)
Definition: FlutterStandardCodec.mm:347
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterStandardCodecHelperReadSize
uint32_t FlutterStandardCodecHelperReadSize(unsigned long *location, CFDataRef data)
Definition: FlutterStandardCodecHelper.cc:49
_range
NSRange _range
Definition: FlutterStandardCodec.mm:354
WriteKeyValuesInfo
Definition: FlutterStandardCodec.mm:258
FlutterStandardTypedData::type
FlutterStandardDataType type
Definition: FlutterCodecs.h:349
FlutterStandardFieldList
@ FlutterStandardFieldList
Definition: FlutterStandardCodecHelper.h:33
user_data
void * user_data
Definition: texture_registrar_unittests.cc:27
-[FlutterStandardWriter writeByte:]
void writeByte:(UInt8 value)
Definition: FlutterStandardCodec.mm:213
FlutterError
Definition: FlutterCodecs.h:246
FlutterStandardCodecHelperWriteUTF8
void FlutterStandardCodecHelperWriteUTF8(CFMutableDataRef data, CFStringRef value)
Definition: FlutterStandardCodecHelper.cc:211
flutter::FlutterStandardDataTypeForField
FlutterStandardDataType FlutterStandardDataTypeForField(FlutterStandardField field)
Definition: FlutterStandardCodec_Internal.h:27
FlutterStandardCodecHelperWriteAlignment
void FlutterStandardCodecHelperWriteAlignment(CFMutableDataRef data, uint8_t alignment)
Definition: FlutterStandardCodecHelper.cc:201
-[FlutterStandardReader readByte]
UInt8 readByte()
Definition: FlutterStandardCodec.mm:376
FlutterStandardCodecHelperReadByte
uint8_t FlutterStandardCodecHelperReadByte(unsigned long *location, CFDataRef data)
Definition: FlutterStandardCodecHelper.cc:42
FlutterStandardCodecObjcType
FlutterStandardCodecObjcType
Definition: FlutterStandardCodecHelper.h:44
FlutterStandardReader
Definition: FlutterCodecs.h:132
FlutterStandardReaderWriter
Definition: FlutterCodecs.h:172
+[FlutterError errorWithCode:message:details:]
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
FlutterStandardCodecHelperReadValueOfType
CFTypeRef FlutterStandardCodecHelperReadValueOfType(unsigned long *location, CFDataRef data, uint8_t type, CFTypeRef(*ReadValue)(CFTypeRef), CFTypeRef(*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef), CFTypeRef user_data)
Definition: FlutterStandardCodecHelper.cc:103
FlutterStandardCodecObjcTypeFlutterStandardTypedData
@ FlutterStandardCodecObjcTypeFlutterStandardTypedData
Definition: FlutterStandardCodecHelper.h:49
FlutterStandardTypedData::elementCount
UInt32 elementCount
Definition: FlutterCodecs.h:354
FlutterStandardTypedData::elementSize
UInt8 elementSize
Definition: FlutterCodecs.h:359
FlutterStandardFieldString
@ FlutterStandardFieldString
Definition: FlutterStandardCodecHelper.h:28
FlutterStandardMessageCodec
Definition: FlutterCodecs.h:209
FlutterStandardCodecObjcTypeNSString
@ FlutterStandardCodecObjcTypeNSString
Definition: FlutterStandardCodecHelper.h:48
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterStandardCodecHelper.h
flutter::elementSizeForFlutterStandardDataType
UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type)
Definition: FlutterStandardCodec_Internal.h:45
flutter
Definition: AccessibilityBridgeMac.h:16
FlutterStandardWriter
Definition: FlutterCodecs.h:92
FlutterStandardCodecObjcTypeNSArray
@ FlutterStandardCodecObjcTypeNSArray
Definition: FlutterStandardCodecHelper.h:51
FlutterStandardCodecHelperReadBytes
void FlutterStandardCodecHelperReadBytes(unsigned long *location, unsigned long length, void *destination, CFDataRef data)
Definition: FlutterStandardCodecHelper.cc:33
FlutterStandardCodecHelperWriteSize
void FlutterStandardCodecHelperWriteSize(CFMutableDataRef data, uint32_t size)
Definition: FlutterStandardCodecHelper.cc:188
FlutterStandardCodec_Internal.h
WriteKeyValuesInfo::data
CFMutableDataRef data
Definition: FlutterStandardCodec.mm:260
FlutterStandardCodecHelperWriteNumber
bool FlutterStandardCodecHelperWriteNumber(CFMutableDataRef data, CFNumberRef number)
Definition: FlutterStandardCodecHelper.cc:239
FlutterStandardField
FlutterStandardField
Definition: FlutterStandardCodecHelper.h:19
FlutterStandardCodecHelperWriteData
void FlutterStandardCodecHelperWriteData(CFMutableDataRef data, CFDataRef value)
Definition: FlutterStandardCodecHelper.cc:232
FlutterStandardCodecHelperWriteBytes
void FlutterStandardCodecHelperWriteBytes(CFMutableDataRef data, const void *bytes, unsigned long length)
Definition: FlutterStandardCodecHelper.cc:182
FlutterStandardTypedData
Definition: FlutterCodecs.h:300
-[FlutterStandardReader readValue]
nullable id readValue()
Definition: FlutterStandardCodec.mm:400
FlutterStandardTypedData::data
NSData * data
Definition: FlutterCodecs.h:344
FlutterStandardCodecHelperReadAlignment
void FlutterStandardCodecHelperReadAlignment(unsigned long *location, uint8_t alignment)
Definition: FlutterStandardCodecHelper.cc:18
FlutterStandardCodecObjcTypeNSNumber
@ FlutterStandardCodecObjcTypeNSNumber
Definition: FlutterStandardCodecHelper.h:47
-[FlutterStandardReader readValueOfType:]
nullable id readValueOfType:(UInt8 type)
Definition: FlutterStandardCodec.mm:429
FlutterStandardFieldNil
@ FlutterStandardFieldNil
Definition: FlutterStandardCodecHelper.h:21
FlutterStandardFieldMap
@ FlutterStandardFieldMap
Definition: FlutterStandardCodecHelper.h:34
FlutterStandardCodecHelperWriteByte
void FlutterStandardCodecHelperWriteByte(CFMutableDataRef data, uint8_t value)
Definition: FlutterStandardCodecHelper.cc:178
FlutterStandardCodecObjcTypeUnknown
@ FlutterStandardCodecObjcTypeUnknown
Definition: FlutterStandardCodecHelper.h:53
FlutterStandardCodecObjcTypeNil
@ FlutterStandardCodecObjcTypeNil
Definition: FlutterStandardCodecHelper.h:46
FlutterStandardCodecObjcTypeNSDictionary
@ FlutterStandardCodecObjcTypeNSDictionary
Definition: FlutterStandardCodecHelper.h:52
FlutterStandardMethodCodec
Definition: FlutterCodecs.h:469
WriteKeyValuesInfo::writer
CFTypeRef writer
Definition: FlutterStandardCodec.mm:259
FlutterStandardCodecObjcTypeNSData
@ FlutterStandardCodecObjcTypeNSData
Definition: FlutterStandardCodecHelper.h:50