231 lines
7.1 KiB
Objective-C
231 lines
7.1 KiB
Objective-C
//
|
|
// FluttifyMessageCodec.m
|
|
// FMDB
|
|
//
|
|
// Created by Yohom Bao on 2020/8/31.
|
|
//
|
|
|
|
#import "FluttifyMessageCodec.h"
|
|
|
|
extern NSMutableDictionary<NSString *, NSObject *> *HEAP;
|
|
|
|
typedef NS_ENUM(NSInteger, FluttifyField) {
|
|
FluttifyFieldNil,
|
|
FluttifyFieldTrue,
|
|
FluttifyFieldFalse,
|
|
FluttifyFieldInt32,
|
|
FluttifyFieldInt64,
|
|
FluttifyFieldIntHex,
|
|
FluttifyFieldFloat64,
|
|
FluttifyFieldString,
|
|
// The following must match the corresponding order from `FlutterStandardDataType`.
|
|
FluttifyFieldUInt8Data,
|
|
FluttifyFieldInt32Data,
|
|
FluttifyFieldInt64Data,
|
|
FluttifyFieldFloat64Data,
|
|
FluttifyFieldList,
|
|
FluttifyFieldMap,
|
|
FluttifyFieldEnum = 126,
|
|
FluttifyFieldRef = 127,
|
|
};
|
|
|
|
UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) {
|
|
switch (type) {
|
|
case FlutterStandardDataTypeUInt8:
|
|
return 1;
|
|
case FlutterStandardDataTypeInt32:
|
|
return 4;
|
|
case FlutterStandardDataTypeInt64:
|
|
return 8;
|
|
case FlutterStandardDataTypeFloat64:
|
|
return 8;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
@implementation FluttifyReaderWriter
|
|
- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data {
|
|
return [[FluttifyWriter alloc] initWithData:data];
|
|
}
|
|
|
|
- (FlutterStandardReader *)readerWithData:(NSData *)data {
|
|
return [[FluttifyReader alloc] initWithData:data];
|
|
}
|
|
@end
|
|
|
|
@implementation FluttifyWriter
|
|
|
|
- (void)writeValue:(id)value {
|
|
if (value == nil || value == [NSNull null]) {
|
|
[self writeByte:FluttifyFieldNil];
|
|
} else if ([value isKindOfClass:[NSNumber class]]) {
|
|
CFNumberRef number = (__bridge CFNumberRef) value;
|
|
BOOL success = NO;
|
|
if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
|
|
BOOL b = CFBooleanGetValue((CFBooleanRef) number);
|
|
[self writeByte:(b ? FluttifyFieldTrue : FluttifyFieldFalse)];
|
|
success = YES;
|
|
} else if (CFNumberIsFloatType(number)) {
|
|
Float64 f;
|
|
success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
|
|
if (success) {
|
|
[self writeByte:FluttifyFieldFloat64];
|
|
[self writeAlignment:8];
|
|
[self writeBytes:(UInt8 *) &f length:8];
|
|
}
|
|
} else if (CFNumberGetByteSize(number) <= 4) {
|
|
SInt32 n;
|
|
success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
|
|
if (success) {
|
|
[self writeByte:FluttifyFieldInt32];
|
|
[self writeBytes:(UInt8 *) &n length:4];
|
|
}
|
|
} else if (CFNumberGetByteSize(number) <= 8) {
|
|
SInt64 n;
|
|
success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
|
|
if (success) {
|
|
[self writeByte:FluttifyFieldInt64];
|
|
[self writeBytes:(UInt8 *) &n length:8];
|
|
}
|
|
}
|
|
if (!success) {
|
|
NSLog(@"Unsupported value: %@ of number type %d", value, CFNumberGetType(number));
|
|
NSAssert(NO, @"Unsupported value for standard codec");
|
|
}
|
|
} else if ([value isKindOfClass:[NSString class]]) {
|
|
NSString *string = value;
|
|
[self writeByte:FluttifyFieldString];
|
|
[self writeUTF8:string];
|
|
} else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
|
|
FlutterStandardTypedData *typedData = value;
|
|
[self writeByte:(FluttifyField) (typedData.type + FluttifyFieldUInt8Data)];
|
|
[self writeSize:typedData.elementCount];
|
|
[self writeAlignment:typedData.elementSize];
|
|
[self writeData:typedData.data];
|
|
}
|
|
// 官方给NSData也自动转换了, 但是fluttify需要的是NSData对象, 所以这里去掉NSData的自动转换
|
|
/*else if ([value isKindOfClass:[NSData class]]) {
|
|
[self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]];
|
|
} */
|
|
else if ([value isKindOfClass:[NSArray class]]) {
|
|
NSArray *array = value;
|
|
[self writeByte:FluttifyFieldList];
|
|
[self writeSize:array.count];
|
|
for (id object in array) {
|
|
[self writeValue:object];
|
|
}
|
|
} else if ([value isKindOfClass:[NSDictionary class]]) {
|
|
NSDictionary *dict = value;
|
|
[self writeByte:FluttifyFieldMap];
|
|
[self writeSize:dict.count];
|
|
for (id key in dict) {
|
|
[self writeValue:key];
|
|
[self writeValue:dict[key]];
|
|
}
|
|
}
|
|
// 传递NSObject类型
|
|
else if ([value isKindOfClass:[NSObject class]]) {
|
|
NSUInteger hash = [value hash];
|
|
NSString* refId = [NSString stringWithFormat:@"%@:%@", NSStringFromClass([value class]), @(hash)];
|
|
[self writeByte:FluttifyFieldRef];
|
|
[self writeUTF8:refId];
|
|
HEAP[refId] = value;
|
|
} else {
|
|
NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
|
|
NSAssert(NO, @"Unsupported value for standard codec");
|
|
}
|
|
}
|
|
@end
|
|
|
|
@implementation FluttifyReader
|
|
|
|
- (FlutterStandardTypedData *)readTypedDataOfType:(FlutterStandardDataType)type {
|
|
UInt32 elementCount = [self readSize];
|
|
UInt8 elementSize = elementSizeForFlutterStandardDataType(type);
|
|
[self readAlignment:elementSize];
|
|
NSData *data = [self readData:elementCount * elementSize];
|
|
|
|
switch (type) {
|
|
case FlutterStandardDataTypeUInt8:
|
|
return [FlutterStandardTypedData typedDataWithBytes:data];
|
|
case FlutterStandardDataTypeInt32:
|
|
return [FlutterStandardTypedData typedDataWithInt32:data];
|
|
case FlutterStandardDataTypeInt64:
|
|
return [FlutterStandardTypedData typedDataWithInt64:data];
|
|
case FlutterStandardDataTypeFloat64:
|
|
return [FlutterStandardTypedData typedDataWithFloat64:data];
|
|
default:
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
- (nullable id)readValueOfType:(UInt8)type {
|
|
FluttifyField field = (FluttifyField) type;
|
|
switch (field) {
|
|
case FluttifyFieldNil:
|
|
return nil;
|
|
case FluttifyFieldTrue:
|
|
return @YES;
|
|
case FluttifyFieldFalse:
|
|
return @NO;
|
|
case FluttifyFieldInt32: {
|
|
SInt32 value;
|
|
[self readBytes:&value length:4];
|
|
return @(value);
|
|
}
|
|
case FluttifyFieldInt64: {
|
|
SInt64 value;
|
|
[self readBytes:&value length:8];
|
|
return @(value);
|
|
}
|
|
case FluttifyFieldFloat64: {
|
|
Float64 value;
|
|
[self readAlignment:8];
|
|
[self readBytes:&value length:8];
|
|
return @(value);
|
|
}
|
|
case FluttifyFieldIntHex:
|
|
case FluttifyFieldString:
|
|
return [self readUTF8];
|
|
case FluttifyFieldUInt8Data:
|
|
case FluttifyFieldInt32Data:
|
|
case FluttifyFieldInt64Data:
|
|
case FluttifyFieldFloat64Data:
|
|
return [self readTypedDataOfType:(FlutterStandardDataType) (field - FluttifyFieldUInt8Data)];
|
|
case FluttifyFieldList: {
|
|
UInt32 length = [self readSize];
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity:length];
|
|
for (UInt32 i = 0; i < length; i++) {
|
|
id value = [self readValue];
|
|
[array addObject:(value == nil ? [NSNull null] : value)];
|
|
}
|
|
return array;
|
|
}
|
|
case FluttifyFieldMap: {
|
|
UInt32 size = [self readSize];
|
|
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:size];
|
|
for (UInt32 i = 0; i < size; i++) {
|
|
id key = [self readValue];
|
|
id val = [self readValue];
|
|
dict[key == nil ? [NSNull null] : key] = val == nil ? [NSNull null] : val;
|
|
}
|
|
return dict;
|
|
}
|
|
// 枚举类型直接使用int值
|
|
case FluttifyFieldEnum: {
|
|
SInt32 value;
|
|
[self readBytes:&value length:4];
|
|
return @(value);
|
|
}
|
|
case FluttifyFieldRef: {
|
|
NSString *refId = [self readUTF8];
|
|
return HEAP[refId];
|
|
}
|
|
default:
|
|
NSAssert(NO, @"Corrupted standard message");
|
|
return nil;
|
|
}
|
|
}
|
|
@end
|