Fix unsafe buffer usage in xfa_basic_data.cpp

Spanify, get bounds checks for free.

Bug: pdfium:2155
Change-Id: If6be531ec2cd5690ac14782b32f7da6d87a0fc82
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/118955
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/parser/cxfa_color.cpp b/xfa/fxfa/parser/cxfa_color.cpp
index 38ce3be..f09251e 100644
--- a/xfa/fxfa/parser/cxfa_color.cpp
+++ b/xfa/fxfa/parser/cxfa_color.cpp
@@ -4,11 +4,6 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "xfa/fxfa/parser/cxfa_color.h"
 
 #include "core/fxcrt/fx_extension.h"
@@ -37,43 +32,46 @@
   if (view.IsEmpty())
     return kDefaultValue;
 
-  const wchar_t* str = view.unterminated_c_str();
-  size_t len = view.GetLength();
+  pdfium::span<const wchar_t> str = view.span();
   size_t cc = 0;
-  while (cc < len && FXSYS_iswspace(str[cc]))
+  while (cc < str.size() && FXSYS_iswspace(str[cc])) {
     cc++;
+  }
 
-  if (cc >= len)
+  if (cc >= str.size()) {
     return kDefaultValue;
+  }
 
   uint8_t r = 0;
   uint8_t g = 0;
   uint8_t b = 0;
