summaryrefslogtreecommitdiff
path: root/src/cairo-image-info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-image-info.c')
-rw-r--r--[-rwxr-xr-x]src/cairo-image-info.c157
1 files changed, 143 insertions, 14 deletions
diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c
index 4489698e8..26e7ae5af 100755..100644
--- a/src/cairo-image-info.c
+++ b/src/cairo-image-info.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Adrian Johnson
@@ -38,12 +39,6 @@
#include "cairo-error-private.h"
#include "cairo-image-info-private.h"
-static uint32_t
-_get_be32 (const unsigned char *p)
-{
- return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
-}
-
/* JPEG (image/jpeg)
*
* http://www.w3.org/Graphics/JPEG/itu-t81.pdf
@@ -169,7 +164,7 @@ static const unsigned char _jpx_signature[] = {
static const unsigned char *
_jpx_next_box (const unsigned char *p)
{
- return p + _get_be32 (p);
+ return p + get_unaligned_be32 (p);
}
static const unsigned char *
@@ -184,8 +179,8 @@ _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
uint32_t length;
if (p + 8 < end) {
- length = _get_be32 (p);
- if (_get_be32 (p + 4) == type && p + length < end)
+ length = get_unaligned_be32 (p);
+ if (get_unaligned_be32 (p + 4) == type && p + length < end)
return TRUE;
}
@@ -207,8 +202,8 @@ _jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
static void
_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
{
- info->height = _get_be32 (p);
- info->width = _get_be32 (p + 4);
+ info->height = get_unaligned_be32 (p);
+ info->width = get_unaligned_be32 (p + 4);
info->num_components = (p[8] << 8) + p[9];
info->bits_per_component = p[10];
}
@@ -280,13 +275,147 @@ _cairo_image_info_get_png_info (cairo_image_info_t *info,
return CAIRO_INT_STATUS_UNSUPPORTED;
p += 4;
- if (_get_be32 (p) != PNG_IHDR)
+ if (get_unaligned_be32 (p) != PNG_IHDR)
return CAIRO_INT_STATUS_UNSUPPORTED;
p += 4;
- info->width = _get_be32 (p);
+ info->width = get_unaligned_be32 (p);
p += 4;
- info->height = _get_be32 (p);
+ info->height = get_unaligned_be32 (p);
return CAIRO_STATUS_SUCCESS;
}
+
+static const unsigned char *
+_jbig2_find_data_end (const unsigned char *p,
+ const unsigned char *end,
+ int type)
+{
+ unsigned char end_seq[2];
+ int mmr;
+
+ /* Segments of type "Immediate generic region" may have an
+ * unspecified data length. The JBIG2 specification specifies the
+ * method to find the end of the data for these segments. */
+ if (type == 36 || type == 38 || type == 39) {
+ if (p + 18 < end) {
+ mmr = p[17] & 0x01;
+ if (mmr) {
+ /* MMR encoding ends with 0x00, 0x00 */
+ end_seq[0] = 0x00;
+ end_seq[1] = 0x00;
+ } else {
+ /* Template encoding ends with 0xff, 0xac */
+ end_seq[0] = 0xff;
+ end_seq[1] = 0xac;
+ }
+ p += 18;
+ while (p < end) {
+ if (p[0] == end_seq[0] && p[1] == end_seq[1]) {
+ /* Skip the 2 terminating bytes and the 4 byte row count that follows. */
+ p += 6;
+ if (p < end)
+ return p;
+ }
+ p++;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static const unsigned char *
+_jbig2_get_next_segment (const unsigned char *p,
+ const unsigned char *end,
+ int *type,
+ const unsigned char **data,
+ unsigned long *data_len)
+{
+ unsigned long seg_num;
+ cairo_bool_t big_page_size;
+ int num_segs;
+ int ref_seg_bytes;
+ int referred_size;
+
+ if (p + 6 >= end)
+ return NULL;
+
+ seg_num = get_unaligned_be32 (p);
+ *type = p[4] & 0x3f;
+ big_page_size = (p[4] & 0x40) != 0;
+ p += 5;
+
+ num_segs = p[0] >> 5;
+ if (num_segs == 7) {
+ num_segs = get_unaligned_be32 (p) & 0x1fffffff;
+ ref_seg_bytes = 4 + ((num_segs + 1)/8);
+ } else {
+ ref_seg_bytes = 1;
+ }
+ p += ref_seg_bytes;
+
+ if (seg_num <= 256)
+ referred_size = 1;
+ else if (seg_num <= 65536)
+ referred_size = 2;
+ else
+ referred_size = 4;
+
+ p += num_segs * referred_size;
+ p += big_page_size ? 4 : 1;
+ if (p + 4 >= end)
+ return NULL;
+
+ *data_len = get_unaligned_be32 (p);
+ p += 4;
+ *data = p;
+
+ if (*data_len == 0xffffffff) {
+ /* if data length is -1 we have to scan through the data to find the end */
+ p = _jbig2_find_data_end (*data, end, *type);
+ if (!p || p >= end)
+ return NULL;
+
+ *data_len = p - *data;
+ } else {
+ p += *data_len;
+ }
+
+ if (p < end)
+ return p;
+ else
+ return NULL;
+}
+
+static void
+_jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p)
+{
+ info->width = get_unaligned_be32 (p);
+ info->height = get_unaligned_be32 (p + 4);
+ info->num_components = 1;
+ info->bits_per_component = 1;
+}
+
+cairo_int_status_t
+_cairo_image_info_get_jbig2_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ unsigned long length)
+{
+ const unsigned char *p = data;
+ const unsigned char *end = data + length;
+ int seg_type;
+ const unsigned char *seg_data;
+ unsigned long seg_data_len;
+
+ while (p && p < end) {
+ p = _jbig2_get_next_segment (p, end, &seg_type, &seg_data, &seg_data_len);
+ if (p && seg_type == 48 && seg_data_len > 8) {
+ /* page information segment */
+ _jbig2_extract_info (info, seg_data);
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}