Advertisement
sophtwhere

NSData+Base64.m

Oct 28th, 2013
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. //  NSData+Base64.m
  3. //  base64
  4. //
  5. //  Created by Matt Gallagher on 2009/06/03.
  6. //  Copyright 2009 Matt Gallagher. All rights reserved.
  7. //
  8. //  This software is provided 'as-is', without any express or implied
  9. //  warranty. In no event will the authors be held liable for any damages
  10. //  arising from the use of this software. Permission is granted to anyone to
  11. //  use this software for any purpose, including commercial applications, and to
  12. //  alter it and redistribute it freely, subject to the following restrictions:
  13. //
  14. //  1. The origin of this software must not be misrepresented; you must not
  15. //     claim that you wrote the original software. If you use this software
  16. //     in a product, an acknowledgment in the product documentation would be
  17. //     appreciated but is not required.
  18. //  2. Altered source versions must be plainly marked as such, and must not be
  19. //     misrepresented as being the original software.
  20. //  3. This notice may not be removed or altered from any source
  21. //     distribution.
  22. //
  23.  
  24. #import "NSData+Base64.h"
  25. #import "NSObject+arcAgnostics.h" // added by Jonathan Annett (sophtwhere)
  26.  
  27. //
  28. // Mapping from 6 bit pattern to ASCII character.
  29. //
  30. static unsigned char base64EncodeLookup[65] =
  31.     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  32.  
  33. //
  34. // Definition for "masked-out" areas of the base64DecodeLookup mapping
  35. //
  36. #define xx 65
  37.  
  38. //
  39. // Mapping from ASCII character to 6 bit pattern.
  40. //
  41. static unsigned char base64DecodeLookup[256] =
  42. {
  43.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  44.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  45.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63,
  46.     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx,
  47.     xx,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  48.     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx,
  49.     xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  50.     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx,
  51.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  52.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  53.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  54.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  55.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  56.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  57.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  58.     xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
  59. };
  60.  
  61. //
  62. // Fundamental sizes of the binary and base64 encode/decode units in bytes
  63. //
  64. #define BINARY_UNIT_SIZE 3
  65. #define BASE64_UNIT_SIZE 4
  66.  
  67. //
  68. // NewBase64Decode
  69. //
  70. // Decodes the base64 ASCII string in the inputBuffer to a newly malloced
  71. // output buffer.
  72. //
  73. //  inputBuffer - the source ASCII string for the decode
  74. //  length - the length of the string or -1 (to specify strlen should be used)
  75. //  outputLength - if not-NULL, on output will contain the decoded length
  76. //
  77. // returns the decoded buffer. Must be free'd by caller. Length is given by
  78. //  outputLength.
  79. //
  80. void *NewBase64Decode(
  81.     const char *inputBuffer,
  82.     size_t length,
  83.     size_t *outputLength)
  84. {
  85.     if (length == -1)
  86.     {
  87.         length = strlen(inputBuffer);
  88.     }
  89.    
  90.     size_t outputBufferSize =
  91.         ((length+BASE64_UNIT_SIZE-1) / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE;
  92.     unsigned char *outputBuffer = (unsigned char *)malloc(outputBufferSize);
  93.    
  94.     size_t i = 0;
  95.     size_t j = 0;
  96.     while (i < length)
  97.     {
  98.         //
  99.         // Accumulate 4 valid characters (ignore everything else)
  100.         //
  101.         unsigned char accumulated[BASE64_UNIT_SIZE];
  102.         size_t accumulateIndex = 0;
  103.         while (i < length)
  104.         {
  105.             unsigned char decode = base64DecodeLookup[inputBuffer[i++]];
  106.             if (decode != xx)
  107.             {
  108.                 accumulated[accumulateIndex] = decode;
  109.                 accumulateIndex++;
  110.                
  111.                 if (accumulateIndex == BASE64_UNIT_SIZE)
  112.                 {
  113.                     break;
  114.                 }
  115.             }
  116.         }
  117.        
  118.         //
  119.         // Store the 6 bits from each of the 4 characters as 3 bytes
  120.         //
  121.         // (Uses improved bounds checking suggested by Alexandre Colucci)
  122.         //
  123.         if(accumulateIndex >= 2)  
  124.             outputBuffer[j] = (accumulated[0] << 2) | (accumulated[1] >> 4);  
  125.         if(accumulateIndex >= 3)  
  126.             outputBuffer[j + 1] = (accumulated[1] << 4) | (accumulated[2] >> 2);  
  127.         if(accumulateIndex >= 4)  
  128.             outputBuffer[j + 2] = (accumulated[2] << 6) | accumulated[3];
  129.         j += accumulateIndex - 1;
  130.     }
  131.    
  132.     if (outputLength)
  133.     {
  134.         *outputLength = j;
  135.     }
  136.     return outputBuffer;
  137. }
  138.  
  139. //
  140. // NewBase64Encode
  141. //
  142. // Encodes the arbitrary data in the inputBuffer as base64 into a newly malloced
  143. // output buffer.
  144. //
  145. //  inputBuffer - the source data for the encode
  146. //  length - the length of the input in bytes
  147. //  separateLines - if zero, no CR/LF characters will be added. Otherwise
  148. //      a CR/LF pair will be added every 64 encoded chars.
  149. //  outputLength - if not-NULL, on output will contain the encoded length
  150. //      (not including terminating 0 char)
  151. //
  152. // returns the encoded buffer. Must be free'd by caller. Length is given by
  153. //  outputLength.
  154. //
  155. char *NewBase64Encode(
  156.     const void *buffer,
  157.     size_t length,
  158.     bool separateLines,
  159.     size_t *outputLength)
  160. {
  161.     const unsigned char *inputBuffer = (const unsigned char *)buffer;
  162.    
  163.     #define MAX_NUM_PADDING_CHARS 2
  164.     #define OUTPUT_LINE_LENGTH 64
  165.     #define INPUT_LINE_LENGTH ((OUTPUT_LINE_LENGTH / BASE64_UNIT_SIZE) * BINARY_UNIT_SIZE)
  166.     #define CR_LF_SIZE 2
  167.    
  168.     //
  169.     // Byte accurate calculation of final buffer size
  170.     //
  171.     size_t outputBufferSize =
  172.             ((length / BINARY_UNIT_SIZE)
  173.                 + ((length % BINARY_UNIT_SIZE) ? 1 : 0))
  174.                     * BASE64_UNIT_SIZE;
  175.     if (separateLines)
  176.     {
  177.         outputBufferSize +=
  178.             (outputBufferSize / OUTPUT_LINE_LENGTH) * CR_LF_SIZE;
  179.     }
  180.    
  181.     //
  182.     // Include space for a terminating zero
  183.     //
  184.     outputBufferSize += 1;
  185.  
  186.     //
  187.     // Allocate the output buffer
  188.     //
  189.     char *outputBuffer = (char *)malloc(outputBufferSize);
  190.     if (!outputBuffer)
  191.     {
  192.         return NULL;
  193.     }
  194.  
  195.     size_t i = 0;
  196.     size_t j = 0;
  197.     const size_t lineLength = separateLines ? INPUT_LINE_LENGTH : length;
  198.     size_t lineEnd = lineLength;
  199.    
  200.     while (true)
  201.     {
  202.         if (lineEnd > length)
  203.         {
  204.             lineEnd = length;
  205.         }
  206.  
  207.         for (; i + BINARY_UNIT_SIZE - 1 < lineEnd; i += BINARY_UNIT_SIZE)
  208.         {
  209.             //
  210.             // Inner loop: turn 48 bytes into 64 base64 characters
  211.             //
  212.             outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
  213.             outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
  214.                 | ((inputBuffer[i + 1] & 0xF0) >> 4)];
  215.             outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i + 1] & 0x0F) << 2)
  216.                 | ((inputBuffer[i + 2] & 0xC0) >> 6)];
  217.             outputBuffer[j++] = base64EncodeLookup[inputBuffer[i + 2] & 0x3F];
  218.         }
  219.        
  220.         if (lineEnd == length)
  221.         {
  222.             break;
  223.         }
  224.        
  225.         //
  226.         // Add the newline
  227.         //
  228.         outputBuffer[j++] = '\r';
  229.         outputBuffer[j++] = '\n';
  230.         lineEnd += lineLength;
  231.     }
  232.    
  233.     if (i + 1 < length)
  234.     {
  235.         //
  236.         // Handle the single '=' case
  237.         //
  238.         outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
  239.         outputBuffer[j++] = base64EncodeLookup[((inputBuffer[i] & 0x03) << 4)
  240.             | ((inputBuffer[i + 1] & 0xF0) >> 4)];
  241.         outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i + 1] & 0x0F) << 2];
  242.         outputBuffer[j++] = '=';
  243.     }
  244.     else if (i < length)
  245.     {
  246.         //
  247.         // Handle the double '=' case
  248.         //
  249.         outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0xFC) >> 2];
  250.         outputBuffer[j++] = base64EncodeLookup[(inputBuffer[i] & 0x03) << 4];
  251.         outputBuffer[j++] = '=';
  252.         outputBuffer[j++] = '=';
  253.     }
  254.     outputBuffer[j] = 0;
  255.    
  256.     //
  257.     // Set the output length and return the buffer
  258.     //
  259.     if (outputLength)
  260.     {
  261.         *outputLength = j;
  262.     }
  263.     return outputBuffer;
  264. }
  265.  
  266. @implementation NSData (Base64)
  267.  
  268. //
  269. // dataFromBase64String:
  270. //
  271. // Creates an NSData object containing the base64 decoded representation of
  272. // the base64 string 'aString'
  273. //
  274. // Parameters:
  275. //    aString - the base64 string to decode
  276. //
  277. // returns the autoreleased NSData representation of the base64 string
  278. //
  279. + (NSData *)dataFromBase64String:(NSString *)aString
  280. {
  281.     NSData *data = [aString dataUsingEncoding:NSASCIIStringEncoding];
  282.     size_t outputLength;
  283.     void *outputBuffer = NewBase64Decode([data bytes], [data length], &outputLength);
  284.     NSData *result = [NSData dataWithBytes:outputBuffer length:outputLength];
  285.     free(outputBuffer);
  286.     return result;
  287. }
  288.  
  289. //
  290. // base64EncodedString
  291. //
  292. // Creates an NSString object that contains the base 64 encoding of the
  293. // receiver's data. Lines are broken at 64 characters long.
  294. //
  295. // returns an autoreleased NSString being the base 64 representation of the
  296. //  receiver.
  297. //
  298. - (NSString *)base64EncodedString
  299. {
  300.     size_t outputLength = 0;
  301.     char *outputBuffer = NewBase64Encode([self bytes], [self length], false, &outputLength);
  302.    
  303.     NSString *result =
  304.         [[[NSString alloc]
  305.             initWithBytes:outputBuffer
  306.             length:outputLength
  307.             encoding:NSASCIIStringEncoding]
  308.         autorelease];
  309.     free(outputBuffer);
  310.     return result;
  311. }
  312.  
  313. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement