1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/Telegraph/PSKeyValueEncoder.m
2016-02-25 01:03:51 +01:00

374 lines
10 KiB
Objective-C

#import "PSKeyValueEncoder.h"
#import <objc/runtime.h>
@interface PSKeyValueEncoder ()
{
@public
NSMutableData *_data;
}
@end
@implementation PSKeyValueEncoder
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_data = [[NSMutableData alloc] init];
}
return self;
}
static inline void writeLength(PSKeyValueEncoder *self, uint32_t value)
{
uint8_t bytes[5];
int length = 0;
if (value > 127)
{
bytes[length++] = ((uint8_t)(value & 127)) | 128;
value >>= 7;
}
if (value > 127)
{
bytes[length++] = ((uint8_t)(value & 127)) | 128;
value >>= 7;
}
if (value > 127)
{
bytes[length++] = ((uint8_t)(value & 127)) | 128;
value >>= 7;
}
if (value > 127)
{
bytes[length++] = ((uint8_t)(value & 127)) | 128;
value >>= 7;
}
bytes[length++] = ((uint8_t)(value & 127));
[self->_data appendBytes:bytes length:length];
}
- (void)encodeString:(NSString *)string forKey:(NSString *)key
{
if (key == nil || string == nil)
return;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)keyData.length);
[_data appendData:keyData];
uint8_t fieldType = PSKeyValueCoderFieldTypeString;
[_data appendBytes:&fieldType length:1];
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)stringData.length);
[_data appendData:stringData];
}
- (void)encodeString:(NSString *)string forCKey:(const char *)key
{
if (key == nil || string == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeString;
[_data appendBytes:&fieldType length:1];
NSData *stringData = [string dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)stringData.length);
[_data appendData:stringData];
}
- (void)encodeInt32:(int32_t)number forKey:(NSString *)key
{
if (key == nil)
return;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)keyData.length);
[_data appendData:keyData];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt32;
[_data appendBytes:&fieldType length:1];
[_data appendBytes:&number length:4];
}
- (void)encodeInt32:(int32_t)number forCKey:(const char *)key
{
if (key == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt32;
[_data appendBytes:&fieldType length:1];
[_data appendBytes:&number length:4];
}
- (void)encodeInt64:(int64_t)number forKey:(NSString *)key
{
if (key == nil)
return;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)keyData.length);
[_data appendData:keyData];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt64;
[_data appendBytes:&fieldType length:1];
[_data appendBytes:&number length:8];
}
- (void)encodeInt64:(int64_t)number forCKey:(const char *)key
{
if (key == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt64;
[_data appendBytes:&fieldType length:1];
[_data appendBytes:&number length:8];
}
- (void)encodeObject:(id<PSCoding>)object forKey:(NSString *)key
{
if (key == nil || object == nil)
return;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)keyData.length);
[_data appendData:keyData];
uint8_t fieldType = PSKeyValueCoderFieldTypeCustomClass;
[_data appendBytes:&fieldType length:1];
uint32_t objectLength = 0;
NSUInteger objectLengthPosition = [_data length];
[_data appendBytes:&objectLength length:4];
NSString *className = NSStringFromClass([object class]);
NSData *classNameData = [className dataUsingEncoding:NSUTF8StringEncoding];
[_data appendData:classNameData];
uint8_t zero = 0;
[_data appendBytes:&zero length:1];
[object encodeWithKeyValueCoder:self];
objectLength = (int)([_data length] - objectLengthPosition - 4);
[_data replaceBytesInRange:NSMakeRange(objectLengthPosition, 4) withBytes:&objectLength];
}
static void encodeObjectValue(PSKeyValueEncoder *self, id<PSCoding> object)
{
uint32_t objectLength = 0;
NSUInteger objectLengthPosition = [self->_data length];
[self->_data appendBytes:&objectLength length:4];
Class objectClass = object_getClass(object);
const char *className = class_getName(objectClass);
[self->_data appendBytes:className length:strlen(className) + 1];
[object encodeWithKeyValueCoder:self];
objectLength = (int)([self->_data length] - objectLengthPosition - 4);
[self->_data replaceBytesInRange:NSMakeRange(objectLengthPosition, 4) withBytes:&objectLength];
}
- (void)encodeObject:(id<PSCoding>)object forCKey:(const char *)key
{
if (key == nil || object == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeCustomClass;
[_data appendBytes:&fieldType length:1];
encodeObjectValue(self, object);
}
- (void)encodeArray:(NSArray *)array forKey:(NSString *)key
{
if (key == nil || array == nil)
return;
NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
writeLength(self, (uint32_t)keyData.length);
[_data appendData:keyData];
uint8_t fieldType = PSKeyValueCoderFieldTypeArray;
[_data appendBytes:&fieldType length:1];
uint32_t objectLength = 0;
NSUInteger objectLengthPosition = [self->_data length];
[self->_data appendBytes:&objectLength length:4];
uint32_t count = (uint32_t)[array count];
writeLength(self, count);
for (uint32_t i = 0; i < count; i++)
{
encodeObjectValue(self, array[i]);
}
objectLength = (int)([_data length] - objectLengthPosition - 4);
[_data replaceBytesInRange:NSMakeRange(objectLengthPosition, 4) withBytes:&objectLength];
}
- (void)encodeArray:(NSArray *)array forCKey:(const char *)key
{
if (key == nil || array == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeArray;
[_data appendBytes:&fieldType length:1];
uint32_t objectLength = 0;
NSUInteger objectLengthPosition = [self->_data length];
[self->_data appendBytes:&objectLength length:4];
uint32_t count = (uint32_t)[array count];
writeLength(self, count);
for (uint32_t i = 0; i < count; i++)
{
encodeObjectValue(self, array[i]);
}
objectLength = (int)([_data length] - objectLengthPosition - 4);
[_data replaceBytesInRange:NSMakeRange(objectLengthPosition, 4) withBytes:&objectLength];
}
- (void)encodeData:(NSData *)data forCKey:(const char *)key
{
if (key == nil || data == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeData;
[_data appendBytes:&fieldType length:1];
writeLength(self, (uint32_t)data.length);
[_data appendData:data];
}
- (void)encodeBytes:(uint8_t const *)value length:(NSUInteger)length forCKey:(const char *)key
{
if (key == nil)
return;
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeData;
[_data appendBytes:&fieldType length:1];
writeLength(self, (uint32_t)length);
[_data appendBytes:value length:length];
}
- (void)encodeInt32Array:(NSArray *)value forCKey:(const char *)key {
if (key == NULL) {
return;
}
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt32Array;
[_data appendBytes:&fieldType length:1];
int32_t count = (int32_t)value.count;
[_data appendBytes:&count length:4];
for (NSNumber *nNumber in value) {
int32_t number = [nNumber intValue];
[_data appendBytes:&number length:4];
}
}
- (void)encodeInt32Dictionary:(NSDictionary *)value forCKey:(const char *)key {
if (key == NULL) {
return;
}
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeInt32Dictionary;
[_data appendBytes:&fieldType length:1];
uint32_t objectLength = 0;
NSUInteger objectLengthPosition = [self->_data length];
[self->_data appendBytes:&objectLength length:4];
NSArray *allKeys = [value allKeys];
uint32_t count = (uint32_t)[allKeys count];
writeLength(self, count);
for (NSNumber *nKey in allKeys) {
id<PSCoding> object = value[nKey];
int32_t objectKey = [nKey intValue];
[self->_data appendBytes:&objectKey length:4];
encodeObjectValue(self, object);
}
objectLength = (int)([_data length] - objectLengthPosition - 4);
[_data replaceBytesInRange:NSMakeRange(objectLengthPosition, 4) withBytes:&objectLength];
}
- (void)encodeDouble:(double)value forCKey:(const char *)key {
uint32_t keyLength = (uint32_t)strlen(key);
writeLength(self, keyLength);
[_data appendBytes:key length:keyLength];
uint8_t fieldType = PSKeyValueCoderFieldTypeDouble;
[_data appendBytes:&fieldType length:1];
[_data appendBytes:&value length:8];
}
- (void)reset
{
[_data setLength:0];
}
- (NSData *)data
{
return _data;
}
@end