Use vector of uint8_t in XFA_Base64Decode().

Preferable to malloc() and pointer arithmetic.
Pass const-ref bytestring rather than pointer while at it.

Change-Id: Ic19d0f9fb3a66724ff1e64573887d7f7d1234b02
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/52656
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 7a1d1fe..bbf340e 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -381,60 +381,58 @@
     49,  50,  51,  255, 255, 255, 255, 255,
 };
 
-uint8_t* XFA_RemoveBase64Whitespace(pdfium::span<const uint8_t> spStr) {
-  uint8_t* pCP = FX_Alloc(uint8_t, spStr.size() + 1);
-  size_t j = 0;
-  for (size_t i = 0; i < spStr.size(); ++i) {
-    if ((spStr[i] & 128) == 0 &&
-        (g_inv_base64[spStr[i]] != 0xFF || spStr[i] == '=')) {
-      pCP[j++] = spStr[i];
-    }
-  }
-  pCP[j] = '\0';
-  return pCP;
+inline uint8_t GetInvBase64(uint8_t x) {
+  return (x & 128) == 0 ? g_inv_base64[x] : 255;
 }
 
-int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) {
-  if (!pStr)
-    return 0;
+std::vector<uint8_t> XFA_RemoveBase64Whitespace(
+    pdfium::span<const uint8_t> spStr) {
+  std::vector<uint8_t> result;
+  result.reserve(spStr.size());
+  for (uint8_t ch : spStr) {
+    if (GetInvBase64(ch) != 255 || ch == '=')
+      result.push_back(ch);
+  }
+  return result;
+}
 
-  uint8_t* pBuffer = XFA_RemoveBase64Whitespace(
-      {reinterpret_cast<const uint8_t*>(pStr), strlen(pStr)});
-  int32_t iLen = strlen((char*)pBuffer);
-  int32_t i = 0, j = 0;
+std::vector<uint8_t> XFA_Base64Decode(const ByteString& bsStr) {
+  std::vector<uint8_t> result;
+  if (bsStr.IsEmpty())
+    return result;
+
+  std::vector<uint8_t> buffer = XFA_RemoveBase64Whitespace(bsStr.AsRawSpan());
+  result.reserve(3 * (buffer.size() / 4));
+
   uint32_t dwLimb = 0;
-  for (; i + 3 < iLen; i += 4) {
-    if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
-        pBuffer[i + 3] == '=') {
-      if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
+  for (size_t i = 0; i + 3 < buffer.size(); i += 4) {
+    if (buffer[i] == '=' || buffer[i + 1] == '=' || buffer[i + 2] == '=' ||
+        buffer[i + 3] == '=') {
+      if (buffer[i] == '=' || buffer[i + 1] == '=') {
         break;
       }
-      if (pBuffer[i + 2] == '=') {
-        dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 1]]);
-        pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
-        j++;
+      if (buffer[i + 2] == '=') {
+        dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 6) |
+                 ((uint32_t)g_inv_base64[buffer[i + 1]]);
+        result.push_back((uint8_t)(dwLimb >> 4) & 0xFF);
       } else {
-        dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
-                 ((uint32_t)g_inv_base64[pBuffer[i + 2]]);
-        pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
-        pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
-        j += 2;
+        dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 12) |
+                 ((uint32_t)g_inv_base64[buffer[i + 1]] << 6) |
+                 ((uint32_t)g_inv_base64[buffer[i + 2]]);
+        result.push_back((uint8_t)(dwLimb >> 10) & 0xFF);
+        result.push_back((uint8_t)(dwLimb >> 2) & 0xFF);
       }
     } else {
-      dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
-               ((uint32_t)g_inv_base64[pBuffer[i + 3]]);
-      pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
-      pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
-      pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
-      j += 3;
+      dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 18) |
+               ((uint32_t)g_inv_base64[buffer[i + 1]] << 12) |
+               ((uint32_t)g_inv_base64[buffer[i + 2]] << 6) |
+               ((uint32_t)g_inv_base64[buffer[i + 3]]);
+      result.push_back((uint8_t)(dwLimb >> 16) & 0xff);
+      result.push_back((uint8_t)(dwLimb >> 8) & 0xff);
+      result.push_back((uint8_t)(dwLimb)&0xff);
     }
   }
-  FX_Free(pBuffer);
-  return j;
+  return result;
 }
 
 FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) {
@@ -477,18 +475,15 @@
 
   FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
   ByteString bsData;  // Must outlive |pImageFileRead|.
-  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> buffer;  // Must outlive |pImageFileRead|.
   RetainPtr<IFX_SeekableReadStream> pImageFileRead;
   if (wsImage.GetLength() > 0) {
     XFA_AttributeValue iEncoding = pImage->GetTransferEncoding();
     if (iEncoding == XFA_AttributeValue::Base64) {
       bsData = wsImage.ToUTF8();
-      buffer.resize(bsData.GetLength());
-      int32_t iRead = XFA_Base64Decode(bsData.c_str(), buffer.data());
-      if (iRead > 0) {
-        pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
-            pdfium::make_span(buffer.data(), iRead));
-      }
+      buffer = XFA_Base64Decode(bsData);
+      if (!buffer.empty())
+        pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(buffer);
     } else {
       bsData = wsImage.ToDefANSI();
       pImageFileRead =