/src/ghostpdl/jpegxr/cr_parse_boxed.c
Line | Count | Source |
1 | | /************************************************************************* |
2 | | * |
3 | | * This software module was originally contributed by Microsoft |
4 | | * Corporation in the course of development of the |
5 | | * ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for |
6 | | * reference purposes and its performance may not have been optimized. |
7 | | * |
8 | | * This software module is an implementation of one or more |
9 | | * tools as specified by the JPEG XR standard. |
10 | | * |
11 | | * ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive |
12 | | * copyright license to copy, distribute, and make derivative works |
13 | | * of this software module or modifications thereof for use in |
14 | | * products claiming conformance to the JPEG XR standard as |
15 | | * specified by ITU-T T.832 | ISO/IEC 29199-2. |
16 | | * |
17 | | * ITU/ISO/IEC give users the same free license to this software |
18 | | * module or modifications thereof for research purposes and further |
19 | | * ITU/ISO/IEC standardization. |
20 | | * |
21 | | * Those intending to use this software module in products are advised |
22 | | * that its use may infringe existing patents. ITU/ISO/IEC have no |
23 | | * liability for use of this software module or modifications thereof. |
24 | | * |
25 | | * Copyright is not released for products that do not conform to |
26 | | * to the JPEG XR standard as specified by ITU-T T.832 | |
27 | | * ISO/IEC 29199-2. |
28 | | * |
29 | | ******** Section to be removed when the standard is published ************ |
30 | | * |
31 | | * Assurance that the contributed software module can be used |
32 | | * (1) in the ITU-T "T.JXR" | ISO/IEC 29199 ("JPEG XR") standard once the |
33 | | * standard has been adopted; and |
34 | | * (2) to develop the JPEG XR standard: |
35 | | * |
36 | | * Microsoft Corporation and any subsequent contributors to the development |
37 | | * of this software grant ITU/ISO/IEC all rights necessary to include |
38 | | * the originally developed software module or modifications thereof in the |
39 | | * JPEG XR standard and to permit ITU/ISO/IEC to offer such a royalty-free, |
40 | | * worldwide, non-exclusive copyright license to copy, distribute, and make |
41 | | * derivative works of this software module or modifications thereof for |
42 | | * use in products claiming conformance to the JPEG XR standard as |
43 | | * specified by ITU-T T.832 | ISO/IEC 29199-2, and to the extent that |
44 | | * such originally developed software module or portions of it are included |
45 | | * in an ITU/ISO/IEC standard. To the extent that the original contributors |
46 | | * may own patent rights that would be required to make, use, or sell the |
47 | | * originally developed software module or portions thereof included in the |
48 | | * ITU/ISO/IEC standard in a conforming product, the contributors will |
49 | | * assure ITU/ISO/IEC that they are willing to negotiate licenses under |
50 | | * reasonable and non-discriminatory terms and conditions with |
51 | | * applicants throughout the world and in accordance with their patent |
52 | | * rights declarations made to ITU/ISO/IEC (if any). |
53 | | * |
54 | | * Microsoft, any subsequent contributors, and ITU/ISO/IEC additionally |
55 | | * gives You a free license to this software module or modifications |
56 | | * thereof for the sole purpose of developing the JPEG XR standard. |
57 | | * |
58 | | ******** end of section to be removed when the standard is published ***** |
59 | | * |
60 | | * Microsoft Corporation retains full right to modify and use the code |
61 | | * for its own purpose, to assign or donate the code to a third party, |
62 | | * and to inhibit third parties from using the code for products that |
63 | | * do not conform to the JPEG XR standard as specified by ITU-T T.832 | |
64 | | * ISO/IEC 29199-2. |
65 | | * |
66 | | * This copyright notice must be included in all copies or derivative |
67 | | * works. |
68 | | * |
69 | | * Copyright (c) ITU-T/ISO/IEC 2008, 2009. |
70 | | ***********************************************************************/ |
71 | | |
72 | | #ifdef _MSC_VER |
73 | | #pragma comment (user,"$Id: cr_parse_boxed.c,v 1.7 2012-03-18 21:47:07 thor Exp $") |
74 | | #endif |
75 | | |
76 | | #include "jxr_priv.h" |
77 | | #include <string.h> |
78 | | #include <stdlib.h> |
79 | | #include <assert.h> |
80 | | |
81 | | /* |
82 | | ** Generate a box-ID from the four-character identifier |
83 | | */ |
84 | 0 | #define MAKE_ID(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d) << 0)) |
85 | | |
86 | | /* |
87 | | ** Read an unsigned long from the file. Return 0 (no kidding) on |
88 | | ** error. A real zero cannot be distinguished from this error, |
89 | | ** though there are no box type or box lengths for which a zero |
90 | | ** would be correct, and this is the only purpose of this function. |
91 | | */ |
92 | | static uint32_t read_ULONG(jxr_container_t c) |
93 | 0 | { |
94 | 0 | unsigned char buffer[4]; |
95 | |
|
96 | 0 | if (fread(buffer,1,sizeof(buffer),c->fd) != sizeof(buffer)) |
97 | 0 | return 0; |
98 | | |
99 | 0 | return ((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0)); |
100 | 0 | } |
101 | | |
102 | | /* |
103 | | ** Read the given box and fill the buffer, which is the given number |
104 | | ** of bytes large. Longer boxes will be simply truncated, though the |
105 | | ** default should be reasonable for all boxes this program needs. |
106 | | ** Returns the box type or zero on error. |
107 | | ** |
108 | | ** For superboxes only the box header is parsed off and the super box is |
109 | | ** entered. |
110 | | */ |
111 | | static uint32_t read_box(jxr_container_t c,unsigned char *buffer,size_t *bufsize) |
112 | 0 | { |
113 | 0 | uint32_t size = read_ULONG(c); |
114 | 0 | uint32_t type = read_ULONG(c); |
115 | 0 | int seek = 0; |
116 | | /* It might be that the size is one in which case the box exceeds the 64 bit |
117 | | ** limit. This is currently not supported here. |
118 | | */ |
119 | 0 | if (size < 8) |
120 | 0 | return 0; |
121 | | |
122 | 0 | if (type == MAKE_ID('j','p','l','h') || /* compositing layer header box */ |
123 | 0 | type == MAKE_ID('j','p','c','h') || /* codestream header box */ |
124 | 0 | type == MAKE_ID('j','p','2','h') || /* jp2 header box */ |
125 | 0 | type == MAKE_ID('c','g','r','g') || /* color group box */ |
126 | 0 | type == MAKE_ID('r','e','s',' ') || /* resolution box */ |
127 | 0 | type == MAKE_ID('u','i','n','f') || /* uuid info box */ |
128 | 0 | type == MAKE_ID('f','t','b','l') || /* fragment table box */ |
129 | 0 | type == MAKE_ID('c','o','m','p') || /* composition box */ |
130 | 0 | type == MAKE_ID('d','r','e','p') || /* desired reproduction box */ |
131 | 0 | type == MAKE_ID('j','p','2','c')) { /* codestream box: Not a super box, but still not parsed here */ |
132 | | /* |
133 | | ** There might be additional super boxes here, but since the content is |
134 | | ** then irrelevant to this program, just read them as normal boxes and |
135 | | ** ignore them. |
136 | | */ |
137 | 0 | *bufsize = size - 8; /* inner data, not box header */ |
138 | 0 | return type; |
139 | 0 | } |
140 | | |
141 | 0 | if (size >= *bufsize) { |
142 | 0 | seek = size - 8 - *bufsize; |
143 | 0 | size = *bufsize; |
144 | 0 | } |
145 | 0 | *bufsize = size; |
146 | |
|
147 | 0 | if (fread(buffer,1,size - 8,c->fd) != size - 8) { |
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | 0 | if (seek > 0) { |
152 | 0 | if (fseek(c->fd,seek,SEEK_CUR) != 0) |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | 0 | return type; |
157 | 0 | } |
158 | | |
159 | | static int parse_ftyp(jxr_container_t c,const unsigned char *buffer,uint32_t size) |
160 | 0 | { |
161 | 0 | int offset = 8; /* start of the compatibility list */ |
162 | |
|
163 | 0 | if (size < 8 + 4 || memcmp(buffer,"jpx ",4)) |
164 | 0 | return JXR_EC_BADFORMAT; /* brand must be 15444-2 as this is a subset of it */ |
165 | | |
166 | 0 | while(offset + 4 < size + 8) { |
167 | 0 | if (!memcmp(buffer+offset,"jxr0",4)) { |
168 | 0 | c->profile_idc = 44; /* subbaseline profile */ |
169 | 0 | return 0; /* is acceptable */ |
170 | 0 | } else if (!memcmp(buffer+offset,"jxr1",4)) { |
171 | 0 | c->profile_idc = 55; /* baseline profile */ |
172 | 0 | return 0; |
173 | 0 | } else if (!memcmp(buffer+offset,"jxr2",4)) { |
174 | 0 | c->profile_idc = 66; /* main profile */ |
175 | 0 | return 0; |
176 | 0 | } else if (!memcmp(buffer+offset,"jxrc",4)) { |
177 | 0 | c->profile_idc = 111; /* advanced profile */ |
178 | 0 | return 0; |
179 | 0 | } |
180 | 0 | offset += 4; |
181 | 0 | } |
182 | | |
183 | | /* not compatible to anything I understand */ |
184 | 0 | return JXR_EC_BADFORMAT; |
185 | 0 | } |
186 | | |
187 | | /* |
188 | | ** Parse off the image header box |
189 | | */ |
190 | | static int parse_ihdr(jxr_container_t c,const unsigned char *buffer,size_t boxsize) |
191 | 0 | { |
192 | 0 | uint32_t width,height,depth,bpc; |
193 | |
|
194 | 0 | if (boxsize != 8 + 4 + 4 + 2 + 1 + 1 + 1 + 1) |
195 | 0 | return JXR_EC_BADFORMAT; |
196 | | |
197 | 0 | width = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | (buffer[7] << 0); |
198 | 0 | height = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3] << 0); |
199 | 0 | depth = (buffer[8] << 8) | (buffer[9] << 0); |
200 | 0 | bpc = buffer[10]; |
201 | |
|
202 | 0 | if (buffer[11] != 11) /* must be JPEGXR */ |
203 | 0 | return JXR_EC_BADFORMAT; |
204 | | |
205 | 0 | if (c->wid && c->wid != width) /* must be consistent */ |
206 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
207 | 0 | c->wid = width; |
208 | |
|
209 | 0 | if (c->hei && c->hei != height) |
210 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
211 | 0 | c->hei = height; |
212 | |
|
213 | 0 | switch(c->c_idx) { |
214 | 0 | case 0: |
215 | 0 | case 1: /* override is possible */ |
216 | 0 | c->depth = depth; /* default depth */ |
217 | 0 | break; |
218 | 0 | case 2: /* alpha channel */ |
219 | 0 | if (depth != 1) |
220 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
221 | 0 | c->depth++; /* include the alpha channel */ |
222 | 0 | c->separate_alpha_image_plane = 1; |
223 | 0 | break; |
224 | 0 | } |
225 | | |
226 | 0 | if (bpc != 255) { |
227 | 0 | if (c->bpp && c->bpp != (bpc & 0x7f) + 1) |
228 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
229 | 0 | c->bpp = (bpc & 0x7f) + 1; |
230 | 0 | } |
231 | | |
232 | 0 | return 0; |
233 | 0 | } |
234 | | |
235 | | /* |
236 | | ** Parse off the number of bits per component box |
237 | | ** There is only one reason why it can be here: To |
238 | | ** support the 565 mode. Alll other modes have |
239 | | ** a consistent number of bits per component. |
240 | | */ |
241 | | static int parse_bpcc(jxr_container_t c,const unsigned char *buffer,size_t size) |
242 | 0 | { |
243 | 0 | uint32_t i; |
244 | |
|
245 | 0 | if (size <= 8) |
246 | 0 | return JXR_EC_BADFORMAT; |
247 | | |
248 | 0 | size -= 8; |
249 | |
|
250 | 0 | if (size == 3) { |
251 | 0 | if (buffer[0] == 4 && buffer[1] == 5 && buffer[2] == 4) { |
252 | 0 | if (c->bpp && c->bpp != 6) |
253 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
254 | 0 | c->bpp = 6; /* 565 mode */ |
255 | 0 | return 0; |
256 | 0 | } |
257 | 0 | } |
258 | | /* |
259 | | ** Here all bit depths must be identical, XR is too limited... |
260 | | */ |
261 | 0 | for(i = 0;i < size;i++) { |
262 | 0 | if (buffer[0] != buffer[i]) |
263 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
264 | 0 | } |
265 | 0 | if (c->bpp && c->bpp != (buffer[0] & 0x7f) + 1) |
266 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
267 | 0 | c->bpp = (buffer[0] & 0x7f) + 1; |
268 | |
|
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | | /* |
273 | | ** Parse the color specification box if we have one |
274 | | */ |
275 | | static int parse_colr(jxr_container_t c,const unsigned char *buffer,size_t boxsize) |
276 | 0 | { |
277 | 0 | if (boxsize < 7 + 8) |
278 | 0 | return JXR_EC_BADFORMAT; |
279 | | |
280 | | /* |
281 | | ** All color specification methods except enumerated are simply ignored here |
282 | | */ |
283 | 0 | if (buffer[0] == 1) { /* enumerated method */ |
284 | 0 | int prec = buffer[1]; |
285 | 0 | if (prec >= 128) |
286 | 0 | prec -= 256; /* binary complement, is signed not unsigned */ |
287 | 0 | prec += 128; /* make unsigned */ |
288 | 0 | if (prec > c->cprec) { |
289 | | /* consider this color instead */ |
290 | 0 | c->cprec = prec; |
291 | 0 | c->color = (buffer[3] << 24) | (buffer[4] << 16) | (buffer[5] << 8) | (buffer[6] << 0); |
292 | 0 | } |
293 | 0 | } |
294 | 0 | return 0; |
295 | 0 | } |
296 | | |
297 | | /* |
298 | | ** Parse off the channel definition box |
299 | | */ |
300 | | static int parse_cdef(jxr_container_t c,const unsigned char *buffer,size_t boxsize) |
301 | 0 | { |
302 | 0 | int channels,i; |
303 | |
|
304 | 0 | if (boxsize < 4 + 8) |
305 | 0 | return JXR_EC_BADFORMAT; |
306 | | |
307 | 0 | channels = (buffer[0] << 8) | (buffer[1] << 0); |
308 | 0 | if (boxsize != (channels * 3 + 1) * 2 + 8) |
309 | 0 | return JXR_EC_BADFORMAT; |
310 | | |
311 | 0 | if (c->channels && c->channels != channels) |
312 | 0 | return JXR_EC_BADFORMAT; /* must be consistent */ |
313 | | |
314 | 0 | c->channels = channels; |
315 | 0 | for(i = 0;i < channels;i++) { |
316 | 0 | int cidx = (buffer[2 + i * 6] << 8) | (buffer[3 + i * 6] << 0); |
317 | 0 | int ctyp = (buffer[4 + i * 6] << 8) | (buffer[5 + i * 6] << 0); |
318 | 0 | int asoc = (buffer[6 + i * 6] << 8) | (buffer[7 + i * 6] << 0); |
319 | 0 | if (cidx == channels-1) { |
320 | | /* The only channel that could be an alpha channel. Comes always last here */ |
321 | 0 | if (ctyp == 1 || ctyp == 2) { |
322 | 0 | c->alpha = ctyp; |
323 | 0 | if (asoc != 0) /* Only if associated with all of the image */ |
324 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
325 | 0 | continue; |
326 | 0 | } |
327 | 0 | } |
328 | | /* Here: Must be a standard channel */ |
329 | 0 | if (ctyp != 0) |
330 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
331 | | /* Association must be the canonical, channel reordering not supported here. */ |
332 | 0 | if (asoc != cidx + 1) |
333 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
334 | 0 | } |
335 | | |
336 | 0 | return 0; |
337 | 0 | } |
338 | | |
339 | | static int parse_pxfm(jxr_container_t c,const unsigned char *buffer,size_t boxsize) |
340 | 0 | { |
341 | 0 | int channels,i,curtype = -1; |
342 | |
|
343 | 0 | if (boxsize < 4 + 8) |
344 | 0 | return JXR_EC_BADFORMAT; |
345 | | |
346 | 0 | channels = (buffer[0] << 8) | (buffer[1] << 0); |
347 | |
|
348 | 0 | if (boxsize != channels * 4 + 2 + 8) |
349 | 0 | return JXR_EC_BADFORMAT; |
350 | | |
351 | 0 | if (c->channels && c->channels != channels) |
352 | 0 | return JXR_EC_BADFORMAT; /* must be consistent */ |
353 | | |
354 | 0 | c->channels = channels; |
355 | 0 | for(i = 0;i < channels;i++) { |
356 | 0 | int channel = (buffer[2 + i * 4] << 8) + (buffer[3 + i * 4] << 0); |
357 | 0 | int type = (buffer[4 + i * 4] << 8) + (buffer[5 + i * 4] << 0); |
358 | |
|
359 | 0 | if (((type == 0x1000 && channel < 3) || (type == 0x2000 && channel == 3)) && channels == 4) { |
360 | 0 | if (curtype == -1 || curtype == 0x1000) { |
361 | 0 | curtype = 0x1000; /* RGBE */ |
362 | 0 | } else { |
363 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* Something else not supported here */ |
364 | 0 | } |
365 | 0 | } else if (type == 0x400a) { |
366 | 0 | if (curtype == -1 || curtype == 0x400a) { |
367 | 0 | curtype = 0x400a; /* half float */ |
368 | 0 | } else { |
369 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* Something else not supported here */ |
370 | 0 | } |
371 | 0 | } else if (type == 0x4017) { |
372 | 0 | if (curtype == -1 || curtype == 0x4017) { |
373 | 0 | curtype = 0x4017; /* single precision float */ |
374 | 0 | } else { |
375 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
376 | 0 | } |
377 | 0 | } else if (type == 0x300d) { |
378 | 0 | if (curtype == -1 || curtype == 0x300d) { |
379 | 0 | curtype = 0x300d; /* fixpoint with 13 fractional bits */ |
380 | 0 | } else { |
381 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
382 | 0 | } |
383 | 0 | } else if (type == 0x3018) { |
384 | 0 | if (curtype == -1 || curtype == 0x3018) { |
385 | 0 | curtype = 0x3018; /* fixpoint with 24 fractional bits */ |
386 | 0 | } else { |
387 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
388 | 0 | } |
389 | 0 | } else if (type == 0) { |
390 | 0 | if (curtype == -1 || curtype == 0) { |
391 | 0 | curtype = 0; /* integer */ |
392 | 0 | } else { |
393 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
394 | 0 | } |
395 | 0 | } else { |
396 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* everything else is not supported here */ |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | 0 | c->pixeltype = curtype; |
401 | |
|
402 | 0 | return 0; |
403 | 0 | } |
404 | | /* |
405 | | ** Parse the image header superbox which provides defaults |
406 | | ** for all codestreams |
407 | | */ |
408 | | static int parse_jp2h(jxr_container_t c,size_t boxsize) |
409 | 0 | { |
410 | 0 | unsigned char buffer[256]; |
411 | 0 | size_t size; |
412 | 0 | uint32_t type; |
413 | 0 | int rc; |
414 | 0 | int have_ihdr = 0; |
415 | 0 | int have_bpcc = 0; |
416 | 0 | int have_colr = 0; |
417 | 0 | int have_cdef = 0; |
418 | 0 | int have_pxfm = 0; |
419 | 0 | int have_res = 0; |
420 | |
|
421 | 0 | do { |
422 | 0 | size = sizeof(buffer); |
423 | 0 | type = read_box(c,buffer,&size); |
424 | 0 | if (type == MAKE_ID('i','h','d','r')) { |
425 | 0 | if (have_ihdr) |
426 | 0 | return JXR_EC_BADFORMAT; |
427 | 0 | have_ihdr = 1; |
428 | 0 | rc = parse_ihdr(c,buffer,size); |
429 | 0 | if (rc) return rc; |
430 | 0 | } else if (type == MAKE_ID('b','p','c','c')) { |
431 | 0 | if (have_bpcc) |
432 | 0 | return JXR_EC_BADFORMAT; |
433 | 0 | have_bpcc = 1; |
434 | 0 | rc = parse_bpcc(c,buffer,size); |
435 | 0 | if (rc) return rc; |
436 | 0 | } else if (type == MAKE_ID('c','o','l','r')) { |
437 | | /* No color group box, thus only one color box */ |
438 | 0 | if (have_colr) |
439 | 0 | return JXR_EC_BADFORMAT; |
440 | 0 | have_colr = 1; |
441 | 0 | rc = parse_colr(c,buffer,size); |
442 | 0 | if (rc) return rc; |
443 | 0 | } else if (type == MAKE_ID('p','c','l','r')) { |
444 | | /* Palette mapping is currently not implemented */ |
445 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
446 | 0 | } else if (type == MAKE_ID('c','m','a','p')) { |
447 | | /* Same difference, cmap exists only for palette mapping */ |
448 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
449 | 0 | } else if (type == MAKE_ID('c','d','e','f')) { |
450 | | /* Channel definition box */ |
451 | 0 | if (have_cdef) |
452 | 0 | return JXR_EC_BADFORMAT; |
453 | 0 | have_cdef = 1; |
454 | 0 | rc = parse_cdef(c,buffer,size); |
455 | 0 | if (rc) return rc; |
456 | 0 | } else if (type == MAKE_ID('p','x','f','m')) { |
457 | 0 | if (have_pxfm) |
458 | 0 | return JXR_EC_BADFORMAT; |
459 | 0 | have_pxfm = 1; |
460 | 0 | rc = parse_pxfm(c,buffer,size); |
461 | 0 | if (rc) return rc; |
462 | 0 | } else if (type == MAKE_ID('r','e','s',' ')) { |
463 | | /* Resolution box. Currently ignored, skip over the superbox */ |
464 | 0 | if (have_res) |
465 | 0 | return JXR_EC_BADFORMAT; |
466 | 0 | have_res = 1; |
467 | 0 | if (fseek(c->fd,size,SEEK_CUR) != 0) |
468 | 0 | return JXR_EC_IO; |
469 | 0 | } |
470 | | /* All other boxes are ignored. */ |
471 | 0 | if (boxsize < size) |
472 | 0 | return JXR_EC_BADFORMAT; |
473 | 0 | boxsize -= size; |
474 | 0 | } while(boxsize); |
475 | | |
476 | 0 | return 0; |
477 | 0 | } |
478 | | |
479 | | /* |
480 | | ** Parse the codestream header superbox which provides settings |
481 | | ** for a specific codestream |
482 | | */ |
483 | | static int parse_jpch(jxr_container_t c,size_t boxsize) |
484 | 0 | { |
485 | 0 | unsigned char buffer[256]; |
486 | 0 | size_t size; |
487 | 0 | uint32_t type; |
488 | 0 | int rc; |
489 | 0 | int have_ihdr = 0; |
490 | 0 | int have_bpcc = 0; |
491 | |
|
492 | 0 | do { |
493 | 0 | size = sizeof(buffer); |
494 | 0 | type = read_box(c,buffer,&size); |
495 | 0 | if (type == MAKE_ID('i','h','d','r')) { |
496 | 0 | if (have_ihdr) |
497 | 0 | return JXR_EC_BADFORMAT; |
498 | 0 | have_ihdr = 1; |
499 | 0 | rc = parse_ihdr(c,buffer,size); |
500 | 0 | if (rc) return rc; |
501 | 0 | } else if (type == MAKE_ID('b','p','c','c')) { |
502 | 0 | if (have_bpcc) |
503 | 0 | return JXR_EC_BADFORMAT; |
504 | 0 | have_bpcc = 1; |
505 | 0 | rc = parse_bpcc(c,buffer,size); |
506 | 0 | if (rc) return rc; |
507 | 0 | } else if (type == MAKE_ID('p','c','l','r')) { |
508 | | /* Palette mapping is currently not implemented */ |
509 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
510 | 0 | } else if (type == MAKE_ID('c','m','a','p')) { |
511 | | /* Same difference, cmap exists only for palette mapping */ |
512 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
513 | 0 | } |
514 | | /* All other boxes are ignored. */ |
515 | 0 | if (boxsize < size) |
516 | 0 | return JXR_EC_BADFORMAT; |
517 | 0 | boxsize -= size; |
518 | 0 | } while(boxsize); |
519 | | |
520 | 0 | return 0; |
521 | 0 | } |
522 | | |
523 | | /* |
524 | | ** Parse the codestream registration box |
525 | | */ |
526 | | static int parse_creg(jxr_container_t c,const unsigned char *buffer,uint32_t size) |
527 | 0 | { |
528 | 0 | if (size < 10 + 8) |
529 | 0 | return JXR_EC_BADFORMAT; |
530 | | |
531 | | /* The grid size is actually pretty irrelevant as long as the resolutions and |
532 | | ** offsets are all identical. Scaling is not supported by this simple code. |
533 | | */ |
534 | 0 | size -= 4 + 8; |
535 | 0 | buffer += 4; |
536 | 0 | while(size) { |
537 | 0 | int cdn; |
538 | 0 | if (size < 6) |
539 | 0 | return JXR_EC_BADFORMAT; |
540 | 0 | cdn = (buffer[0] << 8) | (buffer[1]); |
541 | 0 | if (cdn > 1) /* At most two codestreams supported */ |
542 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
543 | 0 | if (buffer[2] != 1 || buffer[3] != 1 || buffer[4] != 0 || buffer[5] != 0) |
544 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
545 | 0 | buffer += 6; |
546 | 0 | size -= 6; |
547 | 0 | } |
548 | 0 | return 0; |
549 | 0 | } |
550 | | |
551 | | /* |
552 | | ** Parse the opacity box. This is an alternative to the channel definition box |
553 | | ** and somewhat simpler. |
554 | | */ |
555 | | static int parse_opct(jxr_container_t c,const unsigned char *buffer,size_t size) |
556 | 0 | { |
557 | 0 | if (size < 1 + 8) |
558 | 0 | return JXR_EC_BADFORMAT; |
559 | | /* |
560 | | ** Chroma-keying is not supported. |
561 | | */ |
562 | 0 | if (size > 1 + 8) |
563 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
564 | | |
565 | 0 | switch(buffer[0]) { |
566 | 0 | case 0: |
567 | | /* Standard opacity. */ |
568 | 0 | c->alpha = 1; |
569 | 0 | break; |
570 | 0 | case 1: |
571 | | /* Premultiplied opacity. */ |
572 | 0 | c->alpha = 2; |
573 | 0 | break; |
574 | 0 | case 2: /* chroma key */ |
575 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; |
576 | 0 | } |
577 | | |
578 | 0 | return JXR_EC_BADFORMAT; |
579 | 0 | } |
580 | | |
581 | | /* |
582 | | ** Parse the color group super box. Contains only color boxes |
583 | | */ |
584 | | static int parse_cgrp(jxr_container_t c,size_t boxsize) |
585 | 0 | { |
586 | 0 | unsigned char buffer[256]; |
587 | 0 | size_t size; |
588 | 0 | uint32_t type; |
589 | 0 | int rc; |
590 | |
|
591 | 0 | do { |
592 | 0 | size = sizeof(buffer); |
593 | 0 | type = read_box(c,buffer,&size); |
594 | 0 | if (type == MAKE_ID('c','o','l','r')) { |
595 | 0 | rc = parse_colr(c,buffer,size); |
596 | 0 | if (rc) return rc; |
597 | 0 | } else { |
598 | 0 | return JXR_EC_BADFORMAT; |
599 | 0 | } |
600 | 0 | if (boxsize < size) |
601 | 0 | return JXR_EC_BADFORMAT; |
602 | 0 | boxsize -= size; |
603 | 0 | } while(boxsize); |
604 | | |
605 | 0 | return 0; |
606 | 0 | } |
607 | | |
608 | | /* |
609 | | ** Parse the compositing layer header box. |
610 | | */ |
611 | | static int parse_jplh(jxr_container_t c,size_t boxsize) |
612 | 0 | { |
613 | 0 | unsigned char buffer[256]; |
614 | 0 | size_t size; |
615 | 0 | uint32_t type; |
616 | 0 | int rc; |
617 | 0 | int have_creg = 0; |
618 | 0 | int have_cgrp = 0; |
619 | 0 | int have_opct = 0; |
620 | 0 | int have_cdef = 0; |
621 | 0 | int have_pxfm = 0; |
622 | 0 | int have_res = 0; |
623 | |
|
624 | 0 | do { |
625 | 0 | size = sizeof(buffer); |
626 | 0 | type = read_box(c,buffer,&size); |
627 | 0 | if (type == MAKE_ID('c','r','e','g')) { |
628 | 0 | if (have_creg) |
629 | 0 | return JXR_EC_BADFORMAT; |
630 | 0 | have_creg = 1; |
631 | 0 | rc = parse_creg(c,buffer,size); |
632 | 0 | if (rc) return rc; |
633 | 0 | } else if (type == MAKE_ID('c','d','e','f')) { |
634 | 0 | if (have_cdef || have_opct) |
635 | 0 | return JXR_EC_BADFORMAT; |
636 | 0 | have_cdef = 1; |
637 | 0 | rc = parse_cdef(c,buffer,size); |
638 | 0 | if (rc) return rc; |
639 | 0 | } else if (type == MAKE_ID('p','x','f','m')) { |
640 | 0 | if (have_pxfm) |
641 | 0 | return JXR_EC_BADFORMAT; |
642 | 0 | have_pxfm = 1; |
643 | 0 | rc = parse_pxfm(c,buffer,size); |
644 | 0 | if (rc) return rc; |
645 | 0 | } else if (type == MAKE_ID('o','p','c','t')) { |
646 | 0 | if (have_cdef || have_opct) |
647 | 0 | return JXR_EC_BADFORMAT; |
648 | 0 | have_opct = 1; |
649 | 0 | rc = parse_opct(c,buffer,size); |
650 | 0 | if (rc) return rc; |
651 | 0 | } else if (type == MAKE_ID('c','g','r','p')) { |
652 | | /* A color group box */ |
653 | 0 | if (have_cgrp) |
654 | 0 | return JXR_EC_BADFORMAT; |
655 | 0 | have_cgrp = 1; |
656 | 0 | rc = parse_cgrp(c,size); |
657 | 0 | if (rc) return rc; |
658 | 0 | } else if (type == MAKE_ID('r','e','s',' ')) { |
659 | | /* Resolution box. Currently ignored, skip over the superbox */ |
660 | 0 | if (have_res) |
661 | 0 | return JXR_EC_BADFORMAT; |
662 | 0 | have_res = 1; |
663 | 0 | if (fseek(c->fd,size,SEEK_CUR) != 0) |
664 | 0 | return JXR_EC_IO; |
665 | 0 | } |
666 | | /* All other boxes are ignored. */ |
667 | 0 | if (boxsize < size) |
668 | 0 | return JXR_EC_BADFORMAT; |
669 | 0 | boxsize -= size; |
670 | 0 | } while(boxsize); |
671 | | |
672 | 0 | return 0; |
673 | 0 | } |
674 | | |
675 | | int jxr_read_image_container_boxed(jxr_container_t c, FILE*fd) |
676 | 0 | { |
677 | 0 | unsigned char buffer[256]; |
678 | 0 | size_t size; |
679 | 0 | uint32_t type; |
680 | 0 | int rc; |
681 | 0 | int have_ftyp = 0; |
682 | 0 | int have_jp2h = 0; |
683 | 0 | int have_jplh = 0; |
684 | |
|
685 | 0 | c->fd = fd; |
686 | 0 | c->color = -1; /* Still unknown */ |
687 | |
|
688 | 0 | do { |
689 | 0 | size = sizeof(buffer); |
690 | 0 | type = read_box(c,buffer,&size); |
691 | 0 | if (size == 0 && !feof(c->fd)) |
692 | 0 | return JXR_EC_IO; |
693 | 0 | if (type == MAKE_ID('f','t','y','p')) { |
694 | | /* File type box */ |
695 | 0 | if (have_ftyp) |
696 | 0 | return JXR_EC_BADFORMAT; |
697 | 0 | have_ftyp = 1; |
698 | 0 | rc = parse_ftyp(c,buffer,size); |
699 | 0 | if (rc != 0) |
700 | 0 | return rc; |
701 | 0 | } else if (type == MAKE_ID('j','p','2','h')) { |
702 | | /* JP2 header box. Since this is a super box |
703 | | * the data remained in the file */ |
704 | 0 | if (have_jp2h) |
705 | 0 | return JXR_EC_BADFORMAT; |
706 | 0 | have_jp2h = 1; |
707 | 0 | rc = parse_jp2h(c,size); |
708 | 0 | if (rc != 0) |
709 | 0 | return rc; |
710 | 0 | } else if (type == MAKE_ID('j','p','c','h')) { |
711 | | /* Codestream header box */ |
712 | 0 | if (++c->c_idx > 2) |
713 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* Not more than two codestreams supported here */ |
714 | 0 | rc = parse_jpch(c,size); |
715 | 0 | if (rc != 0) |
716 | 0 | return rc; |
717 | 0 | } else if (type == MAKE_ID('j','p','l','h')) { |
718 | | /* Compositing layer header box */ |
719 | 0 | if (have_jplh) |
720 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* layer composition not supported here, only one layer */ |
721 | 0 | have_jplh = 1; |
722 | 0 | rc = parse_jplh(c,size); |
723 | 0 | } else if (type == MAKE_ID('j','p','2','c')) { |
724 | | /* The codestream itself. There can be two of them, one regular and one alpha stream */ |
725 | 0 | if (c->image_offset) { |
726 | | /* Is already the second. */ |
727 | 0 | if (c->alpha_offset) { |
728 | | /* More than two are not supported. */ |
729 | 0 | return JXR_EC_FEATURE_NOT_IMPLEMENTED; /* layer composition not supported here, only one layer */ |
730 | 0 | } |
731 | 0 | c->alpha_offset = ftell(c->fd); |
732 | 0 | c->alpha_size = size; |
733 | 0 | } else { |
734 | 0 | c->image_offset = ftell(c->fd); |
735 | 0 | c->image_size = size; |
736 | 0 | } |
737 | | /* Seek over it. */ |
738 | 0 | if (fseek(c->fd,size,SEEK_CUR) != 0) |
739 | 0 | return JXR_EC_IO; |
740 | 0 | c->image_count++; |
741 | 0 | } else if (type == MAKE_ID('u','i','n','f') || /* uuid info box */ |
742 | 0 | type == MAKE_ID('f','t','b','l') || /* fragment table box */ |
743 | 0 | type == MAKE_ID('c','o','m','p') || /* composition box */ |
744 | 0 | type == MAKE_ID('d','r','e','p')) { /* desired reproduction box */ |
745 | | /* Super boxes we currently don't need - seek over them */ |
746 | 0 | if (fseek(c->fd,size,SEEK_CUR) != 0) |
747 | 0 | return JXR_EC_IO; |
748 | 0 | } |
749 | 0 | } while(!feof(c->fd)); |
750 | | |
751 | | /* |
752 | | ** check whether there are as many channels as we have components. If not |
753 | | ** the result is not supported. |
754 | | */ |
755 | 0 | if (c->channels != c->depth) |
756 | 0 | return JXR_EC_BADFORMAT; |
757 | | |
758 | 0 | return 0; |
759 | 0 | } |