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 "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 
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_bprint_chars(AVBPrint *buf, char c, unsigned n)
117 {
118  unsigned room, real_n;
119 
120  while (1) {
121  room = av_bprint_room(buf);
122  if (n < room)
123  break;
124  if (av_bprint_alloc(buf, n))
125  break;
126  }
127  if (room) {
128  real_n = FFMIN(n, room - 1);
129  memset(buf->str + buf->len, c, real_n);
130  }
131  av_bprint_grow(buf, n);
132 }
133 
134 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
135 {
136  unsigned room;
137  size_t l;
138 
139  if (!*fmt)
140  return;
141  while (1) {
142  room = av_bprint_room(buf);
143  if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
144  break;
145  /* strftime does not tell us how much room it would need: let us
146  retry with twice as much until the buffer is large enough */
147  room = !room ? strlen(fmt) + 1 :
148  room <= INT_MAX / 2 ? room * 2 : INT_MAX;
149  if (av_bprint_alloc(buf, room)) {
150  /* impossible to grow, try to manage something useful anyway */
151  room = av_bprint_room(buf);
152  if (room < 1024) {
153  /* if strftime fails because the buffer has (almost) reached
154  its maximum size, let us try in a local buffer; 1k should
155  be enough to format any real date+time string */
156  char buf2[1024];
157  if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
158  av_bprintf(buf, "%s", buf2);
159  return;
160  }
161  }
162  if (room) {
163  /* if anything else failed and the buffer is not already
164  truncated, let us add a stock string and force truncation */
165  static const char txt[] = "[truncated strftime output]";
166  memset(buf->str + buf->len, '!', room);
167  memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
168  av_bprint_grow(buf, room); /* force truncation */
169  }
170  return;
171  }
172  }
173  av_bprint_grow(buf, l);
174 }
175 
177  unsigned char **mem, unsigned *actual_size)
178 {
179  if (size > av_bprint_room(buf))
180  av_bprint_alloc(buf, size);
181  *actual_size = av_bprint_room(buf);
182  *mem = *actual_size ? buf->str + buf->len : NULL;
183 }
184 
186 {
187  if (buf->len) {
188  *buf->str = 0;
189  buf->len = 0;
190  }
191 }
192 
194 {
195  unsigned real_size = FFMIN(buf->len + 1, buf->size);
196  char *str;
197  int ret = 0;
198 
199  if (ret_str) {
200  if (av_bprint_is_allocated(buf)) {
201  str = av_realloc(buf->str, real_size);
202  if (!str)
203  str = buf->str;
204  buf->str = NULL;
205  } else {
206  str = av_malloc(real_size);
207  if (str)
208  memcpy(str, buf->str, real_size);
209  else
210  ret = AVERROR(ENOMEM);
211  }
212  *ret_str = str;
213  } else {
214  if (av_bprint_is_allocated(buf))
215  av_freep(&buf->str);
216  }
217  buf->size = real_size;
218  return ret;
219 }
220 
221 #define WHITESPACES " \n\t"
222 
223 void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars,
224  enum AVEscapeMode mode, int flags)
225 {
226  const char *src0 = src;
227 
228  if (mode == AV_ESCAPE_MODE_AUTO)
229  mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */
230 
231  switch (mode) {
233  /* enclose the string between '' */
234  av_bprint_chars(dstbuf, '\'', 1);
235  for (; *src; src++) {
236  if (*src == '\'')
237  av_bprintf(dstbuf, "'\\''");
238  else
239  av_bprint_chars(dstbuf, *src, 1);
240  }
241  av_bprint_chars(dstbuf, '\'', 1);
242  break;
243 
244  /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */
245  default:
246  /* \-escape characters */
247  for (; *src; src++) {
248  int is_first_last = src == src0 || !*(src+1);
249  int is_ws = !!strchr(WHITESPACES, *src);
250  int is_strictly_special = special_chars && strchr(special_chars, *src);
251  int is_special =
252  is_strictly_special || strchr("'\\", *src) ||
253  (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE));
254 
255  if (is_strictly_special ||
256  (!(flags & AV_ESCAPE_FLAG_STRICT) &&
257  (is_special || (is_ws && is_first_last))))
258  av_bprint_chars(dstbuf, '\\', 1);
259  av_bprint_chars(dstbuf, *src, 1);
260  }
261  break;
262  }
263 }
264 
265 #ifdef TEST
266 
267 #undef printf
268 
269 static void bprint_pascal(AVBPrint *b, unsigned size)
270 {
271  unsigned i, j;
272  unsigned p[42];
273 
274  av_assert0(size < FF_ARRAY_ELEMS(p));
275 
276  p[0] = 1;
277  av_bprintf(b, "%8d\n", 1);
278  for (i = 1; i <= size; i++) {
279  p[i] = 1;
280  for (j = i - 1; j > 0; j--)
281  p[j] = p[j] + p[j - 1];
282  for (j = 0; j <= i; j++)
283  av_bprintf(b, "%8d", p[j]);
284  av_bprintf(b, "\n");
285  }
286 }
287 
288 int main(void)
289 {
290  AVBPrint b;
291  char buf[256];
292  struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 };
293 
294  av_bprint_init(&b, 0, -1);
295  bprint_pascal(&b, 5);
296  printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
297  printf("%s\n", b.str);
299 
300  av_bprint_init(&b, 0, -1);
301  bprint_pascal(&b, 25);
302  printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
304 
305  av_bprint_init(&b, 0, 2048);
306  bprint_pascal(&b, 25);
307  printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
309 
310  av_bprint_init(&b, 0, 1);
311  bprint_pascal(&b, 5);
312  printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
313 
314  av_bprint_init(&b, 0, 1);
315  bprint_pascal(&b, 25);
316  printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str)/8*8, b.len);
317  /* Note that the size of the automatic buffer is arch-dependant. */
318 
319  av_bprint_init(&b, 0, 0);
320  bprint_pascal(&b, 25);
321  printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
322 
323  av_bprint_init_for_buffer(&b, buf, sizeof(buf));
324  bprint_pascal(&b, 25);
325  printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len);
326 
327  av_bprint_init(&b, 0, -1);
328  av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
329  printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
331 
332  av_bprint_init(&b, 0, 8);
333  av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
334  printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
335 
336  return 0;
337 }
338 
339 #endif
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:93
const char * fmt
Definition: avisynth_c.h:669
memory handling functions
#define vsnprintf
Definition: snprintf.h:36
Use backslash escaping.
Definition: avstring.h:258
void * av_realloc(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:141
#define FF_ARRAY_ELEMS(a)
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:193
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
#define WHITESPACES
Definition: bprint.c:221
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int mem
Definition: avisynth_c.h:721
mode
Definition: f_perms.c:27
#define b
Definition: input.c:42
Use single-quote escaping.
Definition: avstring.h:259
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
error code definitions
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Init a print buffer.
Definition: bprint.c:68
static int av_bprint_is_complete(AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:166
#define AV_ESCAPE_FLAG_STRICT
Escape only specified special characters.
Definition: avstring.h:277
simple assert() macros that are a bit more flexible than ISO C assert().
int size
Use auto-selected escaping mode.
Definition: avstring.h:257
Buffer to print data progressively.
Definition: bprint.h:75
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
#define av_bprint_is_allocated(buf)
Definition: bprint.c:33
static const char * ret_str(int v)
Definition: seek-test.c:33
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:176
NULL
Definition: eval.c:55
#define av_bprint_room(buf)
Definition: bprint.c:32
AVS_Value src
Definition: avisynth_c.h:523
void * buf
Definition: avisynth_c.h:594
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
synthesis window for stochastic i
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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.Buffer references ownership and permissions
static int flags
Definition: cpu.c:23
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:134
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:185
static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
Definition: bprint.c:59
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:223
static int av_bprint_alloc(AVBPrint *buf, unsigned room)
Definition: bprint.c:35
common internal and external API header
static double c[64]
the buffer and buffer 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 AVFilterBuffer structures They must not be accessed but through references stored in AVFilterBufferRef structures Several references can point to the same buffer
printf("static const uint8_t my_array[100] = {\n")
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
#define AV_ESCAPE_FLAG_WHITESPACE
Consider spaces special and escape them even in the middle of the string.
Definition: avstring.h:270
AVEscapeMode
Definition: avstring.h:256
int main(int argc, char **argv)
Definition: main.c:22
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:116