~ubuntu-branches/ubuntu/jaunty/ghostscript/jaunty-updates

« back to all changes in this revision

Viewing changes to base/sjbig2_luratech.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2009-01-20 16:40:45 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090120164045-lnfhi0n30o5lwhwa
Tags: 8.64.dfsg.1~svn9377-0ubuntu1
* New upstream release (SVN rev 9377)
   o Fixes many bugs concerning PDF rendering, to make the PDF printing
     workflow correctly working.
   o Fixes long-standing bugs in many drivers, like input paper tray and
     duplex options not working for the built-in PCL 4, 5, 5c, 5e, and
     6/XL drivers, PDF input not working for bjc600, bjc800, and cups
     output devices, several options not working and uninitialized
     memory with cups output device.
   o Merged nearly all patches of the Ubuntu and Debian packages upstream.
   o Fixes LP: #317810, LP: #314439, LP: #314018.
* debian/patches/03_libpaper_support.dpatch,
  debian/patches/11_gs-cjk_font_glyph_handling_fix.dpatch,
  debian/patches/12_gs-cjk_vertical_writing_metrics_fix.dpatch,
  debian/patches/13_gs-cjk_cjkps_examples.dpatch,
  debian/patches/20_bbox_segv_fix.dpatch,
  debian/patches/21_brother_7x0_gdi_fix.dpatch,
  debian/patches/22_epsn_margin_workaround.dpatch,
  debian/patches/24_gs_man_fix.dpatch,
  debian/patches/25_toolbin_insecure_tmp_usage_fix.dpatch,
  debian/patches/26_assorted_script_fixes.dpatch,
  debian/patches/29_gs_css_fix.dpatch,
  debian/patches/30_ps2pdf_man_improvement.dpatch,
  debian/patches/31_fix-gc-sigbus.dpatch,
  debian/patches/34_ftbfs-on-hurd-fix.dpatch,
  debian/patches/35_disable_libcairo.dpatch,
  debian/patches/38_pxl-duplex.dpatch,
  debian/patches/39_pxl-resolution.dpatch,
  debian/patches/42_gs-init-ps-delaybind-fix.dpatch,
  debian/patches/45_bjc600-bjc800-pdf-input.dpatch,
  debian/patches/48_cups-output-device-pdf-duplex-uninitialized-memory-fix.dpatch,
  debian/patches/50_lips4-floating-point-exception.dpatch,
  debian/patches/52_cups-device-logging.dpatch,
  debian/patches/55_pcl-input-slot-fix.dpatch,
  debian/patches/57_pxl-input-slot-fix.dpatch,
  debian/patches/60_pxl-cups-driver-pdf.dpatch,
  debian/patches/62_onebitcmyk-pdf.dpatch,
  debian/patches/65_too-big-temp-files-1.dpatch,
  debian/patches/67_too-big-temp-files-2.dpatch,
  debian/patches/70_take-into-account-data-in-stream-buffer-before-refill.dpatch:
  Removed, applied upstream.
* debian/patches/01_docdir_fix_for_debian.dpatch,
  debian/patches/02_gs_man_fix_debian.dpatch,
  debian/patches/01_docdir-fix-for-debian.dpatch,
  debian/patches/02_docdir-fix-for-debian.dpatch: Renamed patches to
  make merging with Debian easier.
* debian/patches/32_improve-handling-of-media-size-changes-from-gv.dpatch, 
  debian/patches/33_bad-params-to-xinitimage-on-large-bitmaps.dpatch:
  regenerated for new source directory structure.
* debian/rules: Corrected paths to remove cidfmap (it is in Resource/Init/
  in GS 8.64) and to install headers (source paths are psi/ and base/ now).
* debian/rules: Remove all fontmaps, as DeFoMa replaces them.
* debian/local/pdftoraster/pdftoraster.c,
  debian/local/pdftoraster/pdftoraster.convs, debian/rules: Removed
  added pdftoraster filter and use the one which comes with Ghostscript.
* debian/ghostscript.links: s/8.63/8.64/

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2008 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
  
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
7
   This software is distributed under license and may not be copied, modified
 
