Commit message: None
CVE: CVE-2016-9601
CWE: CWE-119
Vulnerability description: ghostscript before version 9.21 is vulnerable to a heap based buffer overflow that was found in the ghostscript jbig2_decode_gray_scale_image function which is used to decode halftone segments in a JBIG2 image. A document (PostScript or PDF) with an embedded, specially crafted, jbig2 image could trigger a segmentation fault in ghostscript.

Project: ghostscript

jbig2_alloc(Jbig2Allocator *allocator, size_t size, size_t num)
{
    /* check for integer multiplication overflow */
    if (num > 0 && size >= (size_t) - 0x100 / num)
        return NULL;
    return allocator->alloc(allocator, size * num);
}

Project: ghostscript

jbig2_ctx_free(Jbig2Ctx *ctx)
{
    Jbig2Allocator *ca = ctx->allocator;
    int i;

    jbig2_free(ca, ctx->buf);
    if (ctx->segments != NULL) {
        for (i = 0; i < ctx->n_segments; i++)
            jbig2_free_segment(ctx, ctx->segments[i]);
        jbig2_free(ca, ctx->segments);
    }

    if (ctx->pages != NULL) {
        for (i = 0; i <= ctx->current_page; i++)
            if (ctx->pages[i].image != NULL)
                jbig2_image_release(ctx, ctx->pages[i].image);
        jbig2_free(ca, ctx->pages);
    }

    jbig2_free(ca, ctx);
}

Project: ghostscript

jbig2_ctx_new(Jbig2Allocator *allocator, Jbig2Options options, Jbig2GlobalCtx *global_ctx, Jbig2ErrorCallback error_callback, void *error_callback_data)
{
    Jbig2Ctx *result;

    if (allocator == NULL)
        allocator = &jbig2_default_allocator;
    if (error_callback == NULL)
        error_callback = &jbig2_default_error;

    result = (Jbig2Ctx *) jbig2_alloc(allocator, sizeof(Jbig2Ctx), 1);
    if (result == NULL) {
        error_callback(error_callback_data, "initial context allocation failed!", JBIG2_SEVERITY_FATAL, -1);
        return result;
    }

    result->allocator = allocator;
    result->options = options;
    result->global_ctx = (const Jbig2Ctx *)global_ctx;
    result->error_callback = error_callback;
    result->error_callback_data = error_callback_data;

    result->state = (options & JBIG2_OPTIONS_EMBEDDED) ? JBIG2_FILE_SEQUENTIAL_HEADER : JBIG2_FILE_HEADER;

    result->buf = NULL;

    result->n_segments = 0;
    result->n_segments_max = 16;
    result->segments = jbig2_new(result, Jbig2Segment *, result->n_segments_max);
    if (result->segments == NULL) {
        error_callback(error_callback_data, "initial segments allocation failed!", JBIG2_SEVERITY_FATAL, -1);
        jbig2_free(allocator, result);
        return result;
    }
    result->segment_index = 0;

    result->current_page = 0;
    result->max_page_index = 4;
    result->pages = jbig2_new(result, Jbig2Page, result->max_page_index);
    if (result->pages == NULL) {
        error_callback(error_callback_data, "initial pages allocation failed!", JBIG2_SEVERITY_FATAL, -1);
        jbig2_free(allocator, result->segments);
        jbig2_free(allocator, result);
        return result;
    }
    {
        int index;

        for (index = 0; index < result->max_page_index; index++) {
            result->pages[index].state = JBIG2_PAGE_FREE;
            result->pages[index].number = 0;
            result->pages[index].image = NULL;
        }
    }

    return result;
}

Project: ghostscript

jbig2_data_in(Jbig2Ctx *ctx, const unsigned char *data, size_t size)
{
    const size_t initial_buf_size = 1024;

    if (ctx->buf == NULL) {
        size_t buf_size = initial_buf_size;

        do
            buf_size <<= 1;
        while (buf_size < size);
        ctx->buf = jbig2_new(ctx, byte, buf_size);
        if (ctx->buf == NULL) {
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate ctx->buf in jbig2_data_in");
        }
        ctx->buf_size = buf_size;
        ctx->buf_rd_ix = 0;
        ctx->buf_wr_ix = 0;
    } else if (ctx->buf_wr_ix + size > ctx->buf_size) {
        if (ctx->buf_rd_ix <= (ctx->buf_size >> 1) && ctx->buf_wr_ix - ctx->buf_rd_ix + size <= ctx->buf_size) {
            memmove(ctx->buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix);
        } else {
            byte *buf;
            size_t buf_size = initial_buf_size;

            do
                buf_size <<= 1;
            while (buf_size < ctx->buf_wr_ix - ctx->buf_rd_ix + size);
            buf = jbig2_new(ctx, byte, buf_size);
            if (buf == NULL) {
                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate buf in jbig2_data_in");
            }
            memcpy(buf, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix);
            jbig2_free(ctx->allocator, ctx->buf);
            ctx->buf = buf;
            ctx->buf_size = buf_size;
        }
        ctx->buf_wr_ix -= ctx->buf_rd_ix;
        ctx->buf_rd_ix = 0;
    }
    memcpy(ctx->buf + ctx->buf_wr_ix, data, size);
    ctx->buf_wr_ix += size;

    /* data has now been added to buffer */

    for (;;) {
        const byte jbig2_id_string[8] = { 0x97, 0x4a, 0x42, 0x32, 0x0d, 0x0a, 0x1a, 0x0a };
        Jbig2Segment *segment;
        size_t header_size;
        int code;

        switch (ctx->state) {
        case JBIG2_FILE_HEADER:
            /* D.4.1 */
            if (ctx->buf_wr_ix - ctx->buf_rd_ix < 9)
                return 0;
            if (memcmp(ctx->buf + ctx->buf_rd_ix, jbig2_id_string, 8))
                return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "Not a JBIG2 file header");
            /* D.4.2 */
            ctx->file_header_flags = ctx->buf[ctx->buf_rd_ix + 8];
            if (ctx->file_header_flags & 0xFC) {
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "reserved bits (2-7) of file header flags are not zero (0x%02x)", ctx->file_header_flags);
            }
            /* D.4.3 */
            if (!(ctx->file_header_flags & 2)) {        /* number of pages is known */
                if (ctx->buf_wr_ix - ctx->buf_rd_ix < 13)
                    return 0;
                ctx->n_pages = jbig2_get_uint32(ctx->buf + ctx->buf_rd_ix + 9);
                ctx->buf_rd_ix += 13;
                if (ctx->n_pages == 1)
                    jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a single page document");
                else
                    jbig2_error(ctx, JBIG2_SEVERITY_INFO, -1, "file header indicates a %d page document", ctx->n_pages);
            } else {            /* number of pages not known */

                ctx->n_pages = 0;
                ctx->buf_rd_ix += 9;
            }
            /* determine the file organization based on the flags - D.4.2 again */
            if (ctx->file_header_flags & 1) {
                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates sequential organization");
            } else {
                ctx->state = JBIG2_FILE_RANDOM_HEADERS;
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "file header indicates random-access organization");

            }
            break;
        case JBIG2_FILE_SEQUENTIAL_HEADER:
        case JBIG2_FILE_RANDOM_HEADERS:
            segment = jbig2_parse_segment_header(ctx, ctx->buf + ctx->buf_rd_ix, ctx->buf_wr_ix - ctx->buf_rd_ix, &header_size);
            if (segment == NULL)
                return 0;       /* need more data */
            ctx->buf_rd_ix += header_size;

            if (ctx->n_segments == ctx->n_segments_max)
                ctx->segments = jbig2_renew(ctx, ctx->segments, Jbig2Segment *, (ctx->n_segments_max <<= 2));

            ctx->segments[ctx->n_segments++] = segment;
            if (ctx->state == JBIG2_FILE_RANDOM_HEADERS) {
                if ((segment->flags & 63) == 51)        /* end of file */
                    ctx->state = JBIG2_FILE_RANDOM_BODIES;
            } else              /* JBIG2_FILE_SEQUENTIAL_HEADER */
                ctx->state = JBIG2_FILE_SEQUENTIAL_BODY;
            break;
        case JBIG2_FILE_SEQUENTIAL_BODY:
        case JBIG2_FILE_RANDOM_BODIES:
            segment = ctx->segments[ctx->segment_index];
            if (segment->data_length > ctx->buf_wr_ix - ctx->buf_rd_ix)
                return 0;       /* need more data */
            code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
            ctx->buf_rd_ix += segment->data_length;
            ctx->segment_index++;
            if (ctx->state == JBIG2_FILE_RANDOM_BODIES) {
                if (ctx->segment_index == ctx->n_segments)
                    ctx->state = JBIG2_FILE_EOF;
            } else {            /* JBIG2_FILE_SEQUENCIAL_BODY */

                ctx->state = JBIG2_FILE_SEQUENTIAL_HEADER;
            }
            if (code < 0) {
                ctx->state = JBIG2_FILE_EOF;
                return code;
            }
            break;
        case JBIG2_FILE_EOF:
            if (ctx->buf_rd_ix == ctx->buf_wr_ix)
                return 0;
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "Garbage beyond end of file");
        }
    }
}

