summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/fitz/output.h16
-rw-r--r--include/mupdf/fitz/system.h3
-rw-r--r--platform/win32/libmupdf.vcproj4
-rw-r--r--scripts/cmapdump.c1
-rw-r--r--source/fitz/buffer.c44
-rw-r--r--source/fitz/output.c2
-rw-r--r--source/fitz/printf.c258
-rw-r--r--source/pdf/pdf-appearance.c2
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";