8
   or distributed except as expressly authorized under the terms of that
 
9
   license.  Refer to licensing information at http://www.artifex.com/
 
10
   or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
 
11
   San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
 
12
*/
 
13
 
 
14
/* $Id: sjbig2_luratech.c 8784 2008-05-28 18:16:26Z giles $ */
 
15
/* jbig2decode filter implementation -- hooks in luratech JBIG2 */
 
16
 
 
17
#include "memory_.h"
 
18
#include "malloc_.h"  /* should use a gs mem pointer */
 
19
#include "gserrors.h"
 
20
#include "gserror.h"
 
21
#include "gdebug.h"
 
22
#include "strimpl.h"
 
23
#include "sjbig2_luratech.h"
 
24
 
 
25
#include <ldf_jb2.h>
 
26
 
 
27
/* JBIG2Decode stream implementation using the Luratech library */
 
28
 
 
29
/* if linking against a SDK build that requires a separate license key,
 
30
   you can change the following undefs to defines and set them here. */
 
31
/***
 
32
#ifndef JB2_LICENSE_NUM_1
 
33
# undef JB2_LICENSE_NUM_1 
 
34
#endif
 
35
#ifndef JB2_LICENSE_NUM_2
 
36
# undef JB2_LICENSE_NUM_2 
 
37
#endif
 
38
***/
 
39
 
 
40
/* The /JBIG2Decode filter is a fairly memory intensive one to begin with,
 
41
   Furthermore, as a PDF 1.4 feature, we can assume a fairly large 
 
42
   (host-level) machine. We therefore dispense with the normal 
 
43
   Ghostscript memory discipline and let the library allocate all its 
 
44
   resources on the heap. The pointers to these are not enumerated and 
 
45
   so will not be garbage collected. We rely on our release() proc being 
 
46
   called to deallocate state.
 
47
 */
 
48
 /* TODO: check allocations for integer overflow */
 
49
 
 
50
/* create a gc object for our state, defined in sjbig2_luratech.h */
 
51
private_st_jbig2decode_state(); 
 
52
 
 
53
#define JBIG2_BUFFER_SIZE 4096
 
54
 
 
55
/* our implementation of the "parsed" /JBIG2Globals filter parameter */
 
56
typedef struct s_jbig2decode_global_data_s {
 
57
    unsigned char *data;
 
58
    unsigned long size;
 
59
} s_jbig2decode_global_data;
 
60
 
 
61
/* create a global data struct and copy data into it */
 
62
int
 
63
s_jbig2decode_make_global_data(byte *data, uint size, void **result)
 
64
{
 
65
    s_jbig2decode_global_data *global = NULL;
 
66
 
 
67
    global = malloc(sizeof(*global));
 
68
    if (global == NULL) return gs_error_VMerror;
 
69
 
 
70
    global->data = malloc(size);
 
71
    if (global->data == NULL) {
 
72
        free(global);
 
73
        return gs_error_VMerror;
 
74
    }
 
75
    memcpy(global->data, data, size);
 
76
    global->size = size;
 
77
 
 
78
    *result = global;
 
79
    return 0;
 
80
}
 
81
 
 
82
/* free a global data struct and its data */
 
83
void
 
84
s_jbig2decode_free_global_data(void *data)
 
85
{
 
86
    s_jbig2decode_global_data *global = (s_jbig2decode_global_data*)data;
 
87
 
 
88
    if (global->size && global->data) {
 
89
        free(global->data);
 
90
        global->size = 0;
 
91
    }
 
92
    free(global);
 
93
}
 
94
 
 
95
/* store a global ctx pointer in our state structure */
 
96
int
 
97
s_jbig2decode_set_global_data(stream_state *ss, s_jbig2_global_data_t *gd)
 
98
{
 
99
    stream_jbig2decode_state *state = (stream_jbig2decode_state*)ss;
 
100
    if (state == NULL)
 
101
        return gs_error_VMerror;
 
102
    
 
103
    state->global_struct = gd;
 
104
    if (gd != NULL) {
 
105
        s_jbig2decode_global_data *global = (s_jbig2decode_global_data*)(gd->data);
 
106
        state->global_data = global->data;
 
107
        state->global_size = global->size;
 
108
    } else {
 
109
        state->global_data = NULL;
 
110
        state->global_size = 0;
 
111
    }
 
112
    return 0;
 
113
}
 
