xref: /aosp_15_r20/external/cronet/base/strings/stringprintf.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <errno.h>
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <vector>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/scoped_clear_last_error.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker namespace base {
18*6777b538SAndroid Build Coastguard Worker 
StringPrintf(const char * format,...)19*6777b538SAndroid Build Coastguard Worker std::string StringPrintf(const char* format, ...) {
20*6777b538SAndroid Build Coastguard Worker   va_list ap;
21*6777b538SAndroid Build Coastguard Worker   va_start(ap, format);
22*6777b538SAndroid Build Coastguard Worker   std::string result;
23*6777b538SAndroid Build Coastguard Worker   StringAppendV(&result, format, ap);
24*6777b538SAndroid Build Coastguard Worker   va_end(ap);
25*6777b538SAndroid Build Coastguard Worker   return result;
26*6777b538SAndroid Build Coastguard Worker }
27*6777b538SAndroid Build Coastguard Worker 
StringPrintV(const char * format,va_list ap)28*6777b538SAndroid Build Coastguard Worker std::string StringPrintV(const char* format, va_list ap) {
29*6777b538SAndroid Build Coastguard Worker   std::string result;
30*6777b538SAndroid Build Coastguard Worker   StringAppendV(&result, format, ap);
31*6777b538SAndroid Build Coastguard Worker   return result;
32*6777b538SAndroid Build Coastguard Worker }
33*6777b538SAndroid Build Coastguard Worker 
StringAppendF(std::string * dst,const char * format,...)34*6777b538SAndroid Build Coastguard Worker void StringAppendF(std::string* dst, const char* format, ...) {
35*6777b538SAndroid Build Coastguard Worker   va_list ap;
36*6777b538SAndroid Build Coastguard Worker   va_start(ap, format);
37*6777b538SAndroid Build Coastguard Worker   StringAppendV(dst, format, ap);
38*6777b538SAndroid Build Coastguard Worker   va_end(ap);
39*6777b538SAndroid Build Coastguard Worker }
40*6777b538SAndroid Build Coastguard Worker 
StringAppendV(std::string * dst,const char * format,va_list ap)41*6777b538SAndroid Build Coastguard Worker void StringAppendV(std::string* dst, const char* format, va_list ap) {
42*6777b538SAndroid Build Coastguard Worker   // First try with a small fixed size buffer.
43*6777b538SAndroid Build Coastguard Worker   // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
44*6777b538SAndroid Build Coastguard Worker   // and StringUtilTest.StringPrintfBounds.
45*6777b538SAndroid Build Coastguard Worker   char stack_buf[1024];
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker   va_list ap_copy;
48*6777b538SAndroid Build Coastguard Worker   va_copy(ap_copy, ap);
49*6777b538SAndroid Build Coastguard Worker 
50*6777b538SAndroid Build Coastguard Worker   base::ScopedClearLastError last_error;
51*6777b538SAndroid Build Coastguard Worker   int result = vsnprintf(stack_buf, std::size(stack_buf), format, ap_copy);
52*6777b538SAndroid Build Coastguard Worker   va_end(ap_copy);
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker   if (result >= 0 && static_cast<size_t>(result) < std::size(stack_buf)) {
55*6777b538SAndroid Build Coastguard Worker     // It fit.
56*6777b538SAndroid Build Coastguard Worker     dst->append(stack_buf, static_cast<size_t>(result));
57*6777b538SAndroid Build Coastguard Worker     return;
58*6777b538SAndroid Build Coastguard Worker   }
59*6777b538SAndroid Build Coastguard Worker 
60*6777b538SAndroid Build Coastguard Worker   // Repeatedly increase buffer size until it fits.
61*6777b538SAndroid Build Coastguard Worker   size_t mem_length = std::size(stack_buf);
62*6777b538SAndroid Build Coastguard Worker   while (true) {
63*6777b538SAndroid Build Coastguard Worker     if (result < 0) {
64*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
65*6777b538SAndroid Build Coastguard Worker       // On Windows, vsnprintf always returns the number of characters in a
66*6777b538SAndroid Build Coastguard Worker       // fully-formatted string, so if we reach this point, something else is
67*6777b538SAndroid Build Coastguard Worker       // wrong and no amount of buffer-doubling is going to fix it.
68*6777b538SAndroid Build Coastguard Worker       return;
69*6777b538SAndroid Build Coastguard Worker #else
70*6777b538SAndroid Build Coastguard Worker       if (errno != 0 && errno != EOVERFLOW) {
71*6777b538SAndroid Build Coastguard Worker         return;
72*6777b538SAndroid Build Coastguard Worker       }
73*6777b538SAndroid Build Coastguard Worker       // Try doubling the buffer size.
74*6777b538SAndroid Build Coastguard Worker       mem_length *= 2;
75*6777b538SAndroid Build Coastguard Worker #endif
76*6777b538SAndroid Build Coastguard Worker     } else {
77*6777b538SAndroid Build Coastguard Worker       // We need exactly "result + 1" characters.
78*6777b538SAndroid Build Coastguard Worker       mem_length = static_cast<size_t>(result) + 1;
79*6777b538SAndroid Build Coastguard Worker     }
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker     if (mem_length > 32 * 1024 * 1024) {
82*6777b538SAndroid Build Coastguard Worker       // That should be plenty, don't try anything larger.  This protects
83*6777b538SAndroid Build Coastguard Worker       // against huge allocations when using vsnprintf implementations that
84*6777b538SAndroid Build Coastguard Worker       // return -1 for reasons other than overflow without setting errno.
85*6777b538SAndroid Build Coastguard Worker       DLOG(WARNING) << "Unable to printf the requested string due to size.";
86*6777b538SAndroid Build Coastguard Worker       return;
87*6777b538SAndroid Build Coastguard Worker     }
88*6777b538SAndroid Build Coastguard Worker 
89*6777b538SAndroid Build Coastguard Worker     std::vector<char> mem_buf(mem_length);
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker     // NOTE: You can only use a va_list once.  Since we're in a while loop, we
92*6777b538SAndroid Build Coastguard Worker     // need to make a new copy each time so we don't use up the original.
93*6777b538SAndroid Build Coastguard Worker     va_copy(ap_copy, ap);
94*6777b538SAndroid Build Coastguard Worker     result = vsnprintf(&mem_buf[0], mem_length, format, ap_copy);
95*6777b538SAndroid Build Coastguard Worker     va_end(ap_copy);
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker     if ((result >= 0) && (static_cast<size_t>(result) < mem_length)) {
98*6777b538SAndroid Build Coastguard Worker       // It fit.
99*6777b538SAndroid Build Coastguard Worker       dst->append(&mem_buf[0], static_cast<size_t>(result));
100*6777b538SAndroid Build Coastguard Worker       return;
101*6777b538SAndroid Build Coastguard Worker     }
102*6777b538SAndroid Build Coastguard Worker   }
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker }  // namespace base
106