summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gardiner <paul@glidos.net>2012-05-31 16:38:54 +0100
committerRobin Watts <robin.watts@artifex.com>2012-06-12 16:55:29 +0100
commit15f43c4cccc960559ea6967c7fe1439cde54b0aa (patch)
tree0a9385cb96ef1e37d7fed5b158739494bf367bb6
parent2dfb38a5d55737e0bfaca9af5f77f17b3bde8f41 (diff)
downloadmupdf-15f43c4cccc960559ea6967c7fe1439cde54b0aa.tar.xz
A few general utility functions added for the sake of the forms work
-rw-r--r--fitz/fitz-internal.h7
-rw-r--r--fitz/fitz.h2
-rw-r--r--fitz/stm_buffer.c15
-rw-r--r--pdf/mupdf-internal.h8
-rw-r--r--pdf/mupdf.h9
-rw-r--r--pdf/pdf_lex.c52
-rw-r--r--pdf/pdf_object.c179
-rw-r--r--pdf/pdf_stream.c2
-rw-r--r--pdf/pdf_xobject.c120
-rw-r--r--pdf/pdf_xref.c14
10 files changed, 405 insertions, 3 deletions
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 05d7b52f..2f7f8041 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -419,6 +419,13 @@ void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits);
void fz_write_buffer_pad(fz_context *ctx, fz_buffer *buf);
+/*
+ fz_buffer_printf: print formatted to a buffer. The buffer will
+ grow, but the caller must ensure that no more than 256 bytes are
+ added to the buffer per call.
+*/
+void fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, char *fmt, ...);
+
struct fz_stream_s
{
fz_context *ctx;
diff --git a/fitz/fitz.h b/fitz/fitz.h
index ee00b2ed..a66976af 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -403,7 +403,7 @@ void *fz_calloc(fz_context *ctx, unsigned int count, unsigned int size);
exception on failure to allocate.
*/
#define fz_malloc_struct(CTX, STRUCT) \
- Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT)
+ ((STRUCT *)Memento_label(fz_calloc(CTX,1,sizeof(STRUCT)), #STRUCT))
/*
fz_malloc_array: Allocate a block of (non zeroed) memory (with
diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c
index 58539bf8..d14b738f 100644
--- a/fitz/stm_buffer.c
+++ b/fitz/stm_buffer.c
@@ -159,3 +159,18 @@ void fz_write_buffer_pad(fz_context *ctx, fz_buffer *buf)
{
buf->unused_bits = 0;
}
+
+void
+fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ /* Caller guarantees not to generate more than 256 bytes per call */
+ while(buffer->cap - buffer->len < 256)
+ fz_grow_buffer(ctx, buffer);
+
+ buffer->len += vsprintf(buffer->data + buffer->len, fmt, args);
+
+ va_end(args);
+}
diff --git a/pdf/mupdf-internal.h b/pdf/mupdf-internal.h
index aa4334b7..b178494c 100644
--- a/pdf/mupdf-internal.h
+++ b/pdf/mupdf-internal.h
@@ -135,6 +135,11 @@ pdf_obj *pdf_parse_stm_obj(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf);
pdf_obj *pdf_parse_ind_obj(pdf_document *doc, fz_stream *f, pdf_lexbuf *buf, int *num, int *gen, int *stm_ofs);
/*
+ pdf_print_token: print a lexed token to a buffer, growing if necessary
+*/
+void pdf_print_token(fz_context *ctx, fz_buffer *buf, int tok, pdf_lexbuf *lex);
+
+/*
* xref and object / stream api
*/
@@ -296,8 +301,11 @@ struct pdf_xobject_s
};
pdf_xobject *pdf_load_xobject(pdf_document *doc, pdf_obj *obj);
+pdf_obj *pdf_new_xobject(pdf_document *doc, fz_rect *bbox, fz_matrix *mat);
pdf_xobject *pdf_keep_xobject(fz_context *ctx, pdf_xobject *xobj);
void pdf_drop_xobject(fz_context *ctx, pdf_xobject *xobj);
+void pdf_xobject_set_contents(pdf_document *xref, pdf_xobject *from, fz_buffer *buffer);
+
/*
* CMap
diff --git a/pdf/mupdf.h b/pdf/mupdf.h
index bda0e2fa..10cc6f08 100644
--- a/pdf/mupdf.h
+++ b/pdf/mupdf.h
@@ -22,6 +22,8 @@ pdf_obj *pdf_new_string(fz_context *ctx, char *str, int len);
pdf_obj *pdf_new_indirect(fz_context *ctx, int num, int gen, void *doc);
pdf_obj *pdf_new_array(fz_context *ctx, int initialcap);
pdf_obj *pdf_new_dict(fz_context *ctx, int initialcap);
+pdf_obj *pdf_new_rect(fz_context *ctx, fz_rect *rect);
+pdf_obj *pdf_new_matrix(fz_context *ctx, fz_matrix *mtx);
pdf_obj *pdf_copy_array(fz_context *ctx, pdf_obj *array);
pdf_obj *pdf_copy_dict(fz_context *ctx, pdf_obj *dict);
@@ -70,9 +72,11 @@ pdf_obj *pdf_dict_get_key(pdf_obj *dict, int idx);
pdf_obj *pdf_dict_get_val(pdf_obj *dict, int idx);
pdf_obj *pdf_dict_get(pdf_obj *dict, pdf_obj *key);
pdf_obj *pdf_dict_gets(pdf_obj *dict, char *key);
+pdf_obj *pdf_dict_getp(pdf_obj *dict, char *key);
pdf_obj *pdf_dict_getsa(pdf_obj *dict, char *key, char *abbrev);
void pdf_dict_put(pdf_obj *dict, pdf_obj *key, pdf_obj *val);
void pdf_dict_puts(pdf_obj *dict, char *key, pdf_obj *val);
+void pdf_dict_putp(pdf_obj *dict, char *key, pdf_obj *val);
void pdf_dict_del(pdf_obj *dict, pdf_obj *key);
void pdf_dict_dels(pdf_obj *dict, char *key);
void pdf_sort_dict(pdf_obj *dict);
@@ -118,6 +122,11 @@ void pdf_delete_object(pdf_document *xref, int num);
void pdf_update_object(pdf_document *xref, int num, pdf_obj *obj);
/*
+ pdf_get_stream: Return the contents for object in xref table
+*/
+fz_buffer *pdf_get_stream(pdf_document *xref, int num);
+
+/*
pdf_update_stream: Replace stream contents for object in xref table with the passed in buffer.
The buffer contents must match the /Filter setting.
diff --git a/pdf/pdf_lex.c b/pdf/pdf_lex.c
index 6774167a..c6ab6604 100644
--- a/pdf/pdf_lex.c
+++ b/pdf/pdf_lex.c
@@ -461,3 +461,55 @@ pdf_lex(fz_stream *f, pdf_lexbuf *buf)
}
}
}
+
+void pdf_print_token(fz_context *ctx, fz_buffer *fzbuf, int tok, pdf_lexbuf *buf)
+{
+ switch(tok)
+ {
+ case PDF_TOK_NAME:
+ fz_buffer_printf(ctx, fzbuf, "/%s", buf->scratch);
+ break;
+ case PDF_TOK_STRING:
+ {
+ int i;
+ fz_buffer_printf(ctx, fzbuf, "<");
+ for (i = 0; i < buf->len; i++)
+ fz_buffer_printf(ctx, fzbuf, "%02X", buf->scratch[i]);
+ fz_buffer_printf(ctx, fzbuf, ">");
+ }
+ break;
+ case PDF_TOK_OPEN_DICT:
+ fz_buffer_printf(ctx, fzbuf, "<<");
+ break;
+ case PDF_TOK_CLOSE_DICT:
+ fz_buffer_printf(ctx, fzbuf, ">>");
+ break;
+ case PDF_TOK_OPEN_ARRAY:
+ fz_buffer_printf(ctx, fzbuf, "[");
+ break;
+ case PDF_TOK_CLOSE_ARRAY:
+ fz_buffer_printf(ctx, fzbuf, "]");
+ break;
+ case PDF_TOK_OPEN_BRACE:
+ fz_buffer_printf(ctx, fzbuf, "{");
+ break;
+ case PDF_TOK_CLOSE_BRACE:
+ fz_buffer_printf(ctx, fzbuf, "}");
+ break;
+ case PDF_TOK_INT:
+ fz_buffer_printf(ctx, fzbuf, "%d", buf->i);
+ break;
+ case PDF_TOK_REAL:
+ {
+ char sbuf[256];
+ sprintf(sbuf, "%g", buf->f);
+ if (strchr(sbuf, 'e')) /* bad news! */
+ sprintf(sbuf, fabsf(buf->f) > 1 ? "%1.1f" : "%1.8f", buf->f);
+ fz_buffer_printf(ctx, fzbuf, "%s", sbuf);
+ }
+ break;
+ default:
+ fz_buffer_printf(ctx, fzbuf, "%s", buf->scratch);
+ break;
+ }
+}
diff --git a/pdf/pdf_object.c b/pdf/pdf_object.c
index cc5cc662..60f10a54 100644
--- a/pdf/pdf_object.c
+++ b/pdf/pdf_object.c
@@ -567,6 +567,98 @@ pdf_array_contains(pdf_obj *arr, pdf_obj *obj)
return 0;
}
+pdf_obj *pdf_new_rect(fz_context *ctx, fz_rect *rect)
+{
+ pdf_obj *arr = NULL;
+ pdf_obj *item = NULL;
+
+ fz_var(arr);
+ fz_var(item);
+ fz_try(ctx)
+ {
+ arr = pdf_new_array(ctx, 4);
+
+ item = pdf_new_real(ctx, rect->x0);
+ pdf_array_put(arr, 0, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, rect->y0);
+ pdf_array_put(arr, 1, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, rect->x1 - rect->x0);
+ pdf_array_put(arr, 2, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, rect->y1 - rect->y0);
+ pdf_array_put(arr, 3, item);
+ pdf_drop_obj(item);
+ item = NULL;
+ }
+ fz_catch(ctx)
+ {
+ pdf_drop_obj(item);
+ pdf_drop_obj(arr);
+ fz_rethrow(ctx);
+ }
+
+ return arr;
+}
+
+pdf_obj *pdf_new_matrix(fz_context *ctx, fz_matrix *mtx)
+{
+ pdf_obj *arr = NULL;
+ pdf_obj *item = NULL;
+
+ fz_var(arr);
+ fz_var(item);
+ fz_try(ctx)
+ {
+ arr = pdf_new_array(ctx, 6);
+
+ item = pdf_new_real(ctx, mtx->a);
+ pdf_array_put(arr, 0, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, mtx->b);
+ pdf_array_put(arr, 1, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, mtx->c);
+ pdf_array_put(arr, 2, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, mtx->d);
+ pdf_array_put(arr, 3, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, mtx->e);
+ pdf_array_put(arr, 4, item);
+ pdf_drop_obj(item);
+ item = NULL;
+
+ item = pdf_new_real(ctx, mtx->f);
+ pdf_array_put(arr, 5, item);
+ pdf_drop_obj(item);
+ item = NULL;
+ }
+ fz_catch(ctx)
+ {
+ pdf_drop_obj(item);
+ pdf_drop_obj(arr);
+ fz_rethrow(ctx);
+ }
+
+ return arr;
+}
+
/* dicts may only have names as keys! */
static int keyvalcmp(const void *ap, const void *bp)
@@ -743,6 +835,36 @@ pdf_dict_gets(pdf_obj *obj, char *key)
}
pdf_obj *
+pdf_dict_getp(pdf_obj *obj, char *keys)
+{
+ char buf[256];
+ char *k, *e;
+
+ if (strlen(keys)+1 > 256)
+ fz_throw(obj->ctx, "buffer overflow in pdf_dict_getp");
+
+ strcpy(buf, keys);
+
+ e = buf;
+ while (*e && obj)
+ {
+ k = e;
+ while (*e != '/' && *e != '\0')
+ e++;
+
+ if (*e == '/')
+ {
+ *e = '\0';
+ e++;
+ }
+
+ obj = pdf_dict_gets(obj, k);
+ }
+
+ return obj;
+}
+
+pdf_obj *
pdf_dict_get(pdf_obj *obj, pdf_obj *key)
{
if (!key || key->kind != PDF_NAME)
@@ -829,6 +951,63 @@ pdf_dict_puts(pdf_obj *obj, char *key, pdf_obj *val)
}
void
+pdf_dict_putp(pdf_obj *obj, char *keys, pdf_obj *val)
+{
+ fz_context *ctx = obj->ctx;
+ char buf[256];
+ char *k, *e;
+ pdf_obj *cobj = NULL;
+
+ if (strlen(keys)+1 > 256)
+ fz_throw(obj->ctx, "buffer overflow in pdf_dict_getp");
+
+ strcpy(buf, keys);
+
+ e = buf;
+ while (*e)
+ {
+ k = e;
+ while (*e != '/' && *e != '\0')
+ e++;
+
+ if (*e == '/')
+ {
+ *e = '\0';
+ e++;
+ }
+
+ if (*e)
+ {
+ /* Not the last key in the key path. Create subdict if not already there. */
+ cobj = pdf_dict_gets(obj, k);
+ if (cobj == NULL)
+ {
+ cobj = pdf_new_dict(ctx, 1);
+ fz_try(ctx)
+ {
+ pdf_dict_puts(obj, k, cobj);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(cobj);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+ }
+ /* Move to subdict */
+ obj = cobj;
+ }
+ else
+ {
+ /* Last key. Use it to store the value */
+ pdf_dict_puts(obj, k, val);
+ }
+ }
+}
+
+void
pdf_dict_dels(pdf_obj *obj, char *key)
{
RESOLVE(obj);
diff --git a/pdf/pdf_stream.c b/pdf/pdf_stream.c
index fcf9acdc..829210ea 100644
--- a/pdf/pdf_stream.c
+++ b/pdf/pdf_stream.c
@@ -358,7 +358,7 @@ pdf_open_image_stream(pdf_document *xref, int num, int gen, int orig_num, int or
pdf_cache_object(xref, num, gen);
/* RJW: "cannot load stream object (%d %d R)", num, gen */
- if (x->stm_ofs == 0)
+ if (x->stm_ofs == 0 && x->stm_buf == NULL)
fz_throw(xref->ctx, "object is not a stream");
return pdf_open_filter(xref->file, xref, x->obj, orig_num, orig_gen, x->stm_ofs, params);
diff --git a/pdf/pdf_xobject.c b/pdf/pdf_xobject.c
index 1de0b20e..88ab5a01 100644
--- a/pdf/pdf_xobject.c
+++ b/pdf/pdf_xobject.c
@@ -23,7 +23,6 @@ pdf_free_xobject_imp(fz_context *ctx, fz_storable *xobj_)
if (xobj->resources)
pdf_drop_obj(xobj->resources);
if (xobj->contents)
- //fz_drop_buffer(ctx, xobj->contents);
pdf_drop_obj(xobj->contents);
pdf_drop_obj(xobj->me);
fz_free(ctx, xobj);
@@ -111,3 +110,122 @@ pdf_load_xobject(pdf_document *xref, pdf_obj *dict)
return form;
}
+
+pdf_obj *
+pdf_new_xobject(pdf_document *xref, fz_rect *bbox, fz_matrix *mat)
+{
+ int idict_num;
+ pdf_obj *idict = NULL;
+ pdf_obj *dict = NULL;
+ pdf_xobject *form = NULL;
+ pdf_obj *obj = NULL;
+ pdf_obj *res = NULL;
+ pdf_obj *procset = NULL;
+ fz_context *ctx = xref->ctx;
+
+ fz_var(idict);
+ fz_var(dict);
+ fz_var(form);
+ fz_var(obj);
+ fz_var(res);
+ fz_var(procset);
+ fz_try(ctx)
+ {
+ dict = pdf_new_dict(ctx, 0);
+
+ obj = pdf_new_rect(ctx, bbox);
+ pdf_dict_puts(dict, "BBox", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ obj = pdf_new_int(ctx, 1);
+ pdf_dict_puts(dict, "FormType", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ obj = pdf_new_int(ctx, 0);
+ pdf_dict_puts(dict, "Length", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ obj = pdf_new_matrix(ctx, mat);
+ pdf_dict_puts(dict, "Matrix", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ res = pdf_new_dict(ctx, 0);
+ procset = pdf_new_array(ctx, 2);
+ obj = fz_new_name(ctx, "PDF");
+ pdf_array_put(procset, 0, obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+ obj = fz_new_name(ctx, "Text");
+ pdf_array_put(procset, 1, obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+ pdf_dict_puts(res, "ProcSet", procset);
+ pdf_drop_obj(procset);
+ procset = NULL;
+ pdf_dict_puts(dict, "Resources", res);
+
+ obj = fz_new_name(ctx, "Form");
+ pdf_dict_puts(dict, "Subtype", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ obj = fz_new_name(ctx, "XObject");
+ pdf_dict_puts(dict, "Type", obj);
+ pdf_drop_obj(obj);
+ obj = NULL;
+
+ form = fz_malloc_struct(ctx, pdf_xobject);
+ FZ_INIT_STORABLE(form, 1, pdf_free_xobject_imp);
+ form->resources = NULL;
+ form->contents = NULL;
+ form->colorspace = NULL;
+ form->me = NULL;
+
+ form->bbox = *bbox;
+
+ form->matrix = fz_identity;
+
+ form->isolated = 0;
+ form->knockout = 0;
+ form->transparency = 0;
+
+ form->resources = res;
+ res = NULL;
+
+ idict_num = pdf_create_object(xref);
+ pdf_update_object(xref, idict_num, dict);
+ idict = pdf_new_indirect(ctx, idict_num, 0, xref);
+ pdf_drop_obj(dict);
+ dict = NULL;
+
+ pdf_store_item(ctx, idict, form, pdf_xobject_size(form));
+
+ form->contents = pdf_keep_obj(idict);
+ form->me = pdf_keep_obj(idict);
+
+ pdf_drop_xobject(ctx, form);
+ form = NULL;
+ }
+ fz_catch(ctx)
+ {
+ pdf_drop_obj(procset);
+ pdf_drop_obj(res);
+ pdf_drop_obj(obj);
+ pdf_drop_obj(dict);
+ pdf_drop_obj(idict);
+ pdf_drop_xobject(ctx, form);
+ fz_throw(ctx, "failed to create xobject)");
+ }
+
+ return idict;
+}
+
+void pdf_xobject_set_contents(pdf_document *xref, pdf_xobject *form, fz_buffer *buffer)
+{
+ pdf_dict_dels(form->contents, "Filter");
+ pdf_update_stream(xref, pdf_to_num(form->contents), buffer);
+}
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index 9b8a3ee8..af72bc09 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -1135,6 +1135,20 @@ pdf_update_object(pdf_document *xref, int num, pdf_obj *newobj)
x->ofs = 0;
x->obj = pdf_keep_obj(newobj);
}
+
+fz_buffer *
+pdf_get_stream(pdf_document *xref, int num)
+{
+ pdf_xref_entry *x;
+
+ if (num < 0 || num >= xref->len)
+ fz_throw(xref->ctx, "object out of range (%d 0 R); xref size %d", num, xref->len);
+
+ x = &xref->table[num];
+
+ return x->stm_buf;
+}
+
void
pdf_update_stream(pdf_document *xref, int num, fz_buffer *newbuf)
{