Project: ghostscript

jbig2_default_alloc(Jbig2Allocator *allocator, size_t size)
{
    return malloc(size);
}

Project: ghostscript

jbig2_default_free(Jbig2Allocator *allocator, void *p)
{
    free(p);
}

Project: ghostscript

jbig2_default_realloc(Jbig2Allocator *allocator, void *p, size_t size)
{
    return realloc(p, size);
}

Project: ghostscript

jbig2_error(Jbig2Ctx *ctx, Jbig2Severity severity, int32_t segment_number, const char *fmt, ...)
{
    char buf[1024];
    va_list ap;
    int n;
    int code;

    va_start(ap, fmt);
    n = vsnprintf(buf, sizeof(buf), fmt, ap);
    va_end(ap);
    if (n < 0 || n == sizeof(buf))
        strncpy(buf, "jbig2_error: error in generating error string", sizeof(buf));
    code = ctx->error_callback(ctx->error_callback_data, buf, severity, segment_number);
    if (severity == JBIG2_SEVERITY_FATAL)
        code = -1;
    return code;
}

Project: ghostscript

jbig2_free(Jbig2Allocator *allocator, void *p)
{
    allocator->free(allocator, p);
}

Project: ghostscript

jbig2_get_int16(const byte *bptr)
{
    return get_int16(bptr);
}

Project: ghostscript

jbig2_get_int32(const byte *bptr)
{
    return ((int32_t) get_int16(bptr) << 16) | get_uint16(bptr + 2);
}

Project: ghostscript

jbig2_get_uint16(const byte *bptr)
{
    return get_uint16(bptr);
}

Project: ghostscript

jbig2_get_uint32(const byte *bptr)
{
    return ((uint32_t) get_uint16(bptr) << 16) | get_uint16(bptr + 2);
}

Project: ghostscript

jbig2_global_ctx_free(Jbig2GlobalCtx *global_ctx)
{
    jbig2_ctx_free((Jbig2Ctx *) global_ctx);
}

Project: ghostscript

jbig2_make_global_ctx(Jbig2Ctx *ctx)
{
    return (Jbig2GlobalCtx *) ctx;
}

Project: ghostscript

jbig2_realloc(Jbig2Allocator *allocator, void *p, size_t size, size_t num)
{
    /* check for integer multiplication overflow */
    if (num > 0 && size >= (size_t) - 0x100 / num)
        return NULL;
    return allocator->realloc(allocator, p, size * num);
}

Project: ghostscript

jbig2_word_stream_buf_new(Jbig2Ctx *ctx, const byte *data, size_t size)
{
    Jbig2WordStreamBuf *result = jbig2_new(ctx, Jbig2WordStreamBuf, 1);

    if (result == NULL) {
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate Jbig2WordStreamBuf in jbig2_word_stream_buf_new");
        return NULL;
    }

    result->super.get_next_word = jbig2_word_stream_buf_get_next_word;
    result->data = data;
    result->size = size;

    return &result->super;
}

Project: ghostscript

copy_prev_row(Jbig2Image *image, int row)
{
    if (!row) {
        /* no previous row */
        memset(image->data, 0, image->stride);
    } else {
        /* duplicate data from the previous row */
        uint8_t *src = image->data + (row - 1) * image->stride;

        memcpy(src + image->stride, src, image->stride);
    }
}

Project: ghostscript

jbig2_decode_generic_region(Jbig2Ctx *ctx,
                            Jbig2Segment *segment, const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int8_t *gbat = params->gbat;

    if (image->stride * image->height > (1 << 24) && segment->data_length < image->stride * image->height / 256) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number,
                           "region is far larger than data provided (%d << %d), aborting to prevent DOS", segment->data_length, image->stride * image->height);
    }

    if (!params->MMR && params->TPGDON)
        return jbig2_decode_generic_region_TPGDON(ctx, segment, params, as, image, GB_stats);

    if (!params->MMR && params->GBTEMPLATE == 0) {
        if (gbat[0] == +3 && gbat[1] == -1 && gbat[2] == -3 && gbat[3] == -1 && gbat[4] == +2 && gbat[5] == -2 && gbat[6] == -2 && gbat[7] == -2)
            return jbig2_decode_generic_template0(ctx, segment, params, as, image, GB_stats);
        else
            return jbig2_decode_generic_template0_unopt(ctx, segment, params, as, image, GB_stats);
    } else if (!params->MMR && params->GBTEMPLATE == 1)
        return jbig2_decode_generic_template1(ctx, segment, params, as, image, GB_stats);
    else if (!params->MMR && params->GBTEMPLATE == 2) {
        if (gbat[0] == 3 && gbat[1] == -1)
            return jbig2_decode_generic_template2a(ctx, segment, params, as, image, GB_stats);
        else
            return jbig2_decode_generic_template2(ctx, segment, params, as, image, GB_stats);
    } else if (!params->MMR && params->GBTEMPLATE == 3) {
        if (gbat[0] == 2 && gbat[1] == -1)
            return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats);
        else
            return jbig2_decode_generic_template3_unopt(ctx, segment, params, as, image, GB_stats);
    }

    {
        int i;

        for (i = 0; i < 8; i++)
                    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number, "gbat[%d] = %d", i, params->gbat[i]);
    }
    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "decode_generic_region: MMR=%d, GBTEMPLATE=%d NYI", params->MMR, params->GBTEMPLATE);
    return -1;
}

Project: ghostscript

jbig2_decode_generic_region_TPGDON(Jbig2Ctx *ctx,
                                   Jbig2Segment *segment,
                                   const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    switch (params->GBTEMPLATE) {
    case 0:
        return jbig2_decode_generic_template0_TPGDON(ctx, segment, params, as, image, GB_stats);
    case 1:
        return jbig2_decode_generic_template1_TPGDON(ctx, segment, params, as, image, GB_stats);
    case 2:
        return jbig2_decode_generic_template2_TPGDON(ctx, segment, params, as, image, GB_stats);
    case 3:
        return jbig2_decode_generic_template3_TPGDON(ctx, segment, params, as, image, GB_stats);
    }

    return -1;
}

Project: ghostscript

                                    jbig2_decode_generic_template0(Jbig2Ctx *ctx,
                                            Jbig2Segment *segment,
                                            const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    const int rowstride = image->stride;
    int x, y;
    byte *gbreg_line = (byte *) image->data;

    /* todo: currently we only handle the nominal gbat location */

#ifdef OUTPUT_PBM
    printf("P4\n%d %d\n", GBW, GBH);
#endif

    if (GBW <= 0)
                return 0;

    for (y = 0; y < GBH; y++) {
        uint32_t CONTEXT;
        uint32_t line_m1;
        uint32_t line_m2;
        int padded_width = (GBW + 7) & -8;

        line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0;
        line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 6 : 0;
                                        CONTEXT = (line_m1 & 0x7f0) | (line_m2 & 0xf800);

                                        /* 6.2.5.7 3d */
        for (x = 0; x < padded_width; x += 8) {
            byte result = 0;
            int x_minor;
            int minor_width = GBW - x > 8 ? 8 : GBW - x;

            if (y >= 1)
                line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0);

            if (y >= 2)
                line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 6 : 0);

                       /* This is the speed-critical inner loop. */
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
                bool bit;

                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                result |= bit << (7 - x_minor);
                CONTEXT = ((CONTEXT & 0x7bf7) << 1) | bit | ((line_m1 >> (7 - x_minor)) & 0x10) | ((line_m2 >> (7 - x_minor)) & 0x800);
            }
            gbreg_line[x >> 3] = result;
        }
