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