|
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). |
|
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) |
|
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> |
|
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 if (errno != 0 && errno != EOVERFLOW) |
|
74 #endif |
|
75 { |
|
76 // If an error other than overflow occurred, it's never going to work. |
|
77 DLOG(WARNING) << "Unable to printf the requested string due to error."; |
|
78 return; |
|
79 } |
|
80 // Try doubling the buffer size. |
|
81 mem_length *= 2; |
|
82 } else { |
|
83 // We need exactly "result + 1" characters. |
|
84 mem_length = result + 1; |
|
85 } |
|
86 |
|
87 if (mem_length > 32 * 1024 * 1024) { |
|
88 // That should be plenty, don't try anything larger. This protects |
|
89 // against huge allocations when using vsnprintfT implementations that |
|
90 // return -1 for reasons other than overflow without setting errno. |
|
91 DLOG(WARNING) << "Unable to printf the requested string due to size."; |
|
92 return; |
|
93 } |
|
94 |
|
95 std::vector<typename StringType::value_type> mem_buf(mem_length); |
|
96 |
|
97 // NOTE: You can only use a va_list once. Since we're in a while loop, we |
|
98 // need to make a new copy each time so we don't use up the original. |
|
99 GG_VA_COPY(ap_copy, ap); |
|
100 result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); |
|
101 va_end(ap_copy); |
|
102 |
|
103 if ((result >= 0) && (result < mem_length)) { |
|
104 // It fit. |
|
105 dst->append(&mem_buf[0], result); |
|
106 return; |
|
107 } |
|
108 } |
|
109 } |
|
110 |
|
111 } // namespace |
|
112 |
|
113 std::string StringPrintf(const char* format, ...) { |
|
114 va_list ap; |
|
115 va_start(ap, format); |
|
116 std::string result; |
|
117 StringAppendV(&result, format, ap); |
|
118 va_end(ap); |
|
119 return result; |
|
120 } |
|
121 |
|
122 #if !defined(OS_ANDROID) |
|
123 std::wstring StringPrintf(const wchar_t* format, ...) { |
|
124 va_list ap; |
|
125 va_start(ap, format); |
|
126 std::wstring result; |
|
127 StringAppendV(&result, format, ap); |
|
128 va_end(ap); |
|
129 return result; |
|
130 } |
|
131 #endif |
|
132 |
|
133 std::string StringPrintV(const char* format, va_list ap) { |
|
134 std::string result; |
|
135 StringAppendV(&result, format, ap); |
|
136 return result; |
|
137 } |
|
138 |
|
139 const std::string& SStringPrintf(std::string* dst, const char* format, ...) { |
|
140 va_list ap; |
|
141 va_start(ap, format); |
|
142 dst->clear(); |
|
143 StringAppendV(dst, format, ap); |
|
144 va_end(ap); |
|
145 return *dst; |
|
146 } |
|
147 |
|
148 #if !defined(OS_ANDROID) |
|
149 const std::wstring& SStringPrintf(std::wstring* dst, |
|
150 const wchar_t* format, ...) { |
|
151 va_list ap; |
|
152 va_start(ap, format); |
|
153 dst->clear(); |
|
154 StringAppendV(dst, format, ap); |
|
155 va_end(ap); |
|
156 return *dst; |
|
157 } |
|
158 #endif |
|
159 |
|
160 void StringAppendF(std::string* dst, const char* format, ...) { |
|
161 va_list ap; |
|
162 va_start(ap, format); |
|
163 StringAppendV(dst, format, ap); |
|
164 va_end(ap); |
|
165 } |
|
166 |
|
167 #if !defined(OS_ANDROID) |
|
168 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) { |
|
169 va_list ap; |
|
170 va_start(ap, format); |
|
171 StringAppendV(dst, format, ap); |
|
172 va_end(ap); |
|
173 } |
|
174 #endif |
|
175 |
|
176 void StringAppendV(std::string* dst, const char* format, va_list ap) { |
|
177 StringAppendVT(dst, format, ap); |
|
178 } |
|
179 |
|
180 #if !defined(OS_ANDROID) |
|
181 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) { |
|
182 StringAppendVT(dst, format, ap); |
|
183 } |
|
184 #endif |
|
185 |
|
186 } // namespace base |