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 #include <stddef.h> 9 10 #include <vector> 11 12 #include "base/macros.h" 13 #include "base/scoped_clear_errno.h" 14 #include "base/strings/string_util.h" 15 #include "base/strings/utf_string_conversions.h" 16 #include "build/build_config.h" 17 18 namespace base { 19 20 namespace { 21 22 // Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter 23 // is the size of the buffer. These return the number of characters in the 24 // formatted string excluding the NUL terminator. If the buffer is not 25 // large enough to accommodate the formatted string without truncation, they 26 // return the number of characters that would be in the fully-formatted string 27 // (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms). 28 inline int vsnprintfT(char* buffer, 29 size_t buf_size, 30 const char* format, 31 va_list argptr) { 32 return base::vsnprintf(buffer, buf_size, format, argptr); 33 } 34 35 #if defined(OS_WIN) 36 inline int vsnprintfT(wchar_t* buffer, 37 size_t buf_size, 38 const wchar_t* format, 39 va_list argptr) { 40 return base::vswprintf(buffer, buf_size, format, argptr); 41 } 42 #endif 43 44 // Templatized backend for StringPrintF/StringAppendF. This does not finalize 45 // the va_list, the caller is expected to do that. 46 template <class StringType> 47 static void StringAppendVT(StringType* dst, 48 const typename StringType::value_type* format, 49 va_list ap) { 50 // First try with a small fixed size buffer. 51 // This buffer size should be kept in sync with StringUtilTest.GrowBoundary 52 // and StringUtilTest.StringPrintfBounds. 53 typename StringType::value_type stack_buf[1024]; 54 55 va_list ap_copy; 56 va_copy(ap_copy, ap); 57 58 #if !defined(OS_WIN) 59 ScopedClearErrno clear_errno; 60 #endif 61 int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy); 62 va_end(ap_copy); 63 64 if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) { 65 // It fit. 66 dst->append(stack_buf, result); 67 return; 68 } 69 70 // Repeatedly increase buffer size until it fits. 71 int mem_length = arraysize(stack_buf); 72 while (true) { 73 if (result < 0) { 74 #if defined(OS_WIN) 75 // On Windows, vsnprintfT always returns the number of characters in a 76 // fully-formatted string, so if we reach this point, something else is 77 // wrong and no amount of buffer-doubling is going to fix it. 78 return; 79 #else 80 if (errno != 0 && errno != EOVERFLOW) 81 return; 82 // Try doubling the buffer size. 83 mem_length *= 2; 84 #endif 85 } else { 86 // We need exactly "result + 1" characters. 87 mem_length = result + 1; 88 } 89 90 if (mem_length > 32 * 1024 * 1024) { 91 // That should be plenty, don't try anything larger. This protects 92 // against huge allocations when using vsnprintfT implementations that 93 // return -1 for reasons other than overflow without setting errno. 94 DLOG(WARNING) << "Unable to printf the requested string due to size."; 95 return; 96 } 97 98 std::vector<typename StringType::value_type> mem_buf(mem_length); 99 100 // NOTE: You can only use a va_list once. Since we're in a while loop, we 101 // need to make a new copy each time so we don't use up the original. 102 va_copy(ap_copy, ap); 103 result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy); 104 va_end(ap_copy); 105 106 if ((result >= 0) && (result < mem_length)) { 107 // It fit. 108 dst->append(&mem_buf[0], result); 109 return; 110 } 111 } 112 } 113 114 } // namespace 115 116 std::string StringPrintf(const char* format, ...) { 117 va_list ap; 118 va_start(ap, format); 119 std::string result; 120 StringAppendV(&result, format, ap); 121 va_end(ap); 122 return result; 123 } 124 125 #if defined(OS_WIN) 126 std::wstring StringPrintf(const wchar_t* format, ...) { 127 va_list ap; 128 va_start(ap, format); 129 std::wstring result; 130 StringAppendV(&result, format, ap); 131 va_end(ap); 132 return result; 133 } 134 #endif 135 136 std::string StringPrintV(const char* format, va_list ap) { 137 std::string result; 138 StringAppendV(&result, format, ap); 139 return result; 140 } 141 142 const std::string& SStringPrintf(std::string* dst, const char* format, ...) { 143 va_list ap; 144 va_start(ap, format); 145 dst->clear(); 146 StringAppendV(dst, format, ap); 147 va_end(ap); 148 return *dst; 149 } 150 151 #if defined(OS_WIN) 152 const std::wstring& SStringPrintf(std::wstring* dst, 153 const wchar_t* format, ...) { 154 va_list ap; 155 va_start(ap, format); 156 dst->clear(); 157 StringAppendV(dst, format, ap); 158 va_end(ap); 159 return *dst; 160 } 161 #endif 162 163 void StringAppendF(std::string* dst, const char* format, ...) { 164 va_list ap; 165 va_start(ap, format); 166 StringAppendV(dst, format, ap); 167 va_end(ap); 168 } 169 170 #if defined(OS_WIN) 171 void StringAppendF(std::wstring* dst, const wchar_t* format, ...) { 172 va_list ap; 173 va_start(ap, format); 174 StringAppendV(dst, format, ap); 175 va_end(ap); 176 } 177 #endif 178 179 void StringAppendV(std::string* dst, const char* format, va_list ap) { 180 StringAppendVT(dst, format, ap); 181 } 182 183 #if defined(OS_WIN) 184 void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) { 185 StringAppendVT(dst, format, ap); 186 } 187 #endif 188 189 } // namespace base 190