114
 
 
115
/* invert the bits in a buffer */
 
116
/* jbig2 and postscript have different senses of what pixel
 
117
   value is black, so we must invert the image */
 
118
static void
 
119
s_jbig2_invert_buffer(unsigned char *buf, int length)
 
120
{
 
121
    int i;
 
122
    
 
123
    for (i = 0; i < length; i++)
 
124
        *buf++ ^= 0xFF;
 
125
}
 
126
 
 
127
/** callbacks passed to the luratech library */
 
128
 
 
129
/* memory allocator */
 
130
static void * JB2_Callback
 
131
s_jbig2_alloc(unsigned long size, void *userdata)
 
132
{
 
133
    void *result = malloc(size);
 
134
    return result;
 
135
}
 
136
 
 
137
/* memory release */
 
138
static JB2_Error JB2_Callback
 
139
s_jbig2_free(void *ptr, void *userdata)
 
140
{
 
141
    free(ptr);
 
142
    return cJB2_Error_OK;
 
143
}
 
144
 
 
145
/* error callback for jbig2 codec */
 
146
static void JB2_Callback
 
147
s_jbig2_message(const char *message, JB2_Message_Level level, void *userdata)
 
148
{
 
149
    const char *type;
 
150
 
 
151
    if (message == NULL) return;
 
152
    if (message[0] == '\0') return;
 
153
 
 
154
    switch (level) {
 
155
        case cJB2_Message_Information:
 
156
            type = "info"; break;;
 
157
        case cJB2_Message_Warning:
 
158
            type = "WARNING"; break;;
 
159
        case cJB2_Message_Error:
 
160
            type = "ERROR"; break;;
 
161
        default:
 
162
            type = "unknown message"; break;;
 
163
    }
 
164
 
 
165
    if (level == cJB2_Message_Error) {
 
166
        dprintf2("Luratech JBIG2 %s %s\n", type, message);
 
167
    } else {
 
168
        if_debug2('w', "[w]Luratech JBIG2 %s %s\n", type, message);
 
169
    }
 
170
 
 
171
    return;
 
172
}
 
173
 
 
174
/* compressed read callback for jbig2 codec */
 
175
static JB2_Size_T JB2_Callback
 
176
s_jbig2_read(unsigned char *buffer, 
 
177
        JB2_Size_T offset, JB2_Size_T size, void *userdata)
 
178
{
 
179
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) userdata;
 
180
    long available;
 
181
 
 
182
    /* return data from the Globals stream */
 
183
    if (offset < state->global_size) {
 
184
        available = state->global_size - offset;
 
185
        if (available > size) available = size;
 
186
        memcpy(buffer, state->global_data + offset, available);
 
187
        return available;
 
188
    }
 
189
 
 
190
    /* else return data from the image stream */
 
191
    offset -= state->global_size;
 
192
    available = state->infill - offset;
 
193
    if (available > size) available = size;
 
194
    if (available <= 0) return 0;
 
195
 
 
196
    memcpy(buffer, state->inbuf + offset, available);
 
197
    return available;
 
198
}
 
199
 
 
200
/* uncompressed write callback for jbig2 codec */
 
201
static JB2_Error JB2_Callback
 
202
s_jbig2_write(unsigned char *buffer,
 
203
                unsigned long row, unsigned long width,
 
204
                unsigned long bbp, void *userdata)
 
205
{
 
206
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) userdata;
 
207
    unsigned char *line = state->image + row*state->stride;
 
208
    long available = ((width - 1) >> 3) + 1; 
 
209
 
 
210
    if (row >= state->height) {
 
211
        dlprintf2("jbig2decode: output for row index %lu of %lu called!\n", row, state->height);
 
212
        return cJB2_Error_Invalid_Index;
 
213
    }
 
214
 
 
215
    memcpy(line, buffer, available);
 
