16d528ed9Sopenharmony_ci// Copyright 2013 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#include "base/strings/stringprintf.h"
66d528ed9Sopenharmony_ci
76d528ed9Sopenharmony_ci#include <errno.h>
86d528ed9Sopenharmony_ci#include <stddef.h>
96d528ed9Sopenharmony_ci
106d528ed9Sopenharmony_ci#include <iterator>
116d528ed9Sopenharmony_ci#include <vector>
126d528ed9Sopenharmony_ci
136d528ed9Sopenharmony_ci#include "base/scoped_clear_errno.h"
146d528ed9Sopenharmony_ci#include "base/strings/string_util.h"
156d528ed9Sopenharmony_ci#include "base/strings/utf_string_conversions.h"
166d528ed9Sopenharmony_ci#include "util/build_config.h"
176d528ed9Sopenharmony_ci
186d528ed9Sopenharmony_cinamespace base {
196d528ed9Sopenharmony_ci
206d528ed9Sopenharmony_cinamespace {
216d528ed9Sopenharmony_ci
226d528ed9Sopenharmony_ci// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
236d528ed9Sopenharmony_ci// is the size of the buffer. These return the number of characters in the
246d528ed9Sopenharmony_ci// formatted string excluding the NUL terminator. If the buffer is not
256d528ed9Sopenharmony_ci// large enough to accommodate the formatted string without truncation, they
266d528ed9Sopenharmony_ci// return the number of characters that would be in the fully-formatted string
276d528ed9Sopenharmony_ci// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
286d528ed9Sopenharmony_ciinline int vsnprintfT(char* buffer,
296d528ed9Sopenharmony_ci                      size_t buf_size,
306d528ed9Sopenharmony_ci                      const char* format,
316d528ed9Sopenharmony_ci                      va_list argptr) {
326d528ed9Sopenharmony_ci  return base::vsnprintf(buffer, buf_size, format, argptr);
336d528ed9Sopenharmony_ci}
346d528ed9Sopenharmony_ci
356d528ed9Sopenharmony_ci// Templatized backend for StringPrintF/StringAppendF. This does not finalize
366d528ed9Sopenharmony_ci// the va_list, the caller is expected to do that.
376d528ed9Sopenharmony_citemplate <class StringType>
386d528ed9Sopenharmony_cistatic void StringAppendVT(StringType* dst,
396d528ed9Sopenharmony_ci                           const typename StringType::value_type* format,
406d528ed9Sopenharmony_ci                           va_list ap) {
416d528ed9Sopenharmony_ci  // First try with a small fixed size buffer.
426d528ed9Sopenharmony_ci  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
436d528ed9Sopenharmony_ci  // and StringUtilTest.StringPrintfBounds.
446d528ed9Sopenharmony_ci  typename StringType::value_type stack_buf[1024];
456d528ed9Sopenharmony_ci
466d528ed9Sopenharmony_ci  va_list ap_copy;
476d528ed9Sopenharmony_ci  va_copy(ap_copy, ap);
486d528ed9Sopenharmony_ci
496d528ed9Sopenharmony_ci#if !defined(OS_WIN)
506d528ed9Sopenharmony_ci  ScopedClearErrno clear_errno;
516d528ed9Sopenharmony_ci#endif
526d528ed9Sopenharmony_ci  int result = vsnprintfT(stack_buf, std::size(stack_buf), format, ap_copy);
536d528ed9Sopenharmony_ci  va_end(ap_copy);
546d528ed9Sopenharmony_ci
556d528ed9Sopenharmony_ci  if (result >= 0 && result < static_cast<int>(std::size(stack_buf))) {
566d528ed9Sopenharmony_ci    // It fit.
576d528ed9Sopenharmony_ci    dst->append(stack_buf, result);
586d528ed9Sopenharmony_ci    return;
596d528ed9Sopenharmony_ci  }
606d528ed9Sopenharmony_ci
616d528ed9Sopenharmony_ci  // Repeatedly increase buffer size until it fits.
626d528ed9Sopenharmony_ci  int mem_length = std::size(stack_buf);
636d528ed9Sopenharmony_ci  while (true) {
646d528ed9Sopenharmony_ci    if (result < 0) {
656d528ed9Sopenharmony_ci#if defined(OS_WIN)
666d528ed9Sopenharmony_ci      // On Windows, vsnprintfT always returns the number of characters in a
676d528ed9Sopenharmony_ci      // fully-formatted string, so if we reach this point, something else is
686d528ed9Sopenharmony_ci      // wrong and no amount of buffer-doubling is going to fix it.
696d528ed9Sopenharmony_ci      return;
706d528ed9Sopenharmony_ci#else
716d528ed9Sopenharmony_ci      if (errno != 0 && errno != EOVERFLOW)
726d528ed9Sopenharmony_ci        return;
736d528ed9Sopenharmony_ci      // Try doubling the buffer size.
746d528ed9Sopenharmony_ci      mem_length *= 2;
756d528ed9Sopenharmony_ci#endif
766d528ed9Sopenharmony_ci    } else {
776d528ed9Sopenharmony_ci      // We need exactly "result + 1" characters.
786d528ed9Sopenharmony_ci      mem_length = result + 1;
796d528ed9Sopenharmony_ci    }
806d528ed9Sopenharmony_ci
816d528ed9Sopenharmony_ci    if (mem_length > 32 * 1024 * 1024) {
826d528ed9Sopenharmony_ci      // That should be plenty, don't try anything larger.  This protects
836d528ed9Sopenharmony_ci      // against huge allocations when using vsnprintfT implementations that
846d528ed9Sopenharmony_ci      // return -1 for reasons other than overflow without setting errno.
856d528ed9Sopenharmony_ci      DLOG(WARNING) << "Unable to printf the requested string due to size.";
866d528ed9Sopenharmony_ci      return;
876d528ed9Sopenharmony_ci    }
886d528ed9Sopenharmony_ci
896d528ed9Sopenharmony_ci    std::vector<typename StringType::value_type> mem_buf(mem_length);
906d528ed9Sopenharmony_ci
916d528ed9Sopenharmony_ci    // NOTE: You can only use a va_list once.  Since we're in a while loop, we
926d528ed9Sopenharmony_ci    // need to make a new copy each time so we don't use up the original.
936d528ed9Sopenharmony_ci    va_copy(ap_copy, ap);
946d528ed9Sopenharmony_ci    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
956d528ed9Sopenharmony_ci    va_end(ap_copy);
966d528ed9Sopenharmony_ci
976d528ed9Sopenharmony_ci    if ((result >= 0) && (result < mem_length)) {
986d528ed9Sopenharmony_ci      // It fit.
996d528ed9Sopenharmony_ci      dst->append(&mem_buf[0], result);
1006d528ed9Sopenharmony_ci      return;
1016d528ed9Sopenharmony_ci    }
1026d528ed9Sopenharmony_ci  }
1036d528ed9Sopenharmony_ci}
1046d528ed9Sopenharmony_ci
1056d528ed9Sopenharmony_ci}  // namespace
1066d528ed9Sopenharmony_ci
1076d528ed9Sopenharmony_cistd::string StringPrintf(const char* format, ...) {
1086d528ed9Sopenharmony_ci  va_list ap;
1096d528ed9Sopenharmony_ci  va_start(ap, format);
1106d528ed9Sopenharmony_ci  std::string result;
1116d528ed9Sopenharmony_ci  StringAppendV(&result, format, ap);
1126d528ed9Sopenharmony_ci  va_end(ap);
1136d528ed9Sopenharmony_ci  return result;
1146d528ed9Sopenharmony_ci}
1156d528ed9Sopenharmony_ci
1166d528ed9Sopenharmony_cistd::string StringPrintV(const char* format, va_list ap) {
1176d528ed9Sopenharmony_ci  std::string result;
1186d528ed9Sopenharmony_ci  StringAppendV(&result, format, ap);
1196d528ed9Sopenharmony_ci  return result;
1206d528ed9Sopenharmony_ci}
1216d528ed9Sopenharmony_ci
1226d528ed9Sopenharmony_ciconst std::string& SStringPrintf(std::string* dst, const char* format, ...) {
1236d528ed9Sopenharmony_ci  va_list ap;
1246d528ed9Sopenharmony_ci  va_start(ap, format);
1256d528ed9Sopenharmony_ci  dst->clear();
1266d528ed9Sopenharmony_ci  StringAppendV(dst, format, ap);
1276d528ed9Sopenharmony_ci  va_end(ap);
1286d528ed9Sopenharmony_ci  return *dst;
1296d528ed9Sopenharmony_ci}
1306d528ed9Sopenharmony_ci
1316d528ed9Sopenharmony_civoid StringAppendF(std::string* dst, const char* format, ...) {
1326d528ed9Sopenharmony_ci  va_list ap;
1336d528ed9Sopenharmony_ci  va_start(ap, format);
1346d528ed9Sopenharmony_ci  StringAppendV(dst, format, ap);
1356d528ed9Sopenharmony_ci  va_end(ap);
1366d528ed9Sopenharmony_ci}
1376d528ed9Sopenharmony_ci
1386d528ed9Sopenharmony_civoid StringAppendV(std::string* dst, const char* format, va_list ap) {
1396d528ed9Sopenharmony_ci  StringAppendVT(dst, format, ap);
1406d528ed9Sopenharmony_ci}
1416d528ed9Sopenharmony_ci
1426d528ed9Sopenharmony_ci}  // namespace base
143