diff options
-rw-r--r-- | include/mupdf/fitz/output.h | 8 | ||||
-rw-r--r-- | platform/java/mupdf_native.c | 2 | ||||
-rw-r--r-- | source/fitz/output.c | 126 |
3 files changed, 115 insertions, 21 deletions
diff --git a/include/mupdf/fitz/output.h b/include/mupdf/fitz/output.h index 2530be47..e9e13c8e 100644 --- a/include/mupdf/fitz/output.h +++ b/include/mupdf/fitz/output.h @@ -80,6 +80,7 @@ struct fz_output_s fz_output_close_fn *close; fz_output_drop_fn *drop; fz_stream_from_output_fn *as_stream; + char *bp, *wp, *ep; }; /* @@ -93,7 +94,7 @@ struct fz_output_s close: Cleanup function to destroy state when output closed. May permissibly be null. */ -fz_output *fz_new_output(fz_context *ctx, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop); +fz_output *fz_new_output(fz_context *ctx, int bufsiz, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop); /* fz_new_output_with_path: Open an output stream that writes to a @@ -171,6 +172,11 @@ void fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence); int64_t fz_tell_output(fz_context *ctx, fz_output *out); /* + fz_flush_output: Flush unwritten data. +*/ +void fz_flush_output(fz_context *ctx, fz_output *out); + +/* fz_close_output: Flush pending output and close an output stream. */ void fz_close_output(fz_context *, fz_output *); diff --git a/platform/java/mupdf_native.c b/platform/java/mupdf_native.c index 915e6b58..32ba75ef 100644 --- a/platform/java/mupdf_native.c +++ b/platform/java/mupdf_native.c @@ -7100,7 +7100,7 @@ FUN(PDFDocument_nativeSaveWithStream)(JNIEnv *env, jobject self, jobject jstream state->stream = stream; state->array = array; - out = fz_new_output(ctx, state, call_SeekableOutputStream_write, call_SeekableOutputStream_close, call_SeekableOutputStream_drop); + out = fz_new_output(ctx, 8192, state, call_SeekableOutputStream_write, call_SeekableOutputStream_close, call_SeekableOutputStream_drop); out->seek = call_SeekableOutputStream_seek; out->tell = call_SeekableOutputStream_tell; diff --git a/source/fitz/output.c b/source/fitz/output.c index a8301a1e..4e3f39a3 100644 --- a/source/fitz/output.c +++ b/source/fitz/output.c @@ -61,7 +61,18 @@ fz_drop_output_context(fz_context *ctx) if (fz_drop_imp(ctx, ctx->output, &ctx->output->refs)) { - /* FIXME: should we flush here? closing the streams seems wrong */ + fz_try(ctx) + fz_flush_output(ctx, ctx->output->out); + fz_catch(ctx) + fz_warn(ctx, "cannot flush stdout"); + fz_drop_output(ctx, ctx->output->out); + + fz_try(ctx) + fz_flush_output(ctx, ctx->output->err); + fz_catch(ctx) + fz_warn(ctx, "cannot flush stderr"); + fz_drop_output(ctx, ctx->output->err); + fz_free(ctx, ctx->output); ctx->output = NULL; } @@ -167,10 +178,12 @@ file_as_stream(fz_context *ctx, void *opaque) }; fz_output * -fz_new_output(fz_context *ctx, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop) +fz_new_output(fz_context *ctx, int bufsiz, void *state, fz_output_write_fn *write, fz_output_close_fn *close, fz_output_drop_fn *drop) { fz_output *out = NULL; + fz_var(out); + fz_try(ctx) { out = fz_malloc_struct(ctx, fz_output); @@ -178,11 +191,18 @@ fz_new_output(fz_context *ctx, void *state, fz_output_write_fn *write, fz_output out->write = write; out->close = close; out->drop = drop; + if (bufsiz > 0) + { + out->bp = fz_malloc(ctx, bufsiz); + out->wp = out->bp; + out->ep = out->bp + bufsiz; + } } fz_catch(ctx) { if (drop) drop(ctx, state); + fz_free(ctx, out); fz_rethrow(ctx); } return out; @@ -219,7 +239,8 @@ fz_new_output_with_path(fz_context *ctx, const char *filename, int append) if (!file) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open file '%s': %s", filename, strerror(errno)); - out = fz_new_output(ctx, file, file_write, NULL, file_drop); + setvbuf(file, NULL, _IONBF, 0); /* we do our own buffering */ + out = fz_new_output(ctx, 8192, file, file_write, NULL, file_drop); out->seek = file_seek; out->tell = file_tell; out->as_stream = file_as_stream; @@ -257,7 +278,7 @@ buffer_drop(fz_context *ctx, void *opaque) fz_output * fz_new_output_with_buffer(fz_context *ctx, fz_buffer *buf) { - fz_output *out = fz_new_output(ctx, fz_keep_buffer(ctx, buf), buffer_write, NULL, buffer_drop); + fz_output *out = fz_new_output(ctx, 0, fz_keep_buffer(ctx, buf), buffer_write, NULL, buffer_drop); out->seek = buffer_seek; out->tell = buffer_tell; return out; @@ -267,6 +288,7 @@ void fz_close_output(fz_context *ctx, fz_output *out) { if (!out) return; + fz_flush_output(ctx, out); if (out->close) out->close(ctx, out->state); out->close = NULL; @@ -290,6 +312,7 @@ fz_seek_output(fz_context *ctx, fz_output *out, int64_t off, int whence) if (!out) return; if (out->seek == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot seek in unseekable output stream\n"); + fz_flush_output(ctx, out); out->seek(ctx, out->state, off, whence); } @@ -299,6 +322,8 @@ fz_tell_output(fz_context *ctx, fz_output *out) if (!out) return 0; if (out->tell == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot tell in untellable output stream\n"); + if (out->bp) + return out->tell(ctx, out->state) + (out->wp - out->bp); return out->tell(ctx, out->state); } @@ -308,6 +333,7 @@ fz_stream_from_output(fz_context *ctx, fz_output *out) if (!out) return 0; if (out->as_stream == NULL) fz_throw(ctx, FZ_ERROR_GENERIC, "Cannot derive input stream from output stream"); + fz_flush_output(ctx, out); return out->as_stream(ctx, out->state); } @@ -335,17 +361,86 @@ fz_write_printf(fz_context *ctx, fz_output *out, const char *fmt, ...) } void -fz_write_data(fz_context *ctx, fz_output *out, const void *data, size_t size) +fz_flush_output(fz_context *ctx, fz_output *out) +{ + if (out) + { + if (out->wp > out->bp) + { + out->write(ctx, out->state, out->bp, out->wp - out->bp); + out->wp = out->bp; + } + } +} + +void +fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x) +{ + if (out) + { + if (out->bp) + { + if (out->wp < out->ep) + { + *out->wp++ = x; + } + else + { + out->write(ctx, out->state, out->bp, out->wp - out->bp); + out->wp = out->bp; + } + } + else + { + out->write(ctx, out->state, &x, 1); + } + } +} + +void +fz_write_data(fz_context *ctx, fz_output *out, const void *data_, size_t size) { if (out) - out->write(ctx, out->state, data, size); + { + const char *data = data_; + + if (out->bp) + { + if (size >= out->ep - out->bp) /* too large for buffer */ + { + if (out->wp > out->bp) + { + out->write(ctx, out->state, out->bp, out->wp - out->bp); + out->wp = out->bp; + } + out->write(ctx, out->state, data, size); + } + else if (out->wp + size <= out->ep) /* fits in current buffer */ + { + memcpy(out->wp, data, size); + out->wp += size; + } + else /* fits if we flush first */ + { + size_t n = out->ep - out->wp; + memcpy(out->wp, data, n); + out->write(ctx, out->state, out->bp, out->ep - out->bp); + memcpy(out->bp, data + n, size - n); + out->wp = out->bp + size - n; + } + } + else + { + out->write(ctx, out->state, data, size); + } + } } void fz_write_string(fz_context *ctx, fz_output *out, const char *s) { if (out) - out->write(ctx, out->state, s, strlen(s)); + fz_write_data(ctx, out, s, strlen(s)); } void @@ -359,7 +454,7 @@ fz_write_int32_be(fz_context *ctx, fz_output *out, int x) data[3] = x; if (out) - out->write(ctx, out->state, data, 4); + fz_write_data(ctx, out, data, 4); } void @@ -373,7 +468,7 @@ fz_write_int32_le(fz_context *ctx, fz_output *out, int x) data[3] = x>>24; if (out) - out->write(ctx, out->state, data, 4); + fz_write_data(ctx, out, data, 4); } void @@ -385,7 +480,7 @@ fz_write_int16_be(fz_context *ctx, fz_output *out, int x) data[1] = x; if (out) - out->write(ctx, out->state, data, 2); + fz_write_data(ctx, out, data, 2); } void @@ -397,14 +492,7 @@ fz_write_int16_le(fz_context *ctx, fz_output *out, int x) data[1] = x>>8; if (out) - out->write(ctx, out->state, data, 2); -} - -void -fz_write_byte(fz_context *ctx, fz_output *out, unsigned char x) -{ - if (out) - out->write(ctx, out->state, &x, 1); + fz_write_data(ctx, out, data, 2); } void @@ -412,7 +500,7 @@ fz_write_rune(fz_context *ctx, fz_output *out, int rune) { char data[10]; if (out) - out->write(ctx, out->state, data, fz_runetochar(data, rune)); + fz_write_data(ctx, out, data, fz_runetochar(data, rune)); } void |