216
    s_jbig2_invert_buffer(line, available);
 
217
 
 
218
    return cJB2_Error_OK;
 
219
}
 
220
 
 
221
 
 
222
static int
 
223
s_jbig2decode_inbuf(stream_jbig2decode_state *state, stream_cursor_read * pr)
 
224
{
 
225
    long in_size = pr->limit - pr->ptr;
 
226
 
 
227
    /* allocate the input buffer if needed */
 
228
    if (state->inbuf == NULL) {
 
229
        state->inbuf = malloc(JBIG2_BUFFER_SIZE);
 
230
        if (state->inbuf == NULL) return gs_error_VMerror;
 
231
        state->insize = JBIG2_BUFFER_SIZE;
 
232
        state->infill = 0;
 
233
    }
 
234
 
 
235
    /* grow the input buffer if needed */
 
236
    while (state->insize < state->infill + in_size) {
 
237
        unsigned char *new;
 
238
        unsigned long new_size = state->insize;
 
239
 
 
240
        while (new_size < state->infill + in_size)
 
241
            new_size = new_size << 1;
 
242
 
 
243
        if_debug1('s', "[s]jbig2decode growing input buffer to %lu bytes\n",
 
244
                new_size);
 
245
        new = realloc(state->inbuf, new_size);
 
246
        if (new == NULL) return gs_error_VMerror;
 
247
 
 
248
        state->inbuf = new;
 
249
        state->insize = new_size;
 
250
    }
 
251
 
 
252
    /* copy the available input into our buffer */
 
253
    /* note that the gs stream library uses offset-by-one
 
254
        indexing of its buffers while we use zero indexing */
 
255
    memcpy(state->inbuf + state->infill, pr->ptr + 1, in_size);
 
256
    state->infill += in_size;
 
257
    pr->ptr += in_size;
 
258
 
 
259
    return 0;
 
260
}
 
261
 
 
262
/* initialize the steam. */
 
263
static int
 
264
s_jbig2decode_init(stream_state * ss)
 
265
{
 
266
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
 
267
 
 
268
    state->doc = NULL;
 
269
    state->inbuf = NULL;
 
270
    state->insize = 0;
 
271
    state->infill = 0;
 
272
    state->image = NULL;
 
273
    state->width = 0;
 
274
    state->height = 0;
 
275
    state->row = 0;
 
276
    state->stride = 0;
 
277
    state->error = 0;
 
278
    state->offset = 0;
 
279
 
 
280
    return 0;
 
281
}
 
282
 
 
283
/* process a section of the input and return any decoded data.
 
284
   see strimpl.h for return codes.
 
285
 */
 
286
static int
 
287
s_jbig2decode_process(stream_state * ss, stream_cursor_read * pr,
 
288
                  stream_cursor_write * pw, bool last)
 
