]> git.saurik.com Git - wxWidgets.git/blame - src/common/wxprintf.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / wxprintf.cpp
CommitLineData
c9e089e9 1/////////////////////////////////////////////////////////////////////////////
dd0ef332
VS
2// Name: src/common/wxprintf.cpp
3// Purpose: wxWidgets wxPrintf() implementation
247c23b4
VZ
4// Author: Ove Kaven
5// Modified by: Ron Lee, Francesco Montorsi
c9e089e9
OK
6// Created: 09/04/99
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets copyright
65571936 9// Licence: wxWindows licence
c9e089e9
OK
10/////////////////////////////////////////////////////////////////////////////
11
c9e089e9
OK
12// ===========================================================================
13// headers, declarations, constants
14// ===========================================================================
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
8898456d 20 #pragma hdrstop
c9e089e9
OK
21#endif
22
c9e089e9 23#ifndef WX_PRECOMP
8898456d
WS
24 #include "wx/string.h"
25 #include "wx/hash.h"
5ff14574
PC
26 #include "wx/utils.h" // for wxMin and wxMax
27 #include "wx/log.h"
c9e089e9
OK
28#endif
29
47346406 30#include "wx/private/wxprintf.h"
31907d03 31
434d2cb3 32
f6f5941b 33// ============================================================================
dd0ef332 34// printf() implementation
f6f5941b
VZ
35// ============================================================================
36
df17b887
VZ
37// special test mode: define all functions below even if we don't really need
38// them to be able to test them
39#ifdef wxTEST_PRINTF
50e27899 40 #undef wxCRT_VsnprintfW
dd25c6ee 41 #undef wxCRT_VsnprintfA
df17b887
VZ
42#endif
43
f6f5941b
VZ
44// ----------------------------------------------------------------------------
45// implement [v]snprintf() if the system doesn't provide a safe one
7a828c7f
VZ
46// or if the system's one does not support positional parameters
47// (very useful for i18n purposes)
f6f5941b
VZ
48// ----------------------------------------------------------------------------
49
dd25c6ee
VS
50// ----------------------------------------------------------------------------
51// common code for both ANSI and Unicode versions
52// ----------------------------------------------------------------------------
7a828c7f 53
50e27899 54#if !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA)
f2bbe5b6 55
7a828c7f 56
3c7f37ed
MW
57// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn
58// chars from source and write at most outMax chars to dest, returns the
59// number of chars actually written. Does not treat null specially.
dd25c6ee 60template<typename CharType>
3c7f37ed
MW
61static int wxCopyStrWithPercents(
62 size_t maxOut,
dd25c6ee 63 CharType *dest,
3c7f37ed 64 size_t maxIn,
dd25c6ee 65 const CharType *source)
247c23b4
VZ
66{
67 size_t written = 0;
68
3c7f37ed 69 if (maxIn == 0)
247c23b4
VZ
70 return 0;
71
72 size_t i;
3c7f37ed 73 for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++)
247c23b4
VZ
74 {
75 dest[written++] = *source;
76 if (*(source+1) == wxT('%'))
77 {
78 // skip this additional '%' character
79 source++;
80 i++;
81 }
82 }
83
3c7f37ed 84 if (i < maxIn && written < maxOut)
247c23b4
VZ
85 // copy last character inconditionally
86 dest[written++] = *source;
87
88 return written;
89}
90
dd25c6ee
VS
91template<typename CharType>
92static int wxDoVsnprintf(CharType *buf, size_t lenMax,
93 const CharType *format, va_list argptr)
7a828c7f 94{
412a5c57
VZ
95 // useful for debugging, to understand if we are really using this function
96 // rather than the system implementation
97#if 0
50e27899 98 wprintf(L"Using wxCRT_VsnprintfW\n");
412a5c57
VZ
99#endif
100
47346406
VS
101 wxPrintfConvSpecParser<CharType> parser(format);
102
412a5c57 103 wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS];
7a828c7f
VZ
104
105 size_t i;
106
107 // number of characters in the buffer so far, must be less than lenMax
108 size_t lenCur = 0;
109
47346406 110 if (parser.posarg_present && parser.nonposarg_present)
3c7f37ed
MW
111 {
112 buf[0] = 0;
7a828c7f 113 return -1; // format strings with both positional and
3c7f37ed 114 } // non-positional conversion specifier are unsupported !!
7a828c7f 115
3aa077ce
MW
116 // on platforms where va_list is an array type, it is necessary to make a
117 // copy to be able to pass it to LoadArg as a reference.
118 bool ok = true;
119 va_list ap;
120 wxVaCopy(ap, argptr);
121
7a828c7f 122 // now load arguments from stack
47346406 123 for (i=0; i < parser.nargs && ok; i++)
412a5c57
VZ
124 {
125 // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s);
126 // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the
127 // conversion specifier 'type' to a valid value...
47346406 128 ok = parser.pspec[i] && parser.pspec[i]->LoadArg(&argdata[i], ap);
7a828c7f
VZ
129 }
130
3aa077ce
MW
131 va_end(ap);
132
247c23b4 133 // something failed while loading arguments from the variable list...
f2bbe5b6 134 // (e.g. the user repeated twice the same positional argument)
3aa077ce 135 if (!ok)
3c7f37ed
MW
136 {
137 buf[0] = 0;
3aa077ce 138 return -1;
3c7f37ed 139 }
3aa077ce 140
7a828c7f 141 // finally, process each conversion specifier with its own argument
bb809a9a 142 const CharType *toparse = format;
47346406 143 for (i=0; i < parser.nargs; i++)
7a828c7f 144 {
75ac34ce
VZ
145 wxPrintfConvSpec<CharType>& spec = parser.specs[i];
146
147 // skip any asterisks, they're processed as part of the conversion they
148 // apply to
149 if ( spec.m_type == wxPAT_STAR )
150 continue;
151
7a828c7f
VZ
152 // copy in the output buffer the portion of the format string between
153 // last specifier and the current one
75ac34ce 154 size_t tocopy = ( spec.m_pArgPos - toparse );
3c7f37ed
MW
155
156 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
157 tocopy, toparse);
158 if (lenCur == lenMax)
412a5c57 159 {
3c7f37ed 160 buf[lenMax - 1] = 0;
f2bbe5b6 161 return lenMax+1; // not enough space in the output buffer !
412a5c57 162 }
7a828c7f 163
7a828c7f 164 // process this specifier directly in the output buffer
75ac34ce
VZ
165 int n = spec.Process(buf+lenCur, lenMax - lenCur,
166 &argdata[spec.m_pos], lenCur);
7a828c7f 167 if (n == -1)
412a5c57
VZ
168 {
169 buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string
f2bbe5b6 170 return lenMax+1; // not enough space in the output buffer !
412a5c57 171 }
7a828c7f
VZ
172 lenCur += n;
173
412a5c57 174 // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character
7a828c7f 175 // of the format specifier, but we are not interested to it...
75ac34ce 176 toparse = spec.m_pArgEnd + 1;
5f1d3069
RR
177 }
178
7a828c7f
VZ
179 // copy portion of the format string after last specifier
180 // NOTE: toparse is pointing to the character just after the last processed
181 // conversion specifier
182 // NOTE2: the +1 is because we want to copy also the '\0'
183 size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ;
247c23b4 184
55339e8c 185 lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur,
3c7f37ed
MW
186 tocopy, toparse) - 1;
187 if (buf[lenCur])
188 {
189 buf[lenCur] = 0;
f2bbe5b6 190 return lenMax+1; // not enough space in the output buffer !
3c7f37ed 191 }
7a828c7f 192
13ab552e
VZ
193 // Don't do:
194 // wxASSERT(lenCur == wxStrlen(buf));
195 // in fact if we embedded NULLs in the output buffer (using %c with a '\0')
196 // such check would fail
197
f6f5941b
VZ
198 return lenCur;
199}
5f1d3069 200
50e27899 201#endif // !defined(wxCRT_VsnprintfW) || !defined(wxCRT_VsnprintfA)
dd25c6ee
VS
202
203// ----------------------------------------------------------------------------
50e27899 204// wxCRT_VsnprintfW
dd25c6ee
VS
205// ----------------------------------------------------------------------------
206
50e27899 207#if !defined(wxCRT_VsnprintfW)
dd25c6ee
VS
208
209#if !wxUSE_WXVSNPRINTFW
50e27899 210 #error "wxUSE_WXVSNPRINTFW must be 1 if our wxCRT_VsnprintfW is used"
dd25c6ee
VS
211#endif
212
50e27899
VS
213int wxCRT_VsnprintfW(wchar_t *buf, size_t len,
214 const wchar_t *format, va_list argptr)
dd25c6ee
VS
215{
216 return wxDoVsnprintf(buf, len, format, argptr);
217}
218
50e27899 219#else // wxCRT_VsnprintfW is defined
f2bbe5b6 220
52de37c7 221#if wxUSE_WXVSNPRINTFW
50e27899 222 #error "wxUSE_WXVSNPRINTFW must be 0 if our wxCRT_VsnprintfW is not used"
f2bbe5b6
VZ
223#endif
224
50e27899 225#endif // !wxCRT_VsnprintfW
dd25c6ee
VS
226
227// ----------------------------------------------------------------------------
228// wxCRT_VsnprintfA
229// ----------------------------------------------------------------------------
230
231#ifndef wxCRT_VsnprintfA
232
233#if !wxUSE_WXVSNPRINTFA
234 #error "wxUSE_WXVSNPRINTFA must be 1 if our wxCRT_VsnprintfA is used"
235#endif
236
237int wxCRT_VsnprintfA(char *buf, size_t len,
238 const char *format, va_list argptr)
239{
240 return wxDoVsnprintf(buf, len, format, argptr);
241}
242
243#else // wxCRT_VsnprintfA is defined
244
245#if wxUSE_WXVSNPRINTFA
246 #error "wxUSE_WXVSNPRINTFA must be 0 if our wxCRT_VsnprintfA is not used"
247#endif
248
249#endif // !wxCRT_VsnprintfA