#ifdef OUTPUT_PBM
        fwrite(gbreg_line, 1, rowstride, stdout);
#endif
        gbreg_line += rowstride;
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template0_TPGDON(Jbig2Ctx *ctx,
                                      Jbig2Segment *segment,
                                      const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    uint32_t CONTEXT;
    int x, y;
    bool bit;
    int LTP = 0;

    for (y = 0; y < GBH; y++) {
        bit = jbig2_arith_decode(as, &GB_stats[0x9B25]);
        if (bit < 0)
                    return -1;
        LTP ^= bit;
        if (!LTP) {
            for (x = 0; x < GBW; x++) {
                CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
                CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
                CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
                CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
                CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 7;
                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
                CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 13;
                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                jbig2_image_set_pixel(image, x, y, bit);
            }
        } else {
            copy_prev_row(image, y);
        }
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template0_unopt(Jbig2Ctx *ctx,
                                     Jbig2Segment *segment,
                                     const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    uint32_t CONTEXT;
    int x, y;
    bool bit;

    /* this version is generic and easy to understand, but very slow */

    for (y = 0; y < GBH; y++) {
        for (x = 0; x < GBW; x++) {
            CONTEXT = 0;
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
            CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
            CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
            CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
            CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
            CONTEXT |= jbig2_image_get_pixel(image, x + 2, y - 1) << 5;
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 6;
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 7;
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 8;
            CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 9;
            CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[2], y + params->gbat[3]) << 10;
            CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[4], y + params->gbat[5]) << 11;
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 12;
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 2) << 13;
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 14;
            CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[6], y + params->gbat[7]) << 15;
            bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
            if (bit < 0)
                        return -1;
            jbig2_image_set_pixel(image, x, y, bit);
        }
    }
    return 0;
}

Project: ghostscript

jbig2_decode_generic_template1(Jbig2Ctx *ctx,
                               Jbig2Segment *segment,
                               const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    const int rowstride = image->stride;
    int x, y;
    byte *gbreg_line = (byte *) image->data;

    /* todo: currently we only handle the nominal gbat location */

#ifdef OUTPUT_PBM
    printf("P4\n%d %d\n", GBW, GBH);
#endif

    if (GBW <= 0)
                return 0;

    for (y = 0; y < GBH; y++) {
        uint32_t CONTEXT;
        uint32_t line_m1;
        uint32_t line_m2;
        int padded_width = (GBW + 7) & -8;

        line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0;
        line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 5 : 0;
                                        CONTEXT = ((line_m1 >> 1) & 0x1f8) | ((line_m2 >> 1) & 0x1e00);

        /* 6.2.5.7 3d */
        for (x = 0; x < padded_width; x += 8) {
            byte result = 0;
            int x_minor;
            int minor_width = GBW - x > 8 ? 8 : GBW - x;

            if (y >= 1)
                line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0);

            if (y >= 2)
                line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 5 : 0);

                       /* This is the speed-critical inner loop. */
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
                bool bit;

                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                result |= bit << (7 - x_minor);
                CONTEXT = ((CONTEXT & 0xefb) << 1) | bit | ((line_m1 >> (8 - x_minor)) & 0x8) | ((line_m2 >> (8 - x_minor)) & 0x200);
            }
            gbreg_line[x >> 3] = result;
        }
#ifdef OUTPUT_PBM
        fwrite(gbreg_line, 1, rowstride, stdout);
#endif
        gbreg_line += rowstride;
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template2(Jbig2Ctx *ctx,
                               Jbig2Segment *segment,
                               const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    const int rowstride = image->stride;
    int x, y;
    byte *gbreg_line = (byte *) image->data;

    /* todo: currently we only handle the nominal gbat location */

#ifdef OUTPUT_PBM
    printf("P4\n%d %d\n", GBW, GBH);
#endif

    if (GBW <= 0)
                return 0;

    for (y = 0; y < GBH; y++) {
        uint32_t CONTEXT;
        uint32_t line_m1;
        uint32_t line_m2;
        int padded_width = (GBW + 7) & -8;

        line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0;
        line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 4 : 0;
                                        CONTEXT = ((line_m1 >> 3) & 0x7c) | ((line_m2 >> 3) & 0x380);

        /* 6.2.5.7 3d */
        for (x = 0; x < padded_width; x += 8) {
            byte result = 0;
            int x_minor;
            int minor_width = GBW - x > 8 ? 8 : GBW - x;

            if (y >= 1)
                line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0);

            if (y >= 2)
                line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 4 : 0);

                       /* This is the speed-critical inner loop. */
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
                bool bit;

                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                result |= bit << (7 - x_minor);
                CONTEXT = ((CONTEXT & 0x1bd) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80);
            }
            gbreg_line[x >> 3] = result;
        }
#ifdef OUTPUT_PBM
        fwrite(gbreg_line, 1, rowstride, stdout);
#endif
        gbreg_line += rowstride;
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template2_TPGDON(Jbig2Ctx *ctx,
                                      Jbig2Segment *segment,
                                      const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    uint32_t CONTEXT;
    int x, y;
    bool bit;
    int LTP = 0;

    for (y = 0; y < GBH; y++) {
        bit = jbig2_arith_decode(as, &GB_stats[0xE5]);
        if (bit < 0)
                    return -1;
        LTP ^= bit;
        if (!LTP) {
            for (x = 0; x < GBW; x++) {
                CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 2;
                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 3;
                CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 4;
                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 5;
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 6;
                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 2) << 7;
                CONTEXT |= jbig2_image_get_pixel(image, x, y - 2) << 8;
                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 2) << 9;
                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                jbig2_image_set_pixel(image, x, y, bit);
            }
        } else {
            copy_prev_row(image, y);
        }
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template2a(Jbig2Ctx *ctx,
                                Jbig2Segment *segment,
                                const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    const int rowstride = image->stride;
    int x, y;
    byte *gbreg_line = (byte *) image->data;

    /* This is a special case for GBATX1 = 3, GBATY1 = -1 */

#ifdef OUTPUT_PBM
    printf("P4\n%d %d\n", GBW, GBH);
#endif

    if (GBW <= 0)
                return 0;

    for (y = 0; y < GBH; y++) {
        uint32_t CONTEXT;
        uint32_t line_m1;
        uint32_t line_m2;
        int padded_width = (GBW + 7) & -8;

        line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0;
        line_m2 = (y >= 2) ? gbreg_line[-(rowstride << 1)] << 4 : 0;
                                        CONTEXT = ((line_m1 >> 3) & 0x78) | ((line_m1 >> 2) & 0x4) | ((line_m2 >> 3) & 0x380);

        /* 6.2.5.7 3d */
        for (x = 0; x < padded_width; x += 8) {
            byte result = 0;
            int x_minor;
            int minor_width = GBW - x > 8 ? 8 : GBW - x;

            if (y >= 1)
                line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0);

            if (y >= 2)
                line_m2 = (line_m2 << 8) | (x + 8 < GBW ? gbreg_line[-(rowstride << 1) + (x >> 3) + 1] << 4 : 0);

                       /* This is the speed-critical inner loop. */
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
                bool bit;

                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                result |= bit << (7 - x_minor);
                CONTEXT = ((CONTEXT & 0x1b9) << 1) | bit |
                           ((line_m1 >> (10 - x_minor)) & 0x8) | ((line_m1 >> (9 - x_minor)) & 0x4) | ((line_m2 >> (10 - x_minor)) & 0x80);
            }
            gbreg_line[x >> 3] = result;
        }
#ifdef OUTPUT_PBM
        fwrite(gbreg_line, 1, rowstride, stdout);
