base64.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Embedded Linux library
  3. *
  4. * Copyright (C) 2015 Intel Corporation. All rights reserved.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. #include <config.h>
  22. #endif
  23. #include <stdint.h>
  24. #include "utf8.h"
  25. #include "base64.h"
  26. #include "private.h"
  27. LIB_EXPORT uint8_t *l_base64_decode(const char *in, size_t in_len,
  28. size_t *n_written)
  29. {
  30. const char *ptr, *in_end = in + in_len;
  31. uint8_t *out_buf, *out;
  32. int base64_len = 0, pad_len;
  33. uint16_t reg = 0;
  34. for (ptr = in; ptr < in_end; ptr++)
  35. if (l_ascii_isspace(*ptr))
  36. /* Whitespace */
  37. continue;
  38. else if (*ptr == '=')
  39. /* Final padding */
  40. break;
  41. else if (l_ascii_isalnum(*ptr) || *ptr == '+' || *ptr == '/')
  42. /* Base64 character */
  43. base64_len++;
  44. else
  45. /* Bad character */
  46. return NULL;
  47. in_end = ptr;
  48. if ((base64_len & 3) == 1)
  49. /* Invalid length */
  50. return NULL;
  51. pad_len = (4 - base64_len) & 3;
  52. for (; ptr < in + in_len && pad_len; ptr++)
  53. if (l_ascii_isspace(*ptr))
  54. /* Whitespace */
  55. continue;
  56. else if (*ptr == '=')
  57. /* Final padding */
  58. pad_len--;
  59. else
  60. /* Bad character */
  61. return NULL;
  62. if (pad_len)
  63. return NULL;
  64. *n_written = base64_len * 3 / 4;
  65. out_buf = l_malloc(*n_written);
  66. out = out_buf;
  67. base64_len = 0;
  68. for (ptr = in; ptr < in_end; ptr++) {
  69. if (l_ascii_isspace(*ptr))
  70. /* Whitespace */
  71. continue;
  72. /* Base64 character */
  73. reg <<= 6;
  74. if (l_ascii_isupper(*ptr))
  75. reg |= *ptr - 'A' + 0;
  76. else if (l_ascii_islower(*ptr))
  77. reg |= *ptr - 'a' + 26;
  78. else if (l_ascii_isdigit(*ptr))
  79. reg |= *ptr - '0' + 52;
  80. else if (*ptr == '+')
  81. reg |= 62;
  82. else if (*ptr == '/')
  83. reg |= 63;
  84. if ((base64_len & 3) == 1)
  85. *out++ = reg >> 4;
  86. else if ((base64_len & 3) == 2)
  87. *out++ = reg >> 2;
  88. else if ((base64_len & 3) == 3)
  89. *out++ = reg >> 0;
  90. base64_len++;
  91. }
  92. return out_buf;
  93. }
  94. LIB_EXPORT char *l_base64_encode(const uint8_t *in, size_t in_len,
  95. int columns, size_t *n_written)
  96. {
  97. const uint8_t *in_end = in + in_len;
  98. char *out_buf, *out;
  99. size_t out_len;
  100. uint32_t reg;
  101. uint8_t idx;
  102. int i, pad = 4;
  103. int col = 0;
  104. /* For simplicity allow multiples of 4 only */
  105. if (columns & 3)
  106. return NULL;
  107. out_len = (in_len + 2) / 3 * 4;
  108. if (columns && out_len)
  109. out_len += (out_len - 4) / columns;
  110. out_buf = l_malloc(out_len);
  111. *n_written = out_len;
  112. out = out_buf;
  113. while (in < in_end) {
  114. reg = *in++ << 16;
  115. if (in < in_end)
  116. reg |= *in++ << 8;
  117. else
  118. pad--;
  119. if (in < in_end)
  120. reg |= *in++ << 0;
  121. else
  122. pad--;
  123. if (columns && col == columns) {
  124. *out++ = '\n';
  125. col = 0;
  126. }
  127. col += 4;
  128. for (i = 0; i < pad; i++) {
  129. idx = (reg >> 18) & 63;
  130. reg <<= 6;
  131. if (idx < 26)
  132. *out++ = idx + 'A';
  133. else if (idx < 52)
  134. *out++ = idx - 26 + 'a';
  135. else if (idx < 62)
  136. *out++ = idx - 52 + '0';
  137. else
  138. *out++ = (idx == 62) ? '+' : '/';
  139. }
  140. }
  141. for (; pad < 4; pad++)
  142. *out++ = '=';
  143. return out_buf;
  144. }