Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}