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 "avassert.h"
26 #include "avstring.h"
27 #include "bprint.h"
28 #include "common.h"
29 #include "compat/va_copy.h"
30 #include "error.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_malloc(real_size);
249  if (str)
250  memcpy(str, buf->str, real_size);
251  else
252  ret = AVERROR(ENOMEM);
253  }
254  *ret_str = str;
255  } else {
256  if (av_bprint_is_allocated(buf))
257  av_freep(&buf->str);
258  }
259  buf->size = real_size;
260  return ret;
261 }
262 
263 #define WHITESPACES " \n\t\r"
264 
265 void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
266  enum AVEscapeMode mode, int flags)
267 {
268  const char *src0 = src;
269 
270  if (mode == AV_ESCAPE_MODE_AUTO)
271  mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
272 
273  switch (mode) {
275  /* enclose the string between '' */
276  av_bprint_chars(dstbuf, '\'', 1);
277  for (; *src; src++) {
278  if (*src == '\'')
279  av_bprintf(dstbuf, "'\\''");
280  else
281  av_bprint_chars(dstbuf, *src, 1);
282  }
283  av_bprint_chars(dstbuf, '\'', 1);
284  break;
285 
286  /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
287  default:
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);
293  int is_special =
294  is_strictly_special || strchr("'\\", *src) ||
295  (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
296 
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);
302  }
303  break;
304  }
305 }
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:135
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
const char * fmt
Definition: avisynth_c.h:861
Memory handling functions.
#define vsnprintf
Definition: snprintf.h:36
Use backslash escaping.
Definition: avstring.h:315
#define src
Definition: vp8dsp.c:254
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
#define WHITESPACES
Definition: bprint.c:263
int mem
Definition: avisynth_c.h:916
#define av_malloc(s)
#define va_copy(dst, src)
Definition: va_copy.h:31
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
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
Use single-quote escaping.
Definition: avstring.h:316
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
ptrdiff_t size
Definition: opengl_enc.c:100
error code definitions
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
#define AV_ESCAPE_FLAG_STRICT
Escape only specified special characters.
Definition: avstring.h:334
simple assert() macros that are a bit more flexible than ISO C assert().
Use auto-selected escaping mode.
Definition: avstring.h:314
#define FFMIN(a, b)
Definition: common.h:96
#define av_bprint_is_allocated(buf)
Definition: bprint.c:34
int n
Definition: avisynth_c.h:760
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
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
#define av_bprint_room(buf)
Definition: bprint.c:33
void * buf
Definition: avisynth_c.h:766
void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
Append a formatted string to a print buffer.
Definition: bprint.c:117
#define src0
Definition: h264pred.c:138
#define flags(name, subs,...)
Definition: cbs_av1.c:561
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
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
unsigned unsigned size_max
Definition: bprint.h:111
static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
Definition: bprint.c:60
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:265
static int av_bprint_alloc(AVBPrint *buf, unsigned room)
Definition: bprint.c:36
common internal and external API header
static const char * ret_str(int v)
Definition: seek.c:34
#define AV_ESCAPE_FLAG_WHITESPACE
Consider spaces special and escape them even in the middle of the string.
Definition: avstring.h:327
unsigned size_init
Definition: bprint.h:111
AVEscapeMode
Definition: avstring.h:313
#define av_freep(p)
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
mode
Use these values in ebur128_init (or&#39;ed).
Definition: ebur128.h:83
GLuint buffer
Definition: opengl_enc.c:101
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:140