GTMBase64.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. //
  2. // GTMBase64.m
  3. //
  4. // Copyright 2006-2008 Google Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7. // use this file except in compliance with the License. You may obtain a copy
  8. // of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. // License for the specific language governing permissions and limitations under
  16. // the License.
  17. //
  18. #import "GTMBase64.h"
  19. #import "GTMDefines.h"
  20. #import <CommonCrypto/CommonCrypto.h>
  21. #import <CommonCrypto/CommonDigest.h>
  22. static const char *kBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  23. static const char *kWebSafeBase64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  24. static const char kBase64PaddingChar = '=';
  25. static const char kBase64InvalidChar = 99;
  26. static const char kBase64DecodeChars[] = {
  27. // This array was generated by the following code:
  28. // #include <sys/time.h>
  29. // #include <stdlib.h>
  30. // #include <string.h>
  31. // main()
  32. // {
  33. // static const char Base64[] =
  34. // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  35. // char *pos;
  36. // int idx, i, j;
  37. // printf(" ");
  38. // for (i = 0; i < 255; i += 8) {
  39. // for (j = i; j < i + 8; j++) {
  40. // pos = strchr(Base64, j);
  41. // if ((pos == NULL) || (j == 0))
  42. // idx = 99;
  43. // else
  44. // idx = pos - Base64;
  45. // if (idx == 99)
  46. // printf(" %2d, ", idx);
  47. // else
  48. // printf(" %2d/*%c*/,", idx, j);
  49. // }
  50. // printf("\n ");
  51. // }
  52. // }
  53. 99, 99, 99, 99, 99, 99, 99, 99,
  54. 99, 99, 99, 99, 99, 99, 99, 99,
  55. 99, 99, 99, 99, 99, 99, 99, 99,
  56. 99, 99, 99, 99, 99, 99, 99, 99,
  57. 99, 99, 99, 99, 99, 99, 99, 99,
  58. 99, 99, 99, 62/*+*/, 99, 99, 99, 63/*/ */,
  59. 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
  60. 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
  61. 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
  62. 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
  63. 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
  64. 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 99,
  65. 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
  66. 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
  67. 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
  68. 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
  69. 99, 99, 99, 99, 99, 99, 99, 99,
  70. 99, 99, 99, 99, 99, 99, 99, 99,
  71. 99, 99, 99, 99, 99, 99, 99, 99,
  72. 99, 99, 99, 99, 99, 99, 99, 99,
  73. 99, 99, 99, 99, 99, 99, 99, 99,
  74. 99, 99, 99, 99, 99, 99, 99, 99,
  75. 99, 99, 99, 99, 99, 99, 99, 99,
  76. 99, 99, 99, 99, 99, 99, 99, 99,
  77. 99, 99, 99, 99, 99, 99, 99, 99,
  78. 99, 99, 99, 99, 99, 99, 99, 99,
  79. 99, 99, 99, 99, 99, 99, 99, 99,
  80. 99, 99, 99, 99, 99, 99, 99, 99,
  81. 99, 99, 99, 99, 99, 99, 99, 99,
  82. 99, 99, 99, 99, 99, 99, 99, 99,
  83. 99, 99, 99, 99, 99, 99, 99, 99,
  84. 99, 99, 99, 99, 99, 99, 99, 99
  85. };
  86. static const char kWebSafeBase64DecodeChars[] = {
  87. // This array was generated by the following code:
  88. // #include <sys/time.h>
  89. // #include <stdlib.h>
  90. // #include <string.h>
  91. // main()
  92. // {
  93. // static const char Base64[] =
  94. // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  95. // char *pos;
  96. // int idx, i, j;
  97. // printf(" ");
  98. // for (i = 0; i < 255; i += 8) {
  99. // for (j = i; j < i + 8; j++) {
  100. // pos = strchr(Base64, j);
  101. // if ((pos == NULL) || (j == 0))
  102. // idx = 99;
  103. // else
  104. // idx = pos - Base64;
  105. // if (idx == 99)
  106. // printf(" %2d, ", idx);
  107. // else
  108. // printf(" %2d/*%c*/,", idx, j);
  109. // }
  110. // printf("\n ");
  111. // }
  112. // }
  113. 99, 99, 99, 99, 99, 99, 99, 99,
  114. 99, 99, 99, 99, 99, 99, 99, 99,
  115. 99, 99, 99, 99, 99, 99, 99, 99,
  116. 99, 99, 99, 99, 99, 99, 99, 99,
  117. 99, 99, 99, 99, 99, 99, 99, 99,
  118. 99, 99, 99, 99, 99, 62/*-*/, 99, 99,
  119. 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
  120. 60/*8*/, 61/*9*/, 99, 99, 99, 99, 99, 99,
  121. 99, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
  122. 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
  123. 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
  124. 23/*X*/, 24/*Y*/, 25/*Z*/, 99, 99, 99, 99, 63/*_*/,
  125. 99, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
  126. 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
  127. 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
  128. 49/*x*/, 50/*y*/, 51/*z*/, 99, 99, 99, 99, 99,
  129. 99, 99, 99, 99, 99, 99, 99, 99,
  130. 99, 99, 99, 99, 99, 99, 99, 99,
  131. 99, 99, 99, 99, 99, 99, 99, 99,
  132. 99, 99, 99, 99, 99, 99, 99, 99,
  133. 99, 99, 99, 99, 99, 99, 99, 99,
  134. 99, 99, 99, 99, 99, 99, 99, 99,
  135. 99, 99, 99, 99, 99, 99, 99, 99,
  136. 99, 99, 99, 99, 99, 99, 99, 99,
  137. 99, 99, 99, 99, 99, 99, 99, 99,
  138. 99, 99, 99, 99, 99, 99, 99, 99,
  139. 99, 99, 99, 99, 99, 99, 99, 99,
  140. 99, 99, 99, 99, 99, 99, 99, 99,
  141. 99, 99, 99, 99, 99, 99, 99, 99,
  142. 99, 99, 99, 99, 99, 99, 99, 99,
  143. 99, 99, 99, 99, 99, 99, 99, 99,
  144. 99, 99, 99, 99, 99, 99, 99, 99
  145. };
  146. // Tests a character to see if it's a whitespace character.
  147. //
  148. // Returns:
  149. // YES if the character is a whitespace character.
  150. // NO if the character is not a whitespace character.
  151. //
  152. GTM_INLINE BOOL IsSpace(unsigned char c) {
  153. // we use our own mapping here because we don't want anything w/ locale
  154. // support.
  155. static BOOL kSpaces[256] = {
  156. 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // 0-9
  157. 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 10-19
  158. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20-29
  159. 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // 30-39
  160. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40-49
  161. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50-59
  162. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60-69
  163. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 70-79
  164. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-89
  165. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90-99
  166. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100-109
  167. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 110-119
  168. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120-129
  169. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 130-139
  170. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140-149
  171. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150-159
  172. 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160-169
  173. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170-179
  174. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180-189
  175. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 190-199
  176. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200-209
  177. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 210-219
  178. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220-229
  179. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 230-239
  180. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240-249
  181. 0, 0, 0, 0, 0, 1, // 250-255
  182. };
  183. return kSpaces[c];
  184. }
  185. // Calculate how long the data will be once it's base64 encoded.
  186. //
  187. // Returns:
  188. // The guessed encoded length for a source length
  189. //
  190. GTM_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen, BOOL padded) {
  191. NSUInteger intermediate_result = 8 * srcLen + 5;
  192. NSUInteger len = intermediate_result / 6;
  193. if (padded) {
  194. len = ((len + 3) / 4) * 4;
  195. }
  196. return len;
  197. }
  198. // Tries to calculate how long the data will be once it's base64 decoded.
  199. // Unlike the above, this is always an upperbound, since the source data
  200. // could have spaces and might end with the padding characters on them.
  201. //
  202. // Returns:
  203. // The guessed decoded length for a source length
  204. //
  205. GTM_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) {
  206. return (srcLen + 3) / 4 * 3;
  207. }
  208. @interface GTMBase64 (PrivateMethods)
  209. +(NSData *)baseEncode:(const void *)bytes
  210. length:(NSUInteger)length
  211. charset:(const char *)charset
  212. padded:(BOOL)padded;
  213. +(NSData *)baseDecode:(const void *)bytes
  214. length:(NSUInteger)length
  215. charset:(const char*)charset
  216. requirePadding:(BOOL)requirePadding;
  217. +(NSUInteger)baseEncode:(const char *)srcBytes
  218. srcLen:(NSUInteger)srcLen
  219. destBytes:(char *)destBytes
  220. destLen:(NSUInteger)destLen
  221. charset:(const char *)charset
  222. padded:(BOOL)padded;
  223. +(NSUInteger)baseDecode:(const char *)srcBytes
  224. srcLen:(NSUInteger)srcLen
  225. destBytes:(char *)destBytes
  226. destLen:(NSUInteger)destLen
  227. charset:(const char *)charset
  228. requirePadding:(BOOL)requirePadding;
  229. @end
  230. @implementation GTMBase64
  231. //
  232. // Standard Base64 (RFC) handling
  233. //
  234. +(NSData *)encodeData:(NSData *)data {
  235. return [self baseEncode:[data bytes]
  236. length:[data length]
  237. charset:kBase64EncodeChars
  238. padded:YES];
  239. }
  240. +(NSData *)decodeData:(NSData *)data {
  241. return [self baseDecode:[data bytes]
  242. length:[data length]
  243. charset:kBase64DecodeChars
  244. requirePadding:YES];
  245. }
  246. +(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
  247. return [self baseEncode:bytes
  248. length:length
  249. charset:kBase64EncodeChars
  250. padded:YES];
  251. }
  252. +(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
  253. return [self baseDecode:bytes
  254. length:length
  255. charset:kBase64DecodeChars
  256. requirePadding:YES];
  257. }
  258. +(NSString *)stringByEncodingData:(NSData *)data {
  259. NSString *result = nil;
  260. NSData *converted = [self baseEncode:[data bytes]
  261. length:[data length]
  262. charset:kBase64EncodeChars
  263. padded:YES];
  264. if (converted) {
  265. result = [[NSString alloc] initWithData:converted
  266. encoding:NSASCIIStringEncoding] ;
  267. }
  268. return result;
  269. }
  270. +(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
  271. NSString *result = nil;
  272. NSData *converted = [self baseEncode:bytes
  273. length:length
  274. charset:kBase64EncodeChars
  275. padded:YES];
  276. if (converted) {
  277. result = [[NSString alloc] initWithData:converted
  278. encoding:NSASCIIStringEncoding];
  279. }
  280. return result;
  281. }
  282. +(NSData *)decodeString:(NSString *)string {
  283. NSData *result = nil;
  284. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
  285. if (data) {
  286. result = [self baseDecode:[data bytes]
  287. length:[data length]
  288. charset:kBase64DecodeChars
  289. requirePadding:YES];
  290. }
  291. return result;
  292. }
  293. //
  294. // Modified Base64 encoding so the results can go onto urls.
  295. //
  296. // The changes are in the characters generated and also the result isn't
  297. // padded to a multiple of 4.
  298. // Must use the matching call to encode/decode, won't interop with the
  299. // RFC versions.
  300. //
  301. +(NSData *)webSafeEncodeData:(NSData *)data
  302. padded:(BOOL)padded {
  303. return [self baseEncode:[data bytes]
  304. length:[data length]
  305. charset:kWebSafeBase64EncodeChars
  306. padded:padded];
  307. }
  308. +(NSData *)webSafeDecodeData:(NSData *)data {
  309. return [self baseDecode:[data bytes]
  310. length:[data length]
  311. charset:kWebSafeBase64DecodeChars
  312. requirePadding:NO];
  313. }
  314. +(NSData *)webSafeEncodeBytes:(const void *)bytes
  315. length:(NSUInteger)length
  316. padded:(BOOL)padded {
  317. return [self baseEncode:bytes
  318. length:length
  319. charset:kWebSafeBase64EncodeChars
  320. padded:padded];
  321. }
  322. +(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
  323. return [self baseDecode:bytes
  324. length:length
  325. charset:kWebSafeBase64DecodeChars
  326. requirePadding:NO];
  327. }
  328. +(NSString *)stringByWebSafeEncodingData:(NSData *)data
  329. padded:(BOOL)padded {
  330. NSString *result = nil;
  331. NSData *converted = [self baseEncode:[data bytes]
  332. length:[data length]
  333. charset:kWebSafeBase64EncodeChars
  334. padded:padded];
  335. if (converted) {
  336. result = [[NSString alloc] initWithData:converted
  337. encoding:NSASCIIStringEncoding];
  338. }
  339. return result;
  340. }
  341. +(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
  342. length:(NSUInteger)length
  343. padded:(BOOL)padded {
  344. NSString *result = nil;
  345. NSData *converted = [self baseEncode:bytes
  346. length:length
  347. charset:kWebSafeBase64EncodeChars
  348. padded:padded];
  349. if (converted) {
  350. result = [[NSString alloc] initWithData:converted
  351. encoding:NSASCIIStringEncoding] ;
  352. }
  353. return result;
  354. }
  355. +(NSData *)webSafeDecodeString:(NSString *)string {
  356. NSData *result = nil;
  357. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
  358. if (data) {
  359. result = [self baseDecode:[data bytes]
  360. length:[data length]
  361. charset:kWebSafeBase64DecodeChars
  362. requirePadding:NO];
  363. }
  364. return result;
  365. }
  366. #pragma mark - base64
  367. + (NSString *) md5_base64: (NSString *) inPutText
  368. {
  369. const char *cStr = [inPutText UTF8String];
  370. unsigned char digest[16];
  371. CC_MD5( cStr, strlen(cStr), digest );
  372. NSData * base64 = [[NSData alloc]initWithBytes:digest length:16];
  373. base64 = [GTMBase64 encodeData:base64];
  374. NSString * output = [[NSString alloc] initWithData:base64 encoding:NSUTF8StringEncoding];
  375. return output;
  376. }
  377. + (NSString*)encodeBase64String:(NSString * )input {
  378. NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
  379. data = [GTMBase64 encodeData:data];
  380. NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  381. return base64String;
  382. }
  383. + (NSString*)decodeBase64String:(NSString * )input {
  384. NSData *data = [input dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
  385. data = [GTMBase64 decodeData:data];
  386. NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  387. return base64String;
  388. }
  389. + (NSString*)encodeBase64Data:(NSData *)data {
  390. data = [GTMBase64 encodeData:data];
  391. NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  392. return base64String;
  393. }
  394. + (NSString*)decodeBase64Data:(NSData *)data {
  395. data = [GTMBase64 decodeData:data];
  396. NSString *base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  397. return base64String;
  398. }
  399. @end
  400. @implementation GTMBase64 (PrivateMethods)
  401. //
  402. // baseEncode:length:charset:padded:
  403. //
  404. // Does the common lifting of creating the dest NSData. it creates & sizes the
  405. // data for the results. |charset| is the characters to use for the encoding
  406. // of the data. |padding| controls if the encoded data should be padded to a
  407. // multiple of 4.
  408. //
  409. // Returns:
  410. // an autorelease NSData with the encoded data, nil if any error.
  411. //
  412. +(NSData *)baseEncode:(const void *)bytes
  413. length:(NSUInteger)length
  414. charset:(const char *)charset
  415. padded:(BOOL)padded {
  416. // how big could it be?
  417. NSUInteger maxLength = CalcEncodedLength(length, padded);
  418. // make space
  419. NSMutableData *result = [NSMutableData data];
  420. [result setLength:maxLength];
  421. // do it
  422. NSUInteger finalLength = [self baseEncode:bytes
  423. srcLen:length
  424. destBytes:[result mutableBytes]
  425. destLen:[result length]
  426. charset:charset
  427. padded:padded];
  428. if (finalLength) {
  429. _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
  430. } else {
  431. // shouldn't happen, this means we ran out of space
  432. result = nil;
  433. }
  434. return result;
  435. }
  436. //
  437. // baseDecode:length:charset:requirePadding:
  438. //
  439. // Does the common lifting of creating the dest NSData. it creates & sizes the
  440. // data for the results. |charset| is the characters to use for the decoding
  441. // of the data.
  442. //
  443. // Returns:
  444. // an autorelease NSData with the decoded data, nil if any error.
  445. //
  446. //
  447. +(NSData *)baseDecode:(const void *)bytes
  448. length:(NSUInteger)length
  449. charset:(const char *)charset
  450. requirePadding:(BOOL)requirePadding {
  451. // could try to calculate what it will end up as
  452. NSUInteger maxLength = GuessDecodedLength(length);
  453. // make space
  454. NSMutableData *result = [NSMutableData data];
  455. [result setLength:maxLength];
  456. // do it
  457. NSUInteger finalLength = [self baseDecode:bytes
  458. srcLen:length
  459. destBytes:[result mutableBytes]
  460. destLen:[result length]
  461. charset:charset
  462. requirePadding:requirePadding];
  463. if (finalLength) {
  464. if (finalLength != maxLength) {
  465. // resize down to how big it was
  466. [result setLength:finalLength];
  467. }
  468. } else {
  469. // either an error in the args, or we ran out of space
  470. result = nil;
  471. }
  472. return result;
  473. }
  474. //
  475. // baseEncode:srcLen:destBytes:destLen:charset:padded:
  476. //
  477. // Encodes the buffer into the larger. returns the length of the encoded
  478. // data, or zero for an error.
  479. // |charset| is the characters to use for the encoding
  480. // |padded| tells if the result should be padded to a multiple of 4.
  481. //
  482. // Returns:
  483. // the length of the encoded data. zero if any error.
  484. //
  485. +(NSUInteger)baseEncode:(const char *)srcBytes
  486. srcLen:(NSUInteger)srcLen
  487. destBytes:(char *)destBytes
  488. destLen:(NSUInteger)destLen
  489. charset:(const char *)charset
  490. padded:(BOOL)padded {
  491. if (!srcLen || !destLen || !srcBytes || !destBytes) {
  492. return 0;
  493. }
  494. char *curDest = destBytes;
  495. const unsigned char *curSrc = (const unsigned char *)(srcBytes);
  496. // Three bytes of data encodes to four characters of cyphertext.
  497. // So we can pump through three-byte chunks atomically.
  498. while (srcLen > 2) {
  499. // space?
  500. _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
  501. curDest[0] = charset[curSrc[0] >> 2];
  502. curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
  503. curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
  504. curDest[3] = charset[curSrc[2] & 0x3f];
  505. curDest += 4;
  506. curSrc += 3;
  507. srcLen -= 3;
  508. destLen -= 4;
  509. }
  510. // now deal with the tail (<=2 bytes)
  511. switch (srcLen) {
  512. case 0:
  513. // Nothing left; nothing more to do.
  514. break;
  515. case 1:
  516. // One byte left: this encodes to two characters, and (optionally)
  517. // two pad characters to round out the four-character cypherblock.
  518. _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
  519. curDest[0] = charset[curSrc[0] >> 2];
  520. curDest[1] = charset[(curSrc[0] & 0x03) << 4];
  521. curDest += 2;
  522. destLen -= 2;
  523. if (padded) {
  524. _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
  525. curDest[0] = kBase64PaddingChar;
  526. curDest[1] = kBase64PaddingChar;
  527. curDest += 2;
  528. }
  529. break;
  530. case 2:
  531. // Two bytes left: this encodes to three characters, and (optionally)
  532. // one pad character to round out the four-character cypherblock.
  533. _GTMDevAssert(destLen >= 3, @"our calc for encoded length was wrong");
  534. curDest[0] = charset[curSrc[0] >> 2];
  535. curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
  536. curDest[2] = charset[(curSrc[1] & 0x0f) << 2];
  537. curDest += 3;
  538. destLen -= 3;
  539. if (padded) {
  540. _GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong");
  541. curDest[0] = kBase64PaddingChar;
  542. curDest += 1;
  543. }
  544. break;
  545. }
  546. // return the length
  547. return (curDest - destBytes);
  548. }
  549. //
  550. // baseDecode:srcLen:destBytes:destLen:charset:requirePadding:
  551. //
  552. // Decodes the buffer into the larger. returns the length of the decoded
  553. // data, or zero for an error.
  554. // |charset| is the character decoding buffer to use
  555. //
  556. // Returns:
  557. // the length of the encoded data. zero if any error.
  558. //
  559. +(NSUInteger)baseDecode:(const char *)srcBytes
  560. srcLen:(NSUInteger)srcLen
  561. destBytes:(char *)destBytes
  562. destLen:(NSUInteger)destLen
  563. charset:(const char *)charset
  564. requirePadding:(BOOL)requirePadding {
  565. if (!srcLen || !destLen || !srcBytes || !destBytes) {
  566. return 0;
  567. }
  568. int decode;
  569. NSUInteger destIndex = 0;
  570. int state = 0;
  571. char ch = 0;
  572. while (srcLen-- && (ch = *srcBytes++) != 0) {
  573. if (IsSpace(ch)) // Skip whitespace
  574. continue;
  575. if (ch == kBase64PaddingChar)
  576. break;
  577. decode = charset[(unsigned int)ch];
  578. if (decode == kBase64InvalidChar)
  579. return 0;
  580. // Four cyphertext characters decode to three bytes.
  581. // Therefore we can be in one of four states.
  582. switch (state) {
  583. case 0:
  584. // We're at the beginning of a four-character cyphertext block.
  585. // This sets the high six bits of the first byte of the
  586. // plaintext block.
  587. _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
  588. destBytes[destIndex] = decode << 2;
  589. state = 1;
  590. break;
  591. case 1:
  592. // We're one character into a four-character cyphertext block.
  593. // This sets the low two bits of the first plaintext byte,
  594. // and the high four bits of the second plaintext byte.
  595. _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
  596. destBytes[destIndex] |= decode >> 4;
  597. destBytes[destIndex+1] = (decode & 0x0f) << 4;
  598. destIndex++;
  599. state = 2;
  600. break;
  601. case 2:
  602. // We're two characters into a four-character cyphertext block.
  603. // This sets the low four bits of the second plaintext
  604. // byte, and the high two bits of the third plaintext byte.
  605. // However, if this is the end of data, and those two
  606. // bits are zero, it could be that those two bits are
  607. // leftovers from the encoding of data that had a length
  608. // of two mod three.
  609. _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
  610. destBytes[destIndex] |= decode >> 2;
  611. destBytes[destIndex+1] = (decode & 0x03) << 6;
  612. destIndex++;
  613. state = 3;
  614. break;
  615. case 3:
  616. // We're at the last character of a four-character cyphertext block.
  617. // This sets the low six bits of the third plaintext byte.
  618. _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
  619. destBytes[destIndex] |= decode;
  620. destIndex++;
  621. state = 0;
  622. break;
  623. }
  624. }
  625. // We are done decoding Base-64 chars. Let's see if we ended
  626. // on a byte boundary, and/or with erroneous trailing characters.
  627. if (ch == kBase64PaddingChar) { // We got a pad char
  628. if ((state == 0) || (state == 1)) {
  629. return 0; // Invalid '=' in first or second position
  630. }
  631. if (srcLen == 0) {
  632. if (state == 2) { // We run out of input but we still need another '='
  633. return 0;
  634. }
  635. // Otherwise, we are in state 3 and only need this '='
  636. } else {
  637. if (state == 2) { // need another '='
  638. while ((ch = *srcBytes++) && (srcLen-- > 0)) {
  639. if (!IsSpace(ch))
  640. break;
  641. }
  642. if (ch != kBase64PaddingChar) {
  643. return 0;
  644. }
  645. }
  646. // state = 1 or 2, check if all remain padding is space
  647. while ((ch = *srcBytes++) && (srcLen-- > 0)) {
  648. if (!IsSpace(ch)) {
  649. return 0;
  650. }
  651. }
  652. }
  653. } else {
  654. // We ended by seeing the end of the string.
  655. if (requirePadding) {
  656. // If we require padding, then anything but state 0 is an error.
  657. if (state != 0) {
  658. return 0;
  659. }
  660. } else {
  661. // Make sure we have no partial bytes lying around. Note that we do not
  662. // require trailing '=', so states 2 and 3 are okay too.
  663. if (state == 1) {
  664. return 0;
  665. }
  666. }
  667. }
  668. // If then next piece of output was valid and got written to it means we got a
  669. // very carefully crafted input that appeared valid but contains some trailing
  670. // bits past the real length, so just toss the thing.
  671. if ((destIndex < destLen) &&
  672. (destBytes[destIndex] != 0)) {
  673. return 0;
  674. }
  675. return destIndex;
  676. }
  677. @end