#endif
        gbreg_line += rowstride;
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template3(Jbig2Ctx *ctx,
                               Jbig2Segment *segment,
                               const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    const int rowstride = image->stride;
    byte *gbreg_line = (byte *) image->data;
    int x, y;

    /* this routine only handles the nominal AT location */

#ifdef OUTPUT_PBM
    printf("P4\n%d %d\n", GBW, GBH);
#endif

    if (GBW <= 0)
                return 0;

    for (y = 0; y < GBH; y++) {
        uint32_t CONTEXT;
        uint32_t line_m1;
        int padded_width = (GBW + 7) & -8;

        line_m1 = (y >= 1) ? gbreg_line[-rowstride] : 0;
        CONTEXT = (line_m1 >> 1) & 0x3f0;

        /* 6.2.5.7 3d */
        for (x = 0; x < padded_width; x += 8) {
            byte result = 0;
            int x_minor;
            int minor_width = GBW - x > 8 ? 8 : GBW - x;

            if (y >= 1)
                line_m1 = (line_m1 << 8) | (x + 8 < GBW ? gbreg_line[-rowstride + (x >> 3) + 1] : 0);

            /* This is the speed-critical inner loop. */
            for (x_minor = 0; x_minor < minor_width; x_minor++) {
                bool bit;

                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                result |= bit << (7 - x_minor);
                CONTEXT = ((CONTEXT & 0x1f7) << 1) | bit | ((line_m1 >> (10 - x_minor)) & 0x010);
            }
            gbreg_line[x >> 3] = result;
        }
#ifdef OUTPUT_PBM
        fwrite(gbreg_line, 1, rowstride, stdout);
#endif
        gbreg_line += rowstride;
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template3_TPGDON(Jbig2Ctx *ctx,
                                      Jbig2Segment *segment,
                                      const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    uint32_t CONTEXT;
    int x, y;
    bool bit;
    int LTP = 0;

    for (y = 0; y < GBH; y++) {
        bit = jbig2_arith_decode(as, &GB_stats[0x0195]);
        if (bit < 0)
                    return -1;
        LTP ^= bit;
        if (!LTP) {
            for (x = 0; x < GBW; x++) {
                CONTEXT = jbig2_image_get_pixel(image, x - 1, y);
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
                CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
                CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
                CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
                CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
                CONTEXT |= jbig2_image_get_pixel(image, x, y - 1) << 6;
                CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
                CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
                CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
                bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
                if (bit < 0)
                            return -1;
                jbig2_image_set_pixel(image, x, y, bit);
            }
        } else {
            copy_prev_row(image, y);
        }
    }

    return 0;
}

Project: ghostscript

jbig2_decode_generic_template3_unopt(Jbig2Ctx *ctx,
                                     Jbig2Segment *segment,
                                     const Jbig2GenericRegionParams *params, Jbig2ArithState *as, Jbig2Image *image, Jbig2ArithCx *GB_stats)
{
    const int GBW = image->width;
    const int GBH = image->height;
    uint32_t CONTEXT;
    int x, y;
    bool bit;

    /* this version is generic and easy to understand, but very slow */

    for (y = 0; y < GBH; y++) {
        for (x = 0; x < GBW; x++) {
            CONTEXT = 0;
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y) << 0;
            CONTEXT |= jbig2_image_get_pixel(image, x - 2, y) << 1;
            CONTEXT |= jbig2_image_get_pixel(image, x - 3, y) << 2;
            CONTEXT |= jbig2_image_get_pixel(image, x - 4, y) << 3;
            CONTEXT |= jbig2_image_get_pixel(image, x + params->gbat[0], y + params->gbat[1]) << 4;
            CONTEXT |= jbig2_image_get_pixel(image, x + 1, y - 1) << 5;
            CONTEXT |= jbig2_image_get_pixel(image, x + 0, y - 1) << 6;
            CONTEXT |= jbig2_image_get_pixel(image, x - 1, y - 1) << 7;
            CONTEXT |= jbig2_image_get_pixel(image, x - 2, y - 1) << 8;
            CONTEXT |= jbig2_image_get_pixel(image, x - 3, y - 1) << 9;
            bit = jbig2_arith_decode(as, &GB_stats[CONTEXT]);
            if (bit < 0)
                        return -1;
            jbig2_image_set_pixel(image, x, y, bit);
        }
    }
    return 0;
}

Project: ghostscript

jbig2_generic_stats_size(Jbig2Ctx *ctx, int template)
{
    int stats_size = template == 0 ? 1 << 16 : template == 1 ? 1 << 1 << 13 : 1 << 10;

                                        return stats_size;
}

Project: ghostscript

jbig2_decode_pattern_dict(Jbig2Ctx *ctx, Jbig2Segment *segment,
                          const Jbig2PatternDictParams *params, const byte *data, const size_t size, Jbig2ArithCx *GB_stats)
{
    Jbig2PatternDict *hd = NULL;
    Jbig2Image *image = NULL;
    Jbig2GenericRegionParams rparams;
    int code = 0;

    /* allocate the collective image */
    image = jbig2_image_new(ctx, params->HDPW * (params->GRAYMAX + 1), params->HDPH);
    if (image == NULL) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate collective bitmap for halftone dict!");
        return NULL;
    }

    /* fill out the generic region decoder parameters */
    rparams.MMR = params->HDMMR;
    rparams.GBTEMPLATE = params->HDTEMPLATE;
    rparams.TPGDON = 0;         /* not used if HDMMR = 1 */
    rparams.USESKIP = 0;
    rparams.gbat[0] = -(int8_t) params->HDPW;
    rparams.gbat[1] = 0;
    rparams.gbat[2] = -3;
    rparams.gbat[3] = -1;
    rparams.gbat[4] = 2;
    rparams.gbat[5] = -2;
    rparams.gbat[6] = -2;
    rparams.gbat[7] = -2;

    if (params->HDMMR) {
        code = jbig2_decode_generic_mmr(ctx, segment, &rparams, data, size, image);
    } else {
        Jbig2WordStream *ws = jbig2_word_stream_buf_new(ctx, data, size);

        if (ws != NULL) {
            Jbig2ArithState *as = jbig2_arith_new(ctx, ws);

            if (as != NULL) {
                code = jbig2_decode_generic_region(ctx, segment, &rparams, as, image, GB_stats);
            } else {
                code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for as in halftone dict!");
            }

            jbig2_free(ctx->allocator, as);
            jbig2_word_stream_buf_free(ctx, ws);
        } else {
            code = jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "failed to allocate storage for ws in halftone dict!");
        }
    }

    if (code == 0)
        hd = jbig2_hd_new(ctx, params, image);
    jbig2_image_release(ctx, image);

    return hd;
}

Project: ghostscript

jbig2_hd_new(Jbig2Ctx *ctx, const Jbig2PatternDictParams *params, Jbig2Image *image)
{
    Jbig2PatternDict *new;
    const int N = params->GRAYMAX + 1;
    const int HPW = params->HDPW;
    const int HPH = params->HDPH;
    int i;

    /* allocate a new struct */
    new = jbig2_new(ctx, Jbig2PatternDict, 1);
    if (new != NULL) {
        new->patterns = jbig2_new(ctx, Jbig2Image *, N);
        if (new->patterns == NULL) {
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate pattern in collective bitmap dictionary");
            jbig2_free(ctx->allocator, new);
            return NULL;
        }
        new->n_patterns = N;
        new->HPW = HPW;
        new->HPH = HPH;

        /* 6.7.5(4) - copy out the individual pattern images */
        for (i = 0; i < N; i++) {
            new->patterns[i] = jbig2_image_new(ctx, HPW, HPH);
            if (new->patterns[i] == NULL) {
                int j;

                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "failed to allocate pattern element image");
                for (j = 0; j < i; j++)
                    jbig2_free(ctx->allocator, new->patterns[j]);
                jbig2_free(ctx->allocator, new);
                return NULL;
            }
            /* compose with the REPLACE operator; the source
               will be clipped to the destintion, selecting the
               proper sub image */
            jbig2_image_compose(ctx, new->patterns[i], image, -i * HPW, 0, JBIG2_COMPOSE_REPLACE);
        }
    } else {
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "failed to allocate collective bitmap dictionary");
    }

    return new;
}

Project: ghostscript

