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 <time.h>
00025 #include "avassert.h"
00026 #include "bprint.h"
00027 #include "common.h"
00028 #include "error.h"
00029 #include "mem.h"
00030
00031 #define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size))
00032 #define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer)
00033
00034 static int av_bprint_alloc(AVBPrint *buf, unsigned room)
00035 {
00036 char *old_str, *new_str;
00037 unsigned min_size, new_size;
00038
00039 if (buf->size == buf->size_max)
00040 return AVERROR(EIO);
00041 if (!av_bprint_is_complete(buf))
00042 return AVERROR_INVALIDDATA;
00043 min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room);
00044 new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2;
00045 if (new_size < min_size)
00046 new_size = FFMIN(buf->size_max, min_size);
00047 old_str = av_bprint_is_allocated(buf) ? buf->str : NULL;
00048 new_str = av_realloc(old_str, new_size);
00049 if (!new_str)
00050 return AVERROR(ENOMEM);
00051 if (!old_str)
00052 memcpy(new_str, buf->str, buf->len + 1);
00053 buf->str = new_str;
00054 buf->size = new_size;
00055 return 0;
00056 }
00057
00058 static void av_bprint_grow(AVBPrint *buf, unsigned extra_len)
00059 {
00060
00061 extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len);
00062 buf->len += extra_len;
00063 if (buf->size)
00064 buf->str[FFMIN(buf->len, buf->size - 1)] = 0;
00065 }
00066
00067 void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
00068 {
00069 unsigned size_auto = (char *)buf + sizeof(*buf) -
00070 buf->reserved_internal_buffer;
00071
00072 if (size_max == 1)
00073 size_max = size_auto;
00074 buf->str = buf->reserved_internal_buffer;
00075 buf->len = 0;
00076 buf->size = FFMIN(size_auto, size_max);
00077 buf->size_max = size_max;
00078 *buf->str = 0;
00079 if (size_init > buf->size)
00080 av_bprint_alloc(buf, size_init - 1);
00081 }
00082
00083 void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
00084 {
00085 buf->str = buffer;
00086 buf->len = 0;
00087 buf->size = size;
00088 buf->size_max = size;
00089 *buf->str = 0;
00090 }
00091
00092 void av_bprintf(AVBPrint *buf, const char *fmt, ...)
00093 {
00094 unsigned room;
00095 char *dst;
00096 va_list vl;
00097 int extra_len;
00098
00099 while (1) {
00100 room = av_bprint_room(buf);
00101 dst = room ? buf->str + buf->len : NULL;
00102 va_start(vl, fmt);
00103 extra_len = vsnprintf(dst, room, fmt, vl);
00104 va_end(vl);
00105 if (extra_len <= 0)
00106 return;
00107 if (extra_len < room)
00108 break;
00109 if (av_bprint_alloc(buf, extra_len))
00110 break;
00111 }
00112 av_bprint_grow(buf, extra_len);
00113 }
00114
00115 void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
00116 {
00117 unsigned room, real_n;
00118
00119 while (1) {
00120 room = av_bprint_room(buf);
00121 if (n < room)
00122 break;
00123 if (av_bprint_alloc(buf, n))
00124 break;
00125 }
00126 if (room) {
00127 real_n = FFMIN(n, room - 1);
00128 memset(buf->str + buf->len, c, real_n);
00129 }
00130 av_bprint_grow(buf, n);
00131 }
00132
00133 void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm)
00134 {
00135 unsigned room;
00136 size_t l;
00137
00138 if (!*fmt)
00139 return;
00140 while (1) {
00141 room = av_bprint_room(buf);
00142 if (room && (l = strftime(buf->str + buf->len, room, fmt, tm)))
00143 break;
00144
00145
00146 room = !room ? strlen(fmt) + 1 :
00147 room <= INT_MAX / 2 ? room * 2 : INT_MAX;
00148 if (av_bprint_alloc(buf, room)) {
00149
00150 room = av_bprint_room(buf);
00151 if (room < 1024) {
00152
00153
00154
00155 char buf2[1024];
00156 if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) {
00157 av_bprintf(buf, "%s", buf2);
00158 return;
00159 }
00160 }
00161 if (room) {
00162
00163
00164 static const char txt[] = "[truncated strftime output]";
00165 memset(buf->str + buf->len, '!', room);
00166 memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room));
00167 av_bprint_grow(buf, room);
00168 }
00169 return;
00170 }
00171 }
00172 av_bprint_grow(buf, l);
00173 }
00174
00175 void av_bprint_get_buffer(AVBPrint *buf, unsigned size,
00176 unsigned char **mem, unsigned *actual_size)
00177 {
00178 if (size > av_bprint_room(buf))
00179 av_bprint_alloc(buf, size);
00180 *actual_size = av_bprint_room(buf);
00181 *mem = *actual_size ? buf->str + buf->len : NULL;
00182 }
00183
00184 void av_bprint_clear(AVBPrint *buf)
00185 {
00186 if (buf->len) {
00187 *buf->str = 0;
00188 buf->len = 0;
00189 }
00190 }
00191
00192 int av_bprint_finalize(AVBPrint *buf, char **ret_str)
00193 {
00194 unsigned real_size = FFMIN(buf->len + 1, buf->size);
00195 char *str;
00196 int ret = 0;
00197
00198 if (ret_str) {
00199 if (av_bprint_is_allocated(buf)) {
00200 str = av_realloc(buf->str, real_size);
00201 if (!str)
00202 str = buf->str;
00203 buf->str = NULL;
00204 } else {
00205 str = av_malloc(real_size);
00206 if (str)
00207 memcpy(str, buf->str, real_size);
00208 else
00209 ret = AVERROR(ENOMEM);
00210 }
00211 *ret_str = str;
00212 } else {
00213 if (av_bprint_is_allocated(buf))
00214 av_freep(&buf->str);
00215 }
00216 buf->size = real_size;
00217 return ret;
00218 }
00219
00220 #ifdef TEST
00221
00222 #undef printf
00223
00224 static void bprint_pascal(AVBPrint *b, unsigned size)
00225 {
00226 unsigned i, j;
00227 unsigned p[42];
00228
00229 av_assert0(size < FF_ARRAY_ELEMS(p));
00230
00231 p[0] = 1;
00232 av_bprintf(b, "%8d\n", 1);
00233 for (i = 1; i <= size; i++) {
00234 p[i] = 1;
00235 for (j = i - 1; j > 0; j--)
00236 p[j] = p[j] + p[j - 1];
00237 for (j = 0; j <= i; j++)
00238 av_bprintf(b, "%8d", p[j]);
00239 av_bprintf(b, "\n");
00240 }
00241 }
00242
00243 int main(void)
00244 {
00245 AVBPrint b;
00246 char buf[256];
00247 struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 };
00248
00249 av_bprint_init(&b, 0, -1);
00250 bprint_pascal(&b, 5);
00251 printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
00252 printf("%s\n", b.str);
00253 av_bprint_finalize(&b, NULL);
00254
00255 av_bprint_init(&b, 0, -1);
00256 bprint_pascal(&b, 25);
00257 printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
00258 av_bprint_finalize(&b, NULL);
00259
00260 av_bprint_init(&b, 0, 2048);
00261 bprint_pascal(&b, 25);
00262 printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
00263 av_bprint_finalize(&b, NULL);
00264
00265 av_bprint_init(&b, 0, 1);
00266 bprint_pascal(&b, 5);
00267 printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
00268
00269 av_bprint_init(&b, 0, 1);
00270 bprint_pascal(&b, 25);
00271 printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str)/8*8, b.len);
00272
00273
00274 av_bprint_init(&b, 0, 0);
00275 bprint_pascal(&b, 25);
00276 printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b.str), b.len);
00277
00278 av_bprint_init_for_buffer(&b, buf, sizeof(buf));
00279 bprint_pascal(&b, 25);
00280 printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len);
00281
00282 av_bprint_init(&b, 0, -1);
00283 av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
00284 printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
00285 av_bprint_finalize(&b, NULL);
00286
00287 av_bprint_init(&b, 0, 8);
00288 av_bprint_strftime(&b, "%Y-%m-%d", &testtime);
00289 printf("strftime truncated: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str);
00290
00291 return 0;
00292 }
00293
00294 #endif