1// Copyright © 2021 650 Industries. All rights reserved. 2 3#import "NSDictionary+EXStructuredHeadersTests.h" 4 5NS_ASSUME_NONNULL_BEGIN 6 7@implementation NSDictionary (EXStructuredHeadersTests) 8 9- (BOOL)isEqualToTestResult:(id)object 10{ 11 if ([object isKindOfClass:[NSData class]] && [@"binary" isEqualToString:self[@"__type"]]) { 12 NSData *dataToCompare = [[self class] dataFromBase32String:self[@"value"]]; 13 return [object isEqualToData:dataToCompare]; 14 } 15 16 if ([object isKindOfClass:[NSString class]] && [@"token" isEqualToString:self[@"__type"]]) { 17 return [object isEqualToString:self[@"value"]]; 18 } 19 20 // plain isEqual implementation 21 if (self == object) { 22 return YES; 23 } 24 if (![object isKindOfClass:[NSDictionary class]]) { 25 return NO; 26 } 27 return [self isEqualToDictionary:object]; 28} 29 30// https://github.com/ekscrypto/Base32/blob/77e2871b17d71891a6e56e007221d84d77e566b9/Base32/MF_Base32Additions.m 31+ (NSData *)dataFromBase32String:(NSString *)encoding 32{ 33 NSData *data = nil; 34 unsigned char *decodedBytes = NULL; 35 @try { 36#define __ 255 37 static char decodingTable[256] = { 38 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x00 - 0x0F 39 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x10 - 0x1F 40 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x20 - 0x2F 41 __,__,26,27, 28,29,30,31, __,__,__,__, __, 0,__,__, // 0x30 - 0x3F 42 __, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x40 - 0x4F 43 15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x50 - 0x5F 44 __, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x60 - 0x6F 45 15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x70 - 0x7F 46 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x80 - 0x8F 47 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x90 - 0x9F 48 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xA0 - 0xAF 49 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xB0 - 0xBF 50 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xC0 - 0xCF 51 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xD0 - 0xDF 52 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xE0 - 0xEF 53 __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xF0 - 0xFF 54 }; 55 static NSUInteger paddingAdjustment[8] = {0,1,1,1,2,3,3,4}; 56 encoding = [encoding stringByReplacingOccurrencesOfString:@"=" withString:@""]; 57 NSData *encodedData = [encoding dataUsingEncoding:NSASCIIStringEncoding]; 58 unsigned char *encodedBytes = (unsigned char *)[encodedData bytes]; 59 60 NSUInteger encodedLength = [encodedData length]; 61 if( encodedLength >= (NSUIntegerMax - 7) ) return nil; // NSUInteger overflow check 62 NSUInteger encodedBlocks = (encodedLength + 7) >> 3; 63 NSUInteger expectedDataLength = encodedBlocks * 5; 64 65 decodedBytes = calloc(expectedDataLength, 1); 66 if( decodedBytes != NULL ) { 67 68 unsigned char encodedByte1, encodedByte2, encodedByte3, encodedByte4; 69 unsigned char encodedByte5, encodedByte6, encodedByte7, encodedByte8; 70 NSUInteger encodedBytesToProcess = encodedLength; 71 NSUInteger encodedBaseIndex = 0; 72 NSUInteger decodedBaseIndex = 0; 73 unsigned char encodedBlock[8] = {0,0,0,0,0,0,0,0}; 74 NSUInteger encodedBlockIndex = 0; 75 unsigned char c; 76 while( encodedBytesToProcess-- >= 1 ) { 77 c = encodedBytes[encodedBaseIndex++]; 78 if( c == '=' ) break; // padding... 79 80 c = decodingTable[c]; 81 if( c == __ ) continue; 82 83 encodedBlock[encodedBlockIndex++] = c; 84 if( encodedBlockIndex == 8 ) { 85 encodedByte1 = encodedBlock[0]; 86 encodedByte2 = encodedBlock[1]; 87 encodedByte3 = encodedBlock[2]; 88 encodedByte4 = encodedBlock[3]; 89 encodedByte5 = encodedBlock[4]; 90 encodedByte6 = encodedBlock[5]; 91 encodedByte7 = encodedBlock[6]; 92 encodedByte8 = encodedBlock[7]; 93 decodedBytes[decodedBaseIndex] = ((encodedByte1 << 3) & 0xF8) | ((encodedByte2 >> 2) & 0x07); 94 decodedBytes[decodedBaseIndex+1] = ((encodedByte2 << 6) & 0xC0) | ((encodedByte3 << 1) & 0x3E) | ((encodedByte4 >> 4) & 0x01); 95 decodedBytes[decodedBaseIndex+2] = ((encodedByte4 << 4) & 0xF0) | ((encodedByte5 >> 1) & 0x0F); 96 decodedBytes[decodedBaseIndex+3] = ((encodedByte5 << 7) & 0x80) | ((encodedByte6 << 2) & 0x7C) | ((encodedByte7 >> 3) & 0x03); 97 decodedBytes[decodedBaseIndex+4] = ((encodedByte7 << 5) & 0xE0) | (encodedByte8 & 0x1F); 98 decodedBaseIndex += 5; 99 encodedBlockIndex = 0; 100 } 101 } 102 encodedByte7 = 0; 103 encodedByte6 = 0; 104 encodedByte5 = 0; 105 encodedByte4 = 0; 106 encodedByte3 = 0; 107 encodedByte2 = 0; 108 switch (encodedBlockIndex) { 109 case 7: 110 encodedByte7 = encodedBlock[6]; 111 case 6: 112 encodedByte6 = encodedBlock[5]; 113 case 5: 114 encodedByte5 = encodedBlock[4]; 115 case 4: 116 encodedByte4 = encodedBlock[3]; 117 case 3: 118 encodedByte3 = encodedBlock[2]; 119 case 2: 120 encodedByte2 = encodedBlock[1]; 121 case 1: 122 encodedByte1 = encodedBlock[0]; 123 decodedBytes[decodedBaseIndex] = ((encodedByte1 << 3) & 0xF8) | ((encodedByte2 >> 2) & 0x07); 124 decodedBytes[decodedBaseIndex+1] = ((encodedByte2 << 6) & 0xC0) | ((encodedByte3 << 1) & 0x3E) | ((encodedByte4 >> 4) & 0x01); 125 decodedBytes[decodedBaseIndex+2] = ((encodedByte4 << 4) & 0xF0) | ((encodedByte5 >> 1) & 0x0F); 126 decodedBytes[decodedBaseIndex+3] = ((encodedByte5 << 7) & 0x80) | ((encodedByte6 << 2) & 0x7C) | ((encodedByte7 >> 3) & 0x03); 127 decodedBytes[decodedBaseIndex+4] = ((encodedByte7 << 5) & 0xE0); 128 } 129 decodedBaseIndex += paddingAdjustment[encodedBlockIndex]; 130 data = [[NSData alloc] initWithBytes:decodedBytes length:decodedBaseIndex]; 131 } 132 } 133 @catch (NSException *exception) { 134 data = nil; 135 NSLog(@"WARNING: error occured while decoding base 32 string: %@", exception); 136 } 137 @finally { 138 if( decodedBytes != NULL ) { 139 free( decodedBytes ); 140 } 141 } 142 return data; 143} 144 145@end 146 147NS_ASSUME_NONNULL_END 148 149