From 6a8abce9603f69b57e407f0df4044be919f507d7 Mon Sep 17 00:00:00 2001 From: Chris Liddell Date: Tue, 13 May 2014 15:16:59 +0100 Subject: Add an application agnostic memory handler for libjpeg This adds a custom memory management layer between libjpeg and the calling app - in such a way that the code can be shared between mupdf and Ghostscript/PDL. --- source/fitz/filter-dct.c | 70 +++++++++++++++++++- source/fitz/jmemcust.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++ source/fitz/jmemcust.h | 56 ++++++++++++++++ source/fitz/load-jpeg.c | 62 +++++++++++++++++ 4 files changed, 353 insertions(+), 3 deletions(-) create mode 100644 source/fitz/jmemcust.c create mode 100644 source/fitz/jmemcust.h (limited to 'source') diff --git a/source/fitz/filter-dct.c b/source/fitz/filter-dct.c index 86268032..b72c7ce6 100644 --- a/source/fitz/filter-dct.c +++ b/source/fitz/filter-dct.c @@ -1,6 +1,8 @@ #include "mupdf/fitz.h" #include +typedef void * backing_store_ptr; +#include "jmemcust.h" #include typedef struct fz_dctd_s fz_dctd; @@ -26,9 +28,66 @@ struct fz_dctd_s unsigned char buffer[4096]; }; +#ifdef SHARE_JPEG + +#define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)(c->client_data) + +#define fz_dct_mem_init(st) +#define fz_dct_mem_term(st) + +#else /* SHARE_JPEG */ + +#define JZ_DCT_STATE_FROM_CINFO(c) (fz_dctd *)(GET_CUST_MEM_DATA(c)->priv) + +static void * +fz_dct_mem_alloc(j_common_ptr cinfo, size_t size) +{ + fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); + return fz_malloc(state->ctx, size); +} + +static void +fz_dct_mem_free(j_common_ptr cinfo, void *object, size_t size) +{ + fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); + UNUSED(size); + fz_free(state->ctx, object); +} + +static void +fz_dct_mem_init(fz_dctd *state) +{ + j_common_ptr cinfo = (j_common_ptr)&state->cinfo; + jpeg_cust_mem_data *custmptr; + + custmptr = fz_malloc_struct(state->ctx, jpeg_cust_mem_data); + + if (!jpeg_cust_mem_init(custmptr, (void *) state, NULL, NULL, NULL, + fz_dct_mem_alloc, fz_dct_mem_free, + fz_dct_mem_alloc, fz_dct_mem_free, NULL)) + { + fz_free(state->ctx, custmptr); + fz_throw(state->ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler"); + } + + cinfo->client_data = custmptr; +} + +static void +fz_dct_mem_term(fz_dctd *state) +{ + if(state->cinfo.client_data) + { + fz_free(state->ctx, state->cinfo.client_data); + state->cinfo.client_data = NULL; + } +} + +#endif /* SHARE_JPEG */ + static void error_exit(j_common_ptr cinfo) { - fz_dctd *state = cinfo->client_data; + fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); cinfo->err->format_message(cinfo, state->msg); longjmp(state->jb, 1); } @@ -46,11 +105,10 @@ static void term_source(j_decompress_ptr cinfo) static boolean fill_input_buffer(j_decompress_ptr cinfo) { struct jpeg_source_mgr *src = cinfo->src; - fz_dctd *state = cinfo->client_data; + fz_dctd *state = JZ_DCT_STATE_FROM_CINFO(cinfo); fz_stream *curr_stm = state->curr_stm; fz_context *ctx = curr_stm->ctx; - curr_stm->rp = curr_stm->wp; fz_try(ctx) { @@ -115,6 +173,9 @@ next_dctd(fz_stream *stm, int max) cinfo->err = &state->errmgr; jpeg_std_error(cinfo->err); cinfo->err->error_exit = error_exit; + + fz_dct_mem_init(state); + jpeg_create_decompress(cinfo); state->init = 1; @@ -237,6 +298,8 @@ skip: if (state->init) jpeg_destroy_decompress(&state->cinfo); + fz_dct_mem_term(state); + fz_free(ctx, state->scanline); fz_close(state->chain); fz_close(state->jpegtables); @@ -269,6 +332,7 @@ fz_open_dctd(fz_stream *chain, int color_transform, int l2factor, fz_stream *jpe state->color_transform = color_transform; state->init = 0; state->l2factor = l2factor; + state->cinfo.client_data = NULL; } fz_catch(ctx) { diff --git a/source/fitz/jmemcust.c b/source/fitz/jmemcust.c new file mode 100644 index 00000000..c8764509 --- /dev/null +++ b/source/fitz/jmemcust.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2001-2014 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, + CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +#if !defined(SHARE_JPEG) || SHARE_JPEG==0 + +#include "jinclude.h" +#include "jpeglib.h" +#include "jmorecfg.h" +#include "jmemsys.h" +#include "jerror.h" +#include "jmemcust.h" + +GLOBAL(void *) +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + return (void *) (cmem->j_mem_get_small)(cinfo, sizeofobject); +} + +GLOBAL(void) +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + (cmem->j_mem_free_small)(cinfo, object, sizeofobject); +} + +/* + * "Large" objects are treated the same as "small" ones. + * NB: although we include FAR keywords in the routine declarations, + * this file won't actually work in 80x86 small/medium model; at least, + * you probably won't be able to process useful-size images in only 64KB. + */ + +GLOBAL(void FAR *) +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + return (void *) (cmem->j_mem_get_large)(cinfo, sizeofobject); +} + +GLOBAL(void) +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + (cmem->j_mem_free_large)(cinfo, object, sizeofobject); +} + +/* + * This routine computes the total memory space available for allocation. + * Here we always say, "we got all you want bud!" + */ + +GLOBAL(long) +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + long max_bytes_needed, long already_allocated) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + long ret = max_bytes_needed; + + if (cmem->j_mem_avail) + ret = (cmem->j_mem_avail)(cinfo); + + return ret; +} + +/* + * Backing store (temporary file) management. + * Since jpeg_mem_available always promised the moon, + * this should never be called and we can just error out. + */ + +GLOBAL(void) +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + long total_bytes_needed) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + if (cmem->j_mem_open_backing_store) { + (cmem->j_mem_open_backing_store)(cinfo, info, total_bytes_needed); + } + else + ERREXIT(cinfo, JERR_NO_BACKING_STORE); +} + +/* + * These routines take care of any system-dependent initialization and + * cleanup required. Here, there isn't any. + */ + +GLOBAL(long) +jpeg_mem_init (j_common_ptr cinfo) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + long ret = 0; + + if (cmem->j_mem_init) + ret = (cmem->j_mem_init)(cinfo); + + return ret; +} + +GLOBAL(void) +jpeg_mem_term (j_common_ptr cinfo) +{ + jpeg_cust_mem_data *cmem = GET_CUST_MEM_DATA(cinfo); + + if (cmem->j_mem_term) + (cmem->j_mem_term)(cinfo); +} + +GLOBAL(jpeg_cust_mem_data *) +jpeg_cust_mem_init(jpeg_cust_mem_data *custm, void *priv, + j_custmem_init_ptr init, + j_custmem_term_ptr term, + j_custmem_avail_ptr avail, + j_custmem_get_small_ptr get_small, + j_custmem_free_small_ptr free_small, + j_cust_mem_get_large_ptr get_large, + j_custmem_free_large_ptr free_large, + j_custmem_open_backing_store_ptr open_backing_store) +{ + jpeg_cust_mem_data *lcustm = NULL; + + /* We need at least the following for a viable memory manager */ + if (get_small && free_small && get_large && free_large) + { + lcustm = custm; + + lcustm->priv = priv; + lcustm->j_mem_init = init; + lcustm->j_mem_term = term; + lcustm->j_mem_avail = avail; + lcustm->j_mem_get_small = get_small; + lcustm->j_mem_free_small = free_small; + lcustm->j_mem_get_large = get_large; + lcustm->j_mem_free_large = free_large; + lcustm->j_mem_open_backing_store = open_backing_store; + } + return lcustm; +} + +GLOBAL(jpeg_cust_mem_data *) +jpeg_cust_mem_set_private(jpeg_cust_mem_data *custm, void *priv) +{ + if (custm) + { + custm->priv = priv; + } + return custm; +} + +#endif /* !defined(SHARE_JPEG) || SHARE_JPEG==0 */ diff --git a/source/fitz/jmemcust.h b/source/fitz/jmemcust.h new file mode 100644 index 00000000..6371113e --- /dev/null +++ b/source/fitz/jmemcust.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2001-2014 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael, + CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +typedef JMETHOD(long, j_custmem_init_ptr, (j_common_ptr cinfo)); +typedef JMETHOD(void, j_custmem_term_ptr, (j_common_ptr cinfo)); +typedef JMETHOD(long, j_custmem_avail_ptr, (j_common_ptr cinfo)); +typedef JMETHOD(void *, j_custmem_get_small_ptr, + (j_common_ptr cinfo, size_t size)); +typedef JMETHOD(void, j_custmem_free_small_ptr, + (j_common_ptr cinfo, void *object, size_t size)); +typedef JMETHOD(void *, j_cust_mem_get_large_ptr, + (j_common_ptr cinfo, size_t size)); +typedef JMETHOD(void, j_custmem_free_large_ptr, + (j_common_ptr cinfo, void *object, size_t size)); +typedef JMETHOD(void, j_custmem_open_backing_store_ptr, + (j_common_ptr cinfo, backing_store_ptr info, long total_bytes_needed)); + +typedef struct { + j_custmem_init_ptr j_mem_init; + j_custmem_term_ptr j_mem_term; + j_custmem_avail_ptr j_mem_avail; + j_custmem_get_small_ptr j_mem_get_small; + j_custmem_free_small_ptr j_mem_free_small; + j_cust_mem_get_large_ptr j_mem_get_large; + j_custmem_free_large_ptr j_mem_free_large; + j_custmem_open_backing_store_ptr j_mem_open_backing_store; + void *priv; +} jpeg_cust_mem_data; + +#define GET_CUST_MEM_DATA(c) ((jpeg_cust_mem_data *)c->client_data) + +GLOBAL(jpeg_cust_mem_data *) +jpeg_cust_mem_init(jpeg_cust_mem_data *custm, void *priv, + j_custmem_init_ptr init, + j_custmem_term_ptr term, + j_custmem_avail_ptr avail, + j_custmem_get_small_ptr get_small, + j_custmem_free_small_ptr free_small, + j_cust_mem_get_large_ptr get_large, + j_custmem_free_large_ptr free_large, + j_custmem_open_backing_store_ptr open_backing_store); + +GLOBAL(jpeg_cust_mem_data *) +jpeg_cust_mem_set_private(jpeg_cust_mem_data *custm, void *priv); diff --git a/source/fitz/load-jpeg.c b/source/fitz/load-jpeg.c index f3bffd63..15e6e713 100644 --- a/source/fitz/load-jpeg.c +++ b/source/fitz/load-jpeg.c @@ -1,6 +1,65 @@ #include "mupdf/fitz.h" #include +typedef void * backing_store_ptr; +#include "jmemcust.h" + +#ifdef SHARE_JPEG + +#define JZ_CTX_FROM_CINFO(c) (fz_context *)(c->client_data) + +#define fz_jpg_mem_init(ctx, cinfo) +#define fz_jpg_mem_term(cinfo) + +#else /* SHARE_JPEG */ + +#define JZ_CTX_FROM_CINFO(c) (fz_context *)(GET_CUST_MEM_DATA(c)->priv) + +static void * +fz_jpg_mem_alloc(j_common_ptr cinfo, size_t size) +{ + fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo); + return fz_malloc(ctx, size); +} + +static void +fz_jpg_mem_free(j_common_ptr cinfo, void *object, size_t size) +{ + fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo); + UNUSED(size); + fz_free(ctx, object); +} + +static void +fz_jpg_mem_init(fz_context *ctx, struct jpeg_decompress_struct *cinfo) +{ + jpeg_cust_mem_data *custmptr; + + custmptr = fz_malloc_struct(ctx, jpeg_cust_mem_data); + + if (!jpeg_cust_mem_init(custmptr, (void *) ctx, NULL, NULL, NULL, + fz_jpg_mem_alloc, fz_jpg_mem_free, + fz_jpg_mem_alloc, fz_jpg_mem_free, NULL)) + { + fz_free(ctx, custmptr); + fz_throw(ctx, FZ_ERROR_GENERIC, "cannot initialize custom JPEG memory handler"); + } + + cinfo->client_data = custmptr; +} + +static void +fz_jpg_mem_term(struct jpeg_decompress_struct *cinfo) +{ + if(cinfo->client_data) + { + fz_context *ctx = JZ_CTX_FROM_CINFO(cinfo); + fz_free(ctx, cinfo->client_data); + cinfo->client_data = NULL; + } +} + +#endif /* SHARE_JPEG */ static void error_exit(j_common_ptr cinfo) { @@ -168,6 +227,8 @@ fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int * cinfo.err = jpeg_std_error(&err); err.error_exit = error_exit; + fz_jpg_mem_init(ctx, &cinfo); + jpeg_create_decompress(&cinfo); cinfo.src = &src; @@ -222,6 +283,7 @@ fz_load_jpeg_info(fz_context *ctx, unsigned char *rbuf, int rlen, int *xp, int * fz_always(ctx) { jpeg_destroy_decompress(&cinfo); + fz_jpg_mem_term(&cinfo); } fz_catch(ctx) { -- cgit v1.2.3