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 <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <time.h>
25 #include "avstring.h"
26 #include "bprint.h"
27 #include "common.h"
28 #include "compat/va_copy.h"
29 #include "error.h"
30 #include "mem.h"
31 
32 #define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
33 #define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
34 
35 static int av_bprint_alloc(AVBPrint *buf, unsigned room)
36 {
37  char *old_str, *new_str;
38  unsigned min_size, new_size;
39 
40  if (buf->size == buf->size_max)
41  return AVERROR(EIO);
42  if (!av_bprint_is_complete(buf))
43  return AVERROR_INVALIDDATA; /* it is already truncated anyway */
44  min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room);
45  new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2;
46  if (new_size < min_size)
47  new_size = FFMIN(buf->size_max, min_size);
48  old_str = av_bprint_is_allocated(buf) ? buf->str : NULL;
49  new_str = av_realloc(old_str, new_size);
50  if (!new_str)
51  return AVERROR(ENOMEM);
52  if (!old_str)
53  memcpy(new_str, buf->str, buf->len + 1);
54  buf->str = new_str;
55  buf->size = new_size;
56  return 0;
57 }
58 
59 static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
60 {
61  /* arbitrary margin to avoid small overflows */
62  extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
63  buf->len += extra_len;
64  if (buf->size)
65  buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
66 }
67 
68 void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
69 {
70  unsigned size_auto = (char *)buf + sizeof(*buf) -
71  buf->reserved_internal_buffer;
72 
73  if (size_max == 1)
74  size_max = size_auto;
75  buf->str = buf->reserved_internal_buffer;
76  buf->len = 0;
77  buf->size = FFMIN(size_auto, size_max);
78  buf->size_max = size_max;
79  *buf->str = 0;
80  if (size_init > buf->size)
81  av_bprint_alloc(buf, size_init - 1);
82 }
83 
84 void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
85 {
86  buf->str = buffer;
87  buf->len = 0;
88  buf->size = size;
89  buf->size_max = size;
90  *buf->str = 0;
91 }
92 
93 void av_bprintf(AVBPrint *buf, const char *fmt, ...)
94 {
95  unsigned room;
96  char *dst;
97  va_list vl;
98  int extra_len;
99 
100  while (1) {
101  room = av_bprint_room(buf);
102  dst = room ? buf->str + buf->len : NULL;
103  va_start(vl, fmt);
104  extra_len = vsnprintf(dst, room, fmt, vl);
105  va_end(vl);
106  if (extra_len <= 0)
107  return;
108  if (extra_len < room)
109  break;
110  if (av_bprint_alloc(buf, extra_len))
111  break;
112  }
113  av_bprint_grow(buf, extra_len);
114 }
115 
116 void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
117 {
118  unsigned room;
119  char *dst;
120  int extra_len;
121  va_list vl;
122 
123  while (1) {
124  room = av_bprint_room(buf);
125  dst = room ? buf->str + buf->len : NULL;
126  va_copy(vl, vl_arg);
127  extra_len = vsnprintf(dst, room, fmt, vl);
128  va_end(vl);
129  if (extra_len <= 0)
130  return;
131  if (extra_len < room)
132  break;
133  if (av_bprint_alloc(buf, extra_len))
134  break;
135  }
136  av_bprint_grow(buf, extra_len);
137 }
138 
139 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
140 {
141  unsigned room, real_n;
142 
143  while (1) {
144  room = av_bprint_room(buf);
145  if (n < room)
146  break;
147  if (av_bprint_alloc(buf, n))
148  break;
149  }
150  if (room) {
151  real_n = FFMIN(n, room - 1);
152  memset(buf->str + buf->len, c, real_n);
153  }
154  av_bprint_grow(buf, n);
155 }
156 
157 void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
158 {
159  unsigned room, real_n;
160 
161  while (1) {
162  room = av_bprint_room(buf);
163  if (size < room)
164  break;
165  if (av_bprint_alloc(buf, size))
166  break;
167  }
168  if (room) {
169  real_n = FFMIN(size, room - 1);
170  memcpy(buf->str + buf->len, data, real_n);
171  }
172  av_bprint_grow(buf, size);
173 }
174 
175 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
176 {
177  unsigned room;
178  size_t l;
179 
180  if (!*fmt)
181  return;
182  while (1) {
183  room = av_bprint_room(buf);
184  if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
185  break;
186  /* strftime does not tell us how much room it would need: let us
187  retry with twice as much until the buffer is large enough */
188  room = !room ? strlen(fmt) + 1 :
189  room <= INT_MAX / 2 ? room * 2 : INT_MAX;
190  if (av_bprint_alloc(buf, room)) {
191  /* impossible to grow, try to manage something useful anyway */
192  room = av_bprint_room(buf);
193  if (room < 1024) {
194  /* if strftime fails because the buffer has (almost) reached
195  its maximum size, let us try in a local buffer; 1k should
196  be enough to format any real date+time string */
197  char buf2[1024];
198  if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
199  av_bprintf(buf, "%s", buf2);
200  return;
201  }
202  }
203  if (room) {
204  /* if anything else failed and the buffer is not already
205  truncated, let us add a stock string and force truncation */
206  static const char txt[] = "[truncated strftime output]";
207  memset(buf->str + buf->len, '!', room);
208  memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
209  av_bprint_grow(buf, room); /* force truncation */
210  }
211  return;
212  }
213  }
214  av_bprint_grow(buf, l);
215 }
216 
217 void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
218  unsigned char **mem, unsigned *actual_size)
219 {
220  if (size > av_bprint_room(buf))
221  av_bprint_alloc(buf, size);
222  *actual_size = av_bprint_room(buf);
223  *mem = *actual_size ? buf->str + buf->len : NULL;
224 }
225 
226 void av_bprint_clear(AVBPrint *buf)
227 {
228  if (buf->len) {
229  *buf->str = 0;
230  buf->len = 0;
231  }
232 }
233 
234 int av_bprint_finalize(AVBPrint *buf, char **ret_str)
235 {
236  unsigned real_size = FFMIN(buf->len + 1, buf->size);
237  char *str;
238  int ret = 0;
239 
240  if (ret_str) {
241  if (av_bprint_is_allocated(buf)) {
242  str = av_realloc(buf->str, real_size);
243  if (!str)
244  str = buf->str;
245  buf->str = NULL;
246  } else {
247  str = av_malloc(real_size);
248  if (str)
249  memcpy(str, buf->str, real_size);
250  else
251  ret = AVERROR(ENOMEM);
252  }
253  *ret_str = str;
254  } else {
255  if (av_bprint_is_allocated(buf))
256  av_freep(&buf->str);
257  }
258  buf->size = real_size;
259  return ret;
260 }
261 
262 #define WHITESPACES " \n\t\r"
263 
264 void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
265  enum AVEscapeMode mode, int flags)
266 {
267  const char *src0 = src;
268 
269  if (mode == AV_ESCAPE_MODE_AUTO)
270  mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
271 
272  switch (mode) {
274  /* enclose the string between '' */
275  av_bprint_chars(dstbuf, '\'', 1);
276  for (; *src; src++) {
277  if (*src == '\'')
278  av_bprintf(dstbuf, "'\\''");
279  else
280  av_bprint_chars(dstbuf, *src, 1);
281  }
282  av_bprint_chars(dstbuf, '\'', 1);
283  break;
284 
285  case AV_ESCAPE_MODE_XML:
286  /* escape XML non-markup character data as per 2.4 by default: */
287  /* [^<&]* - ([^<&]* ']]>' [^<&]*) */
288 
289  /* additionally, given one of the AV_ESCAPE_FLAG_XML_* flags, */
290  /* escape those specific characters as required. */
291  for (; *src; src++) {
292  switch (*src) {
293  case '&' : av_bprintf(dstbuf, "%s", "&amp;"); break;
294  case '<' : av_bprintf(dstbuf, "%s", "&lt;"); break;
295  case '>' : av_bprintf(dstbuf, "%s", "&gt;"); break;
296  case '\'':
298  goto XML_DEFAULT_HANDLING;
299 
300  av_bprintf(dstbuf, "%s", "&apos;");
301  break;
302  case '"' :
304  goto XML_DEFAULT_HANDLING;
305 
306  av_bprintf(dstbuf, "%s", "&quot;");
307  break;
308 XML_DEFAULT_HANDLING:
309  default: av_bprint_chars(dstbuf, *src, 1);
310  }
311  }
312  break;
313 
314  /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
315  default:
316  /* \-escape characters */
317  for (; *src; src++) {
318  int is_first_last = src == src0 || !*(src+1);
319  int is_ws = !!strchr(WHITESPACES, *src);
320  int is_strictly_special = special_chars && strchr(special_chars, *src);
321  int is_special =
322  is_strictly_special || strchr("'\\", *src) ||
323  (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
324 
325  if (is_strictly_special ||
327  (is_special || (is_ws && is_first_last))))
328  av_bprint_chars(dstbuf, '\\', 1);
329  av_bprint_chars(dstbuf, *src, 1);
330  }
331  break;
332  }
333 }
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_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:234
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:68
va_copy.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:175
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:351
av_bprint_grow
static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
Definition: bprint.c:59
data
const char data[16]
Definition: mxf.c:143
WHITESPACES
#define WHITESPACES
Definition: bprint.c:262
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:157
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
AV_ESCAPE_FLAG_STRICT
#define AV_ESCAPE_FLAG_STRICT
Escape only specified special characters.
Definition: avstring.h:345
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:338
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:357
av_bprint_room
#define av_bprint_room(buf)
Definition: bprint.c:32
size_max
unsigned unsigned size_max
Definition: bprint.h:111
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:116
AV_ESCAPE_MODE_QUOTE
@ AV_ESCAPE_MODE_QUOTE
Use single-quote escaping.
Definition: avstring.h:326
NULL
#define NULL
Definition: coverity.c:32
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:152
src
#define src
Definition: vp8dsp.c:255
time.h
AV_ESCAPE_MODE_AUTO
@ AV_ESCAPE_MODE_AUTO
Use auto-selected escaping mode.
Definition: avstring.h:324
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
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:185
error.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:217
av_bprint_is_allocated
#define av_bprint_is_allocated(buf)
Definition: bprint.c:33
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:327
va_copy
#define va_copy(dst, src)
Definition: va_copy.h:31
src0
#define src0
Definition: h264pred.c:139
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:84
bprint.h
vsnprintf
#define vsnprintf
Definition: snprintf.h:36
common.h
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:93
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:264
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:226
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
mode
mode
Definition: ebur128.h:83
mem.h
size_init
unsigned size_init
Definition: bprint.h:111
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:325
convert_header.str
string str
Definition: convert_header.py:20
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
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:35
AVEscapeMode
AVEscapeMode
Definition: avstring.h:323
avstring.h
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:139