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
29 #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
;
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
)
94 void av_bprintf(AVBPrint
*buf
, const char *fmt
, ...)
102 room
= av_bprint_room(buf
);
103 dst
= room
? buf
->str
+ buf
->len
: NULL
;
105 extra_len
= vsnprintf(dst
, room
, fmt
, vl
);
109 if (extra_len
< room
)
111 if (av_bprint_alloc(buf
, extra_len
))
114 av_bprint_grow(buf
, extra_len
);
117 void av_vbprintf(AVBPrint
*buf
, const char *fmt
, va_list vl_arg
)
125 room
= av_bprint_room(buf
);
126 dst
= room
? buf
->str
+ buf
->len
: NULL
;
128 extra_len
= vsnprintf(dst
, room
, fmt
, vl
);
132 if (extra_len
< room
)
134 if (av_bprint_alloc(buf
, extra_len
))
137 av_bprint_grow(buf
, extra_len
);
140 void av_bprint_chars(AVBPrint
*buf
, char c
, unsigned n
)
142 unsigned room
, real_n
;
145 room
= av_bprint_room(buf
);
148 if (av_bprint_alloc(buf
, n
))
152 real_n
= FFMIN(n
, room
- 1);
153 memset(buf
->str
+ buf
->len
, c
, real_n
);
155 av_bprint_grow(buf
, n
);
158 void av_bprint_append_data(AVBPrint
*buf
, const char *data
, unsigned size
)
160 unsigned room
, real_n
;
163 room
= av_bprint_room(buf
);
166 if (av_bprint_alloc(buf
, size
))
170 real_n
= FFMIN(size
, room
- 1);
171 memcpy(buf
->str
+ buf
->len
, data
, real_n
);
173 av_bprint_grow(buf
, size
);
176 void av_bprint_strftime(AVBPrint
*buf
, const char *fmt
, const struct tm
*tm
)
184 room
= av_bprint_room(buf
);
185 if (room
&& (l
= strftime(buf
->str
+ buf
->len
, room
, fmt
, tm
)))
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
? strlen(fmt
) + 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_malloc(real_size
);
250 memcpy(str
, buf
->str
, real_size
);
252 ret
= AVERROR(ENOMEM
);
256 if (av_bprint_is_allocated(buf
))
259 buf
->size
= real_size
;
263 #define WHITESPACES " \n\t"
265 void av_bprint_escape(AVBPrint
*dstbuf
, const char *src
, const char *special_chars
,
266 enum AVEscapeMode mode
, int flags
)
268 const char *src0
= src
;
270 if (mode
== AV_ESCAPE_MODE_AUTO
)
271 mode
= AV_ESCAPE_MODE_BACKSLASH
; /* TODO: implement a heuristic */
274 case AV_ESCAPE_MODE_QUOTE
:
275 /* enclose the string between '' */
276 av_bprint_chars(dstbuf
, '\'', 1);
277 for (; *src
; src
++) {
279 av_bprintf(dstbuf
, "'\\''");
281 av_bprint_chars(dstbuf
, *src
, 1);
283 av_bprint_chars(dstbuf
, '\'', 1);
286 /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
288 /* \-escape characters */
289 for (; *src
; src
++) {
290 int is_first_last
= src
== src0
|| !*(src
+1);
291 int is_ws
= !!strchr(WHITESPACES
, *src
);
292 int is_strictly_special
= special_chars
&& strchr(special_chars
, *src
);
294 is_strictly_special
|| strchr("'\\", *src
) ||
295 (is_ws
&& (flags
& AV_ESCAPE_FLAG_WHITESPACE
));
297 if (is_strictly_special
||
298 (!(flags
& AV_ESCAPE_FLAG_STRICT
) &&
299 (is_special
|| (is_ws
&& is_first_last
))))
300 av_bprint_chars(dstbuf
, '\\', 1);
301 av_bprint_chars(dstbuf
, *src
, 1);
311 static void bprint_pascal(AVBPrint
*b
, unsigned size
)
316 av_assert0(size
< FF_ARRAY_ELEMS(p
));
319 av_bprintf(b
, "%8d\n", 1);
320 for (i
= 1; i
<= size
; i
++) {
322 for (j
= i
- 1; j
> 0; j
--)
323 p
[j
] = p
[j
] + p
[j
- 1];
324 for (j
= 0; j
<= i
; j
++)
325 av_bprintf(b
, "%8d", p
[j
]);
334 struct tm testtime
= { .tm_year
= 100, .tm_mon
= 11, .tm_mday
= 20 };
336 av_bprint_init(&b
, 0, -1);
337 bprint_pascal(&b
, 5);
338 printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b
.str
), b
.len
);
339 printf("%s\n", b
.str
);
340 av_bprint_finalize(&b
, NULL
);
342 av_bprint_init(&b
, 0, -1);
343 bprint_pascal(&b
, 25);
344 printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b
.str
), b
.len
);
345 av_bprint_finalize(&b
, NULL
);
347 av_bprint_init(&b
, 0, 2048);
348 bprint_pascal(&b
, 25);
349 printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b
.str
), b
.len
);
350 av_bprint_finalize(&b
, NULL
);
352 av_bprint_init(&b
, 0, 1);
353 bprint_pascal(&b
, 5);
354 printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b
.str
), b
.len
);
356 av_bprint_init(&b
, 0, 1);
357 bprint_pascal(&b
, 25);
358 printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b
.str
)/8*8, b
.len
);
359 /* Note that the size of the automatic buffer is arch-dependent. */
361 av_bprint_init(&b
, 0, 0);
362 bprint_pascal(&b
, 25);
363 printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b
.str
), b
.len
);
365 av_bprint_init_for_buffer(&b
, buf
, sizeof(buf
));
366 bprint_pascal(&b
, 25);
367 printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf
), b
.len
);
369 av_bprint_init(&b
, 0, -1);
370 av_bprint_strftime(&b
, "%Y-%m-%d", &testtime
);
371 printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf
), b
.len
, b
.str
);
372 av_bprint_finalize(&b
, NULL
);
374 av_bprint_init(&b
, 0, 8);
375 av_bprint_strftime(&b
, "%Y-%m-%d", &testtime
);
376 printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf
), b
.len
, b
.str
);