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