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 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 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) 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 131 std::string StringPrintV(const char* format, va_list ap) { 132 std::string result; 133 StringAppendV(&result, format, ap); 134 return result; 135 } 136 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) 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 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) 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 174 void StringAppendV(std::string* dst, const char* format, va_list ap) { 175 StringAppendVT(dst, format, ap); 176 } 177 178 #if !defined(OS_ANDROID) 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