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_bprintf(AVBPrint *buf, const char *fmt, ...)
100 {
101  unsigned room;
102  char *dst;
103  va_list vl;
104  int extra_len;
105 
106  while (1) {
107  room = av_bprint_room(buf);
108  dst = room ? buf->str + buf->len : NULL;
109  va_start(vl, fmt);
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_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
123 {
124  unsigned room;
125  char *dst;
126  int extra_len;
127  va_list vl;
128 
129  while (1) {
130  room = av_bprint_room(buf);
131  dst = room ? buf->str + buf->len : NULL;
132  va_copy(vl, vl_arg);
133  extra_len = vsnprintf(dst, room, fmt, vl);
134  va_end(vl);
135  if (extra_len <= 0)
136  return;
137  if (extra_len < room)
138  break;
139  if (av_bprint_alloc(buf, extra_len))
140  break;
141  }
142  av_bprint_grow(buf, extra_len);
143 }
144 
145 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
146 {
147  unsigned room, real_n;
148 
149  while (1) {
150  room = av_bprint_room(buf);
151  if (n < room)
152  break;
153  if (av_bprint_alloc(buf, n))
154  break;
155  }
156  if (room) {
157  real_n = FFMIN(n, room - 1);
158  memset(buf->str + buf->len, c, real_n);
159  }
160  av_bprint_grow(buf, n);
161 }
162 
163 void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
164 {
165  unsigned room, real_n;
166 
167  while (1) {
168  room = av_bprint_room(buf);
169  if (size < room)
170  break;
171  if (av_bprint_alloc(buf, size))
172  break;
173  }
174  if (room) {
175  real_n = FFMIN(size, room - 1);
176  memcpy(buf->str + buf->len, data, real_n);
177  }
178  av_bprint_grow(buf, size);
179 }
180 
181 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
182 {
183  unsigned room;
184  size_t l;
185 
186  if (!*fmt)
187  return;
188  while (1) {
189  room = av_bprint_room(buf);
190  if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
191  break;
192  /* strftime does not tell us how much room it would need: let us
193  retry with twice as much until the buffer is large enough */
194  room = !room ? strlen(fmt) + 1 :
195  room <= INT_MAX / 2 ? room * 2 : INT_MAX;
196  if (av_bprint_alloc(buf, room)) {
197  /* impossible to grow, try to manage something useful anyway */
198  room = av_bprint_room(buf);
199  if (room < 1024) {
200  /* if strftime fails because the buffer has (almost) reached
201  its maximum size, let us try in a local buffer; 1k should
202  be enough to format any real date+time string */
203  char buf2[1024];
204  if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
205  av_bprintf(buf, "%s", buf2);
206  return;
207  }
208  }
209  if (room) {
210  /* if anything else failed and the buffer is not already
211  truncated, let us add a stock string and force truncation */
212  static const char txt[] = "[truncated strftime output]";
213  memset(buf->str + buf->len, '!', room);
214  memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
215  av_bprint_grow(buf, room); /* force truncation */
216  }
217  return;
218  }
219  }
220  av_bprint_grow(buf, l);
221 }
222 
223 void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
224  unsigned char **mem, unsigned *actual_size)
225 {
226  if (size > av_bprint_room(buf))
227  av_bprint_alloc(buf, size);
228  *actual_size = av_bprint_room(buf);
229  *mem = *actual_size ? buf->str + buf->len : NULL;
230 }
231 
232 void av_bprint_clear(AVBPrint *buf)
233 {
234  if (buf->len) {
235  *buf->str = 0;
236  buf->len = 0;
237  }
238 }
239 
240 int av_bprint_finalize(AVBPrint *buf, char **ret_str)
241 {
242  unsigned real_size = FFMIN(buf->len + 1, buf->size);
243  char *str;
244  int ret = 0;
245 
246  if (ret_str) {
247  if (av_bprint_is_allocated(buf)) {
248  str = av_realloc(buf->str, real_size);
249  if (!str)
250  str = buf->str;
251  buf->str = NULL;
252  } else {
253  str = av_memdup(buf->str, real_size);
254  if (!str)
255  ret = AVERROR(ENOMEM);
256  }
257  *ret_str = str;
258  } else {
259  if (av_bprint_is_allocated(buf))
260  av_freep(&buf->str);
261  }
262  buf->size = real_size;
263  return ret;
264 }
265 
266 #define WHITESPACES " \n\t\r"
267 
268 void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
269  enum AVEscapeMode mode, int flags)
270 {
271  const char *src0 = src;
272 
273  if (mode == AV_ESCAPE_MODE_AUTO)
274  mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
275 
276  switch (mode) {
278  /* enclose the string between '' */
279  av_bprint_chars(dstbuf, '\'', 1);
280  for (; *src; src++) {
281  if (*src == '\'')
282  av_bprintf(dstbuf, "'\\''");
283  else
284  av_bprint_chars(dstbuf, *src, 1);
285  }
286  av_bprint_chars(dstbuf, '\'', 1);
287  break;
288 
289  case AV_ESCAPE_MODE_XML:
290  /* escape XML non-markup character data as per 2.4 by default: */
291  /* [^<&]* - ([^<&]* ']]>' [^<&]*) */
292 
293  /* additionally, given one of the AV_ESCAPE_FLAG_XML_* flags, */
294  /* escape those specific characters as required. */
295  for (; *src; src++) {
296  switch (*src) {
297  case '&' : av_bprintf(dstbuf, "%s", "&amp;"); break;
298  case '<' : av_bprintf(dstbuf, "%s", "&lt;"); break;
299  case '>' : av_bprintf(dstbuf, "%s", "&gt;"); break;
300  case '\'':
302  goto XML_DEFAULT_HANDLING;
303 
304  av_bprintf(dstbuf, "%s", "&apos;");
305  break;
306  case '"' :
308  goto XML_DEFAULT_HANDLING;
309 
310  av_bprintf(dstbuf, "%s", "&quot;");
311  break;
312 XML_DEFAULT_HANDLING:
313  default: av_bprint_chars(dstbuf, *src, 1);
314  }
315  }
316  break;
317 
318  /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
319  default:
320  /* \-escape characters */
321  for (; *src; src++) {
322  int is_first_last = src == src0 || !*(src+1);
323  int is_ws = !!strchr(WHITESPACES, *src);
324  int is_strictly_special = special_chars && strchr(special_chars, *src);
325  int is_special =
326  is_strictly_special || strchr("'\\", *src) ||
327  (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
328 
329  if (is_strictly_special ||
331  (is_special || (is_ws && is_first_last))))
332  av_bprint_chars(dstbuf, '\\', 1);
333  av_bprint_chars(dstbuf, *src, 1);
334  }
335  break;
336  }
337 }
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
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:148
WHITESPACES
#define WHITESPACES
Definition: bprint.c:266
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: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:268
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:181
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:240
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: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:223
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:99
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:122
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:232
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:316
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:145
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:163
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:153