1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2008 Adrian Johnson
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Adrian Johnson.
32  *
33  * Contributor(s):
34  *	Adrian Johnson <ajohnson@redneon.com>
35  */
36 
37 #include "cairoint.h"
38 
39 #include "cairo-error-private.h"
40 #include "cairo-image-info-private.h"
41 
42 /* JPEG (image/jpeg)
43  *
44  * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
45  */
46 
47 /* Markers with no parameters. All other markers are followed by a two
48  * byte length of the parameters. */
49 #define TEM       0x01
50 #define RST_begin 0xd0
51 #define RST_end   0xd7
52 #define SOI       0xd8
53 #define EOI       0xd9
54 
55 /* Start of frame markers. */
56 #define SOF0  0xc0
57 #define SOF1  0xc1
58 #define SOF2  0xc2
59 #define SOF3  0xc3
60 #define SOF5  0xc5
61 #define SOF6  0xc6
62 #define SOF7  0xc7
63 #define SOF9  0xc9
64 #define SOF10 0xca
65 #define SOF11 0xcb
66 #define SOF13 0xcd
67 #define SOF14 0xce
68 #define SOF15 0xcf
69 
70 static const unsigned char *
_jpeg_skip_segment(const unsigned char * p)71 _jpeg_skip_segment (const unsigned char *p)
72 {
73     int len;
74 
75     p++;
76     len = (p[0] << 8) | p[1];
77 
78     return p + len;
79 }
80 
81 static void
_jpeg_extract_info(cairo_image_info_t * info,const unsigned char * p)82 _jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p)
83 {
84     info->width = (p[6] << 8) + p[7];
85     info->height = (p[4] << 8) + p[5];
86     info->num_components = p[8];
87     info->bits_per_component = p[3];
88 }
89 
90 cairo_int_status_t
_cairo_image_info_get_jpeg_info(cairo_image_info_t * info,const unsigned char * data,long length)91 _cairo_image_info_get_jpeg_info (cairo_image_info_t	*info,
92 				 const unsigned char	*data,
93 				 long			 length)
94 {
95     const unsigned char *p = data;
96 
97     while (p + 1 < data + length) {
98 	if (*p != 0xff)
99 	    return CAIRO_INT_STATUS_UNSUPPORTED;
100 	p++;
101 
102 	switch (*p) {
103 	    /* skip fill bytes */
104 	case 0xff:
105 	    p++;
106 	    break;
107 
108 	case TEM:
109 	case SOI:
110 	case EOI:
111 	    p++;
112 	    break;
113 
114 	case SOF0:
115 	case SOF1:
116 	case SOF2:
117 	case SOF3:
118 	case SOF5:
119 	case SOF6:
120 	case SOF7:
121 	case SOF9:
122 	case SOF10:
123 	case SOF11:
124 	case SOF13:
125 	case SOF14:
126 	case SOF15:
127 	    /* Start of frame found. Extract the image parameters. */
128 	    if (p + 8 > data + length)
129 		return CAIRO_INT_STATUS_UNSUPPORTED;
130 
131 	    _jpeg_extract_info (info, p);
132 	    return CAIRO_STATUS_SUCCESS;
133 
134 	default:
135 	    if (*p >= RST_begin && *p <= RST_end) {
136 		p++;
137 		break;
138 	    }
139 
140 	    if (p + 3 > data + length)
141 		return CAIRO_INT_STATUS_UNSUPPORTED;
142 
143 	    p = _jpeg_skip_segment (p);
144 	    break;
145 	}
146     }
147 
148     return CAIRO_STATUS_SUCCESS;
149 }
150 
151 /* JPEG 2000 (image/jp2)
152  *
153  * http://www.jpeg.org/public/15444-1annexi.pdf
154  */
155 
156 #define JPX_FILETYPE 0x66747970
157 #define JPX_JP2_HEADER 0x6A703268
158 #define JPX_IMAGE_HEADER 0x69686472
159 
160 static const unsigned char _jpx_signature[] = {
161     0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a
162 };
163 
164 static const unsigned char *
_jpx_next_box(const unsigned char * p)165 _jpx_next_box (const unsigned char *p)
166 {
167     return p + get_unaligned_be32 (p);
168 }
169 
170 static const unsigned char *
_jpx_get_box_contents(const unsigned char * p)171 _jpx_get_box_contents (const unsigned char *p)
172 {
173     return p + 8;
174 }
175 
176 static cairo_bool_t
_jpx_match_box(const unsigned char * p,const unsigned char * end,uint32_t type)177 _jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
178 {
179     uint32_t length;
180 
181     if (p + 8 < end) {
182 	length = get_unaligned_be32 (p);
183 	if (get_unaligned_be32 (p + 4) == type &&  p + length < end)
184 	    return TRUE;
185     }
186 
187     return FALSE;
188 }
189 
190 static const unsigned char *
_jpx_find_box(const unsigned char * p,const unsigned char * end,uint32_t type)191 _jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
192 {
193     while (p < end) {
194 	if (_jpx_match_box (p, end, type))
195 	    return p;
196 	p = _jpx_next_box (p);
197     }
198 
199     return NULL;
200 }
201 
202 static void
_jpx_extract_info(const unsigned char * p,cairo_image_info_t * info)203 _jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
204 {
205     info->height = get_unaligned_be32 (p);
206     info->width = get_unaligned_be32 (p + 4);
207     info->num_components = (p[8] << 8) + p[9];
208     info->bits_per_component = p[10];
209 }
210 
211 cairo_int_status_t
_cairo_image_info_get_jpx_info(cairo_image_info_t * info,const unsigned char * data,unsigned long length)212 _cairo_image_info_get_jpx_info (cairo_image_info_t	*info,
213 				const unsigned char	*data,
214 				unsigned long		 length)
215 {
216     const unsigned char *p = data;
217     const unsigned char *end = data + length;
218 
219     /* First 12 bytes must be the JPEG 2000 signature box. */
220     if (length < ARRAY_LENGTH(_jpx_signature) ||
221 	memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0)
222 	return CAIRO_INT_STATUS_UNSUPPORTED;
223 
224     p += ARRAY_LENGTH(_jpx_signature);
225 
226     /* Next box must be a File Type Box */
227     if (! _jpx_match_box (p, end, JPX_FILETYPE))
228 	return CAIRO_INT_STATUS_UNSUPPORTED;
229 
230     p = _jpx_next_box (p);
231 
232     /* Locate the JP2 header box. */
233     p = _jpx_find_box (p, end, JPX_JP2_HEADER);
234     if (!p)
235 	return CAIRO_INT_STATUS_UNSUPPORTED;
236 
237     /* Step into the JP2 header box. First box must be the Image
238      * Header */
239     p = _jpx_get_box_contents (p);
240     if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER))
241 	return CAIRO_INT_STATUS_UNSUPPORTED;
242 
243     /* Get the image info */
244     p = _jpx_get_box_contents (p);
245     _jpx_extract_info (p, info);
246 
247     return CAIRO_STATUS_SUCCESS;
248 }
249 
250 /* PNG (image/png)
251  *
252  * http://www.w3.org/TR/2003/REC-PNG-20031110/
253  */
254 
255 #define PNG_IHDR 0x49484452
256 
257 static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
258 
259 cairo_int_status_t
_cairo_image_info_get_png_info(cairo_image_info_t * info,const unsigned char * data,unsigned long length)260 _cairo_image_info_get_png_info (cairo_image_info_t     *info,
261                                const unsigned char     *data,
262                                unsigned long            length)
263 {
264     const unsigned char *p = data;
265     const unsigned char *end = data + length;
266 
267     if (length < 8 || memcmp (data, _png_magic, 8) != 0)
268        return CAIRO_INT_STATUS_UNSUPPORTED;
269 
270     p += 8;
271 
272     /* The first chunk must be IDHR. IDHR has 13 bytes of data plus
273      * the 12 bytes of overhead for the chunk. */
274     if (p + 13 + 12 > end)
275        return CAIRO_INT_STATUS_UNSUPPORTED;
276 
277     p += 4;
278     if (get_unaligned_be32 (p) != PNG_IHDR)
279        return CAIRO_INT_STATUS_UNSUPPORTED;
280 
281     p += 4;
282     info->width = get_unaligned_be32 (p);
283     p += 4;
284     info->height = get_unaligned_be32 (p);
285 
286     return CAIRO_STATUS_SUCCESS;
287 }
288 
289 static const unsigned char *
_jbig2_find_data_end(const unsigned char * p,const unsigned char * end,int type)290 _jbig2_find_data_end (const unsigned char *p,
291 		      const unsigned char *end,
292 		      int                  type)
293 {
294     unsigned char end_seq[2];
295     int mmr;
296 
297     /* Segments of type "Immediate generic region" may have an
298      * unspecified data length.  The JBIG2 specification specifies the
299      * method to find the end of the data for these segments. */
300     if (type == 36 || type == 38 || type == 39) {
301 	if (p + 18 < end) {
302 	    mmr = p[17] & 0x01;
303 	    if (mmr) {
304 		/* MMR encoding ends with 0x00, 0x00 */
305 		end_seq[0] = 0x00;
306 		end_seq[1] = 0x00;
307 	    } else {
308 		/* Template encoding ends with 0xff, 0xac */
309 		end_seq[0] = 0xff;
310 		end_seq[1] = 0xac;
311 	    }
312 	    p += 18;
313 	    while (p < end) {
314 		if (p[0] == end_seq[0] && p[1] == end_seq[1]) {
315 		    /* Skip the 2 terminating bytes and the 4 byte row count that follows. */
316 		    p += 6;
317 		    if (p < end)
318 			return p;
319 		}
320 		p++;
321 	    }
322 	}
323     }
324 
325     return NULL;
326 }
327 
328 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)329 _jbig2_get_next_segment (const unsigned char  *p,
330 			 const unsigned char  *end,
331 			 int                  *type,
332 			 const unsigned char **data,
333 			 unsigned long        *data_len)
334 {
335     unsigned long seg_num;
336     cairo_bool_t big_page_size;
337     int num_segs;
338     int ref_seg_bytes;
339     int referred_size;
340 
341     if (p + 6 >= end)
342 	return NULL;
343 
344     seg_num = get_unaligned_be32 (p);
345     *type = p[4] & 0x3f;
346     big_page_size = (p[4] & 0x40) != 0;
347     p += 5;
348 
349     num_segs = p[0] >> 5;
350     if (num_segs == 7) {
351 	num_segs = get_unaligned_be32 (p) & 0x1fffffff;
352 	ref_seg_bytes = 4 + ((num_segs + 1)/8);
353     } else {
354 	ref_seg_bytes = 1;
355     }
356     p += ref_seg_bytes;
357 
358     if (seg_num <= 256)
359 	referred_size = 1;
360     else if (seg_num <= 65536)
361 	referred_size = 2;
362     else
363 	referred_size = 4;
364 
365     p += num_segs * referred_size;
366     p += big_page_size ? 4 : 1;
367     if (p + 4 >= end)
368 	return NULL;
369 
370     *data_len = get_unaligned_be32 (p);
371     p += 4;
372     *data = p;
373 
374     if (*data_len == 0xffffffff) {
375 	/* if data length is -1 we have to scan through the data to find the end */
376 	p = _jbig2_find_data_end (*data, end, *type);
377 	if (!p || p >= end)
378 	    return NULL;
379 
380 	*data_len = p - *data;
381     } else {
382 	p += *data_len;
383     }
384 
385     if (p < end)
386 	return p;
387     else
388 	return NULL;
389 }
390 
391 static void
_jbig2_extract_info(cairo_image_info_t * info,const unsigned char * p)392 _jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p)
393 {
394     info->width = get_unaligned_be32 (p);
395     info->height = get_unaligned_be32 (p + 4);
396     info->num_components = 1;
397     info->bits_per_component = 1;
398 }
399 
400 cairo_int_status_t
_cairo_image_info_get_jbig2_info(cairo_image_info_t * info,const unsigned char * data,unsigned long length)401 _cairo_image_info_get_jbig2_info (cairo_image_info_t	*info,
402 				  const unsigned char	*data,
403 				  unsigned long		 length)
404 {
405     const unsigned char *p = data;
406     const unsigned char *end = data + length;
407     int seg_type;
408     const unsigned char *seg_data;
409     unsigned long seg_data_len;
410 
411     while (p && p < end) {
412 	p = _jbig2_get_next_segment (p, end, &seg_type, &seg_data, &seg_data_len);
413 	if (p && seg_type == 48 && seg_data_len > 8) {
414 	    /* page information segment */
415 	    _jbig2_extract_info (info, seg_data);
416 	    return CAIRO_STATUS_SUCCESS;
417 	}
418     }
419 
420     return CAIRO_INT_STATUS_UNSUPPORTED;
421 }
422