jbig2_hd_release(Jbig2Ctx *ctx, Jbig2PatternDict *dict)
{
    int i;

    if (dict == NULL)
        return;
    for (i = 0; i < dict->n_patterns; i++)
        if (dict->patterns[i])
            jbig2_image_release(ctx, dict->patterns[i]);
    jbig2_free(ctx->allocator, dict->patterns);
    jbig2_free(ctx->allocator, dict);
}

Project: ghostscript

jbig2_pattern_dictionary(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
{
    Jbig2PatternDictParams params;
    Jbig2ArithCx *GB_stats = NULL;
    byte flags;
    int offset = 0;

    /* 7.4.4.1 - Data header */
    if (segment->data_length < 7) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
    }
    flags = segment_data[0];
    params.HDMMR = flags & 1;
    params.HDTEMPLATE = (flags & 6) >> 1;
    params.HDPW = segment_data[1];
    params.HDPH = segment_data[2];
    params.GRAYMAX = jbig2_get_uint32(segment_data + 3);
    offset += 7;

    jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
                "pattern dictionary, flags=%02x, %d grays (%dx%d cell)", flags, params.GRAYMAX + 1, params.HDPW, params.HDPH);

    if (params.HDMMR && params.HDTEMPLATE) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "HDTEMPLATE is %d when HDMMR is %d, contrary to spec", params.HDTEMPLATE, params.HDMMR);
    }
    if (flags & 0xf8) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "Reserved flag bits non-zero");
    }

    /* 7.4.4.2 */
    if (!params.HDMMR) {
        /* allocate and zero arithmetic coding stats */
        int stats_size = jbig2_generic_stats_size(ctx, params.HDTEMPLATE);

        GB_stats = jbig2_new(ctx, Jbig2ArithCx, stats_size);
        if (GB_stats == NULL) {
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate GB_stats in pattern dictionary");
            return 0;
        }
        memset(GB_stats, 0, stats_size);
    }

    segment->result = jbig2_decode_pattern_dict(ctx, segment, &params, segment_data + offset, segment->data_length - offset, GB_stats);

    /* todo: retain GB_stats? */
    if (!params.HDMMR) {
        jbig2_free(ctx->allocator, GB_stats);
    }

    return (segment->result != NULL) ? 0 : -1;
}

Project: ghostscript

jbig2_build_huffman_table(Jbig2Ctx *ctx, const Jbig2HuffmanParams *params)
{
    int *LENCOUNT;
    int LENMAX = -1;
    const int lencountcount = 256;
    const Jbig2HuffmanLine *lines = params->lines;
    int n_lines = params->n_lines;
    int i, j;
    int max_j;
    int log_table_size = 0;
    Jbig2HuffmanTable *result;
    Jbig2HuffmanEntry *entries;
    int CURLEN;
    int firstcode = 0;
    int CURCODE;
    int CURTEMP;

    LENCOUNT = jbig2_new(ctx, int, lencountcount);

    if (LENCOUNT == NULL) {
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate storage for huffman histogram");
        return NULL;
    }
    memset(LENCOUNT, 0, sizeof(int) * lencountcount);

    /* B.3, 1. */
    for (i = 0; i < params->n_lines; i++) {
        int PREFLEN = lines[i].PREFLEN;
        int lts;

        if (PREFLEN > LENMAX) {
            for (j = LENMAX + 1; j < PREFLEN + 1; j++)
                LENCOUNT[j] = 0;
            LENMAX = PREFLEN;
        }
        LENCOUNT[PREFLEN]++;

        lts = PREFLEN + lines[i].RANGELEN;
        if (lts > LOG_TABLE_SIZE_MAX)
            lts = PREFLEN;
        if (lts <= LOG_TABLE_SIZE_MAX && log_table_size < lts)
            log_table_size = lts;
    }
    jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "constructing huffman table log size %d", log_table_size);
    max_j = 1 << log_table_size;

    result = jbig2_new(ctx, Jbig2HuffmanTable, 1);
    if (result == NULL) {
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate result storage in jbig2_build_huffman_table");
        jbig2_free(ctx->allocator, LENCOUNT);
        return NULL;
    }
    result->log_table_size = log_table_size;
    entries = jbig2_new(ctx, Jbig2HuffmanEntry, max_j);
    if (entries == NULL) {
        jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "couldn't allocate entries storage in jbig2_build_huffman_table");
        jbig2_free(ctx->allocator, result);
        jbig2_free(ctx->allocator, LENCOUNT);
        return NULL;
    }
    /* fill now to catch missing JBIG2Globals later */
    memset(entries, 0xFF, sizeof(Jbig2HuffmanEntry) * max_j);
    result->entries = entries;

    LENCOUNT[0] = 0;

    for (CURLEN = 1; CURLEN <= LENMAX; CURLEN++) {
        int shift = log_table_size - CURLEN;

        /* B.3 3.(a) */
        firstcode = (firstcode + LENCOUNT[CURLEN - 1]) << 1;
        CURCODE = firstcode;
        /* B.3 3.(b) */
        for (CURTEMP = 0; CURTEMP < n_lines; CURTEMP++) {
            int PREFLEN = lines[CURTEMP].PREFLEN;

            if (PREFLEN == CURLEN) {
                int RANGELEN = lines[CURTEMP].RANGELEN;
                int start_j = CURCODE << shift;
                int end_j = (CURCODE + 1) << shift;
                byte eflags = 0;

                if (end_j > max_j) {
                    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, -1, "ran off the end of the entries table! (%d >= %d)", end_j, max_j);
                    jbig2_free(ctx->allocator, result->entries);
                    jbig2_free(ctx->allocator, result);
                    jbig2_free(ctx->allocator, LENCOUNT);
                    return NULL;
                }
                /* todo: build extension tables */
                if (params->HTOOB && CURTEMP == n_lines - 1)
                    eflags |= JBIG2_HUFFMAN_FLAGS_ISOOB;
                if (CURTEMP == n_lines - (params->HTOOB ? 3 : 2))
                    eflags |= JBIG2_HUFFMAN_FLAGS_ISLOW;
                if (PREFLEN + RANGELEN > LOG_TABLE_SIZE_MAX) {
                    for (j = start_j; j < end_j; j++) {
                        entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW;
                        entries[j].PREFLEN = PREFLEN;
                        entries[j].RANGELEN = RANGELEN;
                        entries[j].flags = eflags;
                    }
                } else {
                    for (j = start_j; j < end_j; j++) {
                        int32_t HTOFFSET = (j >> (shift - RANGELEN)) & ((1 << RANGELEN) - 1);

                        if (eflags & JBIG2_HUFFMAN_FLAGS_ISLOW)
                            entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW - HTOFFSET;
                        else
                            entries[j].u.RANGELOW = lines[CURTEMP].RANGELOW + HTOFFSET;
                        entries[j].PREFLEN = PREFLEN + RANGELEN;
                        entries[j].RANGELEN = 0;
                        entries[j].flags = eflags;
                    }
                }
                CURCODE++;
            }
        }
    }

    jbig2_free(ctx->allocator, LENCOUNT);

    return result;
}

Project: ghostscript

jbig2_dump_huffman_binary(Jbig2HuffmanState *hs)
{
    const uint32_t word = hs->this_word;
    int i;

    fprintf(stderr, "huffman binary ");
    for (i = 31; i >= 0; i--)
        fprintf(stderr, ((word >> i) & 1) ? "1" : "0");
    fprintf(stderr, "\n");
}

Project: ghostscript

jbig2_dump_huffman_table(const Jbig2HuffmanTable *table)
{
    int i;
    int table_size = (1 << table->log_table_size);

    fprintf(stderr, "huffman table %p (log_table_size=%d, %d entries, entryies=%p):\n", table, table->log_table_size, table_size, table->entries);
    for (i = 0; i < table_size; i++) {
        fprintf(stderr, "%6d: PREFLEN=%d, RANGELEN=%d, ", i, table->entries[i].PREFLEN, table->entries[i].RANGELEN);
        if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISEXT) {
            fprintf(stderr, "ext=%p", table->entries[i].u.ext_table);
        } else {
            fprintf(stderr, "RANGELOW=%d", table->entries[i].u.RANGELOW);
        }
        if (table->entries[i].flags) {
            int need_comma = 0;

            fprintf(stderr, ", flags=0x%x(", table->entries[i].flags);
            if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISOOB) {
                fprintf(stderr, "OOB");
                need_comma = 1;
            }
            if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISLOW) {
                if (need_comma)
                    fprintf(stderr, ",");
                fprintf(stderr, "LOW");
                need_comma = 1;
            }
            if (table->entries[i].flags & JBIG2_HUFFMAN_FLAGS_ISEXT) {
                if (need_comma)
                    fprintf(stderr, ",");
                fprintf(stderr, "EXT");
            }
            fprintf(stderr, ")");
        }
        fprintf(stderr, "\n");
    }
    fprintf(stderr, "\n");
}

