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 187