289
{
 
290
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
 
291
    long in_size = pr->limit - pr->ptr;
 
292
    long out_size = pw->limit - pw->ptr;
 
293
    long available;
 
294
    JB2_Error error;
 
295
    JB2_Scaling_Factor scale = {1,1};
 
296
    JB2_Rect rect = {0,0,0,0};
 
297
    ulong result;
 
298
    int status = last;
 
299
    
 
300
    if (in_size > 0) {
 
301
        /* buffer all available input for the decoder */
 
302
        result = s_jbig2decode_inbuf(state, pr);
 
303
        if (result) return ERRC;
 
304
    }
 
305
 
 
306
    if (last && out_size > 0) {
 
307
 
 
308
        if (state->doc == NULL) {
 
309
 
 
310
            /* initialize the codec state and pass our callbacks */
 
311
            error = JB2_Document_Start( &(state->doc),
 
312
                s_jbig2_alloc, ss,      /* alloc and its data */
 
313
                s_jbig2_free, ss,       /* free and its data */
 
314
                s_jbig2_read, ss,       /* read callback and data */
 
315
                s_jbig2_message, ss);   /* message callback and data */
 
316
            if (error != cJB2_Error_OK) return ERRC;
 
317
 
 
318
#if defined(JB2_LICENSE_NUM_1) && defined(JB2_LICENSE_NUM_2)
 
319
            /* set the license keys if appropriate */
 
320
            error = JB2_Document_Set_License(state->doc, 
 
321
                JB2_LICENSE_NUM_1, JB2_LICENSE_NUM_2);
 
322
            if (error != cJB2_Error_OK) return ERRC;
 
323
#endif
 
324
            /* decode relevent image parameters */
 
325
            error = JB2_Document_Set_Page(state->doc, 0);
 
326
            if (error != cJB2_Error_OK) return ERRC;
 
327
            error = JB2_Document_Get_Property(state->doc, 
 
328
                cJB2_Prop_Page_Width, &result);
 
329
            state->width = result;
 
330
            error = JB2_Document_Get_Property(state->doc, 
 
331
                cJB2_Prop_Page_Height, &result);
 
332
            if (error != cJB2_Error_OK) return ERRC;
 
333
            state->height = result;
 
334
            state->stride = ((state->width - 1) >> 3) + 1;
 
335
            if_debug2('w', "[w]jbig2decode page is %ldx%ld; allocating image\n", state->width, state->height);
 
336
            state->image = malloc(state->height*state->stride);
 
337
 
 
338
            /* start image decode */
 
339
            error = JB2_Document_Decompress_Page(state->doc, scale, rect,
 
340
                s_jbig2_write, ss);
 
341
            if (error != cJB2_Error_OK) return ERRC;
 
342
 
 
343
        }
 
344
 
 
345
        /* copy any buffered image data out */
 
346
        available = state->stride*state->height - state->offset;
 
347
        if (available > 0) {
 
348
            out_size = (out_size > available) ? available : out_size;
 
349
            memcpy(pw->ptr+1, state->image + state->offset, out_size);
 
350
            state->offset += out_size;
 
351
            pw->ptr += out_size;
 
352
        }
 
353
        /* more data to output? */
 
354
        available = state->stride*state->height - state->offset;
 
355
        if (available > 0) return 1; 
 
356
        else return EOFC;
 
357
    }
 
358
    
 
359
    /* handle fatal decoding errors reported through our callback */
 
360
    if (state->error) return ERRC;
 
361
    
 
362
    return status;
 
363
}
 
364
 
 
365
/* stream release. free all our decoder state. */
 
366
static void
 
367
s_jbig2decode_release(stream_state *ss)
 
368
{
 
369
    stream_jbig2decode_state *const state = (stream_jbig2decode_state *) ss;
 
370
 
 
371
    if (state->doc) {
 
372
        JB2_Document_End(&(state->doc));
 
373
        if (state->inbuf) free(state->inbuf);
 
374
        if (state->image) free(state->image);
 
375
    }
 
376
    /* the interpreter calls jbig2decode_free_global_data() separately */
 
377
}
 
378
 
 
379
/* stream template */
 
380
const stream_template s_jbig2decode_template = {
 
381
    &st_jbig2decode_state, 
 
382
    s_jbig2decode_init,
 
383
    s_jbig2decode_process,
 
384
    1, 1, /* min in and out buffer sizes we can handle --should be ~32k,64k for efficiency? */
 
385
    s_jbig2decode_release
 
386
};
 
387
 
 
388
 
 
389
 
 
390
/** encode support **/
 
391
 
 
392
/* we provide a C-only encode filter for generating embedded JBIG2 image 
 
393
   data */
 
394
 
 
395
/* create a gc object for our state, defined in sjbig2_luratech.h */
 
396
private_st_jbig2encode_state();
 
397
 
 
398
/* helper - start up the compression context */
 
399
static int
 
400
s_jbig2encode_start(stream_jbig2encode_state *state)
 
