FFmpeg
bprint.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Nicolas George
3  *
4  * This file is part of FFmpeg.
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include <limits.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 #include "avstring.h"
27 #include "bprint.h"
28 #include "compat/va_copy.h"
29 #include "error.h"
30 #include "macros.h"
31 #include "mem.h"
32 
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)
35 
36 static int av_bprint_alloc(AVBPrint *buf, unsigned room)
37 {
38  char *old_str, *new_str;
39  unsigned min_size, new_size;
40 
41  if (buf->size == buf->size_max)
42  return AVERROR(EIO);
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);
51  if (!new_str)
52  return AVERROR(ENOMEM);
53  if (!old_str)
54  memcpy(new_str, buf->str, buf->len + 1);
55  buf->str = new_str;
56  buf->size = new_size;
57  return 0;
58 }
59 
60 static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
61 {
62  /* arbitrary margin to avoid small overflows */
63  extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
64  buf->len += extra_len;
65  if (buf->size)
66  buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
67 }
68 
69 void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
70 {
71  unsigned size_auto = (char *)buf + sizeof(*buf) -
72  buf->reserved_internal_buffer;
73 
75  size_max = size_auto;
76  buf->str = buf->reserved_internal_buffer;
77  buf->len = 0;
78  buf->size = FFMIN(size_auto, size_max);
79  buf->size_max = size_max;
80  *buf->str = 0;
81  if (size_init > buf->size)
82  av_bprint_alloc(buf, size_init - 1);
83 }
84 
85 void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
86 {
87  if (size == 0) {
89  return;
90  }
91 
92  buf->str = buffer;
93  buf->len = 0;
94  buf->size = size;
95  buf->size_max = size;
96  *buf->str = 0;
97 }
98 
99 void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
100 {
101  unsigned room;
102  char *dst;
103  int extra_len;
104  va_list vl;
105 
106  while (1) {
107  room = av_bprint_room(buf);
108  dst = room ? buf->str + buf->len : NULL;
109  va_copy(vl, vl_arg);
110  extra_len = vsnprintf(dst, room, fmt, vl);
111  va_end(vl);
112  if (extra_len <= 0)
113  return;
114  if (extra_len < room)
115  break;
116  if (av_bprint_alloc(buf, extra_len))
117  break;
118  }
119  av_bprint_grow(buf, extra_len);
120 }
121 
122 void av_bprintf(AVBPrint *buf, const char *fmt, ...)
123 {
124  va_list vl;
125  va_start(vl, fmt);
126  av_vbprintf(buf, fmt, vl);
127  va_end(vl);
128 }
129 
130 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
131 {
132  unsigned room, real_n;
133 
134  while (1) {
135  room = av_bprint_room(buf);
136  if (n < room)
137  break;
138  if (av_bprint_alloc(buf, n))
139  break;
140  }
141  if (room) {
142  real_n = FFMIN(n, room - 1);
143  memset(buf->str + buf->len, c, real_n);
144  }
145  av_bprint_grow(buf, n);
146 }
147 
148 void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
149 {
150  unsigned room, real_n;
151 
152  while (1) {
153  room = av_bprint_room(buf);
154  if (size < room)
155  break;
156  if (av_bprint_alloc(buf, size))
157  break;
158  }
159  if (room) {
160  real_n = FFMIN(size, room - 1);
161  memcpy(buf->str + buf->len, data, real_n);
162  }
163  av_bprint_grow(buf, size);
164 }
165 
166 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
167 {
168  unsigned room;
169  size_t l;
170  size_t fmt_len = strlen(fmt);
171 
172  if (!*fmt)
173  return;
174  while (1) {
175  room = av_bprint_room(buf);
176  if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
177  break;
178 
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)
185  break;
186 
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);
194  if (room < 1024) {
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 */
198  char buf2[1024];
199  if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
200  av_bprintf(buf, "%s", buf2);
201  return;
202  }
203  }
204  if (room) {
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 */
211  }
212  return;
213  }
214  }
215  av_bprint_grow(buf, l);
216 }
217 
218 void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
219  unsigned char **mem, unsigned *actual_size)
220 {
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;
225 }
226 
227 void av_bprint_clear(AVBPrint *buf)
228 {
229  if (buf->len) {
230  *buf->str = 0;
231  buf->len = 0;
232  }
233 }
234 
235 int av_bprint_finalize(AVBPrint *buf, char **ret_str)
236 {
237  unsigned real_size = FFMIN(buf->len + 1, buf->size);
238  char *str;
239  int ret = 0;
240 
241  if (ret_str) {
242  if (av_bprint_is_allocated(buf)) {
243  str = av_realloc(buf->str, real_size);
244  if (!str)
245  str = buf->str;
246  buf->str = NULL;
247  } else {
248  str = av_memdup(buf->str, real_size);
249  if (!str)
250  ret = AVERROR(ENOMEM);
251  }
252  *ret_str = str;
253  } else {
254  if (av_bprint_is_allocated(buf))
255  av_freep(&buf->str);
256  }
257  buf->size = real_size;
258  return ret;
259 }
260 
261 #define WHITESPACES " \n\t\r"
262 
263 void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
264  enum AVEscapeMode mode, int flags)
265 {
266  const char *src0 = src;
267 
268  if (mode == AV_ESCAPE_MODE_AUTO)
269  mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
270 
271  switch (mode) {
273  /* enclose the string between '' */
274  av_bprint_chars(dstbuf, '\'', 1);
275  for (; *src; src++) {
276  if (*src == '\'')
277  av_bprintf(dstbuf, "'\\''");
278  else
279  av_bprint_chars(dstbuf, *src, 1);
280  }
281  av_bprint_chars(dstbuf, '\'', 1);
282  break;
283 
284  case AV_ESCAPE_MODE_XML:
285  /* escape XML non-markup character data as per 2.4 by default: */
286  /* [^<&]* - ([^<&]* ']]>' [^<&]*) */
287 
288  /* additionally, given one of the AV_ESCAPE_FLAG_XML_* flags, */
289  /* escape those specific characters as required. */
290  for (; *src; src++) {
291  switch (*src) {
292  case '&' : av_bprintf(dstbuf, "%s", "&amp;"); break;
293  case '<' : av_bprintf(dstbuf, "%s", "&lt;"); break;
294  case '>' : av_bprintf(dstbuf, "%s", "&gt;"); break;
295  case '\'':
297  goto XML_DEFAULT_HANDLING;
298 
299  av_bprintf(dstbuf, "%s", "&apos;");
300  break;
301  case '"' :
303  goto XML_DEFAULT_HANDLING;
304 
305  av_bprintf(dstbuf, "%s", "&quot;");
306  break;
307 XML_DEFAULT_HANDLING:
308  default: av_bprint_chars(dstbuf, *src, 1);
309  }
310  }
311  break;
312 
313  /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
314  default:
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);
320  int is_special =
321  is_strictly_special || strchr("'\\", *src) ||
322  (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
323 
324  if (is_strictly_special ||
326  (is_special || (is_ws && is_first_last))))
327  av_bprint_chars(dstbuf, '\\', 1);
328  av_bprint_chars(dstbuf, *src, 1);
329  }
330  break;
331  }
332 }
flags
const SwsFlags flags[]
Definition: swscale.c:61
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
va_copy.h
mode
Definition: swscale.c:56
AV_ESCAPE_FLAG_XML_SINGLE_QUOTES
#define AV_ESCAPE_FLAG_XML_SINGLE_QUOTES
Within AV_ESCAPE_MODE_XML, additionally escape single quotes for single quoted attributes.
Definition: avstring.h:342
av_bprint_grow
static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
Definition: bprint.c:60
data
const char data[16]
Definition: mxf.c:149
WHITESPACES
#define WHITESPACES
Definition: bprint.c:261
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:304
av_bprint_init_for_buffer
void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
Init a print buffer using a pre-existing buffer.
Definition: bprint.c:85
AV_ESCAPE_FLAG_STRICT
#define AV_ESCAPE_FLAG_STRICT
Escape only specified special characters.
Definition: avstring.h:336
AV_BPRINT_SIZE_COUNT_ONLY
#define AV_BPRINT_SIZE_COUNT_ONLY
macros.h
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
AV_ESCAPE_FLAG_WHITESPACE
#define AV_ESCAPE_FLAG_WHITESPACE
Consider spaces special and escape them even in the middle of the string.
Definition: avstring.h:329
AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES
Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double quoted attributes.
Definition: avstring.h:348
size_max
unsigned unsigned size_max
Definition: bprint.h:141
av_bprint_room
#define av_bprint_room(buf)
Definition: bprint.c:33
limits.h
AV_ESCAPE_MODE_QUOTE
@ AV_ESCAPE_MODE_QUOTE
Use single-quote escaping.
Definition: avstring.h:317
NULL
#define NULL
Definition: coverity.c:32
av_bprint_escape
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition: bprint.c:263
time.h
av_bprint_strftime
void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
Append a formatted date and time to a print buffer.
Definition: bprint.c:166
AV_ESCAPE_MODE_AUTO
@ AV_ESCAPE_MODE_AUTO
Use auto-selected escaping mode.
Definition: avstring.h:315
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
error.h
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
av_bprint_is_allocated
#define av_bprint_is_allocated(buf)
Definition: bprint.c:34
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
size
int size
Definition: twinvq_data.h:10344
AV_ESCAPE_MODE_XML
@ AV_ESCAPE_MODE_XML
Use XML non-markup character data escaping.
Definition: avstring.h:318
va_copy
#define va_copy(dst, src)
Definition: va_copy.h:31
size_init
unsigned size_init
Definition: bprint.h:141
bprint.h
av_bprint_get_buffer
void av_bprint_get_buffer(AVBPrint *buf, unsigned size, unsigned char **mem, unsigned *actual_size)
Allocate bytes in the buffer for external use.
Definition: bprint.c:218
vsnprintf
#define vsnprintf
Definition: snprintf.h:36
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ret
ret
Definition: filter_design.txt:187
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
ret_str
static const char * ret_str(int v)
Definition: seek.c:34
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
av_vbprintf
void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
Append a formatted string to a print buffer.
Definition: bprint.c:99
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
src0
const pixel *const src0
Definition: h264pred_template.c:419
mem.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AV_ESCAPE_MODE_BACKSLASH
@ AV_ESCAPE_MODE_BACKSLASH
Use backslash escaping.
Definition: avstring.h:316
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
av_bprint_alloc
static int av_bprint_alloc(AVBPrint *buf, unsigned room)
Definition: bprint.c:36
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:130
AVEscapeMode
AVEscapeMode
Definition: avstring.h:314
avstring.h
av_bprint_append_data
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:148
src
#define src
Definition: vp8dsp.c:248
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:155