b64enc.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #include "b64enc.h"
  2. #define paddingChar '='
  3. const unsigned char base64Table[65] =
  4. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  5. long b64enc(unsigned char *out, const unsigned char *in, const long len)
  6. {
  7. unsigned char *p = out;
  8. long i;
  9. for (i = 0; i < len - 2; i += 3)
  10. /* For base64 (`2 ** 6` bits) encoding, every 3 bytes (8 bits) are grouped together
  11. * since LCM(6, 8) == 3.
  12. * To avoid exceeding bound, check `< len - 2`. */
  13. {
  14. /* C will fill `0` after shifting for unsigned types,
  15. * thus to get the first 6 bits of the first byte in the group,
  16. * we shift 2 (`8 - 6`). */
  17. *p = base64Table[(in[i] >> 2)];
  18. p++;
  19. /* `& 00000011` zeros the first 6 bits already processed, and the last 2 bits are left.
  20. * These 2 bits left will be the first 2 bits of the next 6 bits to process (`<< 4`).
  21. * For the second (`i + 1`) byte, `>> 4` produces its first 4 bits.
  22. * Then we join (`|`) the 2 bits and the 4 bits together. */
  23. *p = base64Table[((in[i] & 0x03) << 4 | in[i + 1] >> 4)];
  24. p++;
  25. /* Similar process applied to the last 4 bits of the second byte in the group
  26. * and the first 4 bits of the third byte. */
  27. *p = base64Table[((in[i + 1] & 0x0F) << 2 | in[i + 2] >> 6)];
  28. p++;
  29. /* The last 6 bits of the third byte and the group. */
  30. *p = base64Table[in[i + 2] & 0x3F];
  31. p++;
  32. }
  33. /* Since the loop is over, we have `i >= len - 2` and `i - 3 < len - 2`,
  34. * thus `len - 2 <= i < len + 1`, i.e. `i` is `len - 2`, `len - 1`, or `len`. */
  35. if (i == len) /* no padding needed */
  36. {
  37. /* Closes output string. */
  38. *p = '\0';
  39. /* Returns output string length (null terminator not counted). */
  40. return p - out;
  41. }
  42. else if (i == len - 1) /* 1 byte left alone */
  43. {
  44. /* The processing is similar to above except that:
  45. *
  46. * 1. The last 2 bits are padded with 4-bit zeros (filled by C automatically).
  47. * 2. The output are padded with `==`.
  48. * */
  49. *p = base64Table[in[i] >> 2];
  50. p++;
  51. *p = base64Table[(in[i] & 0x03) << 4];
  52. p++;
  53. *p = paddingChar;
  54. p++;
  55. *p = paddingChar;
  56. p++;
  57. *p = '\0';
  58. return p - out;
  59. }
  60. else if (i == len - 1) /* 1 byte left alone */
  61. {
  62. *p = base64Table[(in[i] >> 2)];
  63. p++;
  64. *p = base64Table[((in[i] & 0x03) << 4 | in[i + 1] >> 4)];
  65. p++;
  66. *p = base64Table[(in[i] & 0x03) << 2];
  67. p++;
  68. *p = paddingChar;
  69. p++;
  70. *p = '\0';
  71. return p - out;
  72. }
  73. else /* bug */
  74. {
  75. return -1;
  76. }
  77. }