Flutter macOS Embedder
FlutterCodecs.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 
6 
7 #include <cstring>
8 
10 
11 @implementation FlutterBinaryCodec
12 + (instancetype)sharedInstance {
13  static id _sharedInstance = nil;
14  if (!_sharedInstance) {
15  _sharedInstance = [[FlutterBinaryCodec alloc] init];
16  }
17  return _sharedInstance;
18 }
19 
20 - (NSData*)encode:(id)message {
21  NSAssert(!message || [message isKindOfClass:[NSData class]], @"");
22  return message;
23 }
24 
25 - (NSData*)decode:(NSData*)message {
26  return message;
27 }
28 @end
29 
30 @implementation FlutterStringCodec
31 + (instancetype)sharedInstance {
32  static id _sharedInstance = nil;
33  if (!_sharedInstance) {
34  _sharedInstance = [[FlutterStringCodec alloc] init];
35  }
36  return _sharedInstance;
37 }
38 
39 - (NSData*)encode:(id)message {
40  if (message == nil) {
41  return nil;
42  }
43  NSAssert([message isKindOfClass:[NSString class]], @"");
44  NSString* stringMessage = message;
45  const char* utf8 = stringMessage.UTF8String;
46  return [NSData dataWithBytes:utf8 length:strlen(utf8)];
47 }
48 
49 - (NSString*)decode:(NSData*)message {
50  if (message == nil) {
51  return nil;
52  }
53  return [[NSString alloc] initWithData:message encoding:NSUTF8StringEncoding];
54 }
55 @end
56 
57 @implementation FlutterJSONMessageCodec
58 + (instancetype)sharedInstance {
59  static id _sharedInstance = nil;
60  if (!_sharedInstance) {
61  _sharedInstance = [[FlutterJSONMessageCodec alloc] init];
62  }
63  return _sharedInstance;
64 }
65 
66 - (NSData*)encode:(id)message {
67  if (message == nil) {
68  return nil;
69  }
70  NSData* encoding;
71  NSError* error;
72  if ([message isKindOfClass:[NSArray class]] || [message isKindOfClass:[NSDictionary class]]) {
73  encoding = [NSJSONSerialization dataWithJSONObject:message options:0 error:&error];
74  } else {
75  // NSJSONSerialization does not support top-level simple values.
76  // We encode as singleton array, then extract the relevant bytes.
77  encoding = [NSJSONSerialization dataWithJSONObject:@[ message ] options:0 error:&error];
78  if (encoding) {
79  encoding = [encoding subdataWithRange:NSMakeRange(1, encoding.length - 2)];
80  }
81  }
82  NSAssert(encoding, @"Invalid JSON message, encoding failed: %@", error);
83  return encoding;
84 }
85 
86 - (id)decode:(NSData*)message {
87  if ([message length] == 0) {
88  return nil;
89  }
90  BOOL isSimpleValue = NO;
91  id decoded = nil;
92  NSError* error;
93  if (0 < message.length) {
94  UInt8 first;
95  [message getBytes:&first length:1];
96  isSimpleValue = first != '{' && first != '[';
97  if (isSimpleValue) {
98  // NSJSONSerialization does not support top-level simple values.
99  // We expand encoding to singleton array, then decode that and extract
100  // the single entry.
101  UInt8 begin = '[';
102  UInt8 end = ']';
103  NSMutableData* expandedMessage = [NSMutableData dataWithLength:message.length + 2];
104  [expandedMessage replaceBytesInRange:NSMakeRange(0, 1) withBytes:&begin];
105  [expandedMessage replaceBytesInRange:NSMakeRange(1, message.length) withBytes:message.bytes];
106  [expandedMessage replaceBytesInRange:NSMakeRange(message.length + 1, 1) withBytes:&end];
107  message = expandedMessage;
108  }
109  decoded = [NSJSONSerialization JSONObjectWithData:message options:0 error:&error];
110  }
111  NSAssert(decoded, @"Invalid JSON message, decoding failed: %@", error);
112  return isSimpleValue ? ((NSArray*)decoded)[0] : decoded;
113 }
114 @end
115 
116 @implementation FlutterJSONMethodCodec
117 + (instancetype)sharedInstance {
118  static id _sharedInstance = nil;
119  if (!_sharedInstance) {
120  _sharedInstance = [[FlutterJSONMethodCodec alloc] init];
121  }
122  return _sharedInstance;
123 }
124 
125 - (NSData*)encodeMethodCall:(FlutterMethodCall*)call {
126  return [[FlutterJSONMessageCodec sharedInstance] encode:@{
127  @"method" : call.method,
128  @"args" : [self wrapNil:call.arguments],
129  }];
130 }
131 
132 - (NSData*)encodeSuccessEnvelope:(id)result {
133  return [[FlutterJSONMessageCodec sharedInstance] encode:@[ [self wrapNil:result] ]];
134 }
135 
136 - (NSData*)encodeErrorEnvelope:(FlutterError*)error {
137  return [[FlutterJSONMessageCodec sharedInstance] encode:@[
138  error.code,
139  [self wrapNil:error.message],
140  [self wrapNil:error.details],
141  ]];
142 }
143 
144 - (FlutterMethodCall*)decodeMethodCall:(NSData*)message {
145  NSDictionary* dictionary = [[FlutterJSONMessageCodec sharedInstance] decode:message];
146  id method = dictionary[@"method"];
147  id arguments = [self unwrapNil:dictionary[@"args"]];
148  NSAssert([method isKindOfClass:[NSString class]], @"Invalid JSON method call");
149  return [FlutterMethodCall methodCallWithMethodName:method arguments:arguments];
150 }
151 
152 - (id)decodeEnvelope:(NSData*)envelope {
153  NSArray* array = [[FlutterJSONMessageCodec sharedInstance] decode:envelope];
154  if (array.count == 1) {
155  return [self unwrapNil:array[0]];
156  }
157  NSAssert(array.count == 3, @"Invalid JSON envelope");
158  id code = array[0];
159  id message = [self unwrapNil:array[1]];
160  id details = [self unwrapNil:array[2]];
161  NSAssert([code isKindOfClass:[NSString class]], @"Invalid JSON envelope");
162  NSAssert(message == nil || [message isKindOfClass:[NSString class]], @"Invalid JSON envelope");
163  return [FlutterError errorWithCode:code message:message details:details];
164 }
165 
166 - (id)wrapNil:(id)value {
167  return value == nil ? [NSNull null] : value;
168 }
169 - (id)unwrapNil:(id)value {
170  return value == [NSNull null] ? nil : value;
171 }
172 @end
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
FlutterError
Definition: FlutterCodecs.h:246
+[FlutterError errorWithCode:message:details:]
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
FlutterMethodCall
Definition: FlutterCodecs.h:220
FlutterStringCodec
Definition: FlutterCodecs.h:63
FlutterCodecs.h
FlutterJSONMethodCodec
Definition: FlutterCodecs.h:455
FlutterBinaryCodec
Definition: FlutterCodecs.h:52
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()
FlutterJSONMessageCodec
Definition: FlutterCodecs.h:81