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