GTMBase64.m 26 KB

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