GTLRBase64.m 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* Copyright (c) 2012 Google Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. //#import <GoogleAPIClientForREST/GTLRBase64.h>
  16. #import "GTLRBase64.h"
  17. // Based on Cyrus Najmabadi's elegent little encoder and decoder from
  18. // http://www.cocoadev.com/index.pl?BaseSixtyFour
  19. static char gStandardEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  20. static char gWebSafeEncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  21. #pragma mark Encode
  22. static NSString *EncodeBase64StringCommon(NSData *data, const char *table) {
  23. if (data == nil) return nil;
  24. const uint8_t* input = data.bytes;
  25. NSUInteger length = data.length;
  26. NSUInteger bufferSize = ((length + 2) / 3) * 4;
  27. NSMutableData* buffer = [NSMutableData dataWithLength:bufferSize];
  28. int8_t *output = buffer.mutableBytes;
  29. for (NSUInteger i = 0; i < length; i += 3) {
  30. NSUInteger value = 0;
  31. for (NSUInteger j = i; j < (i + 3); j++) {
  32. value <<= 8;
  33. if (j < length) {
  34. value |= (0xFF & input[j]);
  35. }
  36. }
  37. NSInteger idx = (i / 3) * 4;
  38. output[idx + 0] = table[(value >> 18) & 0x3F];
  39. output[idx + 1] = table[(value >> 12) & 0x3F];
  40. output[idx + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
  41. output[idx + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
  42. }
  43. NSString *result = [[NSString alloc] initWithData:buffer
  44. encoding:NSASCIIStringEncoding];
  45. return result;
  46. }
  47. NSString *GTLREncodeBase64(NSData *data) {
  48. return EncodeBase64StringCommon(data, gStandardEncodingTable);
  49. }
  50. NSString *GTLREncodeWebSafeBase64(NSData *data) {
  51. return EncodeBase64StringCommon(data, gWebSafeEncodingTable);
  52. }
  53. #pragma mark Decode
  54. static void CreateDecodingTable(const char *encodingTable,
  55. size_t encodingTableSize, char *decodingTable) {
  56. memset(decodingTable, 0, 128);
  57. for (unsigned int i = 0; i < encodingTableSize; i++) {
  58. decodingTable[(unsigned int) encodingTable[i]] = (char)i;
  59. }
  60. }
  61. static NSData *DecodeBase64StringCommon(NSString *base64Str,
  62. char *decodingTable,
  63. BOOL requirePadding) {
  64. // The input string should be plain ASCII
  65. const char *cString = [base64Str cStringUsingEncoding:NSASCIIStringEncoding];
  66. if (cString == nil) return nil;
  67. NSInteger inputLength = (NSInteger)strlen(cString);
  68. if (requirePadding && (inputLength % 4 != 0)) return nil;
  69. if (inputLength == 0) return [NSData data];
  70. NSInteger numEquals = 0;
  71. while (inputLength > 0 && cString[inputLength - 1] == '=') {
  72. inputLength--;
  73. if (++numEquals > 2) return nil; // malformed input
  74. }
  75. NSInteger outputLength = inputLength * 3 / 4;
  76. NSMutableData* data = [NSMutableData dataWithLength:(NSUInteger)outputLength];
  77. uint8_t *output = data.mutableBytes;
  78. NSInteger inputPoint = 0;
  79. NSInteger outputPoint = 0;
  80. char *table = decodingTable;
  81. while (inputPoint < inputLength) {
  82. int i0 = cString[inputPoint++];
  83. int i1 = cString[inputPoint++];
  84. int i2 = inputPoint < inputLength ? cString[inputPoint++] : 'A'; // 'A' will decode to \0
  85. int i3 = inputPoint < inputLength ? cString[inputPoint++] : 'A';
  86. output[outputPoint++] = (uint8_t)((table[i0] << 2) | (table[i1] >> 4));
  87. if (outputPoint < outputLength) {
  88. output[outputPoint++] = (uint8_t)(((table[i1] & 0xF) << 4) | (table[i2] >> 2));
  89. }
  90. if (outputPoint < outputLength) {
  91. output[outputPoint++] = (uint8_t)(((table[i2] & 0x3) << 6) | table[i3]);
  92. }
  93. }
  94. return data;
  95. }
  96. NSData *GTLRDecodeBase64(NSString *base64Str) {
  97. static char decodingTable[128];
  98. static BOOL hasInited = NO;
  99. if (!hasInited) {
  100. CreateDecodingTable(gStandardEncodingTable, sizeof(gStandardEncodingTable),
  101. decodingTable);
  102. hasInited = YES;
  103. }
  104. return DecodeBase64StringCommon(base64Str, decodingTable, YES /* requirePadding */ );
  105. }
  106. NSData *GTLRDecodeWebSafeBase64(NSString *base64Str) {
  107. static char decodingTable[128];
  108. static BOOL hasInited = NO;
  109. if (!hasInited) {
  110. CreateDecodingTable(gWebSafeEncodingTable, sizeof(gWebSafeEncodingTable),
  111. decodingTable);
  112. hasInited = YES;
  113. }
  114. return DecodeBase64StringCommon(base64Str, decodingTable, NO /* requirePadding */);
  115. }