|
Packit |
3f21c4 |
/* Copyright (C) 2001-2012 Artifex Software, Inc.
|
|
Packit |
3f21c4 |
All Rights Reserved.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is provided AS-IS with no warranty, either express or
|
|
Packit |
3f21c4 |
implied.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
This software is distributed under license and may not be copied,
|
|
Packit |
3f21c4 |
modified or distributed except as expressly authorized under the terms
|
|
Packit |
3f21c4 |
of the license contained in the file LICENSE in this distribution.
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Refer to licensing information at http://www.artifex.com or contact
|
|
Packit |
3f21c4 |
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
|
|
Packit |
3f21c4 |
CA 94903, U.S.A., +1(415)492-9861, for further information.
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/*
|
|
Packit |
3f21c4 |
jbig2dec
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3f21c4 |
#include "config.h"
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
#include "os_types.h"
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#include <stdio.h>
|
|
Packit |
3f21c4 |
#include <stdlib.h>
|
|
Packit |
3f21c4 |
#include <stdarg.h>
|
|
Packit |
3f21c4 |
#include <string.h>
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#include "jbig2.h"
|
|
Packit |
3f21c4 |
#include "jbig2_priv.h"
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void *
|
|
Packit |
3f21c4 |
jbig2_default_alloc(Jbig2Allocator *allocator, size_t size)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return malloc(size);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
jbig2_default_free(Jbig2Allocator *allocator, void *p)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
free(p);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void *
|
|
Packit |
3f21c4 |
jbig2_default_realloc(Jbig2Allocator *allocator, void *p, size_t size)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return realloc(p, size);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static Jbig2Allocator jbig2_default_allocator = {
|
|
Packit |
3f21c4 |
jbig2_default_alloc,
|
|
Packit |
3f21c4 |
jbig2_default_free,
|
|
Packit |
3f21c4 |
jbig2_default_realloc
|
|
Packit |
3f21c4 |
};
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* check for integer multiplication overflow */
|
|
Packit |
3f21c4 |
if (num > 0 && size >= (size_t) - 0x100 / num)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
return allocator->alloc(allocator, size * num);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* jbig2_free and jbig2_realloc moved to the bottom of this file */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static int
|
|
Packit |
3f21c4 |
jbig2_default_error(void *data, const char *msg, Jbig2Severity severity, int32_t seg_idx)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* report only fatal errors by default */
|
|
Packit |
3f21c4 |
if (severity == JBIG2_SEVERITY_FATAL) {
|
|
Packit |
3f21c4 |
fprintf(stderr, "jbig2 decoder FATAL ERROR: %s", msg);
|
|
Packit |
3f21c4 |
if (seg_idx != -1)
|
|
Packit |
3f21c4 |
fprintf(stderr, " (segment 0x%02x)", seg_idx);
|
|
Packit |
3f21c4 |
fprintf(stderr, "\n");
|
|
Packit |
3f21c4 |
fflush(stderr);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t segment_number, const char *fmt, ...)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
char buf[1024];
|
|
Packit |
3f21c4 |
va_list ap;
|
|
Packit |
3f21c4 |
int n;
|
|
Packit |
3f21c4 |
int code;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
va_start(ap, fmt);
|
|
Packit |
3f21c4 |
n = vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
Packit |
3f21c4 |
va_end(ap);
|
|
Packit |
3f21c4 |
if (n < 0 || n == sizeof(buf))
|
|
Packit |
3f21c4 |
strncpy(buf, "jbig2_error: error in generating error string", sizeof(buf));
|
|
Packit |
3f21c4 |
code = ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number);
|
|
Packit |
3f21c4 |
if (severity == JBIG2_SEVERITY_FATAL)
|
|
Packit |
3f21c4 |
code = -1;
|
|
Packit |
3f21c4 |
return code;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Jbig2Ctx *
|
|
Packit |
3f21c4 |
jbig2_ctx_new(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCtx *global_ctx, Jbig2ErrorCallback error_callback, void *error_callback_data)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2Ctx *result;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (allocator == NULL)
|
|
Packit |
3f21c4 |
allocator = &jbig2_default_allocator;
|
|
Packit |
3f21c4 |
if (error_callback == NULL)
|
|
Packit |
3f21c4 |
error_callback = &jbig2_default_error;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1);
|
|
Packit |
3f21c4 |
if (result == NULL) {
|
|
Packit |
3f21c4 |
error_callback(error_callback_data, "initial context allocation failed!", JBIG2_SEVERITY_FATAL, -1);
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->allocator = allocator;
|
|
Packit |
3f21c4 |
result->options = options;
|
|
Packit |
3f21c4 |
result->global_ctx = (const Jbig2Ctx *)global_ctx;
|
|
Packit |
3f21c4 |
result->error_callback = error_callback;
|
|
Packit |
3f21c4 |
result->error_callback_data = error_callback_data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->buf = NULL;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->n_segments = 0;
|
|
Packit |
3f21c4 |
result->n_segments_max = 16;
|
|
Packit |
3f21c4 |
result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max);
|
|
Packit |
3f21c4 |
if (result->segments == NULL) {
|
|
Packit |
3f21c4 |
error_callback(error_callback_data, "initial segments allocation failed!", JBIG2_SEVERITY_FATAL, -1);
|
|
Packit |
3f21c4 |
jbig2_free(allocator, result);
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
result->segment_index = 0;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->current_page = 0;
|
|
Packit |
3f21c4 |
result->max_page_index = 4;
|
|
Packit |
3f21c4 |
result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
|
|
Packit |
3f21c4 |
if (result->pages == NULL) {
|
|
Packit |
3f21c4 |
error_callback(error_callback_data, "initial pages allocation failed!", JBIG2_SEVERITY_FATAL, -1);
|
|
Packit |
3f21c4 |
jbig2_free(allocator, result->segments);
|
|
Packit |
3f21c4 |
jbig2_free(allocator, result);
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
int index;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (index = 0; index < result->max_page_index; index++) {
|
|
Packit |
3f21c4 |
result->pages[index].state = JBIG2_PAGE_FREE;
|
|
Packit |
3f21c4 |
result->pages[index].number = 0;
|
|
Packit |
3f21c4 |
result->pages[index].image = NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return result;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
#define get_uint16(bptr)\
|
|
Packit |
3f21c4 |
(((bptr)[0] << 8) | (bptr)[1])
|
|
Packit |
3f21c4 |
#define get_int16(bptr)\
|
|
Packit |
3f21c4 |
(((int)get_uint16(bptr) ^ 0x8000) - 0x8000)
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int16_t
|
|
Packit |
3f21c4 |
jbig2_get_int16(const byte *bptr)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return get_int16(bptr);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
uint16_t
|
|
Packit |
3f21c4 |
jbig2_get_uint16(const byte *bptr)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return get_uint16(bptr);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
int32_t
|
|
Packit |
3f21c4 |
jbig2_get_int32(const byte *bptr)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
uint32_t
|
|
Packit |
3f21c4 |
jbig2_get_uint32(const byte *bptr)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/**
|
|
Packit |
3f21c4 |
* jbig2_data_in: submit data for decoding
|
|
Packit |
3f21c4 |
* @ctx: The jbig2dec decoder context
|
|
Packit |
3f21c4 |
* @data: a pointer to the data buffer
|
|
Packit |
3f21c4 |
* @size: the size of the data buffer in bytes
|
|
Packit |
3f21c4 |
*
|
|
Packit |
3f21c4 |
* Copies the specified data into internal storage and attempts
|
|
Packit |
3f21c4 |
* to (continue to) parse it as part of a jbig2 data stream.
|
|
Packit |
3f21c4 |
*
|
|
Packit |
3f21c4 |
* Return code: 0 on success
|
|
Packit |
3f21c4 |
* -1 if there is a parsing error, or whatever
|
|
Packit |
3f21c4 |
* the error handling callback returns
|
|
Packit |
3f21c4 |
**/
|
|
Packit |
3f21c4 |
int
|
|
Packit |
3f21c4 |
jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
const size_t initial_buf_size = 1024;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (ctx->buf == NULL) {
|
|
Packit |
3f21c4 |
size_t buf_size = initial_buf_size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
do
|
|
Packit |
3f21c4 |
buf_size <<= 1;
|
|
Packit |
3f21c4 |
while (buf_size < size);
|
|
Packit |
3f21c4 |
ctx->buf = jbig2_new(ctx, byte, buf_size);
|
|
Packit |
3f21c4 |
if (ctx->buf == NULL) {
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate ctx->buf in jbig2_data_in");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
ctx->buf_size = buf_size;
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix = 0;
|
|
Packit |
3f21c4 |
ctx->buf_wr_ix = 0;
|
|
Packit |
3f21c4 |
} else if (ctx->buf_wr_ix + size > ctx->buf_size) {
|
|
Packit |
3f21c4 |
if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && ctx->buf_wr_ix - ctx->buf_rd_ix + size <= ctx->buf_size) {
|
|
Packit |
3f21c4 |
memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix);
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
byte *buf;
|
|
Packit |
3f21c4 |
size_t buf_size = initial_buf_size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
do
|
|
Packit |
3f21c4 |
buf_size <<= 1;
|
|
Packit |
3f21c4 |
while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size);
|
|
Packit |
3f21c4 |
buf = jbig2_new(ctx, byte, buf_size);
|
|
Packit |
3f21c4 |
if (buf == NULL) {
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate buf in jbig2_data_in");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
memcpy(buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix);
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, ctx->buf);
|
|
Packit |
3f21c4 |
ctx->buf = buf;
|
|
Packit |
3f21c4 |
ctx->buf_size = buf_size;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
ctx->buf_wr_ix -= ctx->buf_rd_ix;
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix = 0;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
memcpy(ctx->buf + ctx->buf_wr_ix, data, size);
|
|
Packit |
3f21c4 |
ctx->buf_wr_ix += size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* data has now been added to buffer */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (;;) {
|
|
Packit |
3f21c4 |
const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
|
|
Packit |
3f21c4 |
Jbig2Segment *segment;
|
|
Packit |
3f21c4 |
size_t header_size;
|
|
Packit |
3f21c4 |
int code;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
switch (ctx->state) {
|
|
Packit |
3f21c4 |
case JBIG2_FILE_HEADER:
|
|
Packit |
3f21c4 |
/* D.4.1 */
|
|
Packit |
3f21c4 |
if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8))
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "Not a JBIG2 file header");
|
|
Packit |
3f21c4 |
/* D.4.2 */
|
|
Packit |
3f21c4 |
ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8];
|
|
Packit |
3f21c4 |
if (ctx->file_header_flags & 0xFC) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "reserved bits (2-7) of file header flags are not zero (0x%02x)", ctx->file_header_flags);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
/* D.4.3 */
|
|
Packit |
3f21c4 |
if (!(ctx->file_header_flags & 2)) { /* number of pages is known */
|
|
Packit |
3f21c4 |
if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9);
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix += 13;
|
|
Packit |
3f21c4 |
if (ctx->n_pages == 1)
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a single page document");
|
|
Packit |
3f21c4 |
else
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a %d page document", ctx->n_pages);
|
|
Packit |
3f21c4 |
} else { /* number of pages not known */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
ctx->n_pages = 0;
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix += 9;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
/* determine the file organization based on the flags - D.4.2 again */
|
|
Packit |
3f21c4 |
if (ctx->file_header_flags & 1) {
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates sequential organization");
|
|
Packit |
3f21c4 |
} else {
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_RANDOM_HEADERS;
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates random-access organization");
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case JBIG2_FILE_SEQUENTIAL_HEADER:
|
|
Packit |
3f21c4 |
case JBIG2_FILE_RANDOM_HEADERS:
|
|
Packit |
3f21c4 |
segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
|
|
Packit |
3f21c4 |
if (segment == NULL)
|
|
Packit |
3f21c4 |
return 0; /* need more data */
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix += header_size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (ctx->n_segments == ctx->n_segments_max)
|
|
Packit |
3f21c4 |
ctx->segments = jbig2_renew(ctx, ctx->segments, Jbig2Segment *, (ctx->n_segments_max <<= 2));
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
ctx->segments[ctx->n_segments++] = segment;
|
|
Packit |
3f21c4 |
if (ctx->state == JBIG2_FILE_RANDOM_HEADERS) {
|
|
Packit |
3f21c4 |
if ((segment->flags & 63) == 51) /* end of file */
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_RANDOM_BODIES;
|
|
Packit |
3f21c4 |
} else /* JBIG2_FILE_SEQUENTIAL_HEADER */
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case JBIG2_FILE_SEQUENTIAL_BODY:
|
|
Packit |
3f21c4 |
case JBIG2_FILE_RANDOM_BODIES:
|
|
Packit |
3f21c4 |
segment = ctx->segments[ctx->segment_index];
|
|
Packit |
3f21c4 |
if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
|
|
Packit |
3f21c4 |
return 0; /* need more data */
|
|
Packit |
3f21c4 |
code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
|
|
Packit |
3f21c4 |
ctx->buf_rd_ix += segment->data_length;
|
|
Packit |
3f21c4 |
ctx->segment_index++;
|
|
Packit |
3f21c4 |
if (ctx->state == JBIG2_FILE_RANDOM_BODIES) {
|
|
Packit |
3f21c4 |
if (ctx->segment_index == ctx->n_segments)
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_EOF;
|
|
Packit |
3f21c4 |
} else { /* JBIG2_FILE_SEQUENCIAL_BODY */
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
if (code < 0) {
|
|
Packit |
3f21c4 |
ctx->state = JBIG2_FILE_EOF;
|
|
Packit |
3f21c4 |
return code;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
break;
|
|
Packit |
3f21c4 |
case JBIG2_FILE_EOF:
|
|
Packit |
3f21c4 |
if (ctx->buf_rd_ix == ctx->buf_wr_ix)
|
|
Packit |
3f21c4 |
return 0;
|
|
Packit |
3f21c4 |
return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "Garbage beyond end of file");
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_ctx_free(Jbig2Ctx *ctx)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2Allocator *ca = ctx->allocator;
|
|
Packit |
3f21c4 |
int i;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_free(ca, ctx->buf);
|
|
Packit |
3f21c4 |
if (ctx->segments != NULL) {
|
|
Packit |
3f21c4 |
for (i = 0; i < ctx->n_segments; i++)
|
|
Packit |
3f21c4 |
jbig2_free_segment(ctx, ctx->segments[i]);
|
|
Packit |
3f21c4 |
jbig2_free(ca, ctx->segments);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (ctx->pages != NULL) {
|
|
Packit |
3f21c4 |
for (i = 0; i <= ctx->current_page; i++)
|
|
Packit |
3f21c4 |
if (ctx->pages[i].image != NULL)
|
|
Packit |
3f21c4 |
jbig2_image_release(ctx, ctx->pages[i].image);
|
|
Packit |
3f21c4 |
jbig2_free(ca, ctx->pages);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
jbig2_free(ca, ctx);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Jbig2GlobalCtx *
|
|
Packit |
3f21c4 |
jbig2_make_global_ctx(Jbig2Ctx *ctx)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
return (Jbig2GlobalCtx *) ctx;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
jbig2_ctx_free((Jbig2Ctx *) global_ctx);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* I'm not committed to keeping the word stream interface. It's handy
|
|
Packit |
3f21c4 |
when you think you may be streaming your input, but if you're not
|
|
Packit |
3f21c4 |
(as is currently the case), it just adds complexity.
|
|
Packit |
3f21c4 |
*/
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
typedef struct {
|
|
Packit |
3f21c4 |
Jbig2WordStream super;
|
|
Packit |
3f21c4 |
const byte *data;
|
|
Packit |
3f21c4 |
size_t size;
|
|
Packit |
3f21c4 |
} Jbig2WordStreamBuf;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
static void
|
|
Packit |
3f21c4 |
jbig2_word_stream_buf_get_next_word(Jbig2WordStream *self, size_t offset, uint32_t *word)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2WordStreamBuf *z = (Jbig2WordStreamBuf *) self;
|
|
Packit |
3f21c4 |
const byte *data = z->data;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
*word = 0;
|
|
Packit |
3f21c4 |
if (offset + 4 < z->size)
|
|
Packit |
3f21c4 |
*word = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3];
|
|
Packit |
3f21c4 |
else if (offset <= z->size) {
|
|
Packit |
3f21c4 |
size_t i;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
for (i = 0; i < z->size - offset; i++)
|
|
Packit |
3f21c4 |
*word |= data[offset + i] << ((3 - i) << 3);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
Jbig2WordStream *
|
|
Packit |
3f21c4 |
jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
if (result == NULL) {
|
|
Packit |
3f21c4 |
jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate Jbig2WordStreamBuf in jbig2_word_stream_buf_new");
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
|
|
Packit |
3f21c4 |
result->data = data;
|
|
Packit |
3f21c4 |
result->size = size;
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
return &result->super;
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_word_stream_buf_free(Jbig2Ctx *ctx, Jbig2WordStream *ws)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
jbig2_free(ctx->allocator, ws);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
/* When Memento is in use, the ->free and ->realloc calls get
|
|
Packit |
3f21c4 |
* turned into ->Memento_free and ->Memento_realloc, which is
|
|
Packit |
3f21c4 |
* obviously problematic. Undefine free and realloc here to
|
|
Packit |
3f21c4 |
* avoid this. */
|
|
Packit |
3f21c4 |
#ifdef MEMENTO
|
|
Packit |
3f21c4 |
#undef free
|
|
Packit |
3f21c4 |
#undef realloc
|
|
Packit |
3f21c4 |
#endif
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void
|
|
Packit |
3f21c4 |
jbig2_free(Jbig2Allocator *allocator, void *p)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
allocator->free(allocator, p);
|
|
Packit |
3f21c4 |
}
|
|
Packit |
3f21c4 |
|
|
Packit |
3f21c4 |
void *
|
|
Packit |
3f21c4 |
jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num)
|
|
Packit |
3f21c4 |
{
|
|
Packit |
3f21c4 |
/* check for integer multiplication overflow */
|
|
Packit |
3f21c4 |
if (num > 0 && size >= (size_t) - 0x100 / num)
|
|
Packit |
3f21c4 |
return NULL;
|
|
Packit |
3f21c4 |
return allocator->realloc(allocator, p, size * num);
|
|
Packit |
3f21c4 |
}
|