shithub: jbig2

ref: 72f228cadf2b189713cdcb92c1cb20facdab0822
dir: /jbig2_segment.c/

View raw version
/*
    jbig2dec
    
    Copyright (c) 2002-2003 artofcode LLC.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    $Id: jbig2_segment.c,v 1.23 2003/03/10 14:44:01 giles Exp $
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif 
#include "os_types.h"

#include <stddef.h> /* size_t */

#include "jbig2.h"
#include "jbig2_priv.h"
#include "jbig2_symbol_dict.h"

Jbig2Segment *
jbig2_parse_segment_header (Jbig2Ctx *ctx, uint8_t *buf, size_t buf_size,
			    size_t *p_header_size)
{
  Jbig2Segment *result;
  uint8_t rtscarf;
  uint32_t rtscarf_long;
  uint32_t *referred_to_segments;
  int referred_to_segment_count;
  int referred_to_segment_size;
  int pa_size;
  int offset;

  /* minimum possible size of a jbig2 segment header */
  if (buf_size < 11)
    return NULL;

  result = (Jbig2Segment *)jbig2_alloc(ctx->allocator,
					     sizeof(Jbig2Segment));

  /* 7.2.2 */
  result->number = jbig2_get_int32(buf);

  /* 7.2.3 */
  result->flags = buf[4];

  /* 7.2.4 referred-to segments */
  rtscarf = buf[5];
  if ((rtscarf & 0xe0) == 0xe0)
    {
      rtscarf_long = jbig2_get_int32(buf + 5);
      referred_to_segment_count = rtscarf_long & 0x1fffffff;
      offset = 5 + 4 + (referred_to_segment_count + 1) / 8;
    }
  else
    {
      referred_to_segment_count = (rtscarf >> 5);
      offset = 5 + 1;
    }
  result->referred_to_segment_count = referred_to_segment_count;

  /* we now have enough information to compute the full header length */
  referred_to_segment_size = result->number <= 256 ? 1:
        result->number <= 65536 ? 2 : 4;  /* 7.2.5 */
  pa_size = result->flags & 0x40 ? 4 : 1; /* 7.2.6 */
  if (offset + referred_to_segment_count*referred_to_segment_size + pa_size + 4 > buf_size)
    {
      jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number, 
        "jbig2_parse_segment_header() called with insufficient data", -1);
      jbig2_free (ctx->allocator, result);
      return NULL;
    }
    
  /* 7.2.5 */
  if (referred_to_segment_count)
    {
      int i;

      referred_to_segments = jbig2_alloc(ctx->allocator, referred_to_segment_count * referred_to_segment_size * sizeof(uint32_t));
    
      for (i = 0; i < referred_to_segment_count; i++) {
        referred_to_segments[i] = 
          (referred_to_segment_size == 1) ? buf[offset] :
          (referred_to_segment_size == 2) ? jbig2_get_int16(buf+offset) :
            jbig2_get_int32(buf + offset);
        offset += referred_to_segment_size;
        jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number,
            "segment %d refers to segment %d",
            result->number, referred_to_segments[i]);
      }
      result->referred_to_segments = referred_to_segments;
    }
  else /* no referred-to segments */
    {
      result->referred_to_segments = NULL;
    }
  
  /* 7.2.6 */
  if (result->flags & 0x40) {
	result->page_association = jbig2_get_int32(buf + offset);
	offset += 4;
  } else {
	result->page_association = buf[offset++];
  }
  jbig2_error(ctx, JBIG2_SEVERITY_DEBUG, result->number,
  	"segment %d is associated with page %d",
  	result->number, result->page_association);
  	
  /* 7.2.7 */
  result->data_length = jbig2_get_int32(buf + offset);
  *p_header_size = offset + 4;

  return result;
}

void
jbig2_free_segment (Jbig2Ctx *ctx, Jbig2Segment *segment)
{
  if (segment->referred_to_segments != NULL) {
    jbig2_free(ctx->allocator, segment->referred_to_segments);
  }
  /* todo: free result */
  jbig2_free (ctx->allocator, segment);
}

/* find a segment by number */
Jbig2Segment *
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;
}

/* parse the generic portion of a region segment data header */
void
jbig2_get_region_segment_info(Jbig2RegionSegmentInfo *info,
			      const byte *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];
}

/* dispatch code for extension segment parsing */
int jbig2_parse_extension_segment(Jbig2Ctx *ctx, Jbig2Segment *segment,
                            const uint8_t *segment_data)
{
    uint32_t type;
    bool reserved, dependent, necessary;

    type = jbig2_get_int32(segment_data);
    
    reserved = type & 0x20000000;
    dependent = type & 0x40000000;
    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_parse_comment_ascii(ctx, segment, segment_data);
        case 0x20000002: return jbig2_parse_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");
            }
    }
    
    return 0;
}

/* general segment parsing dispatch */
int jbig2_parse_segment (Jbig2Ctx *ctx, Jbig2Segment *segment,
			 const uint8_t *segment_data)
{
  jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
	      "Segment %d, flags=%x, type=%d, data_length=%d",
	      segment->number, segment->flags, segment->flags & 63,
	      segment->data_length);
  switch (segment->flags & 63)
    {
    case 0:
      return jbig2_symbol_dictionary(ctx, segment, segment_data);
    case 4: /* intermediate text region */
    case 6: /* immediate text region */
    case 7: /* immediate lossless text region */
      return jbig2_parse_text_region(ctx, segment, segment_data);
    case 16:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'pattern dictionary'");
    case 20:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'intermediate halftone region'");
    case 22:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'immediate halftone region'");
    case 23:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'immediate lossless halftone region'");
    case 36:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'intermediate generic region'");
    case 38:
      return jbig2_immediate_generic_region(ctx, segment, segment_data);
    case 39:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'immediate lossless generic region'");
    case 40:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'intermediate generic refinement region'");
    case 42:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'immediate generic refinement region'");
    case 43:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'immediate lossless generic refinement region'");
    case 48:
      return jbig2_parse_page_info(ctx, segment, segment_data);
    case 49:
      return jbig2_parse_end_of_page(ctx, segment, segment_data);
    case 50:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'end of stripe'");
    case 51:
      ctx->state = JBIG2_FILE_EOF;
      return jbig2_error(ctx, JBIG2_SEVERITY_INFO, segment->number,
        "end of file");
    case 52:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled segment type 'profile'");
    case 53:
      return jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
        "unhandled table segment");
    case 62:
      return jbig2_parse_extension_segment(ctx, segment, segment_data);
    default:
        jbig2_error(ctx, JBIG2_SEVERITY_WARNING, segment->number,
          "unknown segment type %d", segment->flags & 63);
    }
  return 0;
}