-  while (cc < len) {
+  while (cc < str.size()) {
     if (str[cc] == ',' || !FXSYS_IsDecimalDigit(str[cc]))
       break;
 
     r = r * 10 + str[cc] - '0';
     cc++;
   }
-  if (cc < len && str[cc] == ',') {
+  if (cc < str.size() && str[cc] == ',') {
     cc++;
-    while (cc < len && FXSYS_iswspace(str[cc]))
+    while (cc < str.size() && FXSYS_iswspace(str[cc])) {
       cc++;
+    }
 
-    while (cc < len) {
+    while (cc < str.size()) {
       if (str[cc] == ',' || !FXSYS_IsDecimalDigit(str[cc]))
         break;
 
       g = g * 10 + str[cc] - '0';
       cc++;
     }
-    if (cc < len && str[cc] == ',') {
+    if (cc < str.size() && str[cc] == ',') {
       cc++;
-      while (cc < len && FXSYS_iswspace(str[cc]))
+      while (cc < str.size() && FXSYS_iswspace(str[cc])) {
         cc++;
+      }
 
-      while (cc < len) {
+      while (cc < str.size()) {
         if (str[cc] == ',' || !FXSYS_IsDecimalDigit(str[cc]))
           break;
 
diff --git a/xfa/fxfa/parser/cxfa_localemgr.cpp b/xfa/fxfa/parser/cxfa_localemgr.cpp
index 459b2b9..ef4b8f4 100644
--- a/xfa/fxfa/parser/cxfa_localemgr.cpp
+++ b/xfa/fxfa/parser/cxfa_localemgr.cpp
@@ -4,11 +4,6 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "xfa/fxfa/parser/cxfa_localemgr.h"
 
 #include <time.h>
@@ -18,6 +13,7 @@
 
 #include "core/fxcodec/flate/flatemodule.h"
 #include "core/fxcrt/check.h"
+#include "core/fxcrt/compiler_specific.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "fxjs/gc/container_trace.h"
 #include "fxjs/xfa/cjx_object.h"
@@ -1081,7 +1077,9 @@
   if (!output)
     return nullptr;
 
-  return CXFA_XMLLocale::Create(heap, pdfium::make_span(output.get(), dwSize));
+  // TODO(crbug.com/pdfuim/2155): investigate safety issues.
+  return CXFA_XMLLocale::Create(
+      heap, UNSAFE_BUFFERS(pdfium::make_span(output.get(), dwSize)));
 }
 
 CXFA_LocaleMgr::LangID GetLanguageID(WideString wsLanguage) {
diff --git a/xfa/fxfa/parser/cxfa_localevalue.cpp b/xfa/fxfa/parser/cxfa_localevalue.cpp
index b54c7d3..c938f7a 100644
--- a/xfa/fxfa/parser/cxfa_localevalue.cpp
+++ b/xfa/fxfa/parser/cxfa_localevalue.cpp
@@ -4,11 +4,6 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "xfa/fxfa/parser/cxfa_localevalue.h"
 
 #include <wchar.h>
@@ -391,8 +386,8 @@
 
 bool CXFA_LocaleValue::ValidateCanonicalDate(const WideString& wsDate,
                                              CFX_DateTime* unDate) {
-  static const uint8_t LastDay[12] = {31, 28, 31, 30, 31, 30,
-                                      31, 31, 30, 31, 30, 31};
+  static const std::array<const uint8_t, 12> LastDay = {
+      {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
   static const uint16_t wCountY = 4;
   static const uint16_t wCountM = 2;
   static const uint16_t wCountD = 2;
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 919b245..375e024 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -4,17 +4,13 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "xfa/fxfa/parser/cxfa_node.h"
 
 #include <math.h>
 #include <stdint.h>
 
 #include <algorithm>
+#include <array>
 #include <map>
 #include <memory>
 #include <set>
@@ -380,7 +376,7 @@
 
 constexpr uint8_t kMaxExecuteRecursion = 2;
 
-constexpr uint8_t kInvBase64[128] = {
+constexpr std::array<const uint8_t, 128> kInvBase64 = {{
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,  255,
@@ -390,7 +386,7 @@
     25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
     34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
     49,  50,  51,  255, 255, 255, 255, 255,
-};
+}};
 
 inline uint8_t GetInvBase64(uint8_t x) {
   return (x & 128) == 0 ? kInvBase64[x] : 255;
diff --git a/xfa/fxfa/parser/xfa_basic_data.cpp b/xfa/fxfa/parser/xfa_basic_data.cpp
index 4af24ed..164bddf 100644
--- a/xfa/fxfa/parser/xfa_basic_data.cpp
+++ b/xfa/fxfa/parser/xfa_basic_data.cpp
@@ -4,16 +4,12 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
-#if defined(UNSAFE_BUFFERS_BUILD)
-// TODO(crbug.com/pdfium/2153): resolve buffer safety issues.
-#pragma allow_unsafe_buffers
-#endif
-
 #include "xfa/fxfa/parser/xfa_basic_data.h"
 
 #include <iterator>
 #include <utility>
 
+#include "core/fxcrt/span.h"
 #include "fxjs/xfa/cjx_boolean.h"
 #include "fxjs/xfa/cjx_container.h"
 #include "fxjs/xfa/cjx_datawindow.h"
@@ -62,6 +58,8 @@
 #undef PCKT____
 };
 
+constexpr pdfium::span<const PacketTableRecord> kPacketSpan{kPacketTable};
+
 struct ElementRecord {
   uint32_t hash;  // Hashed as wide string.
   XFA_Element element;
@@ -77,6 +75,8 @@
 #undef ELEM____
 };
 
+constexpr pdfium::span<const ElementRecord> kElementRecordSpan{kElementRecords};
+
 constexpr const char* kElementNames[] = {
 #undef ELEM____
 #define ELEM____(a, b, c, d) b,
@@ -84,6 +84,8 @@
 #undef ELEM____
 };
 
+constexpr const pdfium::span<const char* const> kElementNameSpan{kElementNames};
+
 static_assert(std::size(kElementRecords) == std::size(kElementNames),
               "Size mismatch");
 
@@ -102,6 +104,9 @@
 #undef ATTR____
 };
 
+constexpr pdfium::span<const AttributeRecord> kAttributeRecordSpan{
+    kAttributeRecords};
+
 constexpr const char* kAttributeNames[] = {
 #undef ATTR____
 #define ATTR____(a, b, c, d) b,
@@ -109,6 +114,8 @@
 #undef ATTR____
 };
 
+constexpr pdfium::span<const char* const> kAttributeNameSpan{kAttributeNames};
+
 static_assert(std::size(kAttributeRecords) == std::size(kAttributeNames),
               "Size mismatch");
 
@@ -134,6 +141,9 @@
 #undef VALUE____
 };
 
+constexpr pdfium::span<const char* const> kAttributeValueNameSpan{
+    kAttributeValueNames};
+
 static_assert(std::size(kAttributeValueRecords) ==
                   std::size(kAttributeValueNames),
               "Size mismatch");
@@ -159,6 +169,9 @@
 #undef ELEM_ATTR____
 };
 
+constexpr pdfium::span<const XFA_ATTRIBUTE_CALLBACK>
+    kElementAttributeCallbackSpan{kElementAttributeCallbacks};
+
 static_assert(std::size(kElementAttributeRecords) ==
                   std::size(kElementAttributeCallbacks),
               "Size mismatch");
@@ -166,7 +179,7 @@
 }  // namespace
 
 XFA_PACKETINFO XFA_GetPacketByIndex(XFA_PacketType ePacket) {
-  return kPacketTable[static_cast<uint8_t>(ePacket)].info;
+  return kPacketSpan[static_cast<uint8_t>(ePacket)].info;
 }
 
 std::optional<XFA_PACKETINFO> XFA_GetPacketByName(WideStringView wsName) {
@@ -180,7 +193,7 @@
 }
 
 ByteStringView XFA_ElementToName(XFA_Element elem) {
-  return kElementNames[static_cast<size_t>(elem)];
+  return kElementNameSpan[static_cast<size_t>(elem)];
 }
 
 XFA_Element XFA_GetElementByName(WideStringView name) {
@@ -192,26 +205,26 @@
     return XFA_Element::Unknown;
 
   size_t index = std::distance(std::begin(kElementRecords), elem);
-  return name.EqualsASCII(kElementNames[index]) ? elem->element
-                                                : XFA_Element::Unknown;
+  return name.EqualsASCII(kElementNameSpan[index]) ? elem->element
+                                                   : XFA_Element::Unknown;
 }
 
 ByteStringView XFA_AttributeToName(XFA_Attribute attr) {
-  return kAttributeNames[static_cast<size_t>(attr)];
+  return kAttributeNameSpan[static_cast<size_t>(attr)];
 }
 
 std::optional<XFA_ATTRIBUTEINFO> XFA_GetAttributeByName(WideStringView name) {
   uint32_t hash = FX_HashCode_GetW(name);
   auto* elem = std::lower_bound(
-      std::begin(kAttributeRecords), std::end(kAttributeRecords), hash,
+      kAttributeRecordSpan.begin(), kAttributeRecordSpan.end(), hash,
       [](const AttributeRecord& a, uint32_t hash) { return a.hash < hash; });
-  if (elem == std::end(kAttributeRecords))
+  if (elem == kAttributeRecordSpan.end()) {
     return std::nullopt;
-
-  size_t index = std::distance(std::begin(kAttributeRecords), elem);
-  if (!name.EqualsASCII(kAttributeNames[index]))
+  }
+  size_t index = std::distance(kAttributeRecordSpan.begin(), elem);
+  if (!name.EqualsASCII(kAttributeNameSpan[index])) {
     return std::nullopt;
-
+  }
   XFA_ATTRIBUTEINFO result;
   result.attribute = elem->attribute;
   result.eValueType = elem->script_type;
@@ -219,7 +232,7 @@
 }
 
 ByteStringView XFA_AttributeValueToName(XFA_AttributeValue item) {
-  return kAttributeValueNames[static_cast<int32_t>(item)];
+  return kAttributeValueNameSpan[static_cast<int32_t>(item)];
 }
 
 std::optional<XFA_AttributeValue> XFA_GetAttributeValueByName(
@@ -234,8 +247,9 @@
     return std::nullopt;
 
   size_t index = std::distance(std::begin(kAttributeValueRecords), it);
-  if (!name.EqualsASCII(kAttributeValueNames[index]))
+  if (!name.EqualsASCII(kAttributeValueNameSpan[index])) {
     return std::nullopt;
+  }
 
   return it->eName;
 }
@@ -263,10 +277,10 @@
       result.attribute = attr.value().attribute;
       result.eValueType = attr.value().eValueType;
       size_t index = std::distance(std::begin(kElementAttributeRecords), it);
-      result.callback = kElementAttributeCallbacks[index];
+      result.callback = kElementAttributeCallbackSpan[index];
       return result;
     }
-    element = kElementRecords[static_cast<size_t>(element)].parent;
+    element = kElementRecordSpan[static_cast<size_t>(element)].parent;
   }
   return std::nullopt;
 }