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 
74  if (size_max == 1)
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  buf->str = buffer;
88  buf->len = 0;
89  buf->size = size;
90  buf->size_max = size;
91  *buf->str = 0;
92 }
93 
94 void av_bprintf(AVBPrint *buf, const char *fmt, ...)
95 {
96  unsigned room;
97  char *dst;
98  va_list vl;
99  int extra_len;
100 
101  while (1) {
102  room = av_bprint_room(buf);
103  dst = room ? buf->str + buf->len : NULL;
104  va_start(vl, fmt);
105  extra_len = vsnprintf(dst, room, fmt, vl);
106  va_end(vl);
107  if (extra_len <= 0)
108  return;
109  if (extra_len < room)
110  break;
111  if (av_bprint_alloc(buf, extra_len))
112  break;
113  }
114  av_bprint_grow(buf, extra_len);
115 }
116 
117 void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
118 {
119  unsigned room;
120  char *dst;
121  int extra_len;
122  va_list vl;
123 
124  while (1) {
125  room = av_bprint_room(buf);
126  dst = room ? buf->str + buf->len : NULL;
127  va_copy(vl, vl_arg);
128  extra_len = vsnprintf(dst, room, fmt, vl);
129  va_end(vl);
130  if (extra_len <= 0)
131  return;
132  if (extra_len < room)
133  break;
134  if (av_bprint_alloc(buf, extra_len))
135  break;
136  }
137  av_bprint_grow(buf, extra_len);
138 }
139 
140 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
141 {
142  unsigned room, real_n;
143 
144  while (1) {
145  room = av_bprint_room(buf);
146  if (n < room)
147  break;
148  if (av_bprint_alloc(buf, n))
149  break;
150  }
151  if (room) {
152  real_n = FFMIN(n, room - 1);
153  memset(buf->str + buf->len, c, real_n);
154  }
155  av_bprint_grow(buf, n);
156 }
157 
158 void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
159 {
160  unsigned room, real_n;
161 
162  while (1) {
163  room = av_bprint_room(buf);
164  if (size < room)
165  break;
166  if (av_bprint_alloc(buf, size))
167  break;
168  }
169  if (room) {
170  real_n = FFMIN(size, room - 1);
171  memcpy(buf->str + buf->len, data, real_n);
172  }
173  av_bprint_grow(buf, size);
174 }
175 
176 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
177 {
178  unsigned room;
179  size_t l;
180 
181  if (!*fmt)
182  return;
183  while (1) {
184  room = av_bprint_room(buf);
185  if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
186  break;
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);
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 }
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:215
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
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:343
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:146
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:302
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:337
macros.h
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:330
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:349
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:318
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:176
AV_ESCAPE_MODE_AUTO
@ AV_ESCAPE_MODE_AUTO
Use auto-selected escaping mode.
Definition: avstring.h:316
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
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:319
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:94
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:117
mode
mode
Definition: ebur128.h:83
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:420
mem.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
AV_ESCAPE_MODE_BACKSLASH
@ AV_ESCAPE_MODE_BACKSLASH
Use backslash escaping.
Definition: avstring.h:317
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: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:140
AVEscapeMode
AVEscapeMode
Definition: avstring.h:315
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:158
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:153