Project: ghostscript

jbig2_find_table(Jbig2Ctx *ctx, Jbig2Segment *segment, int index)
{
    int i, table_index = 0;

    for (i = 0; i < segment->referred_to_segment_count; i++) {
        const Jbig2Segment *const rsegment = jbig2_find_segment(ctx, segment->referred_to_segments[i]);

        if (rsegment && (rsegment->flags & 63) == 53) {
            if (table_index == index)
                return (const Jbig2HuffmanParams *)rsegment->result;
            ++table_index;
        }
    }
    return NULL;
}

Project: ghostscript

jbig2_huffman_free(Jbig2Ctx *ctx, Jbig2HuffmanState *hs)
{
    if (hs != NULL)
        jbig2_free(ctx->allocator, hs);
    return;
}

Project: ghostscript

jbig2_huffman_get(Jbig2HuffmanState *hs, const Jbig2HuffmanTable *table, bool *oob)
{
    Jbig2HuffmanEntry *entry;
    byte flags;
    int offset_bits = hs->offset_bits;
    uint32_t this_word = hs->this_word;
    uint32_t next_word;
    int RANGELEN;
    int32_t result;

    if (hs->offset_limit && hs->offset >= hs->offset_limit) {
        jbig2_error(hs->ctx, JBIG2_SEVERITY_FATAL, -1, "end of Jbig2WordStream reached at offset %d", hs->offset);
        if (oob)
            *oob = -1;
        return -1;
    }

    for (;;) {
        int log_table_size = table->log_table_size;
        int PREFLEN;

        /* SumatraPDF: shifting by the size of the operand is undefined */
        entry = &table->entries[log_table_size > 0 ? this_word >> (32 - log_table_size) : 0];
        flags = entry->flags;
        PREFLEN = entry->PREFLEN;
        if ((flags == (byte) - 1) && (PREFLEN == (byte) - 1) && (entry->u.RANGELOW == -1)) {
            if (oob)
                *oob = -1;
            return -1;
        }

        next_word = hs->next_word;
        offset_bits += PREFLEN;
        if (offset_bits >= 32) {
            this_word = next_word;
            hs->offset += 4;
            next_word = huff_get_next_word(hs, hs->offset + 4);
            offset_bits -= 32;
            hs->next_word = next_word;
            PREFLEN = offset_bits;
        }
        if (PREFLEN)
            this_word = (this_word << PREFLEN) | (next_word >> (32 - offset_bits));
        if (flags & JBIG2_HUFFMAN_FLAGS_ISEXT) {
            table = entry->u.ext_table;
        } else
            break;
    }
    result = entry->u.RANGELOW;
    RANGELEN = entry->RANGELEN;
    if (RANGELEN > 0) {
        int32_t HTOFFSET;

        HTOFFSET = this_word >> (32 - RANGELEN);
        if (flags & JBIG2_HUFFMAN_FLAGS_ISLOW)
            result -= HTOFFSET;
        else
            result += HTOFFSET;

        offset_bits += RANGELEN;
        if (offset_bits >= 32) {
            this_word = next_word;
            hs->offset += 4;
            next_word = huff_get_next_word(hs, hs->offset + 4);
            offset_bits -= 32;
            hs->next_word = next_word;
            RANGELEN = offset_bits;
        }
        if (RANGELEN)
            this_word = (this_word << RANGELEN) | (next_word >> (32 - offset_bits));
    }

    hs->this_word = this_word;
    hs->offset_bits = offset_bits;

    if (oob != NULL)
        *oob = (flags & JBIG2_HUFFMAN_FLAGS_ISOOB);

    return result;
}

Project: ghostscript

 jbig2_huffman_offset(Jbig2HuffmanState *hs)
 {
     return hs->offset + (hs->offset_bits >> 3);
}

Project: ghostscript

jbig2_huffman_skip(Jbig2HuffmanState *hs)
{
    int bits = hs->offset_bits & 7;

    if (bits) {
        bits = 8 - bits;
        hs->offset_bits += bits;
        hs->this_word = (hs->this_word << bits) | (hs->next_word >> (32 - hs->offset_bits));
    }

    if (hs->offset_bits >= 32) {
        hs->this_word = hs->next_word;
        hs->offset += 4;
        hs->next_word = huff_get_next_word(hs, hs->offset + 4);
        hs->offset_bits -= 32;
        if (hs->offset_bits) {
            hs->this_word = (hs->this_word << hs->offset_bits) | (hs->next_word >> (32 - hs->offset_bits));
        }
    }
}

Project: ghostscript

jbig2_release_huffman_table(Jbig2Ctx *ctx, Jbig2HuffmanTable *table)
{
    if (table != NULL) {
        jbig2_free(ctx->allocator, table->entries);
        jbig2_free(ctx->allocator, table);
    }
    return;
}

Project: ghostscript

jbig2_table(Jbig2Ctx *ctx, Jbig2Segment *segment, const byte *segment_data)
{
    Jbig2HuffmanParams *params = NULL;
    Jbig2HuffmanLine *line = NULL;

    segment->result = NULL;
    if (segment->data_length < 10)
        goto too_short;

    {
        /* B.2 1) (B.2.1) Code table flags */
        const int code_table_flags = segment_data[0];
        const int HTOOB = code_table_flags & 0x01;      /* Bit 0: HTOOB */

        /* Bits 1-3: Number of bits used in code table line prefix size fields */
        const int HTPS = (code_table_flags >> 1 & 0x07) + 1;

        /* Bits 4-6: Number of bits used in code table line range size fields */
        const int HTRS = (code_table_flags >> 4 & 0x07) + 1;

        /* B.2 2) (B.2.2) The lower bound of the first table line in the encoded table */
        const int32_t HTLOW = jbig2_get_int32(segment_data + 1);

        /* B.2 3) (B.2.3) One larger than the upeer bound of
           the last normal table line in the encoded table */
        const int32_t HTHIGH = jbig2_get_int32(segment_data + 5);

        /* estimated number of lines int this table, used for alloacting memory for lines */
        const size_t lines_max = (segment->data_length * 8 - HTPS * (HTOOB ? 3 : 2)) / (HTPS + HTRS) + (HTOOB ? 3 : 2);

        /* points to a first table line data */
        const byte *lines_data = segment_data + 9;
        const size_t lines_data_bitlen = (segment->data_length - 9) * 8;        /* length in bit */

        /* bit offset: controls bit reading */
        size_t boffset = 0;

        /* B.2 4) */
        int32_t CURRANGELOW = HTLOW;
        size_t NTEMP = 0;

#ifdef JBIG2_DEBUG
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
                    "DECODING USER TABLE... Flags: %d, HTOOB: %d, HTPS: %d, HTRS: %d, HTLOW: %d, HTHIGH: %d",
                    code_table_flags, HTOOB, HTPS, HTRS, HTLOW, HTHIGH);
#endif

        /* allocate HuffmanParams & HuffmanLine */
        params = jbig2_new(ctx, Jbig2HuffmanParams, 1);
        if (params == NULL) {
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not allocate Huffman Table Parameter");
            goto error_exit;
        }
        line = jbig2_new(ctx, Jbig2HuffmanLine, lines_max);
        if (line == NULL) {
            jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not allocate Huffman Table Lines");
            goto error_exit;
        }
        /* B.2 5) */
        while (CURRANGELOW < HTHIGH) {
            /* B.2 5) a) */
            if (boffset + HTPS >= lines_data_bitlen)
                goto too_short;
            line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS);
            /* B.2 5) b) */
            if (boffset + HTRS >= lines_data_bitlen)
                goto too_short;
            line[NTEMP].RANGELEN = jbig2_table_read_bits(lines_data, &boffset, HTRS);
            /* B.2 5) c) */
            line[NTEMP].RANGELOW = CURRANGELOW;
            CURRANGELOW += (1 << line[NTEMP].RANGELEN);
            NTEMP++;
        }
        /* B.2 6), B.2 7) lower range table line */
        if (boffset + HTPS >= lines_data_bitlen)
            goto too_short;
        line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS);
        line[NTEMP].RANGELEN = 32;
        line[NTEMP].RANGELOW = HTLOW - 1;
        NTEMP++;
        /* B.2 8), B.2 9) upper range table line */
        if (boffset + HTPS >= lines_data_bitlen)
            goto too_short;
        line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS);
        line[NTEMP].RANGELEN = 32;
        line[NTEMP].RANGELOW = HTHIGH;
        NTEMP++;
        /* B.2 10) */
        if (HTOOB) {
            /* B.2 10) a), B.2 10) b) out-of-bound table line */
            if (boffset + HTPS >= lines_data_bitlen)
                goto too_short;
            line[NTEMP].PREFLEN = jbig2_table_read_bits(lines_data, &boffset, HTPS);
            line[NTEMP].RANGELEN = 0;
            line[NTEMP].RANGELOW = 0;
            NTEMP++;
        }
        if (NTEMP != lines_max) {
            Jbig2HuffmanLine *new_line = jbig2_renew(ctx, line,
                                         Jbig2HuffmanLine, NTEMP);

            if (new_line == NULL) {
                jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Could not reallocate Huffman Table Lines");
                goto error_exit;
            }
            line = new_line;
        }
        params->HTOOB = HTOOB;
        params->n_lines = NTEMP;
        params->lines = line;
        segment->result = params;

