2 * Copyright (c) 2012 Nicolas George
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "compat/va_copy.h"
33 #define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
34 #define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
36 static int av_bprint_alloc(AVBPrint
*buf
, unsigned room
)
38 char *old_str
, *new_str
;
39 unsigned min_size
, new_size
;
41 if (buf
->size
== buf
->size_max
)
43 if (!av_bprint_is_complete(buf
))
44 return AVERROR_INVALIDDATA
; /* it is already truncated anyway */
45 min_size
= buf
->len
+ 1 + FFMIN(UINT_MAX
- buf
->len
- 1, room
);
46 new_size
= buf
->size
> buf
->size_max
/ 2 ? buf
->size_max
: buf
->size
* 2;
47 if (new_size
< min_size
)
48 new_size
= FFMIN(buf
->size_max
, min_size
);
49 old_str
= av_bprint_is_allocated(buf
) ? buf
->str
: NULL
;
50 new_str
= av_realloc(old_str
, new_size
);
52 return AVERROR(ENOMEM
);
54 memcpy(new_str
, buf
->str
, buf
->len
+ 1);
60 static void av_bprint_grow(AVBPrint
*buf
, unsigned extra_len
)
62 /* arbitrary margin to avoid small overflows */
63 extra_len
= FFMIN(extra_len
, UINT_MAX
- 5 - buf
->len
);
64 buf
->len
+= extra_len
;
66 buf
->str
[FFMIN(buf
->len
, buf
->size
- 1)] = 0;
69 void av_bprint_init(AVBPrint
*buf
, unsigned size_init
, unsigned size_max
)
71 unsigned size_auto
= (char *)buf
+ sizeof(*buf
) -
72 buf
->reserved_internal_buffer
;
74 if (size_max
== AV_BPRINT_SIZE_AUTOMATIC
)
76 buf
->str
= buf
->reserved_internal_buffer
;
78 buf
->size
= FFMIN(size_auto
, size_max
);
79 buf
->size_max
= size_max
;
81 if (size_init
> buf
->size
)
82 av_bprint_alloc(buf
, size_init
- 1);
85 void av_bprint_init_for_buffer(AVBPrint
*buf
, char *buffer
, unsigned size
)
88 av_bprint_init(buf
, 0, AV_BPRINT_SIZE_COUNT_ONLY
);
99 void av_vbprintf(AVBPrint
*buf
, const char *fmt
, va_list vl_arg
)
107 room
= av_bprint_room(buf
);
108 dst
= room
? buf
->str
+ buf
->len
: NULL
;
110 extra_len
= vsnprintf(dst
, room
, fmt
, vl
);
114 if (extra_len
< room
)
116 if (av_bprint_alloc(buf
, extra_len
))
119 av_bprint_grow(buf
, extra_len
);
122 void av_bprintf(AVBPrint
*buf
, const char *fmt
, ...)
126 av_vbprintf(buf
, fmt
, vl
);
130 void av_bprint_chars(AVBPrint
*buf
, char c
, unsigned n
)
132 unsigned room
, real_n
;
135 room
= av_bprint_room(buf
);
138 if (av_bprint_alloc(buf
, n
))
142 real_n
= FFMIN(n
, room
- 1);
143 memset(buf
->str
+ buf
->len
, c
, real_n
);
145 av_bprint_grow(buf
, n
);
148 void av_bprint_append_data(AVBPrint
*buf
, const char *data
, unsigned size
)
150 unsigned room
, real_n
;
153 room
= av_bprint_room(buf
);
156 if (av_bprint_alloc(buf
, size
))
160 real_n
= FFMIN(size
, room
- 1);
161 memcpy(buf
->str
+ buf
->len
, data
, real_n
);
163 av_bprint_grow(buf
, size
);
166 void av_bprint_strftime(AVBPrint
*buf
, const char *fmt
, const struct tm
*tm
)
170 size_t fmt_len
= strlen(fmt
);
175 room
= av_bprint_room(buf
);
176 if (room
&& (l
= strftime(buf
->str
+ buf
->len
, room
, fmt
, tm
)))
179 /* Due to the limitations of strftime() it is not possible to know if
180 * the output buffer is too small or the output is empty.
181 * However, a 256x output space requirement compared to the format
182 * string length is so unlikely we can safely assume empty output. This
183 * allows supporting possibly empty format strings like "%p". */
184 if (room
>> 8 > fmt_len
)
187 /* strftime does not tell us how much room it would need: let us
188 retry with twice as much until the buffer is large enough */
189 room
= !room
? fmt_len
+ 1 :
190 room
<= INT_MAX
/ 2 ? room
* 2 : INT_MAX
;
191 if (av_bprint_alloc(buf
, room
)) {
192 /* impossible to grow, try to manage something useful anyway */
193 room
= av_bprint_room(buf
);
195 /* if strftime fails because the buffer has (almost) reached
196 its maximum size, let us try in a local buffer; 1k should
197 be enough to format any real date+time string */
199 if ((l
= strftime(buf2
, sizeof(buf2
), fmt
, tm
))) {
200 av_bprintf(buf
, "%s", buf2
);
205 /* if anything else failed and the buffer is not already
206 truncated, let us add a stock string and force truncation */
207 static const char txt
[] = "[truncated strftime output]";
208 memset(buf
->str
+ buf
->len
, '!', room
);
209 memcpy(buf
->str
+ buf
->len
, txt
, FFMIN(sizeof(txt
) - 1, room
));
210 av_bprint_grow(buf
, room
); /* force truncation */
215 av_bprint_grow(buf
, l
);
218 void av_bprint_get_buffer(AVBPrint
*buf
, unsigned size
,
219 unsigned char **mem
, unsigned *actual_size
)
221 if (size
> av_bprint_room(buf
))
222 av_bprint_alloc(buf
, size
);
223 *actual_size
= av_bprint_room(buf
);
224 *mem
= *actual_size
? buf
->str
+ buf
->len
: NULL
;
227 void av_bprint_clear(AVBPrint
*buf
)
235 int av_bprint_finalize(AVBPrint
*buf
, char **ret_str
)
237 unsigned real_size
= FFMIN(buf
->len
+ 1, buf
->size
);
242 if (av_bprint_is_allocated(buf
)) {
243 str
= av_realloc(buf
->str
, real_size
);
248 str
= av_memdup(buf
->str
, real_size
);
250 ret
= AVERROR(ENOMEM
);
254 if (av_bprint_is_allocated(buf
))
257 buf
->size
= real_size
;
261 #define WHITESPACES " \n\t\r"
263 void av_bprint_escape(AVBPrint
*dstbuf
, const char *src
, const char *special_chars
,
264 enum AVEscapeMode mode
, int flags
)
266 const char *src0
= src
;
268 if (mode
== AV_ESCAPE_MODE_AUTO
)
269 mode
= AV_ESCAPE_MODE_BACKSLASH
; /* TODO: implement a heuristic */
272 case AV_ESCAPE_MODE_QUOTE
:
273 /* enclose the string between '' */
274 av_bprint_chars(dstbuf
, '\'', 1);
275 for (; *src
; src
++) {
277 av_bprintf(dstbuf
, "'\\''");
279 av_bprint_chars(dstbuf
, *src
, 1);
281 av_bprint_chars(dstbuf
, '\'', 1);
284 case AV_ESCAPE_MODE_XML
:
285 /* escape XML non-markup character data as per 2.4 by default: */
286 /* [^<&]* - ([^<&]* ']]>' [^<&]*) */
288 /* additionally, given one of the AV_ESCAPE_FLAG_XML_* flags, */
289 /* escape those specific characters as required. */
290 for (; *src
; src
++) {
292 case '&' : av_bprintf(dstbuf
, "%s", "&"); break;
293 case '<' : av_bprintf(dstbuf
, "%s", "<"); break;
294 case '>' : av_bprintf(dstbuf
, "%s", ">"); break;
296 if (!(flags
& AV_ESCAPE_FLAG_XML_SINGLE_QUOTES
))
297 goto XML_DEFAULT_HANDLING
;
299 av_bprintf(dstbuf
, "%s", "'");
302 if (!(flags
& AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
))
303 goto XML_DEFAULT_HANDLING
;
305 av_bprintf(dstbuf
, "%s", """);
307 XML_DEFAULT_HANDLING
:
308 default: av_bprint_chars(dstbuf
, *src
, 1);
313 /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
315 /* \-escape characters */
316 for (; *src
; src
++) {
317 int is_first_last
= src
== src0
|| !*(src
+1);
318 int is_ws
= !!strchr(WHITESPACES
, *src
);
319 int is_strictly_special
= special_chars
&& strchr(special_chars
, *src
);
321 is_strictly_special
|| strchr("'\\", *src
) ||
322 (is_ws
&& (flags
& AV_ESCAPE_FLAG_WHITESPACE
));
324 if (is_strictly_special
||
325 (!(flags
& AV_ESCAPE_FLAG_STRICT
) &&
326 (is_special
|| (is_ws
&& is_first_last
))))
327 av_bprint_chars(dstbuf
, '\\', 1);
328 av_bprint_chars(dstbuf
, *src
, 1);