1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
/* Copyright (C) 2001-2021 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., 1305 Grant Avenue - Suite 200, Novato,
CA 94945, U.S.A., +1(415)492-9861, for further information.
*/
/* this is the ps interpreter interface to the jbig2decode filter
used for (1bpp) scanned image compression. PDF only specifies
a decoder filter, and we don't currently implement anything else */
#include "memory_.h"
#include "ghost.h"
#include "oper.h"
#include "gsstruct.h"
#include "gstypes.h"
#include "ialloc.h"
#include "idict.h"
#include "store.h"
#include "stream.h"
#include "strimpl.h"
#include "ifilter.h"
#include "sjbig2.h"
/* We define a structure, s_jbig2_global_data_t,
allocated in the postscript
memory space, to hold a pointer to the global decoder
context (which is allocated by libjbig2). This allows
us to pass the reference through postscript code to
the filter initializer. The opaque data pointer is not
enumerated and will not be garbage collected. We use
a finalize method to deallocate it when the reference
is no longer in use. */
static void jbig2_global_data_finalize(const gs_memory_t *cmem, void *vptr);
gs_private_st_simple_final(st_jbig2_global_data_t, s_jbig2_global_data_t,
"jbig2globaldata", jbig2_global_data_finalize);
/* <source> /JBIG2Decode <file> */
/* <source> <dict> /JBIG2Decode <file> */
static int
z_jbig2decode(i_ctx_t * i_ctx_p)
{
os_ptr op = osp;
ref *sop = NULL;
s_jbig2_global_data_t *gref;
stream_jbig2decode_state state;
/* Extract the global context reference, if any, from the parameter
dictionary and embed it in our stream state. The original object
ref is under the JBIG2Globals key.
We expect the postscript code to resolve this and call
z_jbig2makeglobalctx() below to create an astruct wrapping the
global decoder data and store it under the .jbig2globalctx key
*/
s_jbig2decode_set_global_data((stream_state*)&state, NULL, NULL);
if (r_has_type(op, t_dictionary)) {
check_dict_read(*op);
if ( dict_find_string(op, ".jbig2globalctx", &sop) > 0) {
if (!r_is_struct(sop) || !r_has_stype(sop, imemory, st_jbig2_global_data_t))
return_error(gs_error_typecheck);
gref = r_ptr(sop, s_jbig2_global_data_t);
s_jbig2decode_set_global_data((stream_state*)&state, gref, gref->data);
}
}
/* we pass npop=0, since we've no arguments left to consume */
return filter_read(i_ctx_p, 0, &s_jbig2decode_template,
(stream_state *) & state, (sop ? r_space(sop) : 0));
}
/* <bytestring> .jbig2makeglobalctx <jbig2globalctx> */
/* we call this from ps code to instantiate a jbig2_global_context
object which the JBIG2Decode filter uses if available. The
pointer to the global context is stored in an astruct object
and returned that way since it lives outside the interpreters
memory management */
static int
z_jbig2makeglobalctx(i_ctx_t * i_ctx_p)
{
void *global = NULL;
s_jbig2_global_data_t *st;
os_ptr op = osp;
byte *data;
int size;
int code = 0;
check_type(*op, t_astruct);
size = gs_object_size(imemory, op->value.pstruct);
data = r_ptr(op, byte);
code = s_jbig2decode_make_global_data(imemory->non_gc_memory, data, size,
&global);
if (size > 0 && global == NULL) {
dmlprintf(imemory, "failed to create parsed JBIG2GLOBALS object.");
return_error(gs_error_unknownerror);
}
st = ialloc_struct(s_jbig2_global_data_t,
&st_jbig2_global_data_t,
"jbig2decode parsed global context");
if (st == NULL) return_error(gs_error_VMerror);
st->data = global;
make_astruct(op, a_readonly | icurrent_space, (byte*)st);
return code;
}
/* free our referenced global context data */
static void jbig2_global_data_finalize(const gs_memory_t *cmem, void *vptr)
{
s_jbig2_global_data_t *st = vptr;
(void)cmem; /* unused */
if (st->data) s_jbig2decode_free_global_data(st->data);
st->data = NULL;
}
/* Match the above routine to the corresponding filter name.
This is how our static routines get called externally. */
const op_def zfjbig2_op_defs[] = {
{"1.jbig2makeglobalctx", z_jbig2makeglobalctx},
op_def_begin_filter(),
{"2JBIG2Decode", z_jbig2decode},
op_def_end(0)
};
|