#ifdef JBIG2_DEBUG
        {
            int i;

            for (i = 0; i < NTEMP; i++) {
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
                            "Line: %d, PREFLEN: %d, RANGELEN: %d, RANGELOW: %d",
                            i, params->lines[i].PREFLEN, params->lines[i].RANGELEN, params->lines[i].RANGELOW);
            }
        }
#endif
    }
    return 0;

too_short:
    jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "Segment too short");
error_exit:
    if (line != NULL) {
        jbig2_free(ctx->allocator, line);
    }
    if (params != NULL) {
        jbig2_free(ctx->allocator, params);
    }
    return -1;
}

Project: ghostscript

jbig2_table_free(Jbig2Ctx *ctx, Jbig2HuffmanParams *params)
{
    if (params != NULL) {
        if (params->lines != NULL)
            jbig2_free(ctx->allocator, (void *)params->lines);
        jbig2_free(ctx->allocator, params);
    }
}

Project: ghostscript

jbig2_table_read_bits(const byte *data, size_t *bitoffset, const int bitlen)
{
    uint32_t result = 0;
    uint32_t byte_offset = *bitoffset / 8;
    const int endbit = (*bitoffset & 7) + bitlen;
    const int n_proc_bytes = (endbit + 7) / 8;
    const int rshift = n_proc_bytes * 8 - endbit;
    int i;

    for (i = n_proc_bytes - 1; i >= 0; i--) {
        uint32_t d = data[byte_offset++];
        const int nshift = i * 8 - rshift;

        if (nshift > 0)
            d <<= nshift;
        else if (nshift < 0)
            d >>= -nshift;
        result |= d;
    }
    result &= ~(-1 << bitlen);
    *bitoffset += bitlen;
    return result;
}

Project: ghostscript

test_get_word(Jbig2WordStream *self, int offset, uint32_t *word)
{
    uint32_t val = 0;
    test_stream_t *st = (test_stream_t *) self;

    if (st != NULL) {
        if (st->h != NULL) {
            if (offset >= st->h->input_len)
                return -1;
            if (offset < st->h->input_len) {
                val |= (st->h->input[offset] << 24);
            }
            if (offset + 1 < st->h->input_len) {
                val |= (st->h->input[offset + 1] << 16);
            }
            if (offset + 2 < st->h->input_len) {
                val |= (st->h->input[offset + 2] << 8);
            }
            if (offset + 3 < st->h->input_len) {
                val |= st->h->input[offset + 3];
            }
        }
    }
    *word = val;
    return 0;
}

Project: ghostscript
File: jbig2_image.c

jbig2_image_clear(Jbig2Ctx *ctx, Jbig2Image *image, int value)
{
    const uint8_t fill = value ? 0xFF : 0x00;

    memset(image->data, fill, image->stride * image->height);
}

Project: ghostscript

jbig2_image_clone(Jbig2Ctx *ctx, Jbig2Image *image)
{
    if (image)
        image->refcount++;
    return image;
}

Project: ghostscript

jbig2_image_free(Jbig2Ctx *ctx, Jbig2Image *image)
{
    if (image)
        jbig2_free(ctx->allocator, image->data);
    jbig2_free(ctx->allocator, image);
}

Project: ghostscript
File: jbig2_image.c

jbig2_image_get_pixel(Jbig2Image *image, int x, int y)
{
    const int w = image->width;
    const int h = image->height;
    const int byte = (x >> 3) + y * image->stride;
    const int bit = 7 - (x & 7);

    if ((x < 0) || (x >= w))
        return 0;
    if ((y < 0) || (y >= h))
        return 0;

    return ((image->data[byte] >> bit) & 1);
}

Project: ghostscript

jbig2_image_release(Jbig2Ctx *ctx, Jbig2Image *image)
{
    if (image == NULL)
        return;
    image->refcount--;
    if (!image->refcount)
        jbig2_image_free(ctx, image);
}

Project: ghostscript

jbig2_image_set_pixel(Jbig2Image *image, int x, int y, bool value)
{
    const int w = image->width;
    const int h = image->height;
    int scratch, mask;
    int bit, byte;

    if ((x < 0) || (x >= w))
        return 0;
    if ((y < 0) || (y >= h))
        return 0;

    byte = (x >> 3) + y * image->stride;
    bit = 7 - (x & 7);
    mask = (1 << bit) ^ 0xff;

    scratch = image->data[byte] & mask;
    image->data[byte] = scratch | (value << bit);

    return 1;
}

Project: ghostscript

jbig2_decode_mmr_consume(Jbig2MmrCtx *mmr, int n_bits)
{
    mmr->word <<= n_bits;
    mmr->bit_index += n_bits;
    while (mmr->bit_index >= 8) {
        mmr->bit_index -= 8;
        if (mmr->data_index + 4 < mmr->size)
            mmr->word |= (mmr->data[mmr->data_index + 4] << mmr->bit_index);
        mmr->data_index++;
    }
}

Project: ghostscript

dump_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, Jbig2Page *page)
{
    if (page->x_resolution == 0) {
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (unknown res)", page->number, page->width, page->height);
    } else if (page->x_resolution == page->y_resolution) {
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "page %d image is %dx%d (%d ppm)", page->number, page->width, page->height, page->x_resolution);
    } else {
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
                    "page %d image is %dx%d (%dx%d ppm)", page->number, page->width, page->height, page->x_resolution, page->y_resolution);
    }
    if (page->striped) {
        jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number, "\tmaximum stripe size: %d", page->stripe_size);
    }
}

Project: ghostscript

jbig2_complete_page(Jbig2Ctx *ctx)
{
    int code = 0;

    /* check for unfinished segments */
    if (ctx->segment_index != ctx->n_segments) {
        Jbig2Segment *segment = ctx->segments[ctx->segment_index];

        /* Some versions of Xerox Workcentre generate PDF files
           with the segment data length field of the last segment
           set to -1. Try to cope with this here. */
        if ((segment->data_length & 0xffffffff) == 0xffffffff) {
            jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "File has an invalid segment data length!" " Trying to decode using the available data.");
            segment->data_length = ctx->buf_wr_ix - ctx->buf_rd_ix;
            code = jbig2_parse_segment(ctx, segment, ctx->buf + ctx->buf_rd_ix);
            ctx->buf_rd_ix += segment->data_length;
            ctx->segment_index++;
        }
    }

    /* ensure image exists before marking page as complete */
    if (ctx->pages[ctx->current_page].image != NULL) {
        ctx->pages[ctx->current_page].state = JBIG2_PAGE_COMPLETE;
    }

    return code;
}