401
{
 
402
    JB2_Error err;
 
403
 
 
404
    /* initialize the compression handle */
 
405
    err = JB2_Compress_Start(&(state->cmp),
 
406
        s_jbig2_alloc, state,   /* alloc and its parameter data */
 
407
        s_jbig2_free,  state,   /* free callback */
 
408
        s_jbig2_message, state);/* message callback */
 
409
    if (err != cJB2_Error_OK) return err;
 
410
 
 
411
            /* set the license keys if appropriate */
 
412
#if defined(JB2_LICENSE_NUM_1) && defined(JB2_LICENSE_NUM_2)
 
413
            err = JB2_Document_Set_License(state->cmp,
 
414
                JB2_LICENSE_NUM_1, JB2_LICENSE_NUM_2);
 
415
            if (err != cJB2_Error_OK) return err;
 
416
#endif
 
417
 
 
418
   /* set the image properties */
 
419
   err = JB2_Compress_Set_Property(state->cmp,
 
420
                cJB2_Prop_Page_Width, state->width);
 
421
 
 
422
   err = JB2_Compress_Set_Property(state->cmp,
 
423
                cJB2_Prop_Page_Height, state->height);
 
424
   if (err != cJB2_Error_OK) return err;
 
425
 
 
426
   /* we otherwise use the default compression parameters */
 
427
 
 
428
   return cJB2_Error_OK;
 
429
}
 
430
 
 
431
/* callback for compressed data output */
 
432
static JB2_Size_T JB2_Callback
 
433
s_jbig2encode_write(const unsigned char *buffer,
 
434
                JB2_Size_T pos, JB2_Size_T size, void *userdata)
 
435
{
 
436
    stream_jbig2encode_state *state = (stream_jbig2encode_state *)userdata;
 
437
 
 
438
    /* allocate the output buffer if necessary */
 
439
    if (state->outbuf == NULL) {
 
440
        state->outbuf = malloc(JBIG2_BUFFER_SIZE);
 
441
        if (state->outbuf == NULL) {
 
442
            dprintf("jbig2encode: failed to allocate output buffer\n");
 
443
            return 0; /* can't return an error! */
 
444
        }
 
445
        state->outsize = JBIG2_BUFFER_SIZE;
 
446
    }
 
447
 
 
448
    /* grow the output buffer if necessary */
 
449
    while (pos+size > state->outsize) {
 
450
        unsigned char *new = realloc(state->outbuf, state->outsize*2);
 
451
        if (new == NULL) {
 
452
            dprintf1("jbig2encode: failed to resize output buffer"
 
453
                " beyond %lu bytes\n", state->outsize);
 
454
            return 0; /* can't return an error! */
 
455
        }
 
456
        state->outbuf = new;
 
457
        state->outsize *= 2;
 
458
    }
 
459
 
 
460
    /* copy data into our buffer; there will now be enough room. */
 
461
    memcpy(state->outbuf + pos, buffer, size);
 
462
    if (state->outfill < pos + size) state->outfill = pos + size;
 
463
 
 
464
    return size;
 
465
}                             
 
466
 
 
467
 
 
468
/* initialize the steam. */
 
469
static int
 
470
s_jbig2encode_init(stream_state * ss)
 
471
{
 
472
    stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
 
473
 
 
474
    /* null library context handles */
 
475
    state->cmp = (JB2_Handle_Compress)NULL;
 
476
    state->doc = (JB2_Handle_Document)NULL;
 
477
 
 
478
    /* width and height are set by the client */
 
479
    /* calculate a stride based on those values */
 
480
    state->stride = ((state->width - 1) >> 3) + 1;
 
481
 
 
482
    state->line = malloc(state->stride);
 
483
    if (state->line == NULL) return ERRC;
 
484
    state->linefill = 0;
 
485
 
 
486
    /* null output buffer */
 
487
    state->outbuf = NULL;
 
488
    state->outsize = 0;
 
489
    state->outfill = 0;
 
490
    state->offset = 0;
 
491
 
 
492
    return 0;
 
493
}
 
494
 
 
495
/* process a section of the input and return any encoded data.
 
496
   see strimpl.h for return codes.
 
497
 */
 
498
static int
 
499
s_jbig2encode_process(stream_state * ss, stream_cursor_read * pr,
 
500
                  stream_cursor_write * pw, bool last)
 
