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
13 namespace base {
14
15 namespace {
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).
vsnprintfT(char * buffer,size_t buf_size,const char * format,va_list argptr)23 inline 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)
vsnprintfT(wchar_t * buffer,size_t buf_size,const wchar_t * format,va_list argptr)31 inline 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.
41 template <class StringType>
StringAppendVT(StringType * dst,const typename StringType::value_type * format,va_list ap)42 static 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
StringPrintf(const char * format,...)111 std::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)
StringPrintf(const wchar_t * format,...)121 std::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
StringPrintV(const char * format,va_list ap)131 std::string StringPrintV(const char* format, va_list ap) {
132 std::string result;
133 StringAppendV(&result, format, ap);
134 return result;
135 }
136
SStringPrintf(std::string * dst,const char * format,...)137 const 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)
SStringPrintf(std::wstring * dst,const wchar_t * format,...)147 const 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
StringAppendF(std::string * dst,const char * format,...)158 void 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)
StringAppendF(std::wstring * dst,const wchar_t * format,...)166 void 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
StringAppendV(std::string * dst,const char * format,va_list ap)174 void StringAppendV(std::string* dst, const char* format, va_list ap) {
175 StringAppendVT(dst, format, ap);
176 }
177
178 #if !defined(OS_ANDROID)
StringAppendV(std::wstring * dst,const wchar_t * format,va_list ap)179 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
180 StringAppendVT(dst, format, ap);
181 }
182 #endif
183
184 } // namespace base
185