Project: ghostscript

jbig2_page_info(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
{
    Jbig2Page *page;

    /* a new page info segment implies the previous page is finished */
    page = &(ctx->pages[ctx->current_page]);
    if ((page->number != 0) && ((page->state == JBIG2_PAGE_NEW) || (page->state == JBIG2_PAGE_FREE))) {
        page->state = JBIG2_PAGE_COMPLETE;
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unexpected page info segment, marking previous page finished");
    }

    /* find a free page */
    {
        int index, j;

        index = ctx->current_page;
        while (ctx->pages[index].state != JBIG2_PAGE_FREE) {
            index++;
            if (index >= ctx->max_page_index) {
                /* grow the list */
                ctx->pages = jbig2_renew(ctx, ctx->pages, Jbig2Page, (ctx->max_page_index <<= 2));
                for (j = index; j < ctx->max_page_index; j++) {
                    ctx->pages[j].state = JBIG2_PAGE_FREE;
                    ctx->pages[j].number = 0;
                    ctx->pages[j].image = NULL;

                }
            }
        }
        page = &(ctx->pages[index]);
        ctx->current_page = index;
        page->state = JBIG2_PAGE_NEW;
        page->number = segment->page_association;
    }

    /* FIXME: would be nice if we tried to work around this */
    if (segment->data_length < 19) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "segment too short");
    }

    /* 7.4.8.x */
    page->width = jbig2_get_uint32(segment_data);
    page->height = jbig2_get_uint32(segment_data + 4);

    page->x_resolution = jbig2_get_uint32(segment_data + 8);
    page->y_resolution = jbig2_get_uint32(segment_data + 12);
    page->flags = segment_data[16];

    /* 7.4.8.6 */
    {
        int16_t striping = jbig2_get_int16(segment_data + 17);

        if (striping & 0x8000) {
            page->striped = TRUE;
            page->stripe_size = striping & 0x7FFF;
        } else {
            page->striped = FALSE;
            page->stripe_size = 0;      /* would page->height be better? */
        }
    }
    if (page->height == 0xFFFFFFFF && page->striped == FALSE) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "height is unspecified but page is not markes as striped");
        page->striped = TRUE;
    }
    page->end_row = 0;

    if (segment->data_length > 19) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extra data in segment");
    }

    dump_page_info(ctx, segment, page);

    /* allocate an approprate page image buffer */
    /* 7.4.8.2 */
    if (page->height == 0xFFFFFFFF) {
        page->image = jbig2_image_new(ctx, page->width, page->stripe_size);
    } else {
        page->image = jbig2_image_new(ctx, page->width, page->height);
    }
    if (page->image == NULL) {
        return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "failed to allocate buffer for page image");
    } else {
        /* 8.2 (3) fill the page with the default pixel value */
        jbig2_image_clear(ctx, page->image, (page->flags & 4));
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, segment->number,
                    "allocated %dx%d page image (%d bytes)", page->image->width, page->image->height, page->image->stride * page->image->height);
    }

    return 0;
}

Project: ghostscript

jbig2_page_out(Jbig2Ctx *ctx)
{
    int index;

    /* search for a completed page */
    for (index = 0; index < ctx->max_page_index; index++) {
        if (ctx->pages[index].state == JBIG2_PAGE_COMPLETE) {
            Jbig2Image *img = ctx->pages[index].image;
            uint32_t page_number = ctx->pages[index].number;

            ctx->pages[index].state = JBIG2_PAGE_RETURNED;
            if (img != NULL) {
                jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d returned to the client", page_number);
                return jbig2_image_clone(ctx, img);
            } else {
                jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "page %d returned with no associated image", page_number);
                ;               /* continue */
            }
        }
    }

    /* no pages available */
    return NULL;
}

Project: ghostscript

jbig2_release_page(Jbig2Ctx *ctx, Jbig2Image *image)
{
    int index;

    /* find the matching page struct and mark it released */
    for (index = 0; index < ctx->max_page_index; index++) {
        if (ctx->pages[index].image == image) {
            jbig2_image_release(ctx, image);
            ctx->pages[index].state = JBIG2_PAGE_RELEASED;
            jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, -1, "page %d released by the client", ctx->pages[index].number);
            return 0;
        }
    }

    /* no matching pages */
    jbig2_error(ctx, JBIG2_SEVERITY_WARNING, -1, "jbig2_release_page called on unknown page");
    return 1;
}

Project: ghostscript

jbig2_find_segment(Jbig2Ctx *ctx, uint32_t number)
{
    int index, index_max = ctx->segment_index - 1;
    const Jbig2Ctx *global_ctx = ctx->global_ctx;

    /* FIXME: binary search would be better */
    for (index = index_max; index >= 0; index--)
        if (ctx->segments[index]->number == number)
            return (ctx->segments[index]);

    if (global_ctx)
        for (index = global_ctx->segment_index - 1; index >= 0; index--)
            if (global_ctx->segments[index]->number == number)
                return (global_ctx->segments[index]);

    /* didn't find a match */
    return NULL;
}

Project: ghostscript

jbig2_free_segment(Jbig2Ctx *ctx, Jbig2Segment *segment)
{
    if (segment->referred_to_segments != NULL) {
        jbig2_free(ctx->allocator, segment->referred_to_segments);
    }
    /* todo: we need either some separate fields or
       a more complex result object rather than this
       brittle special casing */
    switch (segment->flags & 63) {
    case 0:                    /* symbol dictionary */
        if (segment->result != NULL)
            jbig2_sd_release(ctx, (Jbig2SymbolDict *) segment->result);
        break;
    case 4:                    /* intermediate text region */
    case 40:                   /* intermediate refinement region */
        if (segment->result != NULL)
            jbig2_image_release(ctx, (Jbig2Image *) segment->result);
        break;
    case 16:                   /* pattern dictionary */
        if (segment->result != NULL)
            jbig2_hd_release(ctx, (Jbig2PatternDict *) segment->result);
        break;
    case 53:                   /* user-supplied huffman table */
        if (segment->result != NULL)
            jbig2_table_free(ctx, (Jbig2HuffmanParams *) segment->result);
        break;
    case 62:
        if (segment->result != NULL)
            jbig2_metadata_free(ctx, (Jbig2Metadata *) segment->result);
        break;
    default:
        /* anything else is probably an undefined pointer */
        break;
    }
    jbig2_free(ctx->allocator, segment);
}

Project: ghostscript

jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info, const uint8_t *segment_data)
{
    /* 7.4.1 */
    info->width = jbig2_get_int32(segment_data);
    info->height = jbig2_get_int32(segment_data + 4);
    info->x = jbig2_get_int32(segment_data + 8);
    info->y = jbig2_get_int32(segment_data + 12);
    info->flags = segment_data[16];
    info->op = (Jbig2ComposeOp)(info->flags & 0x7);
}

Project: ghostscript

jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment, const uint8_t *segment_data)
{
    uint32_t type = jbig2_get_uint32(segment_data);
    bool reserved = type & 0x20000000;

    /* bool dependent = type & 0x40000000; (NYI) */
    bool necessary = type & 0x80000000;

    if (necessary && !reserved) {
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "extension segment is marked 'necessary' but " "not 'reservered' contrary to spec");
    }

    switch (type) {
    case 0x20000000:
        return jbig2_comment_ascii(ctx, segment, segment_data);
    case 0x20000002:
        return jbig2_comment_unicode(ctx, segment, segment_data);
    default:
        if (necessary) {
            return jbig2_error(ctx, JBIG2_SEVERITY_FATAL, segment->number, "unhandled necessary extension segment type 0x%08x", type);
        } else {
            return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number, "unhandled extension segment");
        }
    }
}

Project: ghostscript
File: jbig2_symbol_dict.c

jbig2_sd_glyph(Jbig2SymbolDict *dict, unsigned int id)
{
    if (dict == NULL)
        return NULL;
    return dict->glyphs[id];
 }