1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/strings/stringprintf.h"
6
7#include <errno.h>
8
9#include "base/scoped_clear_errno.h"
10#include "base/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12
13namespace base {
14
15namespace {
16
17// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
18// is the size of the buffer. These return the number of characters in the
19// formatted string excluding the NUL terminator. If the buffer is not
20// large enough to accommodate the formatted string without truncation, they
21// return the number of characters that would be in the fully-formatted string
22// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
23inline int vsnprintfT(char* buffer,
24                      size_t buf_size,
25                      const char* format,
26                      va_list argptr) {
27  return base::vsnprintf(buffer, buf_size, format, argptr);
28}
29
30#if !defined(OS_ANDROID)
31inline int vsnprintfT(wchar_t* buffer,
32                      size_t buf_size,
33                      const wchar_t* format,
34                      va_list argptr) {
35  return base::vswprintf(buffer, buf_size, format, argptr);
36}
37#endif
38
39// Templatized backend for StringPrintF/StringAppendF. This does not finalize
40// the va_list, the caller is expected to do that.
41template <class StringType>
42static void StringAppendVT(StringType* dst,
43                           const typename StringType::value_type* format,
44                           va_list ap) {
45  // First try with a small fixed size buffer.
46  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
47  // and StringUtilTest.StringPrintfBounds.
48  typename StringType::value_type stack_buf[1024];
49
50  va_list ap_copy;
51  GG_VA_COPY(ap_copy, ap);
52
53#if !defined(OS_WIN)
54  ScopedClearErrno clear_errno;
55#endif
56  int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
57  va_end(ap_copy);
58
59  if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
60    // It fit.
61    dst->append(stack_buf, result);
62    return;
63  }
64
65  // Repeatedly increase buffer size until it fits.
66  int mem_length = arraysize(stack_buf);
67  while (true) {
68    if (result < 0) {
69#if defined(OS_WIN)
70      // On Windows, vsnprintfT always returns the number of characters in a
71      // fully-formatted string, so if we reach this point, something else is
72      // wrong and no amount of buffer-doubling is going to fix it.
73      return;
74#else
75      if (errno != 0 && errno != EOVERFLOW)
76        return;
77      // Try doubling the buffer size.
78      mem_length *= 2;
79#endif
80    } else {
81      // We need exactly "result + 1" characters.
82      mem_length = result + 1;
83    }
84
85    if (mem_length > 32 * 1024 * 1024) {
86      // That should be plenty, don't try anything larger.  This protects
87      // against huge allocations when using vsnprintfT implementations that
88      // return -1 for reasons other than overflow without setting errno.
89      DLOG(WARNING) << "Unable to printf the requested string due to size.";
90      return;
91    }
92
93    std::vector<typename StringType::value_type> mem_buf(mem_length);
94
95    // NOTE: You can only use a va_list once.  Since we're in a while loop, we
96    // need to make a new copy each time so we don't use up the original.
97    GG_VA_COPY(ap_copy, ap);
98    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
99    va_end(ap_copy);
100
101    if ((result >= 0) && (result < mem_length)) {
102      // It fit.
103      dst->append(&mem_buf[0], result);
104      return;
105    }
106  }
107}
108
109}  // namespace
110
111std::string StringPrintf(const char* format, ...) {
112  va_list ap;
113  va_start(ap, format);
114  std::string result;
115  StringAppendV(&result, format, ap);
116  va_end(ap);
117  return result;
118}
119
120#if !defined(OS_ANDROID)
121std::wstring StringPrintf(const wchar_t* format, ...) {
122  va_list ap;
123  va_start(ap, format);
124  std::wstring result;
125  StringAppendV(&result, format, ap);
126  va_end(ap);
127  return result;
128}
129#endif
130
131std::string StringPrintV(const char* format, va_list ap) {
132  std::string result;
133  StringAppendV(&result, format, ap);
134  return result;
135}
136
137const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
138  va_list ap;
139  va_start(ap, format);
140  dst->clear();
141  StringAppendV(dst, format, ap);
142  va_end(ap);
143  return *dst;
144}
145
146#if !defined(OS_ANDROID)
147const std::wstring& SStringPrintf(std::wstring* dst,
148                                  const wchar_t* format, ...) {
149  va_list ap;
150  va_start(ap, format);
151  dst->clear();
152  StringAppendV(dst, format, ap);
153  va_end(ap);
154  return *dst;
155}
156#endif
157
158void StringAppendF(std::string* dst, const char* format, ...) {
159  va_list ap;
160  va_start(ap, format);
161  StringAppendV(dst, format, ap);
162  va_end(ap);
163}
164
165#if !defined(OS_ANDROID)
166void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
167  va_list ap;
168  va_start(ap, format);
169  StringAppendV(dst, format, ap);
170  va_end(ap);
171}
172#endif
173
174void StringAppendV(std::string* dst, const char* format, va_list ap) {
175  StringAppendVT(dst, format, ap);
176}
177
178#if !defined(OS_ANDROID)
179void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
180  StringAppendVT(dst, format, ap);
181}
182#endif
183
184}  // namespace base
185