NSData+Base32.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. //
  2. // MF_Base32Additions.m
  3. // Base32 -- RFC 4648 compatible implementation
  4. // see http://www.ietf.org/rfc/rfc4648.txt for more details
  5. //
  6. // Designed to be compiled with Automatic Reference Counting
  7. //
  8. // Created by Dave Poirier on 12-06-14.
  9. // Public Domain
  10. //
  11. #import "NSData+Base32.h"
  12. @implementation MF_Base32Codec
  13. +(NSData *)dataFromBase32String:(NSString *)encoding
  14. {
  15. NSData *data = nil;
  16. unsigned char *decodedBytes = NULL;
  17. @try {
  18. #define __ 255
  19. static char decodingTable[256] = {
  20. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x00 - 0x0F
  21. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x10 - 0x1F
  22. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x20 - 0x2F
  23. __,__,26,27, 28,29,30,31, __,__,__,__, __, 0,__,__, // 0x30 - 0x3F
  24. __, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, // 0x40 - 0x4F
  25. 15,16,17,18, 19,20,21,22, 23,24,25,__, __,__,__,__, // 0x50 - 0x5F
  26. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x60 - 0x6F
  27. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x70 - 0x7F
  28. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x80 - 0x8F
  29. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0x90 - 0x9F
  30. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xA0 - 0xAF
  31. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xB0 - 0xBF
  32. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xC0 - 0xCF
  33. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xD0 - 0xDF
  34. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xE0 - 0xEF
  35. __,__,__,__, __,__,__,__, __,__,__,__, __,__,__,__, // 0xF0 - 0xFF
  36. };
  37. static NSUInteger paddingAdjustment[8] = {0,1,2,2,3,4,4,5};
  38. NSData *encodedData = [encoding dataUsingEncoding:NSASCIIStringEncoding];
  39. unsigned char *encodedBytes = (unsigned char *)[encodedData bytes];
  40. NSUInteger encodedLength = [encodedData length];
  41. NSUInteger encodedBlocks = (encodedLength * 5) / 40;
  42. if( encodedLength % 8 != 0 ) {
  43. encodedBlocks++;
  44. }
  45. NSUInteger expectedDataLength = encodedBlocks * 5;
  46. decodedBytes = malloc(expectedDataLength);
  47. if( decodedBytes != NULL ) {
  48. unsigned char encodedByte1, encodedByte2, encodedByte3, encodedByte4;
  49. unsigned char encodedByte5, encodedByte6, encodedByte7, encodedByte8;
  50. NSUInteger encodedBytesToProcess = encodedLength;
  51. NSUInteger encodedBaseIndex = 0;
  52. NSUInteger decodedBaseIndex = 0;
  53. unsigned char encodedBlock[8] = {0,0,0,0,0,0,0,0};
  54. NSUInteger encodedBlockIndex = 0;
  55. unsigned char c;
  56. while( encodedBytesToProcess-- >= 1 ) {
  57. c = encodedBytes[encodedBaseIndex++];
  58. if( c == '=' ) break; // padding...
  59. c = decodingTable[c];
  60. if( c == __ ) continue;
  61. encodedBlock[encodedBlockIndex++] = c;
  62. if( encodedBlockIndex == 8 ) {
  63. encodedByte1 = encodedBlock[0];
  64. encodedByte2 = encodedBlock[1];
  65. encodedByte3 = encodedBlock[2];
  66. encodedByte4 = encodedBlock[3];
  67. encodedByte5 = encodedBlock[4];
  68. encodedByte6 = encodedBlock[5];
  69. encodedByte7 = encodedBlock[6];
  70. encodedByte8 = encodedBlock[7];
  71. decodedBytes[decodedBaseIndex] = ((encodedByte1 << 3) & 0xF8) | ((encodedByte2 >> 2) & 0x07);
  72. decodedBytes[decodedBaseIndex+1] = ((encodedByte2 << 6) & 0xC0) | ((encodedByte3 << 1) & 0x3E) | ((encodedByte4 >> 4) & 0x01);
  73. decodedBytes[decodedBaseIndex+2] = ((encodedByte4 << 4) & 0xF0) | ((encodedByte5 >> 1) & 0x0F);
  74. decodedBytes[decodedBaseIndex+3] = ((encodedByte5 << 7) & 0x80) | ((encodedByte6 << 2) & 0x7C) | ((encodedByte7 >> 3) & 0x03);
  75. decodedBytes[decodedBaseIndex+4] = ((encodedByte7 << 5) & 0xE0) | (encodedByte8 & 0x1F);
  76. decodedBaseIndex += 5;
  77. encodedBlockIndex = 0;
  78. }
  79. }
  80. encodedByte7 = 0;
  81. encodedByte6 = 0;
  82. encodedByte5 = 0;
  83. encodedByte4 = 0;
  84. encodedByte3 = 0;
  85. encodedByte2 = 0;
  86. switch (encodedBlockIndex) {
  87. case 7:
  88. encodedByte7 = encodedBlock[6];
  89. case 6:
  90. encodedByte6 = encodedBlock[5];
  91. case 5:
  92. encodedByte5 = encodedBlock[4];
  93. case 4:
  94. encodedByte4 = encodedBlock[3];
  95. case 3:
  96. encodedByte3 = encodedBlock[2];
  97. case 2:
  98. encodedByte2 = encodedBlock[1];
  99. case 1:
  100. encodedByte1 = encodedBlock[0];
  101. decodedBytes[decodedBaseIndex] = ((encodedByte1 << 3) & 0xF8) | ((encodedByte2 >> 2) & 0x07);
  102. decodedBytes[decodedBaseIndex+1] = ((encodedByte2 << 6) & 0xC0) | ((encodedByte3 << 1) & 0x3E) | ((encodedByte4 >> 4) & 0x01);
  103. decodedBytes[decodedBaseIndex+2] = ((encodedByte4 << 4) & 0xF0) | ((encodedByte5 >> 1) & 0x0F);
  104. decodedBytes[decodedBaseIndex+3] = ((encodedByte5 << 7) & 0x80) | ((encodedByte6 << 2) & 0x7C) | ((encodedByte7 >> 3) & 0x03);
  105. decodedBytes[decodedBaseIndex+4] = ((encodedByte7 << 5) & 0xE0);
  106. }
  107. decodedBaseIndex += paddingAdjustment[encodedBlockIndex];
  108. data = [[NSData alloc] initWithBytes:decodedBytes length:decodedBaseIndex];
  109. }
  110. }
  111. @catch (NSException *exception) {
  112. data = nil;
  113. NSLog(@"WARNING: error occured while decoding base 32 string: %@", exception);
  114. }
  115. @finally {
  116. if( decodedBytes != NULL ) {
  117. free( decodedBytes );
  118. }
  119. }
  120. return data;
  121. }
  122. +(NSString *)base32StringFromData:(NSData *)data
  123. {
  124. NSString *encoding = nil;
  125. unsigned char *encodingBytes = NULL;
  126. @try {
  127. static char encodingTable[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  128. static NSUInteger paddingTable[] = {0,6,4,3,1};
  129. // Table 3: The Base 32 Alphabet
  130. //
  131. // Value Encoding Value Encoding Value Encoding Value Encoding
  132. // 0 A 9 J 18 S 27 3
  133. // 1 B 10 K 19 T 28 4
  134. // 2 C 11 L 20 U 29 5
  135. // 3 D 12 M 21 V 30 6
  136. // 4 E 13 N 22 W 31 7
  137. // 5 F 14 O 23 X
  138. // 6 G 15 P 24 Y (pad) =
  139. // 7 H 16 Q 25 Z
  140. // 8 I 17 R 26 2
  141. NSUInteger dataLength = [data length];
  142. NSUInteger encodedBlocks = (dataLength * 8) / 40;
  143. NSUInteger padding = paddingTable[dataLength % 5];
  144. if( padding > 0 ) encodedBlocks++;
  145. NSUInteger encodedLength = encodedBlocks * 8;
  146. encodingBytes = malloc(encodedLength);
  147. if( encodingBytes != NULL ) {
  148. NSUInteger rawBytesToProcess = dataLength;
  149. NSUInteger rawBaseIndex = 0;
  150. NSUInteger encodingBaseIndex = 0;
  151. unsigned char *rawBytes = (unsigned char *)[data bytes];
  152. unsigned char rawByte1, rawByte2, rawByte3, rawByte4, rawByte5;
  153. while( rawBytesToProcess >= 5 ) {
  154. rawByte1 = rawBytes[rawBaseIndex];
  155. rawByte2 = rawBytes[rawBaseIndex+1];
  156. rawByte3 = rawBytes[rawBaseIndex+2];
  157. rawByte4 = rawBytes[rawBaseIndex+3];
  158. rawByte5 = rawBytes[rawBaseIndex+4];
  159. encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 3) & 0x1F)];
  160. encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 2) & 0x1C) | ((rawByte2 >> 6) & 0x03) ];
  161. encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 >> 1) & 0x1F)];
  162. encodingBytes[encodingBaseIndex+3] = encodingTable[((rawByte2 << 4) & 0x10) | ((rawByte3 >> 4) & 0x0F)];
  163. encodingBytes[encodingBaseIndex+4] = encodingTable[((rawByte3 << 1) & 0x1E) | ((rawByte4 >> 7) & 0x01)];
  164. encodingBytes[encodingBaseIndex+5] = encodingTable[((rawByte4 >> 2) & 0x1F)];
  165. encodingBytes[encodingBaseIndex+6] = encodingTable[((rawByte4 << 3) & 0x18) | ((rawByte5 >> 5) & 0x07)];
  166. encodingBytes[encodingBaseIndex+7] = encodingTable[rawByte5 & 0x1F];
  167. rawBaseIndex += 5;
  168. encodingBaseIndex += 8;
  169. rawBytesToProcess -= 5;
  170. }
  171. rawByte4 = 0;
  172. rawByte3 = 0;
  173. rawByte2 = 0;
  174. switch (dataLength-rawBaseIndex) {
  175. case 4:
  176. rawByte4 = rawBytes[rawBaseIndex+3];
  177. case 3:
  178. rawByte3 = rawBytes[rawBaseIndex+2];
  179. case 2:
  180. rawByte2 = rawBytes[rawBaseIndex+1];
  181. case 1:
  182. rawByte1 = rawBytes[rawBaseIndex];
  183. encodingBytes[encodingBaseIndex] = encodingTable[((rawByte1 >> 3) & 0x1F)];
  184. encodingBytes[encodingBaseIndex+1] = encodingTable[((rawByte1 << 2) & 0x1C) | ((rawByte2 >> 6) & 0x03) ];
  185. encodingBytes[encodingBaseIndex+2] = encodingTable[((rawByte2 >> 1) & 0x1F)];
  186. encodingBytes[encodingBaseIndex+3] = encodingTable[((rawByte2 << 4) & 0x10) | ((rawByte3 >> 4) & 0x0F)];
  187. encodingBytes[encodingBaseIndex+4] = encodingTable[((rawByte3 << 1) & 0x1E) | ((rawByte4 >> 7) & 0x01)];
  188. encodingBytes[encodingBaseIndex+5] = encodingTable[((rawByte4 >> 2) & 0x1F)];
  189. encodingBytes[encodingBaseIndex+6] = encodingTable[((rawByte4 << 3) & 0x18)];
  190. // we can skip rawByte5 since we have a partial block it would always be 0
  191. break;
  192. }
  193. // compute location from where to begin inserting padding, it may overwrite some bytes from the partial block encoding
  194. // if their value was 0 (cases 1-3).
  195. encodingBaseIndex = encodedLength - padding;
  196. while( padding-- > 0 ) {
  197. encodingBytes[encodingBaseIndex++] = '=';
  198. }
  199. encoding = [[NSString alloc] initWithBytes:encodingBytes length:encodedLength encoding:NSASCIIStringEncoding];
  200. }
  201. }
  202. @catch (NSException *exception) {
  203. encoding = nil;
  204. NSLog(@"WARNING: error occured while tring to encode base 32 data: %@", exception);
  205. }
  206. @finally {
  207. if( encodingBytes != NULL ) {
  208. free( encodingBytes );
  209. }
  210. }
  211. return encoding;
  212. }
  213. @end
  214. @implementation NSString (Base32Addition)
  215. -(NSString *)base32String
  216. {
  217. NSData *utf8encoding = [self dataUsingEncoding:NSUTF8StringEncoding];
  218. return [MF_Base32Codec base32StringFromData:utf8encoding];
  219. }
  220. +(NSString *)stringFromBase32String:(NSString *)base32String
  221. {
  222. NSData *utf8encoding = [MF_Base32Codec dataFromBase32String:base32String];
  223. return [[NSString alloc] initWithData:utf8encoding encoding:NSUTF8StringEncoding];
  224. }
  225. @end
  226. @implementation NSData (Base32Addition)
  227. +(NSData *)dataWithBase32String:(NSString *)base32String
  228. {
  229. return [MF_Base32Codec dataFromBase32String:base32String];
  230. }
  231. -(NSString *)base32String
  232. {
  233. return [MF_Base32Codec base32StringFromData:self];
  234. }
  235. @end