diff options
-rw-r--r-- | include/mupdf/fitz/output.h | 16 | ||||
-rw-r--r-- | include/mupdf/fitz/system.h | 3 | ||||
-rw-r--r-- | platform/win32/libmupdf.vcproj | 4 | ||||
-rw-r--r-- | scripts/cmapdump.c | 1 | ||||
-rw-r--r-- | source/fitz/buffer.c | 44 | ||||
-rw-r--r-- | source/fitz/output.c | 2 | ||||
-rw-r--r-- | source/fitz/printf.c | 258 | ||||
-rw-r--r-- | source/pdf/pdf-appearance.c | 2 |
8 files changed, 306 insertions, 24 deletions
diff --git a/include/mupdf/fitz/output.h b/include/mupdf/fitz/output.h index 8b171f87..01d4d227 100644 --- a/include/mupdf/fitz/output.h +++ b/include/mupdf/fitz/output.h @@ -90,4 +90,20 @@ fz_write_byte(fz_output *out, int x) fz_write(out, &data, 1); } +/* + fz_vsnprintf: Our customised vsnprintf routine. Takes %c, %d, %o, %s, %x, as usual. + Modifiers are not supported except for zero-padding ints (e.g. %02d, %03o, %04x, etc). + %f and %g both output in "as short as possible hopefully lossless non-exponent" form, + see fz_ftoa for specifics. + %C outputs a utf8 encoded int. + %M outputs a fz_matrix*. %R outputs a fz_rect*. %P outputs a fz_point*. +*/ +int fz_vsnprintf(char *buffer, int space, const char *fmt, va_list args); + +/* + fz_vfprintf: Our customised vfprintf routine. Same supported + format specifiers as for fz_vsnprintf. +*/ +int fz_vfprintf(fz_context *ctx, FILE *file, const char *fmt, va_list ap); + #endif diff --git a/include/mupdf/fitz/system.h b/include/mupdf/fitz/system.h index 2f4868f2..41f45245 100644 --- a/include/mupdf/fitz/system.h +++ b/include/mupdf/fitz/system.h @@ -85,7 +85,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); #define snprintf _snprintf #if _MSC_VER < 1800 -#define isnan _isnan +#define isnan(x) _isnan(x) +#define isinf(x) (!_finite(x)) #endif #define hypotf _hypotf diff --git a/platform/win32/libmupdf.vcproj b/platform/win32/libmupdf.vcproj index eae8e594..3b30d923 100644 --- a/platform/win32/libmupdf.vcproj +++ b/platform/win32/libmupdf.vcproj @@ -614,6 +614,10 @@ > </File> <File + RelativePath="..\..\source\fitz\printf.c" + > + </File> + <File RelativePath="..\..\source\fitz\shade.c" > </File> diff --git a/scripts/cmapdump.c b/scripts/cmapdump.c index a9e5de18..2e0e0852 100644 --- a/scripts/cmapdump.c +++ b/scripts/cmapdump.c @@ -15,6 +15,7 @@ #include "../source/fitz/buffer.c" #include "../source/fitz/stream-open.c" #include "../source/fitz/stream-read.c" +#include "../source/fitz/printf.c" #include "../source/pdf/pdf-lex.c" #include "../source/pdf/pdf-cmap.c" diff --git a/source/fitz/buffer.c b/source/fitz/buffer.c index 07ce9361..e9295a26 100644 --- a/source/fitz/buffer.c +++ b/source/fitz/buffer.c @@ -224,45 +224,47 @@ fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...) int ret; va_list args; va_start(args, fmt); - ret = fz_buffer_vprintf(ctx, buffer, fmt, args); - va_end(args); - return ret; } int fz_buffer_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list old_args) { + int slack; int len; + va_list args; + + slack = buffer->cap - buffer->len; +#ifdef _MSC_VER /* Microsoft Visual C */ + args = old_args; +#else + va_copy(args, old_args); +#endif + len = fz_vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); +#ifndef _MSC_VER + va_end(args); +#endif - do + /* len = number of chars written, not including the terminating + * NULL, so len+1 > slack means "truncated". */ + if (len+1 > slack) { - int slack = buffer->cap - buffer->len; + /* Grow the buffer and retry */ + fz_ensure_buffer(ctx, buffer, buffer->len + len); + slack = buffer->cap - buffer->len; - if (slack > 0) - { - va_list args; #ifdef _MSC_VER /* Microsoft Visual C */ - args = old_args; + args = old_args; #else - va_copy(args, old_args); + va_copy(args, old_args); #endif - len = vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); + len = fz_vsnprintf((char *)buffer->data + buffer->len, slack, fmt, args); #ifndef _MSC_VER - va_end(args); + va_end(args); #endif - /* len = number of chars written, not including the terminating - * NULL, so len+1 > slack means "truncated". MSVC differs here - * and returns -1 for truncated. */ - if (len >= 0 && len+1 <= slack) - break; - } - /* Grow the buffer and retry */ - fz_grow_buffer(ctx, buffer); } - while (1); buffer->len += len; diff --git a/source/fitz/output.c b/source/fitz/output.c index 5be0dccf..fe63de92 100644 --- a/source/fitz/output.c +++ b/source/fitz/output.c @@ -11,7 +11,7 @@ file_printf(fz_output *out, const char *fmt, va_list ap) { FILE *file = (FILE *)out->opaque; - return vfprintf(file, fmt, ap); + return fz_vfprintf(out->ctx, file, fmt, ap); } static int diff --git a/source/fitz/printf.c b/source/fitz/printf.c new file mode 100644 index 00000000..ef70aca1 --- /dev/null +++ b/source/fitz/printf.c @@ -0,0 +1,258 @@ +#include "mupdf/fitz.h" + +#ifdef _MSC_VER /* Microsoft Visual C */ +#define va_copy(a, oa) a=oa +#define va_end(a) +#endif + +struct fmtbuf +{ + char *p; + int s; + int n; +}; + +static void fmtputc(struct fmtbuf *out, int c) +{ + if (out->n < out->s) + out->p[out->n] = c; + ++(out->n); +} + +/* + * Compute decimal integer m, exp such that: + * f = m*10^exp + * m is as short as possible with losing exactness + * assumes special cases (NaN, +Inf, -Inf) have been handled. + */ +static void fz_dtoa(float f, char *digits, int *exp, int *neg, int *ndigits) +{ + char buf[20], *s, *p, *e; + int n; + + /* TODO: binary search */ + for (n = 1; n < 9; ++n) { + sprintf(buf, "%+.*e", n, f); + if (strtof(buf, NULL) == f) + break; + } + + *neg = (buf[0] == '-'); + + p = buf + 3; + e = strchr(p, 'e'); + *exp = atoi(e + 1) - (e - p); + + if (e[-1] == '0') { + --e; + ++(*exp); + } + + s = digits; + *s++ = buf[1]; + while (p < e) + *s++ = *p++; + *s = 0; + + *ndigits = s - digits; +} + +/* + * Convert float to shortest possible string that won't lose precision, except: + * NaN to 0, +Inf to FLT_MAX, -Inf to -FLT_MAX. + */ +static void fmtfloat(struct fmtbuf *out, float f) +{ + char digits[40], *s = digits; + int exp, neg, ndigits, point; + + if (isnan(f)) f = 0; + if (isinf(f)) f = f < 0 ? -FLT_MAX : FLT_MAX; + + fz_dtoa(f, digits, &exp, &neg, &ndigits); + point = exp + ndigits; + + if (neg) + fmtputc(out, '-'); + + if (point <= 0) + { + fmtputc(out, '.'); + while (point++ < 0) + fmtputc(out, '0'); + while (ndigits-- > 0) + fmtputc(out, *s++); + } + + else + { + while (ndigits-- > 0) + { + fmtputc(out, *s++); + if (--point == 0 && ndigits > 0) + fmtputc(out, '.'); + } + while (point-- > 0) + fmtputc(out, '0'); + } +} + +static void fmtint(struct fmtbuf *out, int value, int z, int base) +{ + static const char *digits = "0123456789abcdef"; + char buf[40]; + unsigned int a; + int i; + + if (value < 0) + { + fmtputc(out, '-'); + a = -value; + } + else + a = value; + + i = 0; + while (a) { + buf[i++] = digits[a % base]; + a /= base; + } + while (i < z) + buf[i++] = '0'; + while (i > 0) + fmtputc(out, buf[--i]); +} + +int +fz_vsnprintf(char *buffer, int space, const char *fmt, va_list args) +{ + struct fmtbuf out; + fz_matrix *m; + fz_rect *r; + fz_point *p; + int c, i, n, z; + double f; + char *s; + + out.p = buffer; + out.s = space; + out.n = 0; + + while ((c = *fmt++)) + { + if (c == '%') { + c = *fmt++; + if (c == 0) + break; + z = 1; + if (c == '0' && fmt[0] && fmt[1]) { + z = *fmt++ - '0'; + c = *fmt++; + } + switch (c) { + default: + fmtputc(&out, '%'); + fmtputc(&out, c); + break; + case '%': + fmtputc(&out, '%'); + break; + case 'M': + m = va_arg(args, fz_matrix*); + fmtfloat(&out, m->a); fmtputc(&out, ' '); + fmtfloat(&out, m->b); fmtputc(&out, ' '); + fmtfloat(&out, m->c); fmtputc(&out, ' '); + fmtfloat(&out, m->d); fmtputc(&out, ' '); + fmtfloat(&out, m->e); fmtputc(&out, ' '); + fmtfloat(&out, m->f); + break; + case 'R': + r = va_arg(args, fz_rect*); + fmtfloat(&out, r->x0); fmtputc(&out, ' '); + fmtfloat(&out, r->y0); fmtputc(&out, ' '); + fmtfloat(&out, r->x1); fmtputc(&out, ' '); + fmtfloat(&out, r->y1); + break; + case 'P': + p = va_arg(args, fz_point*); + fmtfloat(&out, p->x); fmtputc(&out, ' '); + fmtfloat(&out, p->y); + break; + case 'C': + c = va_arg(args, int); + if (c < 128) + fmtputc(&out, c); + else { + char buf[10]; + n = fz_runetochar(buf, c); + for (i=0; i < n; ++i) + fmtputc(&out, buf[i]); + } + break; + case 'c': + c = va_arg(args, int); + fmtputc(&out, c); + break; + case 'f': + case 'g': + f = va_arg(args, double); + fmtfloat(&out, f); + break; + case 'x': + i = va_arg(args, int); + fmtint(&out, i, z, 16); + break; + case 'd': + i = va_arg(args, int); + fmtint(&out, i, z, 10); + break; + case 'o': + i = va_arg(args, int); + fmtint(&out, i, z, 8); + break; + case 's': + s = va_arg(args, char*); + if (!s) + s = "(null)"; + while ((c = *s++)) + fmtputc(&out, c); + break; + } + } else { + fmtputc(&out, c); + } + } + + fmtputc(&out, 0); + return out.n - 1; +} + +int +fz_vfprintf(fz_context *ctx, FILE *file, const char *fmt, va_list old_args) +{ + char buffer[256]; + int l; + va_list args; + char *b = buffer; + + /* First try using our fixed size buffer */ + va_copy(args, old_args); + l = fz_vsnprintf(buffer, sizeof buffer, fmt, args); + va_end(args); + + /* If that failed, allocate the right size buffer dynamically */ + if (l >= sizeof buffer) + { + b = fz_malloc(ctx, l + 1); + va_copy(args, old_args); + fz_vsnprintf(buffer, l + 1, fmt, args); + va_end(args); + } + + l = fwrite(b, 1, l, file); + + if (b != buffer) + fz_free(ctx, b); + + return l; +} diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c index e1822331..2d1a6b54 100644 --- a/source/pdf/pdf-appearance.c +++ b/source/pdf/pdf-appearance.c @@ -56,7 +56,7 @@ static const char *fmt_q = "q\n"; static const char *fmt_W = "W\n"; static const char *fmt_n = "n\n"; static const char *fmt_BT = "BT\n"; -static const char *fmt_Tm = "%1.2f %1.2f %1.2f %1.2f %1.2f %1.2f Tm\n"; +static const char *fmt_Tm = "%f %f %f %f %f %f Tm\n"; static const char *fmt_Td = "%f %f Td\n"; static const char *fmt_Tj = " Tj\n"; static const char *fmt_ET = "ET\n"; |