History

lavu: add av_bprintf and related.

Nicolas George committed 14 years ago

Commit b75c67d1 parent 594a3d65 files · +350 −3Browse files

Unified · Split

5 files
  1. doc/APIchanges +3 −0
  2. libavutil/Makefile +4 −2
  3. libavutil/avutil.h +1 −1
  4. libavutil/bprint.c +206 −0
  5. libavutil/bprint.h +136 −0
doc/APIchanges+3−0
@@ -13,6 +13,9 @@ libavutil: 2011-04-18 · 12 unmodified lines
1313
1414 API changes, most recent first:
1515
16+2012-03-21 - xxxxxxx - lavu 51.43.100
17+ Add bprint.h for bprint API.
18+
1619 2012-02-21 - xxxxxxx - lavc 54.4.100
1720 Add av_get_pcm_codec() function.
1821
libavutil/Makefile+4−2
@@ -10,6 +10,7 @@ HEADERS = adler32.h \ · 9 unmodified lines
1010 avstring.h \
1111 avutil.h \
1212 base64.h \
13+ bprint.h \
1314 bswap.h \
1415 common.h \
1516 cpu.h \
@@ -47,6 +48,7 @@ OBJS = adler32.o \ · 31 unmodified lines
4748 audioconvert.o \
4849 avstring.o \
4950 base64.o \
51+ bprint.o \
5052 cpu.o \
5153 crc.o \
5254 des.o \
@@ -81,8 +83,8 @@ OBJS-$(ARCH_PPC) += ppc/cpu.o · 28 unmodified lines
8183 OBJS-$(ARCH_X86) += x86/cpu.o
8284
8385
84−TESTPROGS = adler32 aes avstring base64 cpu crc des eval file fifo lfg lls \
85− md5 opt pca parseutils random_seed rational sha tree
86+TESTPROGS = adler32 aes avstring base64 bprint cpu crc des eval file fifo \
87+ lfg lls md5 opt pca parseutils random_seed rational sha tree
8688 TESTPROGS-$(HAVE_LZO1X_999_COMPRESS) += lzo
8789
8890 TOOLS = ffeval
libavutil/avutil.h+1−1
@@ -153,7 +153,7 @@ · 152 unmodified lines
153153 */
154154
155155 #define LIBAVUTIL_VERSION_MAJOR 51
156−#define LIBAVUTIL_VERSION_MINOR 42
156+#define LIBAVUTIL_VERSION_MINOR 43
157157 #define LIBAVUTIL_VERSION_MICRO 100
158158
159159 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
libavutil/bprint.c+206−0
@@ -0,0 +1,206 @@
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 "bprint.h"
25+#include "common.h"
26+#include "error.h"
27+#include "mem.h"
28+
29+#define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
30+#define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
31+
32+static int av_bprint_alloc(AVBPrint *buf, unsigned room)
33+{
34+ char *old_str, *new_str;
35+ unsigned min_size, new_size;
36+
37+ if (buf->size == buf->size_max)
38+ return AVERROR(EIO);
39+ if (!av_bprint_is_complete(buf))
40+ return AVERROR_INVALIDDATA; /* it is already truncated anyway */
41+ min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room);
42+ new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2;
43+ if (new_size < min_size)
44+ new_size = FFMIN(buf->size_max, min_size);
45+ old_str = av_bprint_is_allocated(buf) ? buf->str : NULL;
46+ new_str = av_realloc(old_str, new_size);
47+ if (!new_str)
48+ return AVERROR(ENOMEM);
49+ if (!old_str)
50+ memcpy(new_str, buf->str, buf->len + 1);
51+ buf->str = new_str;
52+ buf->size = new_size;
53+ return 0;
54+}
55+
56+static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
57+{
58+ /* arbitrary margin to avoid small overflows */
59+ extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
60+ buf->len += extra_len;
61+ if (buf->size)
62+ buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
63+}
64+
65+void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
66+{
67+ unsigned size_auto = (char *)buf + sizeof(*buf) -
68+ buf->reserved_internal_buffer;
69+
70+ if (size_max == 1)
71+ size_max = size_auto;
72+ buf->str = buf->reserved_internal_buffer;
73+ buf->len = 0;
74+ buf->size = FFMIN(size_auto, size_max);
75+ buf->size_max = size_max;
76+ *buf->str = 0;
77+ if (size_init > buf->size)
78+ av_bprint_alloc(buf, size_init - 1);
79+}
80+
81+void av_bprintf(AVBPrint *buf, const char *fmt, ...)
82+{
83+ unsigned room;
84+ char *dst;
85+ va_list vl;
86+ int extra_len;
87+
88+ while (1) {
89+ room = av_bprint_room(buf);
90+ dst = room ? buf->str + buf->len : NULL;
91+ va_start(vl, fmt);
92+ extra_len = vsnprintf(dst, room, fmt, vl);
93+ va_end(vl);
94+ if (extra_len <= 0)
95+ return;
96+ if (extra_len < room)
97+ break;
98+ if (av_bprint_alloc(buf, extra_len))
99+ break;
100+ }
101+ av_bprint_grow(buf, extra_len);
102+}
103+
104+void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
105+{
106+ unsigned room, real_n;
107+
108+ while (1) {
109+ room = av_bprint_room(buf);
110+ if (n < room)
111+ break;
112+ if (av_bprint_alloc(buf, n))
113+ break;
114+ }
115+ if (room) {
116+ real_n = FFMIN(n, room - 1);
117+ memset(buf->str + buf->len, c, real_n);
118+ }
119+ av_bprint_grow(buf, n);
120+}
121+
122+int av_bprint_finalize(AVBPrint *buf, char **ret_str)
123+{
124+ unsigned real_size = FFMIN(buf->len + 1, buf->size);
125+ char *str;
126+ int ret = 0;
127+
128+ if (ret_str) {
129+ if (av_bprint_is_allocated(buf)) {
130+ str = av_realloc(buf->str, real_size);
131+ if (!str)
132+ str = buf->str;
133+ buf->str = NULL;
134+ } else {
135+ str = av_malloc(real_size);
136+ if (str)
137+ memcpy(str, buf->str, real_size);
138+ else
139+ ret = AVERROR(ENOMEM);
140+ }
141+ *ret_str = str;
142+ } else {
143+ if (av_bprint_is_allocated(buf))
144+ av_freep(&buf->str);
145+ }
146+ buf->size = real_size;
147+ return ret;
148+}
149+
150+#ifdef TEST
151+
152+#undef printf
153+
154+static void bprint_pascal(AVBPrint *b, unsigned size)
155+{
156+ unsigned p[size + 1], i, j;
157+
158+ p[0] = 1;
159+ av_bprintf(b, "%8d\n", 1);
160+ for (i = 1; i <= size; i++) {
161+ p[i] = 1;
162+ for (j = i - 1; j > 0; j--)
163+ p[j] = p[j] + p[j - 1];
164+ for (j = 0; j <= i; j++)
165+ av_bprintf(b, "%8d", p[j]);
166+ av_bprintf(b, "\n");
167+ }
168+}
169+
170+int main(void)
171+{
172+ AVBPrint b;
173+
174+ av_bprint_init(&b, 0, -1);
175+ bprint_pascal(&b, 5);
176+ printf("Short text in unlimited buffer: %zu/%u\n", strlen(b.str), b.len);
177+ printf("%s\n", b.str);
178+ av_bprint_finalize(&b, NULL);
179+
180+ av_bprint_init(&b, 0, -1);
181+ bprint_pascal(&b, 25);
182+ printf("Long text in unlimited buffer: %zu/%u\n", strlen(b.str), b.len);
183+ av_bprint_finalize(&b, NULL);
184+
185+ av_bprint_init(&b, 0, 2048);
186+ bprint_pascal(&b, 25);
187+ printf("Long text in limited buffer: %zu/%u\n", strlen(b.str), b.len);
188+ av_bprint_finalize(&b, NULL);
189+
190+ av_bprint_init(&b, 0, 1);
191+ bprint_pascal(&b, 5);
192+ printf("Short text in automatic buffer: %zu/%u\n", strlen(b.str), b.len);
193+
194+ av_bprint_init(&b, 0, 1);
195+ bprint_pascal(&b, 25);
196+ printf("Long text in automatic buffer: %zu/%u\n", strlen(b.str), b.len);
197+ /* Note that the size of the automatic buffer is arch-dependant. */
198+
199+ av_bprint_init(&b, 0, 0);
200+ bprint_pascal(&b, 25);
201+ printf("Long text count only buffer: %zu/%u\n", strlen(b.str), b.len);
202+
203+ return 0;
204+}
205+
206+#endif
libavutil/bprint.h+136−0
@@ -0,0 +1,136 @@
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+#ifndef AVUTIL_BPRINT_H
22+#define AVUTIL_BPRINT_H
23+
24+#include "attributes.h"
25+
26+/**
27+ * Define a structure with extra padding to a fixed size
28+ * This helps ensuring binary compatibility with future versions.
29+ */
30+#define FF_PAD_STRUCTURE(size, ...) \
31+ __VA_ARGS__ \
32+ char reserved_padding[size - sizeof(struct { __VA_ARGS__ })];
33+
34+/**
35+ * Buffer to print data progressively
36+ *
37+ * The string buffer grows as necessary and is always 0-terminated.
38+ * The content of the string is never accessed, and thus is
39+ * encoding-agnostic and can even hold binary data.
40+ *
41+ * Small buffers are kept in the structure itself, and thus require no
42+ * memory allocation at all (unless the contents of the buffer is needed
43+ * after the structure goes out of scope). This is almost as lightweight as
44+ * declaring a local "char buf[512]".
45+ *
46+ * The length of the string can go beyond the allocated size: the buffer is
47+ * then truncated, but the functions still keep account of the actual total
48+ * length.
49+ *
50+ * In other words, buf->len can be greater than buf->size and records the
51+ * total length of what would have been to the buffer if there had been
52+ * enough memory.
53+ *
54+ * Append operations do not need to be tested for failure: if a memory
55+ * allocation fails, data stop being appended to the buffer, but the length
56+ * is still updated. This situation can be tested with
57+ * av_bprint_is_complete().
58+ *
59+ * The size_max field determines several possible behaviours:
60+ *
61+ * size_max = -1 (= UINT_MAX) or any large value will let the buffer be
62+ * reallocated as necessary, with an amortized linear cost.
63+ *
64+ * size_max = 0 prevents writing anything to the buffer: only the total
65+ * length is computed. The write operations can then possibly be repeated in
66+ * a buffer with exactly the necessary size
67+ * (using size_init = size_max = len + 1).
68+ *
69+ * size_max = 1 is automatically replaced by the exact size available in the
70+ * structure itself, thus ensuring no dynamic memory allocation. The
71+ * internal buffer is large enough to hold a reasonable paragraph of text,
72+ * such as the current paragraph.
73+ */
74+typedef struct AVBPrint {
75+ FF_PAD_STRUCTURE(1024,
76+ char *str; /** string so far */
77+ unsigned len; /** length so far */
78+ unsigned size; /** allocated memory */
79+ unsigned size_max; /** maximum allocated memory */
80+ char reserved_internal_buffer[1];
81+ )
82+} AVBPrint;
83+
84+/**
85+ * Init a print buffer.
86+ *
87+ * @param buf buffer to init
88+ * @param size_init initial size (including the final 0)
89+ * @param size_max maximum size;
90+ * 0 means do not write anything, just count the length;
91+ * 1 is replaced by the maximum value for automatic storage
92+ */
93+void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
94+
95+/**
96+ * Convenience macros for special values for size_max.
97+ */
98+#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1)
99+#define AV_BPRINT_SIZE_AUTOMATIC 1
100+#define AV_BPRINT_SIZE_COUNT_ONLY 0
101+
102+/**
103+ * Append a formated string to a print buffer.
104+ */
105+void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3);
106+
107+/**
108+ * Append char c n times to a print buffer.
109+ */
110+void av_bprint_chars(AVBPrint *buf, char c, unsigned n);
111+
112+/**
113+ * Test if the print buffer is complete (not truncated).
114+ *
115+ * It may have been truncated due to a memory allocation failure
116+ * or the size_max limit (compare size and size_max if necessary).
117+ */
118+static inline int av_bprint_is_complete(AVBPrint *buf)
119+{
120+ return buf->len < buf->size;
121+}
122+
123+/**
124+ * Finalize a print buffer.
125+ *
126+ * The print buffer can no longer be used afterwards,
127+ * but the len and size fields are still valid.
128+ *
129+ * @arg[out] ret_str if not NULL, used to return a permanent copy of the
130+ * buffer contents, or NULL if memory allocation fails;
131+ * if NULL, the buffer is discarded and freed
132+ * @return 0 for success or error code (probably AVERROR(ENOMEM))
133+ */
134+int av_bprint_finalize(AVBPrint *buf, char **ret_str);
135+
136+#endif /* AVUTIL_BPRINT_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t