OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/stringprintf.h" | |
6 | |
7 #include <errno.h> | |
8 | |
9 #include "base/scoped_clear_errno.h" | |
10 #include "base/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 | |
OLD | NEW |