501
{
 
502
    stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
 
503
    long in_size = pr->limit - pr->ptr;
 
504
    long out_size = pw->limit - pw->ptr;
 
505
    long available, segment;
 
506
    JB2_Error err;
 
507
 
 
508
    /* Be greedy in filling our internal line buffer so we always
 
509
       make read progress on a stream. */
 
510
    if (in_size > 0) {
 
511
        /* initialize the encoder if necessary */
 
512
        if (state->cmp == (JB2_Handle_Compress)NULL)
 
513
            s_jbig2encode_start(state);
 
514
 
 
515
        available = in_size;
 
516
 
 
517
        /* try to fill the line buffer */
 
518
        segment = state->stride - state->linefill;
 
519
        if (segment > 0) {
 
520
            segment = (segment < available) ? segment : available;
 
521
            memcpy(state->line + state->linefill, pr->ptr+1, segment);
 
522
            pr->ptr += segment;
 
523
            available -= segment;
 
524
            state->linefill += segment;
 
525
        }
 
526
        /* pass a full line buffer to the encoder library */
 
527
        if (state->linefill == state->stride) {
 
528
            s_jbig2_invert_buffer(state->line, state->stride);
 
529
            err = JB2_Compress_Line(state->cmp, state->line);
 
530
            state->linefill = 0;
 
531
            if (err != cJB2_Error_OK) return ERRC;
 
532
        }
 
533
        /* pass remaining full lines to the encoder library */
 
534
        while (available >= state->stride) {
 
535
           memcpy(state->line, pr->ptr+1, state->stride);
 
536
           s_jbig2_invert_buffer(state->line, state->stride);
 
537
           err = JB2_Compress_Line(state->cmp, state->line);
 
538
           pr->ptr += state->stride;
 
539
           available = pr->limit - pr->ptr;
 
540
           if (err != cJB2_Error_OK) return ERRC;
 
541
        }
 
542
        /* copy remaining data into the line buffer */
 
543
        if (available > 0) {
 
544
            /* available is always < stride here */
 
545
            memcpy(state->line, pr->ptr+1, available);
 
546
            pr->ptr += available;
 
547
            state->linefill = available;
 
548
        }
 
549
        if (!last) return 0; /* request more data */
 
550
    }
 
551
 
 
552
    if (last && state->outbuf == NULL) {
 
553
        /* convert the compression context to a document context */
 
554
        err = JB2_Compress_End(&(state->cmp), &(state->doc));
 
555
        if (err != cJB2_Error_OK) return ERRC;
 
556
        /* dump the compressed data out through a callback; 
 
557
           unfortunately we can't serialize this across process calls */
 
558
        err = JB2_Document_Export_Document(state->doc,
 
559
            s_jbig2encode_write, state,
 
560
            cJB2_Export_Format_Stream_For_PDF);
 
561
        if (err != cJB2_Error_OK) return ERRC;
 
562
    }
 
563
 
 
564
    if (state->outbuf != NULL) {
 
565
        /* copy available output data */
 
566
        available = min(out_size, state->outfill - state->offset);
 
567
        memcpy(pw->ptr + 1, state->outbuf + state->offset, available);
 
568
        pw->ptr += available;
 
569
        state->offset += available;
 
570
 
 
571
        /* need further output space? */
 
572
        if (state->outfill - state->offset > 0) return 1;
 
573
        else return EOFC; /* all done */
 
574
    }
 
575
 
 
576
    /* something went wrong above */
 
577
    return ERRC;
 
578
}
 
579
 
 
580
/* stream release. free all our decoder state.
 
581
 */
 
582
static void
 
583
s_jbig2encode_release(stream_state *ss)
 
584
{
 
585
    stream_jbig2encode_state *state = (stream_jbig2encode_state *)ss;
 
586
 
 
587
    if (state->outbuf != NULL) free(state->outbuf);
 
588
    if (state->line != NULL) free(state->line);
 
589
}
 
590
 
 
591
/* stream template */
 
592
const stream_template s_jbig2encode_template = {
 
593
    &st_jbig2encode_state,
 
594
    s_jbig2encode_init,
 
595
    s_jbig2encode_process,
 
596
    1024, 1024, /* min in and out buffer sizes; could be smaller, but 
 
597
                   this is more efficient */
 
598
    s_jbig2encode_release
 
599
};