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