• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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