GTMBase64.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  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 charact 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. FOUNDATION_STATIC_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. FOUNDATION_STATIC_INLINE NSUInteger CalcEncodedLength(NSUInteger srcLen,
  189. BOOL padded) {
  190. NSUInteger intermediate_result = 8 * srcLen + 5;
  191. NSUInteger len = intermediate_result / 6;
  192. if (padded) {
  193. len = ((len + 3) / 4) * 4;
  194. }
  195. return len;
  196. }
  197. // Tries to calculate how long the data will be once it's base64 decoded.
  198. // Unlinke the above, this is always an upperbound, since the source data
  199. // could have spaces and might end with the padding characters on them.
  200. //
  201. // Returns:
  202. // The guessed decoded length for a source length
  203. //
  204. FOUNDATION_STATIC_INLINE NSUInteger GuessDecodedLength(NSUInteger srcLen) {
  205. return (srcLen + 3) / 4 * 3;
  206. }
  207. @interface GTMBase64 (PrivateMethods)
  208. +(NSData *)baseEncode:(const void *)bytes
  209. length:(NSUInteger)length
  210. charset:(const char *)charset
  211. padded:(BOOL)padded;
  212. +(NSData *)baseDecode:(const void *)bytes
  213. length:(NSUInteger)length
  214. charset:(const char*)charset
  215. requirePadding:(BOOL)requirePadding;
  216. +(NSUInteger)baseEncode:(const char *)srcBytes
  217. srcLen:(NSUInteger)srcLen
  218. destBytes:(char *)destBytes
  219. destLen:(NSUInteger)destLen
  220. charset:(const char *)charset
  221. padded:(BOOL)padded;
  222. +(NSUInteger)baseDecode:(const char *)srcBytes
  223. srcLen:(NSUInteger)srcLen
  224. destBytes:(char *)destBytes
  225. destLen:(NSUInteger)destLen
  226. charset:(const char *)charset
  227. requirePadding:(BOOL)requirePadding;
  228. @end
  229. @implementation GTMBase64
  230. //
  231. // Standard Base64 (RFC) handling
  232. //
  233. +(NSData *)encodeData:(NSData *)data {
  234. return [self baseEncode:[data bytes]
  235. length:[data length]
  236. charset:kBase64EncodeChars
  237. padded:YES];
  238. }
  239. +(NSData *)decodeData:(NSData *)data {
  240. return [self baseDecode:[data bytes]
  241. length:[data length]
  242. charset:kBase64DecodeChars
  243. requirePadding:YES];
  244. }
  245. +(NSData *)encodeBytes:(const void *)bytes length:(NSUInteger)length {
  246. return [self baseEncode:bytes
  247. length:length
  248. charset:kBase64EncodeChars
  249. padded:YES];
  250. }
  251. +(NSData *)decodeBytes:(const void *)bytes length:(NSUInteger)length {
  252. return [self baseDecode:bytes
  253. length:length
  254. charset:kBase64DecodeChars
  255. requirePadding:YES];
  256. }
  257. +(NSString *)stringByEncodingData:(NSData *)data {
  258. NSString *result = nil;
  259. NSData *converted = [self baseEncode:[data bytes]
  260. length:[data length]
  261. charset:kBase64EncodeChars
  262. padded:YES];
  263. if (converted) {
  264. result = [[NSString alloc] initWithData:converted
  265. encoding:NSASCIIStringEncoding];
  266. }
  267. return result;
  268. }
  269. +(NSString *)stringByEncodingBytes:(const void *)bytes length:(NSUInteger)length {
  270. NSString *result = nil;
  271. NSData *converted = [self baseEncode:bytes
  272. length:length
  273. charset:kBase64EncodeChars
  274. padded:YES];
  275. if (converted) {
  276. result = [[NSString alloc] initWithData:converted
  277. encoding:NSASCIIStringEncoding];
  278. }
  279. return result;
  280. }
  281. +(NSData *)decodeString:(NSString *)string {
  282. NSData *result = nil;
  283. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
  284. if (data) {
  285. result = [self baseDecode:[data bytes]
  286. length:[data length]
  287. charset:kBase64DecodeChars
  288. requirePadding:YES];
  289. }
  290. return result;
  291. }
  292. //
  293. // Modified Base64 encoding so the results can go onto urls.
  294. //
  295. // The changes are in the characters generated and also the result isn't
  296. // padded to a multiple of 4.
  297. // Must use the matching call to encode/decode, won't interop with the
  298. // RFC versions.
  299. //
  300. +(NSData *)webSafeEncodeData:(NSData *)data
  301. padded:(BOOL)padded {
  302. return [self baseEncode:[data bytes]
  303. length:[data length]
  304. charset:kWebSafeBase64EncodeChars
  305. padded:padded];
  306. }
  307. +(NSData *)webSafeDecodeData:(NSData *)data {
  308. return [self baseDecode:[data bytes]
  309. length:[data length]
  310. charset:kWebSafeBase64DecodeChars
  311. requirePadding:NO];
  312. }
  313. +(NSData *)webSafeEncodeBytes:(const void *)bytes
  314. length:(NSUInteger)length
  315. padded:(BOOL)padded {
  316. return [self baseEncode:bytes
  317. length:length
  318. charset:kWebSafeBase64EncodeChars
  319. padded:padded];
  320. }
  321. +(NSData *)webSafeDecodeBytes:(const void *)bytes length:(NSUInteger)length {
  322. return [self baseDecode:bytes
  323. length:length
  324. charset:kWebSafeBase64DecodeChars
  325. requirePadding:NO];
  326. }
  327. +(NSString *)stringByWebSafeEncodingData:(NSData *)data
  328. padded:(BOOL)padded {
  329. NSString *result = nil;
  330. NSData *converted = [self baseEncode:[data bytes]
  331. length:[data length]
  332. charset:kWebSafeBase64EncodeChars
  333. padded:padded];
  334. if (converted) {
  335. result = [[NSString alloc] initWithData:converted
  336. encoding:NSASCIIStringEncoding];
  337. }
  338. return result;
  339. }
  340. +(NSString *)stringByWebSafeEncodingBytes:(const void *)bytes
  341. length:(NSUInteger)length
  342. padded:(BOOL)padded {
  343. NSString *result = nil;
  344. NSData *converted = [self baseEncode:bytes
  345. length:length
  346. charset:kWebSafeBase64EncodeChars
  347. padded:padded];
  348. if (converted) {
  349. result = [[NSString alloc] initWithData:converted
  350. encoding:NSASCIIStringEncoding];
  351. }
  352. return result;
  353. }
  354. +(NSData *)webSafeDecodeString:(NSString *)string {
  355. NSData *result = nil;
  356. NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding];
  357. if (data) {
  358. result = [self baseDecode:[data bytes]
  359. length:[data length]
  360. charset:kWebSafeBase64DecodeChars
  361. requirePadding:NO];
  362. }
  363. return result;
  364. }
  365. @end
  366. @implementation GTMBase64 (PrivateMethods)
  367. //
  368. // baseEncode:length:charset:padded:
  369. //
  370. // Does the common lifting of creating the dest NSData. it creates & sizes the
  371. // data for the results. |charset| is the characters to use for the encoding
  372. // of the data. |padding| controls if the encoded data should be padded to a
  373. // multiple of 4.
  374. //
  375. // Returns:
  376. // an autorelease NSData with the encoded data, nil if any error.
  377. //
  378. +(NSData *)baseEncode:(const void *)bytes
  379. length:(NSUInteger)length
  380. charset:(const char *)charset
  381. padded:(BOOL)padded {
  382. // how big could it be?
  383. NSUInteger maxLength = CalcEncodedLength(length, padded);
  384. // make space
  385. NSMutableData *result = [NSMutableData data];
  386. [result setLength:maxLength];
  387. // do it
  388. NSUInteger finalLength = [self baseEncode:bytes
  389. srcLen:length
  390. destBytes:[result mutableBytes]
  391. destLen:[result length]
  392. charset:charset
  393. padded:padded];
  394. if (finalLength) {
  395. _GTMDevAssert(finalLength == maxLength, @"how did we calc the length wrong?");
  396. } else {
  397. // shouldn't happen, this means we ran out of space
  398. result = nil;
  399. }
  400. return result;
  401. }
  402. //
  403. // baseDecode:length:charset:requirePadding:
  404. //
  405. // Does the common lifting of creating the dest NSData. it creates & sizes the
  406. // data for the results. |charset| is the characters to use for the decoding
  407. // of the data.
  408. //
  409. // Returns:
  410. // an autorelease NSData with the decoded data, nil if any error.
  411. //
  412. //
  413. +(NSData *)baseDecode:(const void *)bytes
  414. length:(NSUInteger)length
  415. charset:(const char *)charset
  416. requirePadding:(BOOL)requirePadding {
  417. // could try to calculate what it will end up as
  418. NSUInteger maxLength = GuessDecodedLength(length);
  419. // make space
  420. NSMutableData *result = [NSMutableData data];
  421. [result setLength:maxLength];
  422. // do it
  423. NSUInteger finalLength = [self baseDecode:bytes
  424. srcLen:length
  425. destBytes:[result mutableBytes]
  426. destLen:[result length]
  427. charset:charset
  428. requirePadding:requirePadding];
  429. if (finalLength) {
  430. if (finalLength != maxLength) {
  431. // resize down to how big it was
  432. [result setLength:finalLength];
  433. }
  434. } else {
  435. // either an error in the args, or we ran out of space
  436. result = nil;
  437. }
  438. return result;
  439. }
  440. //
  441. // baseEncode:srcLen:destBytes:destLen:charset:padded:
  442. //
  443. // Encodes the buffer into the larger. returns the length of the encoded
  444. // data, or zero for an error.
  445. // |charset| is the characters to use for the encoding
  446. // |padded| tells if the result should be padded to a multiple of 4.
  447. //
  448. // Returns:
  449. // the length of the encoded data. zero if any error.
  450. //
  451. +(NSUInteger)baseEncode:(const char *)srcBytes
  452. srcLen:(NSUInteger)srcLen
  453. destBytes:(char *)destBytes
  454. destLen:(NSUInteger)destLen
  455. charset:(const char *)charset
  456. padded:(BOOL)padded {
  457. if (!srcLen || !destLen || !srcBytes || !destBytes) {
  458. return 0;
  459. }
  460. char *curDest = destBytes;
  461. const unsigned char *curSrc = (const unsigned char *)(srcBytes);
  462. // Three bytes of data encodes to four characters of cyphertext.
  463. // So we can pump through three-byte chunks atomically.
  464. while (srcLen > 2) {
  465. // space?
  466. _GTMDevAssert(destLen >= 4, @"our calc for encoded length was wrong");
  467. curDest[0] = charset[curSrc[0] >> 2];
  468. curDest[1] = charset[((curSrc[0] & 0x03) << 4) + (curSrc[1] >> 4)];
  469. curDest[2] = charset[((curSrc[1] & 0x0f) << 2) + (curSrc[2] >> 6)];
  470. curDest[3] = charset[curSrc[2] & 0x3f];
  471. curDest += 4;
  472. curSrc += 3;
  473. srcLen -= 3;
  474. destLen -= 4;
  475. }
  476. // now deal with the tail (<=2 bytes)
  477. switch (srcLen) {
  478. case 0:
  479. // Nothing left; nothing more to do.
  480. break;
  481. case 1:
  482. // One byte left: this encodes to two characters, and (optionally)
  483. // two pad characters to round out the four-character cypherblock.
  484. _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
  485. curDest[0] = charset[curSrc[0] >> 2];
  486. curDest[1] = charset[(curSrc[0] & 0x03) << 4];
  487. curDest += 2;
  488. destLen -= 2;
  489. if (padded) {
  490. _GTMDevAssert(destLen >= 2, @"our calc for encoded length was wrong");
  491. curDest[0] = kBase64PaddingChar;
  492. curDest[1] = kBase64PaddingChar;
  493. curDest += 2;
  494. //destLen -= 2;
  495. }
  496. break;
  497. case 2:
  498. // Two bytes left: this encodes to three characters, and (optionally)
  499. // one pad character to round out the four-character cypherblock.
  500. _GTMDevAssert(destLen >= 3, @"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];
  504. curDest += 3;
  505. destLen -= 3;
  506. if (padded) {
  507. _GTMDevAssert(destLen >= 1, @"our calc for encoded length was wrong");
  508. curDest[0] = kBase64PaddingChar;
  509. curDest += 1;
  510. //destLen -= 1;
  511. }
  512. break;
  513. }
  514. // return the length
  515. return (curDest - destBytes);
  516. }
  517. //
  518. // baseDecode:srcLen:destBytes:destLen:charset:requirePadding:
  519. //
  520. // Decodes the buffer into the larger. returns the length of the decoded
  521. // data, or zero for an error.
  522. // |charset| is the character decoding buffer to use
  523. //
  524. // Returns:
  525. // the length of the encoded data. zero if any error.
  526. //
  527. +(NSUInteger)baseDecode:(const char *)srcBytes
  528. srcLen:(NSUInteger)srcLen
  529. destBytes:(char *)destBytes
  530. destLen:(NSUInteger)destLen
  531. charset:(const char *)charset
  532. requirePadding:(BOOL)requirePadding {
  533. if (!srcLen || !destLen || !srcBytes || !destBytes) {
  534. return 0;
  535. }
  536. int decode;
  537. NSUInteger destIndex = 0;
  538. int state = 0;
  539. char ch = 0;
  540. while (srcLen-- && (ch = *srcBytes++) != 0) {
  541. if (IsSpace(ch)) // Skip whitespace
  542. continue;
  543. if (ch == kBase64PaddingChar)
  544. break;
  545. decode = charset[(unsigned int)ch];
  546. if (decode == kBase64InvalidChar)
  547. return 0;
  548. // Four cyphertext characters decode to three bytes.
  549. // Therefore we can be in one of four states.
  550. switch (state) {
  551. case 0:
  552. // We're at the beginning of a four-character cyphertext block.
  553. // This sets the high six bits of the first byte of the
  554. // plaintext block.
  555. _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
  556. destBytes[destIndex] = decode << 2;
  557. state = 1;
  558. break;
  559. case 1:
  560. // We're one character into a four-character cyphertext block.
  561. // This sets the low two bits of the first plaintext byte,
  562. // and the high four bits of the second plaintext byte.
  563. _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
  564. destBytes[destIndex] |= decode >> 4;
  565. destBytes[destIndex+1] = (decode & 0x0f) << 4;
  566. destIndex++;
  567. state = 2;
  568. break;
  569. case 2:
  570. // We're two characters into a four-character cyphertext block.
  571. // This sets the low four bits of the second plaintext
  572. // byte, and the high two bits of the third plaintext byte.
  573. // However, if this is the end of data, and those two
  574. // bits are zero, it could be that those two bits are
  575. // leftovers from the encoding of data that had a length
  576. // of two mod three.
  577. _GTMDevAssert((destIndex+1) < destLen, @"our calc for decoded length was wrong");
  578. destBytes[destIndex] |= decode >> 2;
  579. destBytes[destIndex+1] = (decode & 0x03) << 6;
  580. destIndex++;
  581. state = 3;
  582. break;
  583. case 3:
  584. // We're at the last character of a four-character cyphertext block.
  585. // This sets the low six bits of the third plaintext byte.
  586. _GTMDevAssert(destIndex < destLen, @"our calc for decoded length was wrong");
  587. destBytes[destIndex] |= decode;
  588. destIndex++;
  589. state = 0;
  590. break;
  591. }
  592. }
  593. // We are done decoding Base-64 chars. Let's see if we ended
  594. // on a byte boundary, and/or with erroneous trailing characters.
  595. if (ch == kBase64PaddingChar) { // We got a pad char
  596. if ((state == 0) || (state == 1)) {
  597. return 0; // Invalid '=' in first or second position
  598. }
  599. if (srcLen == 0) {
  600. if (state == 2) { // We run out of input but we still need another '='
  601. return 0;
  602. }
  603. // Otherwise, we are in state 3 and only need this '='
  604. } else {
  605. if (state == 2) { // need another '='
  606. while ((ch = *srcBytes++) && (srcLen-- > 0)) {
  607. if (!IsSpace(ch))
  608. break;
  609. }
  610. if (ch != kBase64PaddingChar) {
  611. return 0;
  612. }
  613. }
  614. // state = 1 or 2, check if all remain padding is space
  615. while ((ch = *srcBytes++) && (srcLen-- > 0)) {
  616. if (!IsSpace(ch)) {
  617. return 0;
  618. }
  619. }
  620. }
  621. } else {
  622. // We ended by seeing the end of the string.
  623. if (requirePadding) {
  624. // If we require padding, then anything but state 0 is an error.
  625. if (state != 0) {
  626. return 0;
  627. }
  628. } else {
  629. // Make sure we have no partial bytes lying around. Note that we do not
  630. // require trailing '=', so states 2 and 3 are okay too.
  631. if (state == 1) {
  632. return 0;
  633. }
  634. }
  635. }
  636. // If then next piece of output was valid and got written to it means we got a
  637. // very carefully crafted input that appeared valid but contains some trailing
  638. // bits past the real length, so just toss the thing.
  639. if ((destIndex < destLen) &&
  640. (destBytes[destIndex] != 0)) {
  641. return 0;
  642. }
  643. return destIndex;
  644. }
  645. @end