iccprofile: Decode 'dict' data type
[deark.git] / modules / bmff.c
blob632e5585b204dc3e6b4f351460be56f8ec99d57e
1 // This file is part of Deark.
2 // Copyright (C) 2016-2018 Jason Summers
3 // See the file COPYING for terms of use.
5 // ISO Base Media File Format, and related formats
6 // (JPEG 2000, MP4, QuickTime, etc.)
8 #include <deark-config.h>
9 #include <deark-private.h>
10 #include <deark-fmtutil.h>
12 // TODO: Rethink how to subdivide these formats into modules.
13 DE_DECLARE_MODULE(de_module_bmff);
14 DE_DECLARE_MODULE(de_module_jpeg2000);
16 typedef struct localctx_struct {
17 u32 major_brand;
18 u8 is_bmff;
19 u8 is_jp2_jpx_jpm, is_jpx, is_jpm;
20 u8 is_mj2;
21 u8 is_heif;
22 u8 is_jpegxt;
23 i64 max_entries_to_print;
25 u8 exif_item_id_known;
26 unsigned int exif_item_id;
27 i64 exif_item_offs;
28 i64 exif_item_len;
29 } lctx;
31 typedef void (*handler_fn_type)(deark *c, lctx *d, struct de_boxesctx *bctx);
33 struct box_type_info {
34 u32 boxtype;
35 // flags1 is intended to be used to indicate which formats/brands use this box.
36 // 0x00000001 = Generic BMFF (isom brand, etc.)
37 // 0x00000008 = MJ2
38 // 0x00010000 = JP2/JPX/JPM
39 // 0x00040000 = JPEG XT
40 // 0x00080000 = HEIF
41 // 0x01000000 = Used in ilst boxes
42 u32 flags1;
43 // flags2: 0x1 = is_superbox
44 // flags2: 0x2 = critical top-level box (used for format identification)
45 u32 flags2;
46 const char *name;
47 handler_fn_type hfn;
50 #define BRAND_heic 0x68656963U
51 #define BRAND_isom 0x69736f6dU
52 #define BRAND_mif1 0x6d696631U
53 #define BRAND_mp41 0x6d703431U
54 #define BRAND_mp42 0x6d703432U
55 #define BRAND_M4A 0x4d344120U
56 #define BRAND_jp2 0x6a703220U
57 #define BRAND_jpm 0x6a706d20U
58 #define BRAND_jpx 0x6a707820U
59 #define BRAND_mjp2 0x6d6a7032U
60 #define BRAND_mj2s 0x6d6a3273U
61 #define BRAND_qt 0x71742020U
63 #define BOX_alis 0x616c6973U
64 #define BOX_auxC 0x61757843U
65 #define BOX_co64 0x636f3634U
66 #define BOX_ctts 0x63747473U
67 #define BOX_data 0x64617461U
68 #define BOX_elst 0x656c7374U
69 #define BOX_ftyp 0x66747970U
70 #define BOX_grpl 0x6772706cU
71 #define BOX_hvcC 0x68766343U
72 #define BOX_idat 0x69646174U
73 #define BOX_iinf 0x69696e66U
74 #define BOX_iloc 0x696c6f63U
75 #define BOX_ilst 0x696c7374U
76 #define BOX_infe 0x696e6665U
77 #define BOX_iods 0x696f6473U
78 #define BOX_ipco 0x6970636fU
79 #define BOX_ipma 0x69706d61U
80 #define BOX_ipro 0x6970726fU
81 #define BOX_iprp 0x69707270U
82 #define BOX_iref 0x69726566U
83 #define BOX_ispe 0x69737065U
84 #define BOX_jP 0x6a502020U
85 #define BOX_jp2c 0x6a703263U
86 #define BOX_load 0x6c6f6164U
87 #define BOX_mdat 0x6d646174U
88 #define BOX_mdhd 0x6d646864U
89 #define BOX_mvhd 0x6d766864U
90 #define BOX_name 0x6e616d65U
91 #define BOX_pitm 0x7069746dU
92 #define BOX_pnot 0x706e6f74U
93 #define BOX_rsrc 0x72737263U
94 #define BOX_sbgp 0x73626770U
95 #define BOX_sdtp 0x73647470U
96 #define BOX_sgpd 0x73677064U
97 #define BOX_stsd 0x73747364U
98 #define BOX_tkhd 0x746b6864U
99 #define BOX_uuid 0x75756964U
100 #define BOX_wide 0x77696465U
101 #define BOX_xml 0x786d6c20U
102 #define BOX_PICT 0x50494354U
103 #define BOX_THMB 0x54484d42U
104 #define BOX_PRVW 0x50525657U
106 #define BOX_blank 0x2d2d2d2dU // "----"
107 #define BOX_cpil 0x6370696cU
108 #define BOX_gnre 0x676e7265U
109 #define BOX_tmpo 0x746d706fU
110 #define BOX_a9ART 0xa9415254U
111 #define BOX_a9cmt 0xa9636d74U
112 #define BOX_a9nam 0xa96e616dU
113 #define BOX_a9too 0xa9746f6fU
115 // JP2:
116 #define BOX_cdef 0x63646566U
117 #define BOX_colr 0x636f6c72U
118 #define BOX_jp2h 0x6a703268U
119 #define BOX_ihdr 0x69686472U
120 #define BOX_res 0x72657320U
121 #define BOX_resc 0x72657363U
122 #define BOX_resd 0x72657364U
123 #define BOX_uinf 0x75696e66U
124 #define BOX_ulst 0x756c7374U
125 #define BOX_url 0x75726c20U
126 // JPX:
127 #define BOX_jpch 0x6a706368U
128 #define BOX_jplh 0x6a706c68U
129 #define BOX_cgrp 0x63677270U
130 #define BOX_ftbl 0x6674626cU
131 #define BOX_comp 0x636f6d70U
132 #define BOX_asoc 0x61736f63U
133 #define BOX_drep 0x64726570U
134 #define BOX_dtbl 0x6474626cU
135 #define BOX_flst 0x666c7374U
136 #define BOX_lbl 0x6c626c20U
137 #define BOX_nlst 0x6e6c7374U
138 #define BOX_rreq 0x72726571U
139 // JPM:
140 #define BOX_page 0x70616765U
141 #define BOX_lobj 0x6c6f626aU
142 #define BOX_objc 0x6f626a63U
143 #define BOX_sdat 0x73646174U
144 #define BOX_mhdr 0x6d686472U
145 #define BOX_lhdr 0x6c686472U
146 #define BOX_ohdr 0x6f686472U
147 #define BOX_pagt 0x70616774U
148 #define BOX_pcol 0x70636f6cU
149 #define BOX_phdr 0x70686472U
150 #define BOX_scal 0x7363616cU
151 // BMFF, QuickTime, MP4, ...:
152 #define BOX_cinf 0x63696e66U
153 #define BOX_clip 0x636c6970U
154 #define BOX_dinf 0x64696e66U
155 #define BOX_dref 0x64726566U
156 #define BOX_edts 0x65647473U
157 //#define BOX_extr 0x65787472U // Irregular format?
158 #define BOX_fdsa 0x66647361U
159 #define BOX_fiin 0x6669696eU
160 #define BOX_free 0x66726565U
161 #define BOX_hdlr 0x68646c72U
162 #define BOX_hinf 0x68696e66U
163 #define BOX_hmhd 0x686d6864U
164 #define BOX_hnti 0x686e7469U
165 #define BOX_matt 0x6d617474U
166 #define BOX_mdia 0x6d646961U
167 #define BOX_meco 0x6d65636fU
168 #define BOX_meta 0x6d657461U
169 #define BOX_minf 0x6d696e66U
170 #define BOX_mfra 0x6d667261U
171 #define BOX_moof 0x6d6f6f66U
172 #define BOX_moov 0x6d6f6f76U
173 #define BOX_mvex 0x6d766578U
174 #define BOX_nmhd 0x6e6d6864U
175 #define BOX_paen 0x7061656eU
176 #define BOX_rinf 0x72696e66U
177 #define BOX_schi 0x73636869U
178 #define BOX_sinf 0x73696e66U
179 #define BOX_skip 0x736b6970U
180 #define BOX_smhd 0x736d6864U
181 #define BOX_stbl 0x7374626cU
182 #define BOX_stco 0x7374636fU
183 #define BOX_strd 0x73747264U
184 #define BOX_strk 0x7374726bU
185 #define BOX_stsc 0x73747363U
186 #define BOX_stss 0x73747373U
187 #define BOX_stsz 0x7374737aU
188 #define BOX_stts 0x73747473U
189 #define BOX_stz2 0x73747a32U
190 #define BOX_traf 0x74726166U
191 #define BOX_trak 0x7472616bU
192 #define BOX_tref 0x74726566U
193 #define BOX_udta 0x75647461U
194 #define BOX_vmhd 0x766d6864U
195 // JPEG XT
196 #define BOX_LCHK 0x4c43484bU
197 #define BOX_RESI 0x52455349U
198 #define BOX_SPEC 0x53504543U
200 #define CODE_Exif 0x45786966U
201 #define CODE_rICC 0x72494343U
202 #define CODE_prof 0x70726f66U
204 static const u8 *g_uuid_cr3_85c0 = (const u8*)"\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48";
205 static const u8 *g_uuid_cr3_eaf4 = (const u8*)"\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16";
207 // Called for each primary or compatible brand.
208 // Brand-specific setup can be done here.
209 static void apply_brand(deark *c, lctx *d, u32 brand_id)
211 switch(brand_id) {
212 case BRAND_jp2:
213 d->is_jp2_jpx_jpm = 1;
214 break;
215 case BRAND_jpx:
216 d->is_jpx = 1;
217 d->is_jp2_jpx_jpm = 1;
218 break;
219 case BRAND_jpm:
220 d->is_jpm = 1;
221 d->is_jp2_jpx_jpm = 1;
222 break;
223 case BRAND_mjp2:
224 case BRAND_mj2s:
225 d->is_bmff = 1;
226 d->is_mj2 = 1;
227 break;
228 case BRAND_isom:
229 case BRAND_mp41:
230 case BRAND_mp42:
231 case BRAND_M4A:
232 case BRAND_qt:
233 d->is_bmff = 1;
234 break;
235 case BRAND_mif1:
236 case BRAND_heic:
237 d->is_heif = 1;
238 break;
239 default:
240 if((brand_id>>16) == 0x3367) { // "3g??"
241 d->is_bmff = 1;
246 // JPEG 2000 signature box (presumably)
247 static void do_box_jP(deark *c, lctx *d, struct de_boxesctx *bctx)
249 u32 n;
250 struct de_boxdata *curbox = bctx->curbox;
252 if(curbox->level!=0) return;
253 if(curbox->payload_len<4) return;
254 n = (u32)dbuf_getu32be(bctx->f, curbox->payload_pos);
255 if(n==0x0d0a870a) {
256 de_dbg(c, "found JPEG 2000 signature");
260 static void do_box_ftyp(deark *c, lctx *d, struct de_boxesctx *bctx)
262 i64 i;
263 i64 mver;
264 i64 num_compat_brands;
265 struct de_fourcc brand4cc;
266 struct de_boxdata *curbox = bctx->curbox;
268 if(curbox->payload_len<4) goto done;
269 dbuf_read_fourcc(bctx->f, curbox->payload_pos, &brand4cc, 4, 0x0);
270 d->major_brand = brand4cc.id;
271 de_dbg(c, "major brand: '%s'", brand4cc.id_dbgstr);
272 if(curbox->level==0)
273 apply_brand(c, d, d->major_brand);
275 if(curbox->payload_len<8) goto done;
276 mver = dbuf_getu32be(bctx->f, curbox->payload_pos+4);
277 de_dbg(c, "minor version: %u", (unsigned int)mver);
279 if(curbox->payload_len<12) goto done;
280 num_compat_brands = (curbox->payload_len - 8)/4;
282 for(i=0; i<num_compat_brands; i++) {
283 dbuf_read_fourcc(bctx->f, curbox->payload_pos + 8 + i*4, &brand4cc, 4, 0x0);
284 if(brand4cc.id==0) continue; // Placeholder. Ignore.
285 de_dbg(c, "compatible brand: '%s'", brand4cc.id_dbgstr);
286 if(curbox->level==0)
287 apply_brand(c, d, brand4cc.id);
290 done:
294 static void do_read_version_and_flags(deark *c, lctx *d, struct de_boxesctx *bctx,
295 u8 *version, u32 *flags, int dbgflag)
297 u8 version1;
298 u32 flags1;
299 u32 n;
300 struct de_boxdata *curbox = bctx->curbox;
302 n = (u32)dbuf_getu32be(bctx->f, curbox->payload_pos);
303 version1 = (u8)(n>>24);
304 flags1 = n&0x00ffffff;
305 if(dbgflag) {
306 de_dbg(c, "version=%d, flags=0x%06x", (int)version1, (unsigned int)flags1);
308 if(version) *version = version1;
309 if(flags) *flags = flags1;
312 // For any box whose entire contents are a UTF-8 text string.
313 static void do_box_justtext(deark *c, lctx *d, struct de_boxesctx *bctx)
315 struct de_boxdata *curbox = bctx->curbox;
316 de_ucstring *s = NULL;
317 const char *name;
319 name = curbox->box_name ? curbox->box_name : "value";
320 s = ucstring_create(c);
321 dbuf_read_to_ucstring_n(bctx->f, curbox->payload_pos, curbox->payload_len,
322 DE_DBG_MAX_STRLEN, s, 0, DE_ENCODING_UTF8);
323 de_dbg(c, "%s: \"%s\"", name, ucstring_getpsz_d(s));
324 ucstring_destroy(s);
327 static const char *get_ilst_type_name(unsigned int ns, unsigned int wkt)
329 const char *name = NULL;
331 if(ns!=0) goto done;
333 switch(wkt) {
334 case 0: name="binary"; break;
335 case 1: name="UTF-8"; break;
336 case 2: name="UTF-16"; break;
337 case 3: name="S/JIS"; break;
338 case 4: name="UTF-8 sort key"; break;
339 case 5: name="UTF-16 sort key"; break;
340 case 13: name="JPEG"; break;
341 case 14: name="PNG"; break;
342 case 21: name="signed int"; break;
343 case 22: name="unsigned int"; break;
344 case 23: name="float32"; break;
345 case 24: name="float64"; break;
346 case 27: name="BMP"; break;
347 case 28: name="metadata atom"; break;
349 done:
350 if(!name) name="?";
351 return name;
354 static void do_box_data(deark *c, lctx *d, struct de_boxesctx *bctx)
356 unsigned int type_field, type_namespace, wkt;
357 unsigned int cntry, lang;
358 i64 vlen;
359 struct de_boxdata *curbox = bctx->curbox;
360 struct de_boxdata *par;
361 struct de_boxdata *gpar;
362 i64 pos = curbox->payload_pos;
363 de_ucstring *s = NULL;
365 par = curbox->parent;
366 if(!par) goto done;
367 gpar = par->parent;
368 if(!gpar) goto done;
369 if(gpar->boxtype != BOX_ilst) goto done;
371 if(curbox->payload_len<8) goto done;
372 type_field = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
373 type_namespace = type_field>>24;
374 wkt = (type_field & 0x00ffffff); // well-known type (if namespace==0)
375 de_dbg(c, "type: %u, %u (%s)", type_namespace, wkt,
376 get_ilst_type_name(type_namespace, wkt));
378 cntry = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
379 lang = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
380 de_dbg(c, "locale: %u, %u", cntry, lang);
382 if(type_namespace!=0) goto done;
383 vlen = curbox->payload_pos + curbox->payload_len - pos;
385 if(wkt==1 || wkt==4) { // UTF-8
386 s = ucstring_create(c);
387 dbuf_read_to_ucstring_n(bctx->f, pos, vlen,
388 DE_DBG_MAX_STRLEN, s, 0, DE_ENCODING_UTF8);
389 de_dbg(c, "value: \"%s\"", ucstring_getpsz_d(s));
391 else if(wkt==21 && vlen==1) { // 1-byte signed int
392 int n;
393 n = (int)(signed char)dbuf_getbyte(bctx->f, pos);
394 de_dbg(c, "value: %d", n);
396 else if(wkt==21 && vlen==2) { // 2-byte BE signed int
397 int n;
398 n = (int)dbuf_geti16be(bctx->f, pos);
399 de_dbg(c, "value: %d", n);
401 else if(wkt==0) {
402 de_dbg_hexdump(c, bctx->f, pos, vlen, 256, "value", 0x1);
404 // TODO: There are lots more types
406 done:
407 ucstring_destroy(s);
410 static void do_box_hdlr(deark *c, lctx *d, struct de_boxesctx *bctx)
412 de_ucstring *s = NULL;
413 struct de_boxdata *curbox = bctx->curbox;
414 i64 pos = curbox->payload_pos;
415 struct de_fourcc tmp4cc;
417 if(curbox->payload_len<4) goto done;
418 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
419 pos += 4;
420 if(curbox->payload_len<24) goto done;
421 pos += 4; // "Predefined"
423 dbuf_read_fourcc(bctx->f, pos, &tmp4cc, 4, 0x0);
424 de_dbg(c, "handler type: '%s'", tmp4cc.id_dbgstr);
425 pos += 4;
427 pos += 12; // reserved
428 if(curbox->payload_len<25) goto done;
429 if(dbuf_getbyte(bctx->f, pos) == 0x00) goto done;
431 s = ucstring_create(c);
432 dbuf_read_to_ucstring_n(bctx->f, pos, curbox->payload_pos + curbox->payload_len - pos,
433 DE_DBG_MAX_STRLEN, s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_UTF8);
434 de_dbg(c, "metadata type name: \"%s\"", ucstring_getpsz_d(s));
436 done:
437 ucstring_destroy(s);
440 static void do_box_tkhd(deark *c, lctx *d, struct de_boxesctx *bctx)
442 u8 version;
443 u32 flags;
444 i64 pos;
445 double w, h;
446 i64 n;
447 struct de_boxdata *curbox = bctx->curbox;
449 if(curbox->payload_len<4) return;
451 pos = curbox->payload_pos;
452 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
453 pos+=4;
455 if(version==1) {
456 if(curbox->payload_len<96) return;
458 else {
459 if(curbox->payload_len<84) return;
462 // creation time, mod time
463 if(version==1)
464 pos += 8 + 8;
465 else
466 pos += 4 + 4;
468 n = dbuf_getu32be_p(bctx->f, &pos);
469 de_dbg(c, "track id: %d", (int)n);
471 pos += 4; // reserved
473 // duration
474 if(version==1)
475 pos += 8;
476 else
477 pos += 4;
479 pos += 4*2; // reserved
480 pos += 2; // layer
481 pos += 2; // alternate group
483 n = dbuf_getu16be_p(bctx->f, &pos);
484 de_dbg(c, "volume: %.3f", ((double)n)/256.0);
486 pos += 2; // reserved
487 pos += 4*9; // matrix
489 w = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
490 pos += 4;
491 h = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
492 pos += 4;
493 de_dbg(c, "dimensions: %.1f"DE_CHAR_TIMES"%.1f", w, h);
496 static void do_box_vmhd(deark *c, lctx *d, struct de_boxesctx *bctx)
498 u8 version;
499 u32 flags;
500 size_t k;
501 unsigned int clr[3];
502 unsigned int graphicsmode;
503 struct de_boxdata *curbox = bctx->curbox;
504 i64 pos = curbox->payload_pos;
506 if(curbox->payload_len<12) return;
507 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
508 pos += 4;
509 if(version!=0 || flags!=0x1) return;
511 graphicsmode = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
512 de_dbg(c, "graphicsmode: %u", graphicsmode);
514 for(k=0; k<3; k++) {
515 clr[k] = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
517 de_dbg(c, "opcolor: (%d,%d,%d)", (int)clr[0], (int)clr[1], (int)clr[2]);
520 static void do_box_PICT(deark *c, lctx *d, struct de_boxesctx *bctx)
522 struct de_boxdata *curbox = bctx->curbox;
523 dbuf *outf = NULL;
525 outf = dbuf_create_output_file(c, "pict", NULL, DE_CREATEFLAG_IS_AUX);
526 dbuf_write_zeroes(outf, 512);
527 dbuf_copy(bctx->f, curbox->payload_pos, curbox->payload_len, outf);
528 dbuf_close(outf);
531 static void do_box_smhd(deark *c, lctx *d, struct de_boxesctx *bctx)
533 u8 version;
534 u32 flags;
535 unsigned int n;
536 struct de_boxdata *curbox = bctx->curbox;
537 i64 pos = curbox->payload_pos;
539 if(curbox->payload_len<8) return;
540 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
541 pos += 4;
542 if(version!=0 || flags!=0x0) return;
544 n = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
545 de_dbg(c, "balance: %u", n);
548 static void do_box_mvhd(deark *c, lctx *d, struct de_boxesctx *bctx)
550 u8 version;
551 u32 flags;
552 i64 pos;
553 i64 n;
554 i64 timescale;
555 double nd;
556 struct de_boxdata *curbox = bctx->curbox;
558 if(curbox->payload_len<4) return;
560 pos = curbox->payload_pos;
561 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
562 pos+=4;
564 if(version==1) {
565 if(curbox->payload_len<112) return;
567 else {
568 if(curbox->payload_len<100) return;
571 // creation time, mod time
572 if(version==1)
573 pos += 8 + 8;
574 else
575 pos += 4 + 4;
577 timescale = dbuf_getu32be_p(bctx->f, &pos);
578 de_dbg(c, "timescale: %d time units per second", (int)timescale);
580 // duration
581 if(version==1) {
582 n = dbuf_geti64be(bctx->f, pos);
583 pos += 8;
585 else {
586 n = dbuf_getu32be_p(bctx->f, &pos);
588 if(timescale>0)
589 nd = (double)n / (double)timescale;
590 else
591 nd = 0.0;
592 de_dbg(c, "duration: %d time units (%.2f seconds)", (int)n, nd);
594 nd = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
595 pos += 4; // rate
596 de_dbg(c, "rate: %.3f", nd);
598 n = dbuf_getu16be_p(bctx->f, &pos);
599 de_dbg(c, "volume: %.3f", ((double)n)/256.0);
601 pos += 2; // reserved
602 pos += 4*2; // reserved
603 pos += 4*9; // matrix
604 pos += 4*6; // pre_defined
606 n = dbuf_getu32be(bctx->f, pos);
607 de_dbg(c, "next track id: %d", (int)n);
610 static void do_box_mdhd(deark *c, lctx *d, struct de_boxesctx *bctx)
612 u8 version;
613 u32 flags;
614 i64 pos;
615 i64 n;
616 i64 timescale;
617 double nd;
618 struct de_boxdata *curbox = bctx->curbox;
620 // TODO: Share code with do_box_mvhd()?
621 if(curbox->payload_len<4) return;
623 pos = curbox->payload_pos;
624 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
625 pos+=4;
627 if(version==1) {
628 if(curbox->payload_len<36) return;
630 else {
631 if(curbox->payload_len<24) return;
634 // creation time, mod time
635 if(version==1)
636 pos += 8 + 8;
637 else
638 pos += 4 + 4;
640 timescale = dbuf_getu32be_p(bctx->f, &pos);
641 de_dbg(c, "timescale: %d time units per second", (int)timescale);
643 // duration
644 if(version==1) {
645 n = dbuf_geti64be(bctx->f, pos);
646 pos += 8;
648 else {
649 n = dbuf_getu32be_p(bctx->f, &pos);
651 if(timescale>0)
652 nd = (double)n / (double)timescale;
653 else
654 nd = 0.0;
655 de_dbg(c, "duration: %d time units (%.2f seconds)", (int)n, nd);
658 static void do_box_stsc(deark *c, lctx *d, struct de_boxesctx *bctx)
660 u8 version;
661 u32 flags;
662 struct de_boxdata *curbox = bctx->curbox;
663 i64 pos = curbox->payload_pos;
664 i64 e_count, e_to_print;
665 i64 bytesleft;
666 i64 k;
668 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
669 pos += 4;
670 if(version!=0 || flags!=0) return;
672 e_count = dbuf_getu32be_p(bctx->f, &pos);
673 de_dbg(c, "entry count: %u", (unsigned int)e_count);
675 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
676 if(bytesleft/12 < e_count) return;
678 e_to_print = de_min_int(e_count, d->max_entries_to_print);
680 for(k=0; k<e_to_print; k++) {
681 i64 first_chunk, spc, sdi;
682 first_chunk = dbuf_getu32be_p(bctx->f, &pos);
683 spc = dbuf_getu32be_p(bctx->f, &pos);
684 sdi = dbuf_getu32be_p(bctx->f, &pos);
685 de_dbg(c, "entry[%d]: first chunk=%d, samples/chunk=%d, descr. index=%d",
686 (int)k, (int)first_chunk, (int)spc, (int)sdi);
688 if(e_to_print < e_count) {
689 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
690 (int)(e_count-e_to_print), pos);
694 static void do_box_stsd(deark *c, lctx *d, struct de_boxesctx *bctx)
696 u8 version;
697 u32 flags;
698 i64 pos;
699 i64 num_entries;
700 i64 entry_size;
701 struct de_fourcc fmt4cc;
702 struct de_boxdata *curbox = bctx->curbox;
704 if(curbox->payload_len<8) return;
706 pos = curbox->payload_pos;
707 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
708 pos += 4;
709 if(version!=0) return;
711 num_entries = dbuf_getu32be_p(bctx->f, &pos);
712 de_dbg(c, "number of sample description entries: %d", (int)num_entries);
714 while(1) {
715 if(pos + 16 >= curbox->payload_pos + curbox->payload_len) break;
716 entry_size = dbuf_getu32be(bctx->f, pos);
717 de_dbg(c, "sample description entry at %d, len=%d", (int)pos, (int)entry_size);
718 if(entry_size<16) break;
720 de_dbg_indent(c, 1);
721 dbuf_read_fourcc(bctx->f, pos+4, &fmt4cc, 4, 0x0);
722 de_dbg(c, "data format: '%s'", fmt4cc.id_dbgstr);
723 de_dbg_indent(c, -1);
725 pos += entry_size;
729 // Decode a table of (4- or 8-byte) integers.
730 // Limit to d->max_entries_to_print.
731 static void do_simple_int_table(deark *c, lctx *d, struct de_boxesctx *bctx,
732 i64 pos1, i64 e_count, i64 e_size,
733 const char *s1, const char *s2)
735 i64 bytesleft;
736 i64 e_to_print;
737 i64 k;
738 struct de_boxdata *curbox = bctx->curbox;
739 i64 pos = pos1;
741 if(e_count<=0) return;
742 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
743 if(bytesleft < e_size*e_count) return;
745 e_to_print = de_min_int(e_count, d->max_entries_to_print);
747 for(k=0; k<e_to_print; k++) {
748 i64 n;
750 if(e_size==8) {
751 n = dbuf_geti64be(bctx->f, pos); pos += 8;
753 else {
754 n = dbuf_getu32be_p(bctx->f, &pos);
757 de_dbg(c, "%s[%"I64_FMT"]: %s=%"I64_FMT, s1, k, s2, n);
759 if(e_to_print < e_count) {
760 de_dbg(c, "[%"I64_FMT" more %s(s) omitted, starting at %"I64_FMT"]",
761 e_count-e_to_print, s1, pos);
765 static void do_box_stsz(deark *c, lctx *d, struct de_boxesctx *bctx)
767 u8 version;
768 u32 flags;
769 struct de_boxdata *curbox = bctx->curbox;
770 i64 pos = curbox->payload_pos;
771 i64 s_size, s_count;
773 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
774 pos += 4;
775 if(version!=0 || flags!=0) return;
777 s_size = dbuf_getu32be_p(bctx->f, &pos);
778 de_dbg(c, "sample size: %u", (unsigned int)s_size);
779 s_count = dbuf_getu32be_p(bctx->f, &pos);
780 de_dbg(c, "sample count: %u", (unsigned int)s_count);
782 if(s_size!=0) goto done;
784 do_simple_int_table(c, d, bctx, pos, s_count, 4, "sample", "entry size");
786 done:
790 // stco and co64
791 static void do_box_stco(deark *c, lctx *d, struct de_boxesctx *bctx)
793 u8 version;
794 u32 flags;
795 struct de_boxdata *curbox = bctx->curbox;
796 i64 pos = curbox->payload_pos;
797 i64 e_count;
798 i64 e_size;
800 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
801 pos += 4;
802 if(version!=0 || flags!=0) return;
804 e_size = (bctx->curbox->boxtype == BOX_co64) ? 8 : 4;
805 e_count = dbuf_getu32be_p(bctx->f, &pos);
806 de_dbg(c, "entry count: %u", (unsigned int)e_count);
808 do_simple_int_table(c, d, bctx, pos, e_count, e_size, "entry", "chunk offset");
811 static void do_box_stss(deark *c, lctx *d, struct de_boxesctx *bctx)
813 u8 version;
814 u32 flags;
815 struct de_boxdata *curbox = bctx->curbox;
816 i64 pos = curbox->payload_pos;
817 i64 e_count;
819 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
820 pos += 4;
821 if(version!=0 || flags!=0) return;
823 e_count = dbuf_getu32be_p(bctx->f, &pos);
824 de_dbg(c, "entry count: %u", (unsigned int)e_count);
826 do_simple_int_table(c, d, bctx, pos, e_count, 4, "entry", "sample number");
829 static void do_box_stts(deark *c, lctx *d, struct de_boxesctx *bctx)
831 u8 version;
832 u32 flags;
833 struct de_boxdata *curbox = bctx->curbox;
834 i64 pos = curbox->payload_pos;
835 i64 e_count, e_to_print;
836 i64 bytesleft;
837 i64 k;
839 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
840 pos += 4;
841 if(version!=0 || flags!=0) return;
843 e_count = dbuf_getu32be_p(bctx->f, &pos);
844 de_dbg(c, "entry count: %u", (unsigned int)e_count);
846 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
847 if(bytesleft/8 < e_count) return;
849 e_to_print = de_min_int(e_count, d->max_entries_to_print);
851 for(k=0; k<e_to_print; k++) {
852 i64 s_count, s_delta;
853 s_count = dbuf_getu32be_p(bctx->f, &pos);
854 s_delta = dbuf_getu32be_p(bctx->f, &pos);
855 de_dbg(c, "entry[%d]: sample count=%d, delta=%d", (int)k,
856 (int)s_count, (int)s_delta);
858 if(e_to_print < e_count) {
859 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
860 (int)(e_count-e_to_print), pos);
864 static void do_box_ctts(deark *c, lctx *d, struct de_boxesctx *bctx)
866 u8 version;
867 u32 flags;
868 struct de_boxdata *curbox = bctx->curbox;
869 i64 pos = curbox->payload_pos;
870 i64 e_count, e_to_print;
871 i64 bytesleft;
872 i64 k;
874 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
875 pos += 4;
876 if(version>1 || flags!=0) return;
878 e_count = dbuf_getu32be_p(bctx->f, &pos);
879 de_dbg(c, "entry count: %u", (unsigned int)e_count);
881 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
882 if(bytesleft < e_count*8) return;
884 e_to_print = e_count;
885 if(e_to_print > d->max_entries_to_print) {
886 e_to_print = d->max_entries_to_print;
889 for(k=0; k<e_to_print; k++) {
890 i64 s_count, s_offset;
891 s_count = dbuf_getu32be_p(bctx->f, &pos);
892 if(version==0) {
893 s_offset = dbuf_getu32be_p(bctx->f, &pos);
895 else {
896 s_offset = dbuf_geti32be(bctx->f, pos); pos += 4;
898 de_dbg(c, "entry[%d]: sample count=%"I64_FMT", offset=%"I64_FMT,
899 (int)k, s_count, s_offset);
901 if(e_to_print < e_count) {
902 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
903 (int)(e_count-e_to_print), pos);
907 static void do_box_full_superbox(deark *c, lctx *d, struct de_boxesctx *bctx)
909 struct de_boxdata *curbox = bctx->curbox;
911 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
912 curbox->extra_bytes_before_children = 4;
915 static void do_box_meta(deark *c, lctx *d, struct de_boxesctx *bctx)
917 if(bctx->curbox->payload_len>=8) {
918 // The QuickTime spec says 'meta' is not a full box, but in newer files
919 // it is. I don't know how you're supposed to know, but sniffing for
920 // "hdlr" should be good enough.
921 u32 n = (u32)dbuf_getu32be(bctx->f, bctx->curbox->payload_pos+4);
922 if(n==BOX_hdlr) {
923 return;
927 do_box_full_superbox(c, d, bctx);
930 static void do_box_jp2c(deark *c, lctx *d, struct de_boxesctx *bctx)
932 struct de_boxdata *curbox = bctx->curbox;
934 de_dbg(c, "JPEG 2000 codestream at %d, len=%d",
935 (int)curbox->payload_pos, (int)curbox->payload_len);
937 // I think this box is used regardless of the compression format, so make
938 // sure it seems to be in "JPEG 2000" format.
939 // This is a hack -- we could track the compression method instead.
940 if((u32)dbuf_getu32be(bctx->f, curbox->payload_pos) != 0xff4fff51U) {
941 de_dbg(c, "[non-J2C]");
942 return;
945 dbuf_create_file_from_slice(bctx->f, curbox->payload_pos, curbox->payload_len,
946 "j2c", NULL, 0);
949 #define POW10_MAX_E 12
950 static i64 limited_ipow10(int e)
952 i64 n = 1;
954 if(e < 0 || e > POW10_MAX_E) return 1;
955 while(e>0) {
956 n *= 10;
957 e--;
959 return n;
962 // TODO: Decide whether to use pow()/libm.
963 static double limited_pow10(int e)
965 if(e < -POW10_MAX_E || e > POW10_MAX_E) return 0.0;
966 if(e < 0) {
967 return 1.0 / (double)limited_ipow10(e);
969 return (double)limited_ipow10(e);
972 static void format_jp2_res(char *buf, size_t buflen,
973 i64 num, i64 denom, int exponent)
975 char descr[100];
977 if(denom != 0 && exponent >= -POW10_MAX_E && exponent <= POW10_MAX_E) {
978 double dpm, dpi;
980 dpm = ((double)num / (double)denom) * limited_pow10(exponent);
981 dpi = dpm * 0.0254;
982 de_snprintf(descr, sizeof(descr), " = %f points/meter (%f dpi)", dpm, dpi);
984 else {
985 descr[0] = '\0';
987 de_snprintf(buf, buflen, "(%"I64_FMT",%"I64_FMT",%d)%s",
988 num, denom, exponent, descr);
991 static void do_box_resc_resd(deark *c, lctx *d, struct de_boxesctx *bctx)
993 i64 vn, vd, hn, hd;
994 int ve, he;
995 struct de_boxdata *curbox = bctx->curbox;
996 const char *name;
997 i64 pos = curbox->payload_pos;
998 char res_buf[160];
1000 if(curbox->boxtype==BOX_resc)
1001 name = "capture";
1002 else
1003 name = "display";
1005 if(curbox->payload_len<10) return;
1006 vn = dbuf_getu16be_p(bctx->f, &pos);
1007 vd = dbuf_getu16be_p(bctx->f, &pos);
1008 hn = dbuf_getu16be_p(bctx->f, &pos);
1009 hd = dbuf_getu16be_p(bctx->f, &pos);
1010 ve = (int)(signed char)dbuf_getbyte_p(bctx->f, &pos);
1011 he = (int)(signed char)dbuf_getbyte_p(bctx->f, &pos);
1012 format_jp2_res(res_buf, sizeof(res_buf), vn, vd, ve);
1013 de_dbg(c, "vert. %s grid res.: %s", name, res_buf);
1014 format_jp2_res(res_buf, sizeof(res_buf), hn, hd, he);
1015 de_dbg(c, "horz. %s grid res.: %s", name, res_buf);
1018 static const char *get_rreq_sf_name(UI n)
1020 static const u8 ids[11] = {1, 2, 5, 8, 12, 18, 19, 20, 31, 45, 46};
1021 static const char *names[11] = { "no extensions", "has layers",
1022 "cmpr=JPEG 2000/15444-1", "no opacity", "contiguous",
1023 "layers not req'd", "discrete layers", "1 codestream per layer",
1024 "scaling not req'd", "sRGB", "sRGB-gray" };
1025 size_t i;
1027 for(i=0; i<DE_ARRAYCOUNT(ids); i++) {
1028 if((UI)ids[i]==n) return names[i];
1030 return "?";
1033 static void do_box_rreq(deark *c, lctx *d, struct de_boxesctx *bctx)
1035 i64 pos = bctx->curbox->payload_pos;
1036 i64 endpos = pos + bctx->curbox->payload_len;
1037 UI ml;
1038 i64 nsf, nvf;
1039 u64 msk;
1040 i64 i;
1042 if(pos>=endpos) goto done;
1043 ml = (UI)dbuf_getbyte_p(bctx->f, &pos);
1044 de_dbg(c, "ml: %u byte(s)", ml);
1045 if(ml<1 || ml>8) goto done;
1047 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1048 pos += (i64)ml;
1049 de_dbg(c, "fuam: 0x%"U64_FMTx, msk);
1051 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1052 pos += (i64)ml;
1053 de_dbg(c, "dcm: 0x%"U64_FMTx, msk);
1055 nsf = dbuf_getu16be_p(bctx->f, &pos);
1056 de_dbg(c, "nsf: %d", (int)nsf);
1058 for(i=0; i<nsf; i++) {
1059 UI sf;
1061 if(pos>=endpos) goto done;
1062 sf = (UI)dbuf_getu16be_p(bctx->f, &pos);
1063 de_dbg(c, "standard feature[%d]: %u (%s)", (int)i, sf, get_rreq_sf_name(sf));
1065 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1066 pos += (i64)ml;
1067 de_dbg_indent(c, 1);
1068 de_dbg(c, "mask: 0x%"U64_FMTx, msk);
1069 de_dbg_indent(c, -1);
1072 if(pos>=endpos) goto done;
1073 nvf = dbuf_getu16be_p(bctx->f, &pos);
1074 de_dbg(c, "num. vendor features: %d", (int)nvf);
1076 for(i=0; i<nvf; i++) {
1077 u8 ubuf[16];
1078 char uuid_string[50];
1080 if(pos>=endpos) goto done;
1081 dbuf_read(bctx->f, ubuf, pos, 16);
1082 fmtutil_render_uuid(c, ubuf, uuid_string, sizeof(uuid_string));
1083 de_dbg(c, "vendor feature[%d]: {%s}", (int)i, uuid_string);
1084 pos += 16;
1086 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1087 pos += (i64)ml;
1088 de_dbg_indent(c, 1);
1089 de_dbg(c, "mask: 0x%"U64_FMTx, msk);
1090 de_dbg_indent(c, -1);
1093 done:
1097 static const char *get_jpeg2000_cmpr_name(deark *c, lctx *d, u8 ct)
1099 const char *name = NULL;
1101 if(ct==7) { name="JPEG 2000"; goto done; }
1102 if(d->is_jpx) {
1103 switch(ct) {
1104 case 0: name="uncompressed"; break;
1105 case 1: name="MH"; break;
1106 case 2: name="MR"; break;
1107 case 3: name="MMR"; break;
1108 case 4: name="JBIG bi-level"; break;
1109 case 5: name="JPEG"; break;
1110 case 6: name="JPEG-LS"; break;
1111 case 8: name="JBIG2"; break;
1112 case 9: name="JBIG"; break;
1115 // TODO: JPM
1116 done:
1117 if(!name) name="?";
1118 return name;
1121 static void do_box_ihdr(deark *c, lctx *d, struct de_boxesctx *bctx)
1123 i64 w, h, n;
1124 u8 b;
1125 struct de_boxdata *curbox = bctx->curbox;
1126 i64 pos = curbox->payload_pos;
1127 char tmps[80];
1129 if(curbox->payload_len<14) return;
1130 h = dbuf_getu32be_p(bctx->f, &pos);
1131 w = dbuf_getu32be_p(bctx->f, &pos);
1132 de_dbg_dimensions(c, w, h);
1134 n = dbuf_getu16be_p(bctx->f, &pos);
1135 de_dbg(c, "number of components: %d", (int)n);
1137 b = dbuf_getbyte_p(bctx->f, &pos);
1138 if(b==255) {
1139 de_strlcpy(tmps, "various", sizeof(tmps));
1141 else {
1142 de_snprintf(tmps, sizeof(tmps), "%u bits/comp., %ssigned",
1143 (unsigned int)(1+(b&0x7f)), (b&0x80)?"":"un");
1145 de_dbg(c, "bits-per-component code: %u (%s)", (unsigned int)b, tmps);
1147 b = dbuf_getbyte_p(bctx->f, &pos);
1148 de_dbg(c, "compression type: %u (%s)", (unsigned int)b,
1149 get_jpeg2000_cmpr_name(c, d, b));
1151 b = dbuf_getbyte_p(bctx->f, &pos);
1152 de_dbg(c, "colorspace-is-unknown flag: %d", (int)b);
1153 b = dbuf_getbyte_p(bctx->f, &pos);
1154 de_dbg(c, "has-IPR: %d", (int)b);
1157 static const char *get_channel_type_name(i64 t)
1159 const char *name;
1160 switch(t) {
1161 case 0: name = "colour image data for associated color"; break;
1162 case 1: name = "opacity"; break;
1163 case 2: name = "premultiplied opacity"; break;
1164 case 65535: name = "not specified"; break;
1165 default: name = "?";
1167 return name;
1170 static void do_box_cdef(deark *c, lctx *d, struct de_boxesctx *bctx)
1172 i64 ndescs;
1173 struct de_boxdata *curbox = bctx->curbox;
1174 i64 pos = curbox->payload_pos;
1175 i64 k;
1177 ndescs = dbuf_getu16be_p(bctx->f, &pos);
1178 de_dbg(c, "number of channel descriptions: %d", (int)ndescs);
1180 for(k=0; k<ndescs; k++) {
1181 i64 idx, typ, asoc;
1183 if(pos+6 > curbox->payload_pos + curbox->payload_len) break;
1184 de_dbg(c, "channel description[%d] at %"I64_FMT, (int)k, pos);
1185 de_dbg_indent(c, 1);
1186 idx = dbuf_getu16be_p(bctx->f, &pos);
1187 de_dbg(c, "channel index: %d", (int)idx);
1188 typ = dbuf_getu16be_p(bctx->f, &pos);
1189 de_dbg(c, "channel type: %d (%s)", (int)typ, get_channel_type_name(typ));
1190 asoc = dbuf_getu16be_p(bctx->f, &pos);
1191 de_dbg(c, "index of associated color: %d", (int)asoc);
1192 de_dbg_indent(c, -1);
1196 // BMFF-style 'colr' box
1197 static void do_box_colr_bmff(deark *c, lctx *d, struct de_boxesctx *bctx)
1199 struct de_boxdata *curbox = bctx->curbox;
1200 i64 pos = curbox->payload_pos;
1201 struct de_fourcc ct4cc; // colour_type
1203 if(curbox->payload_len<4) goto done;
1205 dbuf_read_fourcc(bctx->f, pos, &ct4cc, 4, 0x0);
1206 de_dbg(c, "colour type: '%s'", ct4cc.id_dbgstr);
1207 pos += 4;
1209 if(ct4cc.id==CODE_rICC || ct4cc.id==CODE_prof) {
1210 dbuf_create_file_from_slice(bctx->f, pos,
1211 curbox->payload_pos+curbox->payload_len-pos,
1212 "icc", NULL, DE_CREATEFLAG_IS_AUX);
1215 done:
1219 // JP2/JPX-style 'colr' box
1220 static void do_box_colr_jp2(deark *c, lctx *d, struct de_boxesctx *bctx)
1222 u8 meth;
1223 u8 n;
1224 struct de_boxdata *curbox = bctx->curbox;
1225 i64 pos = curbox->payload_pos;
1226 const char *s;
1228 if(curbox->payload_len<3) goto done;
1229 meth = dbuf_getbyte_p(bctx->f, &pos);
1230 switch(meth) {
1231 case 1: s="enumerated"; break;
1232 case 2: s="ICC profile (restricted)"; break;
1233 case 3: s="ICC profile (any)"; break; // JPX only
1234 case 4: s="vendor"; break; // JPX only
1235 default: s="?";
1237 de_dbg(c, "specification method: %d (%s)", (int)meth, s);
1239 n = dbuf_getbyte_p(bctx->f, &pos);
1240 de_dbg(c, "precedence: %u", (UI)n);
1241 n = dbuf_getbyte_p(bctx->f, &pos);
1242 de_dbg(c, "approximation code: %u", (UI)n);
1244 if(meth==1) {
1245 unsigned int enumcs;
1246 if(curbox->payload_len<7) goto done;
1247 enumcs = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
1248 switch(enumcs) {
1249 // TODO: There are lots more valid values for JPX.
1250 case 16: s="sRGB"; break;
1251 case 17: s="sRGB-like grayscale"; break;
1252 case 18: s="sYCC"; break;
1253 default: s="?";
1255 de_dbg(c, "enumerated colourspace: %u (%s)", enumcs, s);
1257 else if(meth==2 || meth==3) {
1258 dbuf_create_file_from_slice(bctx->f,
1259 curbox->payload_pos+3, curbox->payload_len-3,
1260 "icc", NULL, DE_CREATEFLAG_IS_AUX);
1263 done:
1267 static void do_box_ulst(deark *c, lctx *d, struct de_boxesctx *bctx)
1269 struct de_boxdata *curbox = bctx->curbox;
1270 i64 pos = curbox->payload_pos;
1271 i64 nuuids;
1272 i64 k;
1273 u8 ubuf[16];
1274 char uuid_string[50];
1276 nuuids = dbuf_getu16be_p(bctx->f, &pos);
1277 de_dbg(c, "number of UUIDs: %d", (int)nuuids);
1279 for(k=0; k<nuuids; k++) {
1280 if(pos+16 > curbox->payload_pos + curbox->payload_len) break;
1281 dbuf_read(bctx->f, ubuf, pos, 16);
1282 fmtutil_render_uuid(c, ubuf, uuid_string, sizeof(uuid_string));
1283 de_dbg(c, "UUID[%d]: {%s}", (int)k, uuid_string);
1284 pos += 16;
1288 static void do_box_url(deark *c, lctx *d, struct de_boxesctx *bctx)
1290 de_ucstring *s = NULL;
1291 struct de_boxdata *curbox = bctx->curbox;
1292 i64 pos = curbox->payload_pos;
1293 u32 flags = 0;
1295 do_read_version_and_flags(c, d, bctx, NULL, &flags, 1);
1296 pos += 4;
1298 // "If the self-contained flag is set, [...] no string is present".
1299 // But there is no flag named "self-contained".
1300 // I assume it is flag 0x1.
1301 if(flags&0x000001) goto done;
1303 s = ucstring_create(c);
1304 dbuf_read_to_ucstring_n(bctx->f,
1305 pos, curbox->payload_pos + curbox->payload_len - pos, DE_DBG_MAX_STRLEN,
1306 s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_UTF8);
1307 de_dbg(c, "URL: \"%s\"", ucstring_getpsz_d(s));
1308 done:
1309 ucstring_destroy(s);
1312 static void do_box_dtbl(deark *c, lctx *d, struct de_boxesctx *bctx)
1314 i64 ndr;
1315 struct de_boxdata *curbox = bctx->curbox;
1317 ndr = dbuf_getu16be(bctx->f, curbox->payload_pos);
1318 de_dbg(c, "number of data references: %d", (int)ndr);
1320 curbox->num_children_is_known = 1;
1321 curbox->num_children = ndr;
1322 curbox->extra_bytes_before_children = 2;
1325 static void do_box_dref(deark *c, lctx *d, struct de_boxesctx *bctx)
1327 i64 nitems;
1328 u8 version;
1329 struct de_boxdata *curbox = bctx->curbox;
1330 i64 pos = curbox->payload_pos;
1332 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1333 pos += 4;
1335 nitems = dbuf_getu32be_p(bctx->f, &pos);
1336 de_dbg(c, "number of items: %u", (unsigned int)nitems);
1338 curbox->num_children_is_known = 1;
1339 curbox->num_children = nitems;
1340 curbox->extra_bytes_before_children = pos - curbox->payload_pos;
1343 static void do_box_iinf(deark *c, lctx *d, struct de_boxesctx *bctx)
1345 i64 nitems;
1346 u8 version;
1347 struct de_boxdata *curbox = bctx->curbox;
1348 i64 pos = curbox->payload_pos;
1350 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1351 pos += 4;
1353 if(version==0) {
1354 nitems = dbuf_getu16be_p(bctx->f, &pos);
1356 else {
1357 nitems = dbuf_getu32be_p(bctx->f, &pos);
1359 de_dbg(c, "number of items: %d", (int)nitems);
1361 curbox->num_children_is_known = 1;
1362 curbox->num_children = nitems;
1363 curbox->extra_bytes_before_children = pos - curbox->payload_pos;
1366 static void extract_exif_item(deark *c, lctx *d, dbuf *f)
1368 i64 dpos, dlen;
1369 u8 b0,b1;
1371 if(!d->exif_item_id_known) return;
1372 if(d->exif_item_offs<=0) return;
1373 if(d->exif_item_len<24) return;
1374 // I'm just guessing the format of this item. It seems to start with 10
1375 // bytes of header info.
1376 dpos = d->exif_item_offs+10;
1377 dlen = d->exif_item_len-10;
1378 b0 = dbuf_getbyte(f, dpos);
1379 b1 = dbuf_getbyte(f, dpos+1);
1380 if(!((b0=='M' && b1=='M') || (b0=='I' && b1=='I'))) {
1381 return;
1383 de_dbg(c, "Exif item segment at %"I64_FMT", size=%"I64_FMT, dpos, dlen);
1384 de_dbg_indent(c, 1);
1385 fmtutil_handle_exif(c, dpos, dlen);
1386 de_dbg_indent(c, -1);
1389 static void do_box_iloc(deark *c, lctx *d, struct de_boxesctx *bctx)
1391 u8 version;
1392 struct de_boxdata *curbox = bctx->curbox;
1393 i64 pos = curbox->payload_pos;
1394 unsigned int u;
1395 unsigned int offset_size, length_size, base_offset_size, index_size;
1396 i64 item_count;
1397 i64 k;
1398 int saved_indent_level;
1400 de_dbg_indent_save(c, &saved_indent_level);
1401 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1402 pos += 4;
1404 // TODO: Support more versions
1405 if(version!=1) goto done;
1407 u = (unsigned int)dbuf_getbyte_p(bctx->f, &pos);
1408 offset_size = u>>4;
1409 de_dbg(c, "offset size: %u", offset_size);
1410 if(offset_size!=0 && offset_size!=4 && offset_size!=8) goto done;
1411 length_size = u&0xf;
1412 de_dbg(c, "length size: %u", length_size);
1413 if(length_size!=0 && length_size!=4 && length_size!=8) goto done;
1415 u = (unsigned int)dbuf_getbyte_p(bctx->f, &pos);
1416 base_offset_size = u>>4;
1417 de_dbg(c, "base offset size: %u", base_offset_size);
1418 if(base_offset_size!=0 && base_offset_size!=4 && base_offset_size!=8) goto done;
1419 index_size = u&0xf;
1420 de_dbg(c, "index size: %u", index_size);
1421 if(index_size!=0 && index_size!=4 && index_size!=8) goto done;
1423 item_count = dbuf_getu16be_p(bctx->f, &pos);
1424 de_dbg(c, "item count: %d", (int)item_count);
1426 for(k=0; k<item_count; k++) {
1427 unsigned int item_id;
1428 i64 extent_count;
1429 i64 e;
1430 unsigned int cnstr_meth;
1432 if(pos >= curbox->payload_pos+curbox->payload_len) goto done;
1433 de_dbg(c, "item[%d] at %"I64_FMT, (int)k, pos);
1434 de_dbg_indent(c, 1);
1435 item_id = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1436 de_dbg(c, "item id: %u", item_id);
1438 u = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1439 cnstr_meth = u&0xf;
1440 de_dbg(c, "construction method: %u", cnstr_meth);
1442 pos += 2; // data reference index
1443 pos += base_offset_size;
1445 extent_count = dbuf_getu16be_p(bctx->f, &pos);
1446 de_dbg(c, "extent count: %d", (int)extent_count);
1448 for(e=0; e<extent_count; e++) {
1449 i64 xoffs = 0;
1450 i64 xlen = 0;
1452 if(pos >= curbox->payload_pos+curbox->payload_len) goto done;
1453 de_dbg(c, "extent[%d]", (int)e);
1454 de_dbg_indent(c, 1);
1455 pos += index_size;
1457 if(offset_size>0) {
1458 xoffs = dbuf_getint_ext(bctx->f, pos, offset_size, 0, 0);
1459 de_dbg(c, "offset: %"I64_FMT, xoffs);
1461 pos += offset_size;
1463 if(length_size>0) {
1464 xlen = dbuf_getint_ext(bctx->f, pos, length_size, 0, 0);
1465 de_dbg(c, "length: %"I64_FMT, xlen);
1467 pos += length_size;
1469 if(d->exif_item_id_known && item_id==d->exif_item_id && extent_count==1) {
1470 de_dbg(c, "[Exif item]");
1471 d->exif_item_offs = xoffs;
1472 d->exif_item_len = xlen;
1475 de_dbg_indent(c, -1);
1478 de_dbg_indent(c, -1);
1481 done:
1482 if(d->exif_item_id_known) {
1483 extract_exif_item(c, d, bctx->f);
1485 de_dbg_indent_restore(c, saved_indent_level);
1488 static void do_box_infe(deark *c, lctx *d, struct de_boxesctx *bctx)
1490 u8 version;
1491 struct de_boxdata *curbox = bctx->curbox;
1492 i64 pos = curbox->payload_pos;
1493 i64 n;
1494 unsigned int item_id;
1496 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1497 pos += 4;
1499 if(version==2 || version==3) {
1500 struct de_fourcc itemtype4cc;
1502 if(version==2) {
1503 item_id = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1505 else {
1506 item_id = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
1508 de_dbg(c, "item id: %u", item_id);
1510 n = dbuf_getu16be_p(bctx->f, &pos);
1511 de_dbg(c, "item protection: %u", (unsigned int)n);
1513 dbuf_read_fourcc(bctx->f, pos, &itemtype4cc, 4, 0x0);
1514 pos += 4;
1515 de_dbg(c, "item type: '%s'", itemtype4cc.id_dbgstr);
1517 if(itemtype4cc.id==CODE_Exif) {
1518 d->exif_item_id_known = 1;
1519 d->exif_item_id = item_id;
1522 // TODO: string item_name
1523 // TODO: sometimes there are additional strings after item_name
1527 static void do_box_ispe(deark *c, lctx *d, struct de_boxesctx *bctx)
1529 struct de_boxdata *curbox = bctx->curbox;
1530 i64 pos = curbox->payload_pos;
1531 i64 w, h;
1533 if(curbox->payload_len<12) return;
1534 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
1535 pos += 4;
1536 w = dbuf_getu32be_p(bctx->f, &pos);
1537 h = dbuf_getu32be_p(bctx->f, &pos);
1538 de_dbg_dimensions(c, w, h);
1541 static void do_box_xml(deark *c, lctx *d, struct de_boxesctx *bctx)
1543 struct de_boxdata *curbox = bctx->curbox;
1545 // TODO: Detect the specific XML format, and use it to choose a better
1546 // filename.
1547 de_dbg(c, "XML data at %d, len=%d", (int)curbox->payload_pos, (int)curbox->payload_len);
1548 dbuf_create_file_from_slice(bctx->f, curbox->payload_pos, curbox->payload_len,
1549 "xml", NULL, DE_CREATEFLAG_IS_AUX);
1552 static void do_box_THMB(deark *c, lctx *d, struct de_boxesctx *bctx)
1554 struct de_boxdata *curbox = bctx->curbox;
1555 i64 img_pos;
1556 i64 img_len;
1558 if(!curbox->parent) return;
1559 if(!curbox->parent->is_uuid) return;
1560 if(de_memcmp(curbox->parent->uuid, g_uuid_cr3_85c0, 16)) return;
1561 if(curbox->payload_len<20) return;
1562 img_pos= curbox->payload_pos+16;
1563 if(dbuf_memcmp(bctx->f, img_pos, "\xff\xd8\xff", 3)) return;
1564 img_len = dbuf_getu32be(bctx->f, curbox->payload_pos+8);
1565 de_dbg(c, "image at %"I64_FMT", len=%"I64_FMT, img_pos, img_len);
1566 if(img_pos+img_len > curbox->payload_pos+curbox->payload_len) return;
1567 dbuf_create_file_from_slice(bctx->f, img_pos, img_len, "thumb.jpg", NULL,
1568 DE_CREATEFLAG_IS_AUX);
1571 static void do_box_PRVW(deark *c, lctx *d, struct de_boxesctx *bctx)
1573 struct de_boxdata *curbox = bctx->curbox;
1574 i64 img_pos;
1575 i64 img_len;
1577 if(!curbox->parent) return;
1578 if(!curbox->parent->is_uuid) return;
1579 if(de_memcmp(curbox->parent->uuid, g_uuid_cr3_eaf4, 16)) return;
1580 if(curbox->payload_len<20) return;
1581 img_pos= curbox->payload_pos+16;
1582 if(dbuf_memcmp(bctx->f, img_pos, "\xff\xd8\xff", 3)) return;
1583 img_len = dbuf_getu32be(bctx->f, curbox->payload_pos+12);
1584 de_dbg(c, "image at %"I64_FMT", len=%"I64_FMT, img_pos, img_len);
1585 if(img_pos+img_len > curbox->payload_pos+curbox->payload_len) return;
1586 dbuf_create_file_from_slice(bctx->f, img_pos, img_len, "preview.jpg", NULL,
1587 DE_CREATEFLAG_IS_AUX);
1590 // The first line that matches will be used, so items related to more-specific
1591 // formats/brands should be listed first.
1592 static const struct box_type_info box_type_info_arr[] = {
1593 {BOX_ftyp, 0x00000000, 0x00000002, "file type", do_box_ftyp},
1594 {BOX_jP , 0x00010008, 0x00000002, "JPEG 2000 signature", do_box_jP},
1595 {BOX_mdat, 0x00000008, 0x00000001, "media data", NULL},
1596 {BOX_mdat, 0x00080001, 0x00000000, "media data", NULL},
1597 {BOX_alis, 0x00000001, 0x00000000, "Macintosh file alias", NULL},
1598 {BOX_cinf, 0x00000001, 0x00000001, "complete track information", NULL},
1599 {BOX_clip, 0x00000001, 0x00000001, NULL, NULL},
1600 {BOX_co64, 0x00000001, 0x00000000, "chunk offset", do_box_stco},
1601 {BOX_colr, 0x00080001, 0x00000000, "colour information", do_box_colr_bmff},
1602 {BOX_dinf, 0x00080001, 0x00000001, "data information", NULL},
1603 {BOX_dref, 0x00080001, 0x00000001, "data reference", do_box_dref},
1604 {BOX_edts, 0x00000001, 0x00000001, "edit", NULL},
1605 {BOX_elst, 0x00000001, 0x00000000, "edit list", NULL},
1606 {BOX_fdsa, 0x00000001, 0x00000001, NULL, NULL},
1607 {BOX_fiin, 0x00000001, 0x00000001, "FD item information", NULL},
1608 {BOX_free, 0x00090001, 0x00000000, "free space", NULL},
1609 {BOX_hdlr, 0x00080001, 0x00000000, "handler reference", do_box_hdlr},
1610 {BOX_hinf, 0x00000001, 0x00000001, NULL, NULL},
1611 {BOX_hmhd, 0x00000001, 0x00000000, "hint media header", NULL},
1612 {BOX_hnti, 0x00000001, 0x00000001, NULL, NULL},
1613 {BOX_iinf, 0x00080001, 0x00000001, "item info", do_box_iinf},
1614 {BOX_iloc, 0x00080001, 0x00000000, "item location", do_box_iloc},
1615 {BOX_ilst, 0x00000001, 0x00000001, "metadata item list", NULL},
1616 {BOX_infe, 0x00080001, 0x00000000, "item info entry", do_box_infe},
1617 {BOX_iods, 0x00000001, 0x00000000, "object descriptor", NULL},
1618 {BOX_iref, 0x00080001, 0x00000001, "item reference", do_box_full_superbox},
1619 {BOX_load, 0x00000001, 0x00000000, "track load settings", NULL},
1620 {BOX_matt, 0x00000001, 0x00000001, NULL, NULL},
1621 {BOX_mdhd, 0x00000001, 0x00000000, "media header", do_box_mdhd},
1622 {BOX_mdia, 0x00000001, 0x00000001, "media", NULL},
1623 {BOX_meco, 0x00000001, 0x00000001, "additional metadata container", NULL},
1624 {BOX_meta, 0x00080001, 0x00000001, "metadata", do_box_meta},
1625 {BOX_minf, 0x00000001, 0x00000001, "media information", NULL},
1626 {BOX_mfra, 0x00000001, 0x00000001, "movie fragment random access", NULL},
1627 {BOX_moof, 0x00000001, 0x00000001, "movie fragment", NULL},
1628 {BOX_moov, 0x00000001, 0x00000001, "movie (metadata container)", NULL},
1629 {BOX_mvex, 0x00000001, 0x00000001, "movie extends", NULL},
1630 {BOX_mvhd, 0x00000001, 0x00000000, "movie header", do_box_mvhd},
1631 {BOX_nmhd, 0x00000001, 0x00000000, "null media header", NULL},
1632 {BOX_paen, 0x00000001, 0x00000001, NULL, NULL},
1633 {BOX_pnot, 0x00000001, 0x00000000, "reference to movie preview", NULL},
1634 {BOX_rinf, 0x00000001, 0x00000001, "restricted scheme information", NULL},
1635 {BOX_rsrc, 0x00000001, 0x00000000, "Macintosh resource alias", NULL},
1636 {BOX_sbgp, 0x00000001, 0x00000000, "sample-to-group", NULL},
1637 {BOX_schi, 0x00000001, 0x00000001, "scheme information", NULL},
1638 {BOX_sdtp, 0x00000001, 0x00000000, "independent and disposable samples", NULL},
1639 {BOX_sgpd, 0x00000001, 0x00000000, "sample group description", NULL},
1640 {BOX_sinf, 0x00000001, 0x00000001, "protection scheme information", NULL},
1641 {BOX_skip, 0x00080001, 0x00000000, "user-data", NULL},
1642 {BOX_smhd, 0x00000001, 0x00000000, "sound media header", do_box_smhd},
1643 {BOX_stbl, 0x00000001, 0x00000001, "sample table", NULL},
1644 {BOX_stco, 0x00000001, 0x00000000, "chunk offset", do_box_stco},
1645 {BOX_strd, 0x00000001, 0x00000001, "sub track definition", NULL},
1646 {BOX_strk, 0x00000001, 0x00000001, "sub track", NULL},
1647 {BOX_stsc, 0x00000001, 0x00000000, "sample to chunk", do_box_stsc},
1648 {BOX_stsd, 0x00000001, 0x00000000, "sample description", do_box_stsd},
1649 {BOX_stss, 0x00000001, 0x00000000, "sync sample", do_box_stss},
1650 {BOX_stsz, 0x00000001, 0x00000000, "sample sizes", do_box_stsz},
1651 {BOX_stts, 0x00000001, 0x00000000, "decoding time to sample", do_box_stts},
1652 {BOX_ctts, 0x00000001, 0x00000000, "composition time to sample", do_box_ctts},
1653 {BOX_stz2, 0x00000001, 0x00000000, "compact sample size", NULL},
1654 {BOX_tkhd, 0x00000001, 0x00000000, "track header", do_box_tkhd},
1655 {BOX_traf, 0x00000001, 0x00000001, "track fragment", NULL},
1656 {BOX_trak, 0x00000001, 0x00000001, "track", NULL},
1657 {BOX_tref, 0x00000001, 0x00000001, "track reference", NULL},
1658 {BOX_udta, 0x00000001, 0x00000001, "user data", NULL},
1659 {BOX_url , 0x00090001, 0x00000000, "URL", do_box_url},
1660 {BOX_vmhd, 0x00000001, 0x00000000, "video media header", do_box_vmhd},
1661 {BOX_wide, 0x00000001, 0x00000000, "reserved space", NULL},
1662 {BOX_PICT, 0x00000001, 0x00000000, "QuickDraw picture", do_box_PICT},
1663 {BOX_PRVW, 0x00000001, 0x00000000, "preview", do_box_PRVW},
1664 {BOX_THMB, 0x00000001, 0x00000000, "thumbnail", do_box_THMB},
1665 {BOX_asoc, 0x00010000, 0x00000001, "association", NULL},
1666 {BOX_cgrp, 0x00010000, 0x00000001, "colour group", NULL},
1667 {BOX_cdef, 0x00010000, 0x00000000, "channel definition", do_box_cdef},
1668 {BOX_colr, 0x00010000, 0x00000000, "colour specification", do_box_colr_jp2},
1669 {BOX_comp, 0x00010000, 0x00000001, NULL, NULL},
1670 {BOX_drep, 0x00010000, 0x00000001, NULL, NULL},
1671 {BOX_dtbl, 0x00010000, 0x00000001, "data reference", do_box_dtbl},
1672 {BOX_flst, 0x00010000, 0x00000000, "fragment list", NULL},
1673 {BOX_ftbl, 0x00010000, 0x00000001, "fragment table", NULL},
1674 {BOX_ihdr, 0x00010000, 0x00000000, "image header", do_box_ihdr},
1675 {BOX_jp2c, 0x00010008, 0x00000000, "contiguous codestream", do_box_jp2c},
1676 {BOX_jp2h, 0x00010000, 0x00000001, "JP2 header", NULL},
1677 {BOX_jpch, 0x00010000, 0x00000001, "codestream header", NULL},
1678 {BOX_jplh, 0x00010000, 0x00000001, "compositing layer header", NULL},
1679 {BOX_lhdr, 0x00010000, 0x00000000, "layout object header", NULL},
1680 {BOX_lbl , 0x00010000, 0x00000000, "label", do_box_justtext},
1681 {BOX_lobj, 0x00010000, 0x00000001, "layout object", NULL},
1682 {BOX_mhdr, 0x00010000, 0x00000000, "compound image header", NULL},
1683 {BOX_nlst, 0x00010000, 0x00000000, "number list", NULL},
1684 {BOX_objc, 0x00010000, 0x00000001, "object", NULL},
1685 {BOX_ohdr, 0x00010000, 0x00000000, "object header", NULL},
1686 {BOX_page, 0x00010000, 0x00000001, "page", NULL},
1687 {BOX_pagt, 0x00010000, 0x00000000, "page table", NULL},
1688 {BOX_pcol, 0x00010000, 0x00000001, "page collection", NULL},
1689 {BOX_phdr, 0x00010000, 0x00000000, "page header", NULL},
1690 {BOX_res , 0x00010000, 0x00000001, "resolution", NULL},
1691 {BOX_resc, 0x00010000, 0x00000000, "capture resolution", do_box_resc_resd},
1692 {BOX_resd, 0x00010000, 0x00000000, "default display resolution", do_box_resc_resd},
1693 {BOX_rreq, 0x00010000, 0x00000000, "reader requirements", do_box_rreq},
1694 {BOX_scal, 0x00010000, 0x00000000, "object scale", NULL},
1695 {BOX_sdat, 0x00010000, 0x00000001, NULL, NULL},
1696 {BOX_uinf, 0x00010000, 0x00000001, "UUID info", NULL},
1697 {BOX_ulst, 0x00010000, 0x00000000, "UUID list", do_box_ulst},
1698 {BOX_xml , 0x00010008, 0x00000000, "XML", do_box_xml},
1699 {BOX_LCHK, 0x00040000, 0x00000000, "checksum", NULL},
1700 {BOX_RESI, 0x00040000, 0x00000000, "residual codestream", NULL},
1701 {BOX_SPEC, 0x00040000, 0x00000001, NULL, NULL},
1702 {BOX_auxC, 0x00080000, 0x00000000, "auxiliary type property", NULL},
1703 {BOX_grpl, 0x00080000, 0x00000000, "groups list", NULL},
1704 {BOX_idat, 0x00080000, 0x00000000, "item data", NULL},
1705 {BOX_ipco, 0x00080000, 0x00000001, "item property container", NULL},
1706 {BOX_ipma, 0x00080000, 0x00000000, "item property association", NULL},
1707 {BOX_ipro, 0x00080000, 0x00000000, "item protection", NULL},
1708 {BOX_iprp, 0x00080000, 0x00000001, "item properties", NULL},
1709 {BOX_ispe, 0x00080000, 0x00000000, "image spatial extents", do_box_ispe},
1710 {BOX_hvcC, 0x00080000, 0x00000000, "HEVC configuration", NULL},
1711 {BOX_pitm, 0x00080000, 0x00000000, "primary item", NULL}
1714 // TODO: These ilst (iTunes metadata?) boxes should probably go in the above
1715 // list, but the logic for finding the right box will be complicated.
1716 // Superboxes are not flagged in this list, because that determination
1717 // is based on their location, not their type.
1718 static const struct box_type_info ilst_box_type_info_arr[] = {
1719 {BOX_data, 0x01000000, 0x00000000, "value atom", do_box_data},
1720 {BOX_name, 0x01000000, 0x00000000, "name atom", NULL},
1721 {BOX_blank, 0x01000000, 0x00000000, "custom metadata item", NULL},
1722 {BOX_cpil, 0x01000000, 0x00000000, "compilation", NULL},
1723 {BOX_gnre, 0x01000000, 0x00000000, "genre (enumerated)", NULL},
1724 {BOX_tmpo, 0x01000000, 0x00000000, "tempo", NULL},
1725 {BOX_a9ART, 0x01000000, 0x00000000, "artist", NULL},
1726 {BOX_a9cmt, 0x01000000, 0x00000000, "comment", NULL},
1727 {BOX_a9nam, 0x01000000, 0x00000000, "name / title", NULL},
1728 {BOX_a9too, 0x01000000, 0x00000000, "encoder software", NULL}
1731 static const struct box_type_info *find_box_type_info(deark *c, lctx *d,
1732 u32 boxtype, int level)
1734 size_t k;
1735 u32 mask = 0;
1737 if(d->is_bmff) mask |= 0x00000001;
1738 if(d->is_mj2) mask |= 0x000000008;
1739 if(d->is_jp2_jpx_jpm) mask |= 0x00010000;
1740 if(d->is_jpegxt) mask |= 0x00040000;
1741 if(d->is_heif) mask |= 0x00080000;
1743 for(k=0; k<DE_ARRAYCOUNT(box_type_info_arr); k++) {
1744 if(box_type_info_arr[k].boxtype != boxtype) continue;
1745 if(level==0 && (box_type_info_arr[k].flags2 & 0x2)) {
1746 // Critical box. Always match.
1747 return &box_type_info_arr[k];
1749 if((box_type_info_arr[k].flags1 & mask)==0) continue;
1750 return &box_type_info_arr[k];
1752 return NULL;
1755 static const struct box_type_info *find_ilst_box_type_info(deark *c, lctx *d,
1756 u32 boxtype)
1758 size_t k;
1760 for(k=0; k<DE_ARRAYCOUNT(ilst_box_type_info_arr); k++) {
1761 if(ilst_box_type_info_arr[k].boxtype != boxtype) continue;
1762 return &ilst_box_type_info_arr[k];
1764 return NULL;
1767 static void my_box_identify_fn(deark *c, struct de_boxesctx *bctx)
1769 const struct box_type_info *bti;
1770 lctx *d = (lctx*)bctx->userdata;
1771 struct de_boxdata *curbox = bctx->curbox;
1772 struct de_boxdata *par = curbox->parent;
1773 struct de_boxdata *gpar = NULL;
1774 int is_ilst_child = 0;
1776 if(curbox->boxtype != BOX_uuid) {
1777 curbox->box_name = "?";
1780 if(par) {
1781 gpar = par->parent;
1784 if((par && (par->boxtype==BOX_ilst)) ||
1785 (gpar && (gpar->boxtype==BOX_ilst)) )
1787 is_ilst_child = 1;
1790 if(is_ilst_child) {
1791 bti = find_ilst_box_type_info(c, d, curbox->boxtype);
1793 else {
1794 bti = find_box_type_info(c, d, curbox->boxtype, curbox->level);
1797 if(bti) {
1798 // So that we don't have to run "find" again in my_box_handler(),
1799 // record it here.
1800 curbox->box_userdata = (void*)bti;
1802 if(bti->name) {
1803 curbox->box_name = bti->name;
1806 // TODO: Do we need special handling of 'data' boxes?
1809 static int my_box_handler(deark *c, struct de_boxesctx *bctx)
1811 const struct box_type_info *bti;
1812 lctx *d = (lctx*)bctx->userdata;
1813 struct de_boxdata *curbox = bctx->curbox;
1815 if(curbox->is_uuid) {
1816 if(!de_memcmp(curbox->uuid, g_uuid_cr3_85c0, 16)) {
1817 curbox->is_superbox = 1;
1819 else if(!de_memcmp(curbox->uuid, g_uuid_cr3_eaf4, 16)) {
1820 curbox->is_superbox = 1;
1821 curbox->extra_bytes_before_children = 8;
1823 else {
1824 return fmtutil_default_box_handler(c, bctx);
1826 return 1;
1829 bti = (const struct box_type_info *)curbox->box_userdata;
1831 if(bti && (bti->flags2 & 0x1)) {
1832 curbox->is_superbox = 1;
1834 else if(d->is_bmff && curbox->parent && (curbox->parent->boxtype==BOX_ilst)) {
1835 curbox->is_superbox = 1;
1838 if(bti && bti->hfn) {
1839 bti->hfn(c, d, bctx);
1842 return 1;
1845 static void de_run_bmff(deark *c, de_module_params *mparams)
1847 lctx *d = NULL;
1848 struct de_boxesctx *bctx = NULL;
1849 int skip_autodetect = 0;
1850 const char *s;
1852 d = de_malloc(c, sizeof(lctx));
1853 bctx = de_malloc(c, sizeof(struct de_boxesctx));
1855 if(de_havemodcode(c, mparams, 'T')) {
1856 d->is_jpegxt = 1;
1857 skip_autodetect = 1;
1859 if(de_havemodcode(c, mparams, 'X')) {
1860 d->is_jpx = 1;
1861 d->is_jp2_jpx_jpm = 1;
1862 skip_autodetect = 1;
1864 if(de_havemodcode(c, mparams, 'B')) {
1865 d->is_bmff = 1;
1866 skip_autodetect = 1;
1869 if(!skip_autodetect) {
1870 u32 first_boxtype;
1871 // Try to detect old QuickTime files that don't have an ftyp box.
1872 first_boxtype = (u32)de_getu32be(4);
1873 if(first_boxtype==BOX_mdat || first_boxtype==BOX_moov ||
1874 first_boxtype==BOX_free || first_boxtype==BOX_wide ||
1875 first_boxtype==BOX_skip || first_boxtype==BOX_pnot)
1877 d->is_bmff = 1;
1881 s = de_get_ext_option(c, "bmff:maxentries");
1882 if(s) {
1883 d->max_entries_to_print = de_atoi64(s);
1885 else {
1886 d->max_entries_to_print = 32;
1888 if(d->max_entries_to_print<0) {
1889 d->max_entries_to_print = 0;
1892 bctx->userdata = (void*)d;
1893 bctx->f = c->infile;
1894 bctx->identify_box_fn = my_box_identify_fn;
1895 bctx->handle_box_fn = my_box_handler;
1897 fmtutil_read_boxes_format(c, bctx);
1899 de_free(c, bctx);
1900 de_free(c, d);
1903 static int de_identify_jpeg2000(deark *c)
1905 if(!dbuf_memcmp(c->infile, 0, "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a", 12))
1906 return 100;
1907 return 0;
1910 static void de_help_bmff(deark *c)
1912 de_msg(c, "-opt bmff:maxentries=<n> : Number of sample table entries to print with -d");
1915 void de_module_jpeg2000(deark *c, struct deark_module_info *mi)
1917 mi->id = "jpeg2000";
1918 mi->desc = "JPEG 2000 image";
1919 mi->desc2 = "resources only";
1920 mi->run_fn = de_run_bmff;
1921 mi->identify_fn = de_identify_jpeg2000;
1924 static int de_identify_bmff(deark *c)
1926 u32 first_boxtype;
1928 first_boxtype = (u32)de_getu32be(4);
1929 if(first_boxtype==BOX_ftyp) return 80;
1930 if(first_boxtype==BOX_mdat) return 35;
1931 if(first_boxtype==BOX_moov) return 35;
1932 if(first_boxtype==BOX_skip) return 10;
1933 if(first_boxtype==BOX_wide) return 10;
1934 if(first_boxtype==BOX_pnot) return 10;
1935 if(first_boxtype==BOX_free) return 9;
1936 return 0;
1939 void de_module_bmff(deark *c, struct deark_module_info *mi)
1941 mi->id = "bmff";
1942 mi->desc = "ISO Base Media File Format";
1943 mi->desc2 = "MP4, QuickTime, etc.";
1944 mi->id_alias[0] = "mp4";
1945 mi->run_fn = de_run_bmff;
1946 mi->identify_fn = de_identify_bmff;
1947 mi->help_fn = de_help_bmff;