Make core/fxcrt compliant with UNSAFE_BUFFERS() macro.
First application is the (very C-style files) in core/fxcrt. This
CL flags the places which have still not been able to be converted.
Change-Id: I16652f7f9d065f499392bf64b993cb19854ce7ac
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116070
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index e2d1c6e..1531a7c 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -143,6 +143,7 @@
configs += [
"../../:pdfium_strict_config",
"../../:pdfium_noshorten_config",
+ "../../:pdfium_nounsafe_buffer_usage_config",
]
public_deps = [
"../../:freetype_common",
diff --git a/core/fxcrt/fx_extension.cpp b/core/fxcrt/fx_extension.cpp
index 0f6b720..77afea1 100644
--- a/core/fxcrt/fx_extension.cpp
+++ b/core/fxcrt/fx_extension.cpp
@@ -29,88 +29,98 @@
} // namespace
float FXSYS_wcstof(const wchar_t* pwsStr, size_t nLength, size_t* pUsedLen) {
- DCHECK(pwsStr);
- if (nLength == 0)
- return 0.0f;
+ // SAFETY: TODO(tsepez): This is an enormous unsafe block, pretty hard to
+ // explain its soundness.
+ UNSAFE_BUFFERS({
+ DCHECK(pwsStr);
+ if (nLength == 0) {
+ return 0.0f;
+ }
- size_t nUsedLen = 0;
- bool bNegtive = false;
- switch (pwsStr[nUsedLen]) {
- case '-':
- bNegtive = true;
- [[fallthrough]];
- case '+':
- nUsedLen++;
- break;
- }
-
- float fValue = 0.0f;
- while (nUsedLen < nLength) {
- wchar_t wch = pwsStr[nUsedLen];
- if (!FXSYS_IsDecimalDigit(wch))
- break;
-
- fValue = fValue * 10.0f + (wch - L'0');
- nUsedLen++;
- }
-
- if (nUsedLen < nLength && pwsStr[nUsedLen] == L'.') {
- float fPrecise = 0.1f;
- while (++nUsedLen < nLength) {
- wchar_t wch = pwsStr[nUsedLen];
- if (!FXSYS_IsDecimalDigit(wch))
+ size_t nUsedLen = 0;
+ bool bNegtive = false;
+ switch (pwsStr[nUsedLen]) {
+ case '-':
+ bNegtive = true;
+ [[fallthrough]];
+ case '+':
+ nUsedLen++;
break;
-
- fValue += (wch - L'0') * fPrecise;
- fPrecise *= 0.1f;
- }
- }
-
- if (nUsedLen < nLength &&
- (pwsStr[nUsedLen] == 'e' || pwsStr[nUsedLen] == 'E')) {
- ++nUsedLen;
-
- bool negative_exponent = false;
- if (nUsedLen < nLength &&
- (pwsStr[nUsedLen] == '-' || pwsStr[nUsedLen] == '+')) {
- negative_exponent = pwsStr[nUsedLen] == '-';
- ++nUsedLen;
}
- int32_t exp_value = 0;
+ float fValue = 0.0f;
while (nUsedLen < nLength) {
wchar_t wch = pwsStr[nUsedLen];
if (!FXSYS_IsDecimalDigit(wch))
break;
- exp_value = exp_value * 10.0f + (wch - L'0');
- // Exponent is outside the valid range, fail.
- if ((negative_exponent &&
- -exp_value < std::numeric_limits<float>::min_exponent10) ||
- (!negative_exponent &&
- exp_value > std::numeric_limits<float>::max_exponent10)) {
- if (pUsedLen)
- *pUsedLen = 0;
- return 0.0f;
- }
+ fValue = fValue * 10.0f + (wch - L'0');
+ nUsedLen++;
+ }
+ if (nUsedLen < nLength && pwsStr[nUsedLen] == L'.') {
+ float fPrecise = 0.1f;
+ while (++nUsedLen < nLength) {
+ wchar_t wch = pwsStr[nUsedLen];
+ if (!FXSYS_IsDecimalDigit(wch)) {
+ break;
+ }
+
+ fValue += (wch - L'0') * fPrecise;
+ fPrecise *= 0.1f;
+ }
+ }
+
+ if (nUsedLen < nLength &&
+ (pwsStr[nUsedLen] == 'e' || pwsStr[nUsedLen] == 'E')) {
++nUsedLen;
- }
- for (size_t i = exp_value; i > 0; --i) {
- if (exp_value > 0) {
- if (negative_exponent)
- fValue /= 10;
- else
- fValue *= 10;
+ bool negative_exponent = false;
+ if (nUsedLen < nLength &&
+ (pwsStr[nUsedLen] == '-' || pwsStr[nUsedLen] == '+')) {
+ negative_exponent = pwsStr[nUsedLen] == '-';
+ ++nUsedLen;
+ }
+
+ int32_t exp_value = 0;
+ while (nUsedLen < nLength) {
+ wchar_t wch = pwsStr[nUsedLen];
+ if (!FXSYS_IsDecimalDigit(wch)) {
+ break;
+ }
+
+ exp_value = exp_value * 10.0f + (wch - L'0');
+ // Exponent is outside the valid range, fail.
+ if ((negative_exponent &&
+ -exp_value < std::numeric_limits<float>::min_exponent10) ||
+ (!negative_exponent &&
+ exp_value > std::numeric_limits<float>::max_exponent10)) {
+ if (pUsedLen) {
+ *pUsedLen = 0;
+ }
+ return 0.0f;
+ }
+
+ ++nUsedLen;
+ }
+
+ for (size_t i = exp_value; i > 0; --i) {
+ if (exp_value > 0) {
+ if (negative_exponent) {
+ fValue /= 10;
+ } else {
+ fValue *= 10;
+ }
+ }
}
}
- }
- if (pUsedLen)
- *pUsedLen = nUsedLen;
+ if (pUsedLen) {
+ *pUsedLen = nUsedLen;
+ }
- return bNegtive ? -fValue : fValue;
+ return bNegtive ? -fValue : fValue;
+ });
}
wchar_t* FXSYS_wcsncpy(wchar_t* dstStr, const wchar_t* srcStr, size_t count) {
@@ -118,9 +128,15 @@
DCHECK(srcStr);
DCHECK(count > 0);
- for (size_t i = 0; i < count; ++i)
- if ((dstStr[i] = srcStr[i]) == L'\0')
- break;
+ // SAFETY: TODO(tsepez): This is UNSAFE_BUFFER_USAGE as well.
+ UNSAFE_BUFFERS({
+ for (size_t i = 0; i < count; ++i) {
+ dstStr[i] = srcStr[i];
+ if (dstStr[i] == L'\0') {
+ break;
+ }
+ }
+ });
return dstStr;
}
@@ -129,25 +145,34 @@
DCHECK(s2);
DCHECK(count > 0);
- while (count-- > 0) {
- wchar_t wch1 = static_cast<wchar_t>(FXSYS_towlower(*s1++));
- wchar_t wch2 = static_cast<wchar_t>(FXSYS_towlower(*s2++));
- if (wch1 != wch2) {
- return wch1 > wch2 ? 1 : -1;
+ // SAFETY: TODO(tsepez): This is UNSAFE_BUFFER_USAGE as well.
+ UNSAFE_BUFFERS({
+ while (count-- > 0) {
+ wchar_t wch1 = static_cast<wchar_t>(FXSYS_towlower(*s1++));
+ wchar_t wch2 = static_cast<wchar_t>(FXSYS_towlower(*s2++));
+ if (wch1 != wch2) {
+ return wch1 > wch2 ? 1 : -1;
+ }
}
- }
+ });
return 0;
}
void FXSYS_IntToTwoHexChars(uint8_t n, char* buf) {
static const char kHex[] = "0123456789ABCDEF";
- buf[0] = kHex[n / 16];
- buf[1] = kHex[n % 16];
+ // SAFETY: TODO(tsepez): This is UNSAFE_BUFFER_USAGE as well.
+ UNSAFE_BUFFERS({
+ buf[0] = kHex[n / 16];
+ buf[1] = kHex[n % 16];
+ });
}
void FXSYS_IntToFourHexChars(uint16_t n, char* buf) {
- FXSYS_IntToTwoHexChars(n / 256, buf);
- FXSYS_IntToTwoHexChars(n % 256, buf + 2);
+ // SAFETY: TODO(tsepez): This is UNSAFE_BUFFER_USAGE as well.
+ UNSAFE_BUFFERS({
+ FXSYS_IntToTwoHexChars(n / 256, buf);
+ FXSYS_IntToTwoHexChars(n % 256, buf + 2);
+ });
}
size_t FXSYS_ToUTF16BE(uint32_t unicode, char* buf) {
@@ -159,9 +184,12 @@
FXSYS_IntToFourHexChars(unicode, buf);
return 4;
}
- pdfium::SurrogatePair surrogate_pair(unicode);
- FXSYS_IntToFourHexChars(surrogate_pair.high(), buf);
- FXSYS_IntToFourHexChars(surrogate_pair.low(), buf + 4);
+ // SAFETY: TODO(tsepez): This is UNSAFE_BUFFER_USAGE as well.
+ UNSAFE_BUFFERS({
+ pdfium::SurrogatePair surrogate_pair(unicode);
+ FXSYS_IntToFourHexChars(surrogate_pair.high(), buf);
+ FXSYS_IntToFourHexChars(surrogate_pair.low(), buf + 4);
+ });
return 8;
}
diff --git a/core/fxcrt/fx_memory_pa.cpp b/core/fxcrt/fx_memory_pa.cpp
index be6e2af..82df893 100644
--- a/core/fxcrt/fx_memory_pa.cpp
+++ b/core/fxcrt/fx_memory_pa.cpp
@@ -6,10 +6,14 @@
#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fx_safe_types.h"
-#include "partition_alloc/partition_alloc.h"
-#if !defined(PDF_USE_PARTITION_ALLOC)
+#if defined(PDF_USE_PARTITION_ALLOC)
+UNSAFE_HEADERS_BEGIN()
+#include "partition_alloc/partition_alloc.h"
+UNSAFE_HEADERS_END()
+#else
#error "File compiled under wrong build option."
#endif
diff --git a/core/fxcrt/fx_system.cpp b/core/fxcrt/fx_system.cpp
index 0286b07..4eb1864 100644
--- a/core/fxcrt/fx_system.cpp
+++ b/core/fxcrt/fx_system.cpp
@@ -11,6 +11,7 @@
#include <limits>
#include "build/build_config.h"
+#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/fx_extension.h"
namespace {
@@ -26,8 +27,13 @@
// Process the sign.
bool neg = *str == '-';
- if (neg || *str == '+')
- str++;
+ if (neg || *str == '+') {
+ // SAFETY: `str` points at the start of the string, which is a character or
+ // a terminating NUL. `*str` is non-NUL from the condition above, so `str`
+ // is pointing inside the string. Afterward, `str` may be pointing at the
+ // terminating NUL.
+ UNSAFE_BUFFERS(str++);
+ }
IntType num = 0;
while (*str && FXSYS_IsDecimalDigit(*str)) {
@@ -37,15 +43,17 @@
// Return MIN when the represented number is signed type and is smaller
// than the min value.
return std::numeric_limits<IntType>::min();
- } else {
- // Return MAX when the represented number is signed type and is larger
- // than the max value, or the number is unsigned type and out of range.
- return std::numeric_limits<IntType>::max();
}
+ // Return MAX when the represented number is signed type and is larger
+ // than the max value, or the number is unsigned type and out of range.
+ return std::numeric_limits<IntType>::max();
}
-
num = num * 10 + val;
- str++;
+
+ // SAFETY: The loop terminates if `str` is ever pointing at the terminating
+ // NUL. `str` is only moved by one character at a time, so inside the loop
+ // `str` always points inside the string.
+ UNSAFE_BUFFERS(str++);
}
// When it is a negative value, -num should be returned. Since num may be of
// unsigned type, use ~num + 1 to avoid the warning of applying unary minus
@@ -55,19 +63,20 @@
template <typename T, typename UT, typename STR_T>
STR_T FXSYS_IntToStr(T value, STR_T str, int radix) {
+ // SAFETY: TODO(tsepez): investigate safety throughout.
if (radix < 2 || radix > 16) {
str[0] = 0;
return str;
}
if (value == 0) {
str[0] = '0';
- str[1] = 0;
+ UNSAFE_BUFFERS(str[1]) = 0;
return str;
}
int i = 0;
UT uvalue;
if (value < 0) {
- str[i++] = '-';
+ UNSAFE_BUFFERS(str[i++]) = '-';
// Standard trick to avoid undefined behaviour when negating INT_MIN.
uvalue = static_cast<UT>(-(value + 1)) + 1;
} else {
@@ -80,10 +89,10 @@
order = order / radix;
}
for (int d = digits - 1; d > -1; d--) {
- str[d + i] = "0123456789abcdef"[uvalue % radix];
+ UNSAFE_BUFFERS(str[d + i] = "0123456789abcdef"[uvalue % radix]);
uvalue /= radix;
}
- str[digits + i] = 0;
+ UNSAFE_BUFFERS(str[digits + i]) = 0;
return str;
}
@@ -154,10 +163,11 @@
char* s = str;
while (*str) {
*str = tolower(*str);
- str++;
+ UNSAFE_BUFFERS(str++); // SAFETY: NUL check in while condition.
}
return s;
}
+
char* FXSYS_strupr(char* str) {
if (!str) {
return nullptr;
@@ -165,10 +175,11 @@
char* s = str;
while (*str) {
*str = toupper(*str);
- str++;
+ UNSAFE_BUFFERS(str++); // SAFETY: NUL check in while condition.
}
return s;
}
+
wchar_t* FXSYS_wcslwr(wchar_t* str) {
if (!str) {
return nullptr;
@@ -176,10 +187,11 @@
wchar_t* s = str;
while (*str) {
*str = FXSYS_towlower(*str);
- str++;
+ UNSAFE_BUFFERS(str++); // SAFETY: NUL check in while condition.
}
return s;
}
+
wchar_t* FXSYS_wcsupr(wchar_t* str) {
if (!str) {
return nullptr;
@@ -187,7 +199,7 @@
wchar_t* s = str;
while (*str) {
*str = FXSYS_towupper(*str);
- str++;
+ UNSAFE_BUFFERS(str++); // SAFETY: NUL check in while condition.
}
return s;
}
@@ -198,8 +210,12 @@
do {
f = toupper(*str1);
l = toupper(*str2);
- ++str1;
- ++str2;
+ // SAFETY: The loop breaks when `*str1` is NUL, so `str1` is always inside
+ // its string.
+ UNSAFE_BUFFERS(++str1);
+ // SAFETY: The loop breaks when `*str1` is non-NUL but `*str2` is NUL (as
+ // checked by `f != l`), so `str2` is always inside its string.
+ UNSAFE_BUFFERS(++str2);
} while (f && f == l);
return f - l;
}
@@ -210,8 +226,12 @@
do {
f = FXSYS_towupper(*str1);
l = FXSYS_towupper(*str2);
- ++str1;
- ++str2;
+ // SAFETY: The loop breaks when `*str1` is NUL, so `str1` is always inside
+ // its string.
+ UNSAFE_BUFFERS(++str1);
+ // SAFETY: The loop breaks when `*str1` is non-NUL but `*str2` is NUL (as
+ // checked by `f != l`), so `str2` is always inside its string.
+ UNSAFE_BUFFERS(++str2);
} while (f && f == l);
return f - l;
}
diff --git a/core/fxcrt/fx_unicode.cpp b/core/fxcrt/fx_unicode.cpp
index ae21d90..f992c46 100644
--- a/core/fxcrt/fx_unicode.cpp
+++ b/core/fxcrt/fx_unicode.cpp
@@ -11,6 +11,8 @@
#include <iterator>
#include "core/fxcrt/check.h"
+#include "core/fxcrt/check_op.h"
+#include "core/fxcrt/compiler_specific.h"
namespace {
@@ -33,15 +35,16 @@
};
#undef CHARPROP____
-constexpr size_t kTextLayoutCodePropertiesSize =
- std::size(kTextLayoutCodeProperties);
-
-static_assert(kTextLayoutCodePropertiesSize == 65536, "missing characters");
+static_assert(std::size(kTextLayoutCodeProperties) == 65536,
+ "missing characters");
uint16_t GetUnicodeProperties(wchar_t wch) {
size_t idx = static_cast<size_t>(wch);
- if (idx < kTextLayoutCodePropertiesSize)
- return kTextLayoutCodeProperties[idx];
+ if (idx < std::size(kTextLayoutCodeProperties)) {
+ // SAFETY: `std::size(kTextLayoutCodeProperties)` is the size of the table,
+ // so the condition above verifies `idx` is in range.
+ return UNSAFE_BUFFERS(kTextLayoutCodeProperties[idx]);
+ }
return 0;
}
@@ -66,16 +69,16 @@
};
#undef CHARPROP____
-constexpr size_t kExtendedTextLayoutCodePropertiesSize =
- std::size(kExtendedTextLayoutCodeProperties);
-
-static_assert(kExtendedTextLayoutCodePropertiesSize == 65536,
+static_assert(std::size(kExtendedTextLayoutCodeProperties) == 65536,
"missing characters");
uint16_t GetExtendedUnicodeProperties(wchar_t wch) {
size_t idx = static_cast<size_t>(wch);
- if (idx < kExtendedTextLayoutCodePropertiesSize)
- return kExtendedTextLayoutCodeProperties[idx];
+ if (idx < std::size(kExtendedTextLayoutCodeProperties)) {
+ // SAFETY: `std::size(kExtendedTextLayoutCodeProperties)` is the size of
+ // the table, so the condition above verifies `idx` is in range.
+ return UNSAFE_BUFFERS(kExtendedTextLayoutCodeProperties[idx]);
+ }
return 0;
}
@@ -125,14 +128,12 @@
0xFF5D, 0xFF5B, 0xFF60, 0xFF5F, 0xFF63, 0xFF62,
};
-constexpr size_t kFXTextLayoutBidiMirrorSize =
- std::size(kFXTextLayoutBidiMirror);
-
// Check that the mirror indicies in the fx_ucddata.inc table are in bounds.
#undef CHARPROP____
-#define CHARPROP____(mirror, ct, bd, bt) \
- static_assert(mirror == kMirrorMax || mirror < kFXTextLayoutBidiMirrorSize, \
- "Bad mirror index");
+#define CHARPROP____(mirror, ct, bd, bt) \
+ static_assert( \
+ mirror == kMirrorMax || mirror < std::size(kFXTextLayoutBidiMirror), \
+ "Bad mirror index");
#include "core/fxcrt/fx_ucddata.inc" // NOLINT(build/include)
#undef CHARPROP____
@@ -143,10 +144,13 @@
wchar_t GetMirrorChar(wchar_t wch) {
uint16_t prop = GetUnicodeProperties(wch);
size_t idx = prop >> kMirrorBitPos;
- if (idx == kMirrorMax)
+ if (idx == kMirrorMax) {
return wch;
- DCHECK(idx < kFXTextLayoutBidiMirrorSize);
- return kFXTextLayoutBidiMirror[idx];
+ }
+ CHECK_LT(idx, std::size(kFXTextLayoutBidiMirror));
+ // SAFETY: `std::size(kFXTextLayoutBidiMirror)` is the size of the table, so
+ // the CHECK() above verifies `idx` is in range.
+ return UNSAFE_BUFFERS(kFXTextLayoutBidiMirror[idx]);
}
FX_BIDICLASS GetBidiClass(wchar_t wch) {
diff --git a/core/fxcrt/span.h b/core/fxcrt/span.h
index 5f7adcd..2e51cd2 100644
--- a/core/fxcrt/span.h
+++ b/core/fxcrt/span.h
@@ -17,8 +17,13 @@
#include "core/fxcrt/check.h"
#include "core/fxcrt/compiler_specific.h"
+// SAFETY: TODO(crbug.com/pdfium/2085): this entire file is to be replaced
+// with the fully annotated one that is being prepared in base/.
+
#if defined(PDF_USE_PARTITION_ALLOC)
+UNSAFE_HEADERS_BEGIN()
#include "partition_alloc/pointers/raw_ptr.h"
+UNSAFE_HEADERS_END()
#else
#include "core/fxcrt/unowned_ptr_exclusion.h"
#endif
@@ -267,7 +272,7 @@
const span subspan(size_t pos, size_t count = dynamic_extent) const {
CHECK(pos <= size_);
CHECK(count == dynamic_extent || count <= size_ - pos);
- return span(static_cast<T*>(data_) + pos,
+ return span(UNSAFE_BUFFERS(static_cast<T*>(data_) + pos),
count == dynamic_extent ? size_ - pos : count);
}
@@ -279,7 +284,7 @@
// [span.elem], span element access
T& operator[](size_t index) const noexcept {
CHECK(index < size_);
- return static_cast<T*>(data_)[index];
+ return UNSAFE_BUFFERS(static_cast<T*>(data_)[index]);
}
constexpr T& front() const noexcept {
@@ -289,14 +294,16 @@
constexpr T& back() const noexcept {
CHECK(!empty());
- return *(data() + size() - 1);
+ return UNSAFE_BUFFERS(*(data() + size() - 1));
}
constexpr T* data() const noexcept { return static_cast<T*>(data_); }
// [span.iter], span iterator support
constexpr iterator begin() const noexcept { return static_cast<T*>(data_); }
- constexpr iterator end() const noexcept { return begin() + size_; }
+ constexpr iterator end() const noexcept {
+ return UNSAFE_BUFFERS(begin() + size_);
+ }
constexpr const_iterator cbegin() const noexcept { return begin(); }
constexpr const_iterator cend() const noexcept { return end(); }
diff --git a/core/fxcrt/string_template.cpp b/core/fxcrt/string_template.cpp
index 531905b..91ec7b1 100644
--- a/core/fxcrt/string_template.cpp
+++ b/core/fxcrt/string_template.cpp
@@ -64,12 +64,7 @@
template <typename T>
size_t StringTemplate<T>::Remove(T chRemove) {
- size_t count = 0;
- for (const auto& ch : span()) {
- if (ch == chRemove) {
- count++;
- }
- }
+ size_t count = std::count(span().begin(), span().end(), chRemove);
if (count == 0) {
return 0;
}
diff --git a/core/fxcrt/unowned_ptr.h b/core/fxcrt/unowned_ptr.h
index 8f0d897..fba0e25 100644
--- a/core/fxcrt/unowned_ptr.h
+++ b/core/fxcrt/unowned_ptr.h
@@ -39,10 +39,13 @@
// into an unowned array is desired, which performs the same checks.
#include "build/build_config.h"
+#include "core/fxcrt/compiler_specific.h"
#if defined(PDF_USE_PARTITION_ALLOC)
+UNSAFE_HEADERS_BEGIN()
#include "partition_alloc/partition_alloc_buildflags.h"
#include "partition_alloc/pointers/raw_ptr.h"
+UNSAFE_HEADERS_END()
#if !BUILDFLAG(USE_PARTITION_ALLOC)
#error "pdf_use_partition_alloc=true requires use_partition_alloc=true"
@@ -65,7 +68,6 @@
#include <type_traits>
#include <utility>
-#include "core/fxcrt/compiler_specific.h"
#include "core/fxcrt/unowned_ptr_exclusion.h"
namespace fxcrt {
diff --git a/core/fxcrt/widestring.cpp b/core/fxcrt/widestring.cpp
index 5abfc0d..84676d5 100644
--- a/core/fxcrt/widestring.cpp
+++ b/core/fxcrt/widestring.cpp
@@ -57,192 +57,199 @@
std::optional<size_t> GuessSizeForVSWPrintf(const wchar_t* pFormat,
va_list argList) {
size_t nMaxLen = 0;
- for (const wchar_t* pStr = pFormat; *pStr != 0; pStr++) {
- if (*pStr != '%' || *(pStr = pStr + 1) == '%') {
- ++nMaxLen;
- continue;
- }
- int iWidth = 0;
- for (; *pStr != 0; pStr++) {
- if (*pStr == '#') {
- nMaxLen += 2;
- } else if (*pStr == '*') {
- iWidth = va_arg(argList, int);
- } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' && *pStr != ' ') {
- break;
+ // SAFETY: TODO(tsepez): investigate lack of safety.
+ UNSAFE_BUFFERS({
+ for (const wchar_t* pStr = pFormat; *pStr != 0; pStr++) {
+ if (*pStr != '%' || *(pStr = pStr + 1) == '%') {
+ ++nMaxLen;
+ continue;
}
- }
- if (iWidth == 0) {
- iWidth = FXSYS_wtoi(pStr);
- while (FXSYS_IsDecimalDigit(*pStr))
- ++pStr;
- }
- if (iWidth < 0 || iWidth > 128 * 1024)
- return std::nullopt;
- uint32_t nWidth = static_cast<uint32_t>(iWidth);
- int iPrecision = 0;
- if (*pStr == '.') {
- pStr++;
- if (*pStr == '*') {
- iPrecision = va_arg(argList, int);
- pStr++;
- } else {
- iPrecision = FXSYS_wtoi(pStr);
+ int iWidth = 0;
+ for (; *pStr != 0; pStr++) {
+ if (*pStr == '#') {
+ nMaxLen += 2;
+ } else if (*pStr == '*') {
+ iWidth = va_arg(argList, int);
+ } else if (*pStr != '-' && *pStr != '+' && *pStr != '0' &&
+ *pStr != ' ') {
+ break;
+ }
+ }
+ if (iWidth == 0) {
+ iWidth = FXSYS_wtoi(pStr);
while (FXSYS_IsDecimalDigit(*pStr))
++pStr;
}
- }
- if (iPrecision < 0 || iPrecision > 128 * 1024)
- return std::nullopt;
- uint32_t nPrecision = static_cast<uint32_t>(iPrecision);
- int nModifier = 0;
- if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') {
- pStr += 3;
- nModifier = FORCE_INT64;
- } else {
- switch (*pStr) {
- case 'h':
- nModifier = FORCE_ANSI;
- pStr++;
- break;
- case 'l':
- nModifier = FORCE_UNICODE;
- pStr++;
- break;
- case 'F':
- case 'N':
- case 'L':
- pStr++;
- break;
+ if (iWidth < 0 || iWidth > 128 * 1024) {
+ return std::nullopt;
}
- }
- size_t nItemLen = 0;
- switch (*pStr | nModifier) {
- case 'c':
- case 'C':
- nItemLen = 2;
- va_arg(argList, int);
- break;
- case 'c' | FORCE_ANSI:
- case 'C' | FORCE_ANSI:
- nItemLen = 2;
- va_arg(argList, int);
- break;
- case 'c' | FORCE_UNICODE:
- case 'C' | FORCE_UNICODE:
- nItemLen = 2;
- va_arg(argList, int);
- break;
- case 's': {
- const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*);
- if (pstrNextArg) {
- nItemLen = wcslen(pstrNextArg);
- if (nItemLen < 1) {
- nItemLen = 1;
- }
+ uint32_t nWidth = static_cast<uint32_t>(iWidth);
+ int iPrecision = 0;
+ if (*pStr == '.') {
+ pStr++;
+ if (*pStr == '*') {
+ iPrecision = va_arg(argList, int);
+ pStr++;
} else {
- nItemLen = 6;
- }
- } break;
- case 'S': {
- const char* pstrNextArg = va_arg(argList, const char*);
- if (pstrNextArg) {
- nItemLen = strlen(pstrNextArg);
- if (nItemLen < 1) {
- nItemLen = 1;
+ iPrecision = FXSYS_wtoi(pStr);
+ while (FXSYS_IsDecimalDigit(*pStr)) {
+ ++pStr;
}
- } else {
- nItemLen = 6;
}
- } break;
- case 's' | FORCE_ANSI:
- case 'S' | FORCE_ANSI: {
- const char* pstrNextArg = va_arg(argList, const char*);
- if (pstrNextArg) {
- nItemLen = strlen(pstrNextArg);
- if (nItemLen < 1) {
- nItemLen = 1;
- }
- } else {
- nItemLen = 6;
- }
- } break;
- case 's' | FORCE_UNICODE:
- case 'S' | FORCE_UNICODE: {
- const wchar_t* pstrNextArg = va_arg(argList, wchar_t*);
- if (pstrNextArg) {
- nItemLen = wcslen(pstrNextArg);
- if (nItemLen < 1) {
- nItemLen = 1;
- }
- } else {
- nItemLen = 6;
- }
- } break;
- }
- if (nItemLen != 0) {
- if (nPrecision != 0 && nItemLen > nPrecision) {
- nItemLen = nPrecision;
}
- if (nItemLen < nWidth) {
- nItemLen = nWidth;
+ if (iPrecision < 0 || iPrecision > 128 * 1024) {
+ return std::nullopt;
}
- } else {
- switch (*pStr) {
- case 'd':
- case 'i':
- case 'u':
- case 'x':
- case 'X':
- case 'o':
- if (nModifier & FORCE_INT64) {
- va_arg(argList, int64_t);
+ uint32_t nPrecision = static_cast<uint32_t>(iPrecision);
+ int nModifier = 0;
+ if (*pStr == L'I' && *(pStr + 1) == L'6' && *(pStr + 2) == L'4') {
+ pStr += 3;
+ nModifier = FORCE_INT64;
+ } else {
+ switch (*pStr) {
+ case 'h':
+ nModifier = FORCE_ANSI;
+ pStr++;
+ break;
+ case 'l':
+ nModifier = FORCE_UNICODE;
+ pStr++;
+ break;
+ case 'F':
+ case 'N':
+ case 'L':
+ pStr++;
+ break;
+ }
+ }
+ size_t nItemLen = 0;
+ switch (*pStr | nModifier) {
+ case 'c':
+ case 'C':
+ nItemLen = 2;
+ va_arg(argList, int);
+ break;
+ case 'c' | FORCE_ANSI:
+ case 'C' | FORCE_ANSI:
+ nItemLen = 2;
+ va_arg(argList, int);
+ break;
+ case 'c' | FORCE_UNICODE:
+ case 'C' | FORCE_UNICODE:
+ nItemLen = 2;
+ va_arg(argList, int);
+ break;
+ case 's': {
+ const wchar_t* pstrNextArg = va_arg(argList, const wchar_t*);
+ if (pstrNextArg) {
+ nItemLen = wcslen(pstrNextArg);
+ if (nItemLen < 1) {
+ nItemLen = 1;
+ }
} else {
- va_arg(argList, int);
+ nItemLen = 6;
}
- nItemLen = 32;
- if (nItemLen < nWidth + nPrecision) {
- nItemLen = nWidth + nPrecision;
- }
- break;
- case 'a':
- case 'A':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- va_arg(argList, double);
- nItemLen = 128;
- if (nItemLen < nWidth + nPrecision) {
- nItemLen = nWidth + nPrecision;
- }
- break;
- case 'f':
- if (nWidth + nPrecision > 100) {
- nItemLen = nPrecision + nWidth + 128;
+ } break;
+ case 'S': {
+ const char* pstrNextArg = va_arg(argList, const char*);
+ if (pstrNextArg) {
+ nItemLen = strlen(pstrNextArg);
+ if (nItemLen < 1) {
+ nItemLen = 1;
+ }
} else {
- double f;
- char pszTemp[256];
- f = va_arg(argList, double);
- FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth,
- nPrecision + 6, f);
- nItemLen = strlen(pszTemp);
+ nItemLen = 6;
}
- break;
- case 'p':
- va_arg(argList, void*);
- nItemLen = 32;
- if (nItemLen < nWidth + nPrecision) {
- nItemLen = nWidth + nPrecision;
+ } break;
+ case 's' | FORCE_ANSI:
+ case 'S' | FORCE_ANSI: {
+ const char* pstrNextArg = va_arg(argList, const char*);
+ if (pstrNextArg) {
+ nItemLen = strlen(pstrNextArg);
+ if (nItemLen < 1) {
+ nItemLen = 1;
+ }
+ } else {
+ nItemLen = 6;
}
- break;
- case 'n':
- va_arg(argList, int*);
- break;
+ } break;
+ case 's' | FORCE_UNICODE:
+ case 'S' | FORCE_UNICODE: {
+ const wchar_t* pstrNextArg = va_arg(argList, wchar_t*);
+ if (pstrNextArg) {
+ nItemLen = wcslen(pstrNextArg);
+ if (nItemLen < 1) {
+ nItemLen = 1;
+ }
+ } else {
+ nItemLen = 6;
+ }
+ } break;
}
+ if (nItemLen != 0) {
+ if (nPrecision != 0 && nItemLen > nPrecision) {
+ nItemLen = nPrecision;
+ }
+ if (nItemLen < nWidth) {
+ nItemLen = nWidth;
+ }
+ } else {
+ switch (*pStr) {
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'o':
+ if (nModifier & FORCE_INT64) {
+ va_arg(argList, int64_t);
+ } else {
+ va_arg(argList, int);
+ }
+ nItemLen = 32;
+ if (nItemLen < nWidth + nPrecision) {
+ nItemLen = nWidth + nPrecision;
+ }
+ break;
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ va_arg(argList, double);
+ nItemLen = 128;
+ if (nItemLen < nWidth + nPrecision) {
+ nItemLen = nWidth + nPrecision;
+ }
+ break;
+ case 'f':
+ if (nWidth + nPrecision > 100) {
+ nItemLen = nPrecision + nWidth + 128;
+ } else {
+ double f;
+ char pszTemp[256];
+ f = va_arg(argList, double);
+ FXSYS_snprintf(pszTemp, sizeof(pszTemp), "%*.*f", nWidth,
+ nPrecision + 6, f);
+ nItemLen = strlen(pszTemp);
+ }
+ break;
+ case 'p':
+ va_arg(argList, void*);
+ nItemLen = 32;
+ if (nItemLen < nWidth + nPrecision) {
+ nItemLen = nWidth + nPrecision;
+ }
+ break;
+ case 'n':
+ va_arg(argList, int*);
+ break;
+ }
+ }
+ nMaxLen += nItemLen;
}
- nMaxLen += nItemLen;
- }
+ });
nMaxLen += 32; // Fudge factor.
return nMaxLen;
}