00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdarg.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include "bprint.h"
00025 #include "common.h"
00026 #include "error.h"
00027 #include "mem.h"
00028
00029 #define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
00030 #define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
00031
00032 static int av_bprint_alloc(AVBPrint *buf, unsigned room)
00033 {
00034 char *old_str, *new_str;
00035 unsigned min_size, new_size;
00036
00037 if (buf->size == buf->size_max)
00038 return AVERROR(EIO);
00039 if (!av_bprint_is_complete(buf))
00040 return AVERROR_INVALIDDATA;
00041 min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room);
00042 new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2;
00043 if (new_size < min_size)
00044 new_size = FFMIN(buf->size_max, min_size);
00045 old_str = av_bprint_is_allocated(buf) ? buf->str : NULL;
00046 new_str = av_realloc(old_str, new_size);
00047 if (!new_str)
00048 return AVERROR(ENOMEM);
00049 if (!old_str)
00050 memcpy(new_str, buf->str, buf->len + 1);
00051 buf->str = new_str;
00052 buf->size = new_size;
00053 return 0;
00054 }
00055
00056 static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
00057 {
00058
00059 extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
00060 buf->len += extra_len;
00061 if (buf->size)
00062 buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
00063 }
00064
00065 void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
00066 {
00067 unsigned size_auto = (char *)buf + sizeof(*buf) -
00068 buf->reserved_internal_buffer;
00069
00070 if (size_max == 1)
00071 size_max = size_auto;
00072 buf->str = buf->reserved_internal_buffer;
00073 buf->len = 0;
00074 buf->size = FFMIN(size_auto, size_max);
00075 buf->size_max = size_max;
00076 *buf->str = 0;
00077 if (size_init > buf->size)
00078 av_bprint_alloc(buf, size_init - 1);
00079 }
00080
00081 void av_bprintf(AVBPrint *buf, const char *fmt, ...)
00082 {
00083 unsigned room;
00084 char *dst;
00085 va_list vl;
00086 int extra_len;
00087
00088 while (1) {
00089 room = av_bprint_room(buf);
00090 dst = room ? buf->str + buf->len : NULL;
00091 va_start(vl, fmt);
00092 extra_len = vsnprintf(dst, room, fmt, vl);
00093 va_end(vl);
00094 if (extra_len <= 0)
00095 return;
00096 if (extra_len < room)
00097 break;
00098 if (av_bprint_alloc(buf, extra_len))
00099 break;
00100 }
00101 av_bprint_grow(buf, extra_len);
00102 }
00103
00104 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
00105 {
00106 unsigned room, real_n;
00107
00108 while (1) {
00109 room = av_bprint_room(buf);
00110 if (n < room)
00111 break;
00112 if (av_bprint_alloc(buf, n))
00113 break;
00114 }
00115 if (room) {
00116 real_n = FFMIN(n, room - 1);
00117 memset(buf->str + buf->len, c, real_n);
00118 }
00119 av_bprint_grow(buf, n);
00120 }
00121
00122 void av_bprint_clear(AVBPrint *buf)
00123 {
00124 if (buf->len) {
00125 *buf->str = 0;
00126 buf->len = 0;
00127 }
00128 }
00129
00130 int av_bprint_finalize(AVBPrint *buf, char **ret_str)
00131 {
00132 unsigned real_size = FFMIN(buf->len + 1, buf->size);
00133 char *str;
00134 int ret = 0;
00135
00136 if (ret_str) {
00137 if (av_bprint_is_allocated(buf)) {
00138 str = av_realloc(buf->str, real_size);
00139 if (!str)
00140 str = buf->str;
00141 buf->str = NULL;
00142 } else {
00143 str = av_malloc(real_size);
00144 if (str)
00145 memcpy(str, buf->str, real_size);
00146 else
00147 ret = AVERROR(ENOMEM);
00148 }
00149 *ret_str = str;
00150 } else {
00151 if (av_bprint_is_allocated(buf))
00152 av_freep(&buf->str);
00153 }
00154 buf->size = real_size;
00155 return ret;
00156 }
00157
00158 #ifdef TEST
00159
00160 #undef printf
00161
00162 static void bprint_pascal(AVBPrint *b, unsigned size)
00163 {
00164 unsigned p[size + 1], i, j;
00165
00166 p[0] = 1;
00167 av_bprintf(b, "%8d\n", 1);
00168 for (i = 1; i <= size; i++) {
00169 p[i] = 1;
00170 for (j = i - 1; j > 0; j--)
00171 p[j] = p[j] + p[j - 1];
00172 for (j = 0; j <= i; j++)
00173 av_bprintf(b, "%8d", p[j]);
00174 av_bprintf(b, "\n");
00175 }
00176 }
00177
00178 int main(void)
00179 {
00180 AVBPrint b;
00181
00182 av_bprint_init(&b, 0, -1);
00183 bprint_pascal(&b, 5);
00184 printf("Short text in unlimited buffer: %zu/%u\n", strlen(b.str), b.len);
00185 printf("%s\n", b.str);
00186 av_bprint_finalize(&b, NULL);
00187
00188 av_bprint_init(&b, 0, -1);
00189 bprint_pascal(&b, 25);
00190 printf("Long text in unlimited buffer: %zu/%u\n", strlen(b.str), b.len);
00191 av_bprint_finalize(&b, NULL);
00192
00193 av_bprint_init(&b, 0, 2048);
00194 bprint_pascal(&b, 25);
00195 printf("Long text in limited buffer: %zu/%u\n", strlen(b.str), b.len);
00196 av_bprint_finalize(&b, NULL);
00197
00198 av_bprint_init(&b, 0, 1);
00199 bprint_pascal(&b, 5);
00200 printf("Short text in automatic buffer: %zu/%u\n", strlen(b.str), b.len);
00201
00202 av_bprint_init(&b, 0, 1);
00203 bprint_pascal(&b, 25);
00204 printf("Long text in automatic buffer: %zu/%u\n", strlen(b.str), b.len);
00205
00206
00207 av_bprint_init(&b, 0, 0);
00208 bprint_pascal(&b, 25);
00209 printf("Long text count only buffer: %zu/%u\n", strlen(b.str), b.len);
00210
00211 return 0;
00212 }
00213
00214 #endif