|
104 | 104 | }
|
105 | 105 |
|
106 | 106 | void
|
107 |
| -_fillArgsToInvocation(NSMethodSignature *signature, void **args, NSInvocation *invocation, NSUInteger offset, int64_t stringTypeBitmask, NSMutableArray<NSString *> *stringTypeBucket) { |
| 107 | +_fillArgsToInvocation(NSMethodSignature *signature, void **args, NSInvocation *invocation, NSUInteger offset, int64_t *stringTypeBitmaskPtr, NSMutableArray<NSString *> *stringTypeBucket) { |
108 | 108 | for (NSUInteger i = offset; i < signature.numberOfArguments; i++) {
|
109 | 109 | const char *argType = [signature getArgumentTypeAtIndex:i];
|
110 | 110 | NSUInteger argsIndex = i - offset;
|
|
119 | 119 | // Already put struct in pointer on Dart side.
|
120 | 120 | [invocation setArgument:args[argsIndex] atIndex:i];
|
121 | 121 | } else if (argType[0] == '@' &&
|
122 |
| - (stringTypeBitmask >> argsIndex & 0x1) == 1) { |
| 122 | + (*stringTypeBitmaskPtr >> (argsIndex + 1) & 0x1) == 1) { |
123 | 123 | const unichar *data = ((const unichar **)args)[argsIndex];
|
124 | 124 | // First four uint16_t is for data length.
|
125 |
| - const NSUInteger dataOffset = 4; |
| 125 | + const NSUInteger lengthDataSize = 4; |
126 | 126 | uint64_t length = data[0];
|
127 |
| - for (int i = 1; i < dataOffset; i++) { |
| 127 | + for (int i = 1; i < lengthDataSize; i++) { |
128 | 128 | length <<= 16;
|
129 | 129 | length |= data[i];
|
130 | 130 | }
|
131 |
| - NSString *realArg = [NSString stringWithCharacters:data + dataOffset length:length]; |
| 131 | + NSString *realArg = [NSString stringWithCharacters:data + lengthDataSize length:length]; |
132 | 132 | [stringTypeBucket addObject:realArg];
|
133 | 133 | free((void *)data); // Malloc data on dart side, need free here.
|
134 | 134 | [invocation setArgument:&realArg atIndex:i];
|
|
138 | 138 | }
|
139 | 139 | }
|
140 | 140 |
|
| 141 | + |
| 142 | +/// Return data for NSString: [--dataLength(64bit--)][--dataContent(utf16 without BOM)--] |
| 143 | +/// @param retVal origin return value |
| 144 | +/// @param stringTypeBitmaskPtr pointer to bitmask |
| 145 | +void *_dataForNSStringReturnValue(NSString *retVal, int64_t *stringTypeBitmaskPtr) { |
| 146 | + // first bit is for return value. |
| 147 | + *stringTypeBitmaskPtr |= 0x1; |
| 148 | + NSUInteger length = 0; |
| 149 | + const uint16_t *utf16BufferPtr = native_convert_nsstring_to_utf16(retVal, &length); |
| 150 | + size_t size = sizeof(uint16_t) * length; |
| 151 | + const size_t lengthDataSize = 4; |
| 152 | + // free memory on dart side. |
| 153 | + uint16_t *dataPtr = (uint16_t *)malloc(size + sizeof(uint16_t) * lengthDataSize); |
| 154 | + memcpy(dataPtr + lengthDataSize, utf16BufferPtr, size); |
| 155 | + uint16_t lengthData[4] = { |
| 156 | + static_cast<uint16_t>(length >> 48 & 0xffff), |
| 157 | + static_cast<uint16_t>(length >> 32 & 0xffff), |
| 158 | + static_cast<uint16_t>(length >> 16 & 0xffff), |
| 159 | + static_cast<uint16_t>(length & 0xffff) |
| 160 | + }; |
| 161 | + memcpy(dataPtr, lengthData, sizeof(uint16_t) * lengthDataSize); |
| 162 | + return dataPtr; |
| 163 | +} |
| 164 | + |
141 | 165 | void *
|
142 |
| -native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void **args, void (^callback)(void *), Dart_Port dartPort, int64_t stringTypeBitmask) { |
143 |
| - if (!object || !selector || !signature) { |
| 166 | +native_instance_invoke(id object, SEL selector, NSMethodSignature *signature, dispatch_queue_t queue, void **args, void (^callback)(void *), Dart_Port dartPort, int64_t *stringTypeBitmaskPtr) { |
| 167 | + if (!object || !selector || !signature || !stringTypeBitmaskPtr) { |
144 | 168 | return NULL;
|
145 | 169 | }
|
146 | 170 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
147 | 171 | invocation.target = object;
|
148 | 172 | invocation.selector = selector;
|
149 | 173 | NSMutableArray<NSString *> *stringTypeBucket = [NSMutableArray array];
|
150 |
| - _fillArgsToInvocation(signature, args, invocation, 2, stringTypeBitmask, stringTypeBucket); |
| 174 | + _fillArgsToInvocation(signature, args, invocation, 2, stringTypeBitmaskPtr, stringTypeBucket); |
151 | 175 |
|
152 | 176 | void *(^resultBlock)() = ^() {
|
153 | 177 | void *result = NULL;
|
|
159 | 183 | } else {
|
160 | 184 | [invocation getReturnValue:&result];
|
161 | 185 | if (returnType == '@') {
|
162 |
| - [DNObjectDealloc attachHost:(__bridge id)result |
163 |
| - dartPort:dartPort]; |
| 186 | + BOOL isNSString = [(__bridge id)result isKindOfClass:NSString.class]; |
| 187 | + // highest bit is a flag for decode. |
| 188 | + BOOL decodeRetVal = (*stringTypeBitmaskPtr & (1LL << 63)) != 0; |
| 189 | + // return value is a NSString and needs decode. |
| 190 | + if (isNSString && decodeRetVal) { |
| 191 | + result = _dataForNSStringReturnValue((__bridge NSString *)result, stringTypeBitmaskPtr); |
| 192 | + } else { |
| 193 | + [DNObjectDealloc attachHost:(__bridge id)result |
| 194 | + dartPort:dartPort]; |
| 195 | + } |
164 | 196 | }
|
165 | 197 | }
|
166 | 198 | }
|
|
198 | 230 | }
|
199 | 231 |
|
200 | 232 | void *
|
201 |
| -native_block_invoke(void *block, void **args, Dart_Port dartPort, int64_t stringTypeBitmask) { |
| 233 | +native_block_invoke(void *block, void **args, Dart_Port dartPort, int64_t *stringTypeBitmaskPtr) { |
| 234 | + if (!block || !stringTypeBitmaskPtr) { |
| 235 | + return nullptr; |
| 236 | + } |
202 | 237 | const char *typeString = DNBlockTypeEncodeString((__bridge id)block);
|
203 | 238 | NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:typeString];
|
204 | 239 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
205 | 240 | NSMutableArray<NSString *> *stringTypeBucket = [NSMutableArray array];
|
206 |
| - _fillArgsToInvocation(signature, args, invocation, 1, stringTypeBitmask, stringTypeBucket); |
| 241 | + _fillArgsToInvocation(signature, args, invocation, 1, stringTypeBitmaskPtr, stringTypeBucket); |
207 | 242 | [invocation invokeWithTarget:(__bridge id)block];
|
208 | 243 | void *result = NULL;
|
209 | 244 | const char returnType = signature.methodReturnType[0];
|
|
213 | 248 | [invocation getReturnValue:result];
|
214 | 249 | } else {
|
215 | 250 | [invocation getReturnValue:&result];
|
216 |
| - if (returnType == '@') { |
| 251 | + BOOL isNSString = [(__bridge id)result isKindOfClass:NSString.class]; |
| 252 | + BOOL decodeRetVal = (*stringTypeBitmaskPtr & (1LL << 63)) != 0; |
| 253 | + // return value is a NSString and needs decode. |
| 254 | + if (isNSString && decodeRetVal) { |
| 255 | + result = _dataForNSStringReturnValue((__bridge NSString *)result, stringTypeBitmaskPtr); |
| 256 | + } else { |
217 | 257 | [DNObjectDealloc attachHost:(__bridge id)result
|
218 | 258 | dartPort:dartPort];
|
219 | 259 | }
|
|
0 commit comments