Copy upstream code as of Chromium 39d53
For libchrome r1075024 uprev, where base/base64.cc will use the new
function modp_b64_encode_data, change made in crrev.com/1074948.
BUG=None
TEST=emerge modp_b64
Change-Id: I4fefddd140d431ee6fca4d27ffa8199372e4bebb
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/external/modp_b64/+/4060326
Tested-by: Grace Cham <hscham@chromium.org>
Commit-Queue: Grace Cham <hscham@chromium.org>
Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
diff --git a/modp_b64.cc b/modp_b64.cc
index fdb8a40..2901a8f 100644
--- a/modp_b64.cc
+++ b/modp_b64.cc
@@ -45,39 +45,11 @@
/* public header */
#include "modp_b64.h"
-/*
- * If you are ripping this out of the library, comment out the next
- * line and uncomment the next lines as approrpiate
- */
-//#include "config.h"
-
-/* if on motoral, sun, ibm; uncomment this */
-/* #define WORDS_BIGENDIAN 1 */
-/* else for Intel, Amd; uncomment this */
-/* #undef WORDS_BIGENDIAN */
-
#include "modp_b64_data.h"
#define BADCHAR 0x01FFFFFF
-/**
- * you can control if we use padding by commenting out this
- * next line. However, I highly recommend you use padding and not
- * using it should only be for compatability with a 3rd party.
- * Also, 'no padding' is not tested!
- */
-#define DOPAD 1
-
-/*
- * if we aren't doing padding
- * set the pad character to NULL
- */
-#ifndef DOPAD
-#undef CHARPAD
-#define CHARPAD '\0'
-#endif
-
-size_t modp_b64_encode(char* dest, const char* str, size_t len)
+size_t modp_b64_encode_data(char* dest, const char* str, size_t len)
{
size_t i = 0;
uint8_t* p = (uint8_t*) dest;
@@ -113,97 +85,42 @@
*p++ = CHARPAD;
}
- *p = '\0';
return p - (uint8_t*)dest;
}
-#ifdef WORDS_BIGENDIAN /* BIG ENDIAN -- SUN / IBM / MOTOROLA */
-int modp_b64_decode(char* dest, const char* src, int len)
-{
- if (len == 0) return 0;
-
-#ifdef DOPAD
- /* if padding is used, then the message must be at least
- 4 chars and be a multiple of 4.
- there can be at most 2 pad chars at the end */
- if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR;
- if (src[len-1] == CHARPAD) {
- len--;
- if (src[len -1] == CHARPAD) {
- len--;
- }
- }
-#endif /* DOPAD */
-
- size_t i;
- int leftover = len % 4;
- size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
-
- uint8_t* p = (uint8_t*) dest;
- uint32_t x = 0;
- uint32_t* destInt = (uint32_t*) p;
- uint32_t* srcInt = (uint32_t*) src;
- uint32_t y = *srcInt++;
- for (i = 0; i < chunks; ++i) {
- x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
- d2[y >> 8 & 0xff] | d3[y & 0xff];
-
- if (x >= BADCHAR) return MODP_B64_ERROR;
- *destInt = x << 8;
- p += 3;
- destInt = (uint32_t*)p;
- y = *srcInt++;
- }
-
- switch (leftover) {
- case 0:
- x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
- d2[y >> 8 & 0xff] | d3[y & 0xff];
- if (x >= BADCHAR) return MODP_B64_ERROR;
- *p++ = ((uint8_t*)&x)[1];
- *p++ = ((uint8_t*)&x)[2];
- *p = ((uint8_t*)&x)[3];
- return (chunks+1)*3;
- case 1:
- x = d3[y >> 24];
- *p = (uint8_t)x;
- break;
- case 2:
- x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff];
- *p = (uint8_t)(x >> 4);
- break;
- default: /* case 3 */
- x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 +
- d3[(y >> 8) & 0xff];
- *p++ = (uint8_t) (x >> 10);
- *p = (uint8_t) (x >> 2);
- break;
- }
-
- if (x >= BADCHAR) return MODP_B64_ERROR;
- return 3*chunks + (6*leftover)/8;
+size_t modp_b64_encode(char* dest, const char* str, size_t len) {
+ size_t output_size = modp_b64_encode_data(dest, str, len);
+ dest[output_size] = '\0';
+ return output_size;
}
-#else /* LITTLE ENDIAN -- INTEL AND FRIENDS */
-
-size_t modp_b64_decode(char* dest, const char* src, size_t len)
-{
- if (len == 0) return 0;
-
-#ifdef DOPAD
- /*
- * if padding is used, then the message must be at least
- * 4 chars and be a multiple of 4
- */
- if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; /* error */
- /* there can be at most 2 pad chars at the end */
- if (src[len-1] == CHARPAD) {
+size_t do_decode_padding(const char* src, size_t len, ModpDecodePolicy policy) {
+ if (policy == ModpDecodePolicy::kNoPaddingValidation) {
+ while (len > 0 && src[len - 1] == CHARPAD) {
len--;
- if (src[len -1] == CHARPAD) {
- len--;
- }
}
-#endif
+ } else {
+ const size_t remainder = len % 4;
+ if (policy == ModpDecodePolicy::kStrict && (remainder != 0 || len < 4))
+ return MODP_B64_ERROR;
+ if (remainder == 0) {
+ if (src[len - 1] == CHARPAD) {
+ len--;
+ if (src[len - 1] == CHARPAD) {
+ len--;
+ }
+ }
+ }
+ }
+ return len % 4 == 1 ? MODP_B64_ERROR : len;
+}
+
+size_t modp_b64_decode(char* dest, const char* src, size_t len, ModpDecodePolicy policy)
+{
+ if (len == 0 ||
+ (len = do_decode_padding(src, len, policy)) == MODP_B64_ERROR) {
+ return len;
+ }
size_t i;
int leftover = len % 4;
@@ -229,7 +146,6 @@
*p++ = ((uint8_t*)(&x))[1];
*p = ((uint8_t*)(&x))[2];
return (chunks+1)*3;
- break;
case 1: /* with padding this is an impossible case */
x = d0[y[0]];
*p = *((uint8_t*)(&x)); // i.e. first char/byte in int
@@ -249,5 +165,3 @@
return 3*chunks + (6*leftover)/8;
}
-
-#endif /* if bigendian / else / endif */
diff --git a/modp_b64/modp_b64.h b/modp_b64/modp_b64.h
index 0a2669d..9d11f81 100644
--- a/modp_b64/modp_b64.h
+++ b/modp_b64/modp_b64.h
@@ -37,17 +37,16 @@
* len contains the number of bytes in the src
* dest should be allocated by the caller to contain
* at least modp_b64_encode_len(len) bytes (see below)
- * This will contain the null-terminated b64 encoded result
- * returns length of the destination string plus the ending null byte
- * i.e. the result will be equal to strlen(dest) + 1
+ * This will contain the (non-null terminated) b64 bytes.
+ * returns length of the destination string.
*
* Example
- *
+ *
* \code
* char* src = ...;
* int srclen = ...; //the length of number of bytes in src
* char* dest = (char*) malloc(modp_b64_encode_len);
- * int len = modp_b64_encode(dest, src, sourcelen);
+ * int len = modp_b64_encode_data(dest, src, sourcelen);
* if (len == -1) {
* printf("Error\n");
* } else {
@@ -56,6 +55,17 @@
* \endcode
*
*/
+size_t modp_b64_encode_data(char* dest, const char* str, size_t len);
+
+/**
+ * Same as modp_b64_encode_data, but additionally sets a null terminator at the
+ * end of `dest` (i.e. at dest[output_size]).
+ * Like modp_b64_encode_data, returns the length of the destination string (i.e.
+ * not counting the null terminator).
+ *
+ * TODO(csharrison): Consider removing this once all callers migrate to
+ * modp_b64_encode_data.
+ */
size_t modp_b64_encode(char* dest, const char* str, size_t len);
/**
@@ -79,11 +89,27 @@
* if (len == -1) { error }
* \endcode
*/
-size_t modp_b64_decode(char* dest, const char* src, size_t len);
+enum class ModpDecodePolicy {
+ // src length must be divisible by 4, with a max of 2 pad chars.
+ kStrict,
+
+ // Matches the infra spec: https://infra.spec.whatwg.org/#forgiving-base64
+ // _except_ for ignoring whitespace (Step 1).
+ kForgiving,
+
+ // src length % 4 must not equal 1, after stripping all pad chars.
+ // Accepts any number of pad chars.
+ kNoPaddingValidation,
+};
+size_t modp_b64_decode(
+ char* dest,
+ const char* src,
+ size_t len,
+ ModpDecodePolicy policy = ModpDecodePolicy::kStrict);
/**
- * The maximum input that can be passed into modp_b64_encode. Lengths beyond
- * this will overflow modp_b64_encode_len.
+ * The maximum input that can be passed into modp_b64_encode{_data}.
+ * Lengths beyond this will overflow modp_b64_encode_len.
*
* This works because modp_b64_encode_len(A) computes:
* ceiling[max_len / 3] * 4 + 1
@@ -91,23 +117,27 @@
* = floor[(SIZE_MAX-1)/4] * 4 + 1
* <= SIZE_MAX-1 + 1
* = SIZE_MAX
+ *
+ * Note: technically modp_b64_encode_data can take one extra byte, but for
+ * simplicity the bound is shared between the two functions.
*/
#define MODP_B64_MAX_INPUT_LEN ((SIZE_MAX - 1) / 4 * 3)
/**
* Given a source string of length len, this returns the amount of
- * memory the destination string should have.
+ * memory the destination string should have, for modp_b64_encode_data and
+ * modp_b64_encode, respectively.
*
* remember, this is integer math
* 3 bytes turn into 4 chars
- * ceiling[len / 3] * 4 + 1
+ * ceiling[len / 3] * 4
*
- * +1 is for any extra null.
*
- * WARNING: This expression will overflow if the A is above
+ * WARNING: These expressions will overflow if the A is above
* MODP_B64_MAX_INPUT_LEN. The caller must check this bound first.
*/
-#define modp_b64_encode_len(A) ((A+2)/3 * 4 + 1)
+#define modp_b64_encode_data_len(A) ((A + 2) / 3 * 4)
+#define modp_b64_encode_len(A) (modp_b64_encode_data_len(A) + 1)
/**
* Given a base64 string of length len,
@@ -120,69 +150,10 @@
*/
#define modp_b64_decode_len(A) (A / 4 * 3 + 2)
-/**
- * Will return the strlen of the output from encoding.
- * This may be less than the required number of bytes allocated.
- *
- * This allows you to 'deserialized' a struct
- * \code
- * char* b64encoded = "...";
- * int len = strlen(b64encoded);
- *
- * struct datastuff foo;
- * if (modp_b64_encode_strlen(sizeof(struct datastuff)) != len) {
- * // wrong size
- * return false;
- * } else {
- * // safe to do;
- * if (modp_b64_decode((char*) &foo, b64encoded, len) == -1) {
- * // bad characters
- * return false;
- * }
- * }
- * // foo is filled out now
- * \endcode
- */
-#define modp_b64_encode_strlen(A) ((A + 2)/ 3 * 4)
-
#define MODP_B64_ERROR ((size_t)-1)
#ifdef __cplusplus
}
-
-#include <string>
-
-inline std::string& modp_b64_encode(std::string& s)
-{
- std::string x(modp_b64_encode_len(s.size()), '\0');
- size_t d = modp_b64_encode(const_cast<char*>(x.data()), s.data(), (int)s.size());
- x.erase(d, std::string::npos);
- s.swap(x);
- return s;
-}
-
-/**
- * base 64 decode a string (self-modifing)
- * On failure, the string is empty.
- *
- * This function is for C++ only (duh)
- *
- * \param[in,out] s the string to be decoded
- * \return a reference to the input string
- */
-inline std::string& modp_b64_decode(std::string& s)
-{
- std::string x(modp_b64_decode_len(s.size()), '\0');
- size_t d = modp_b64_decode(const_cast<char*>(x.data()), s.data(), (int)s.size());
- if (d == MODP_B64_ERROR) {
- x.clear();
- } else {
- x.erase(d, std::string::npos);
- }
- s.swap(x);
- return s;
-}
-
#endif /* __cplusplus */
#endif /* MODP_B64 */