jpeg2000: Added some box names
[deark.git] / modules / bmff.c
blobee1db7ecea0ebc606b9d54d4dd4bdab0864c1328
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>
11 // TODO: Rethink how to subdivide these formats into modules.
12 DE_DECLARE_MODULE(de_module_bmff);
13 DE_DECLARE_MODULE(de_module_jpeg2000);
15 typedef struct localctx_struct {
16 u32 major_brand;
17 u8 is_bmff;
18 u8 is_jp2_jpx_jpm, is_jpx, is_jpm;
19 u8 is_mj2;
20 u8 is_heif;
21 u8 is_jpegxt;
22 i64 max_entries_to_print;
24 u8 exif_item_id_known;
25 unsigned int exif_item_id;
26 i64 exif_item_offs;
27 i64 exif_item_len;
28 } lctx;
30 typedef void (*handler_fn_type)(deark *c, lctx *d, struct de_boxesctx *bctx);
32 struct box_type_info {
33 u32 boxtype;
34 // flags1 is intended to be used to indicate which formats/brands use this box.
35 // 0x00000001 = Generic BMFF (isom brand, etc.)
36 // 0x00000008 = MJ2
37 // 0x00010000 = JP2/JPX/JPM
38 // 0x00040000 = JPEG XT
39 // 0x00080000 = HEIF
40 // 0x01000000 = Used in ilst boxes
41 u32 flags1;
42 // flags2: 0x1 = is_superbox
43 // flags2: 0x2 = critical top-level box (used for format identification)
44 u32 flags2;
45 const char *name;
46 handler_fn_type hfn;
49 #define BRAND_heic 0x68656963U
50 #define BRAND_isom 0x69736f6dU
51 #define BRAND_mif1 0x6d696631U
52 #define BRAND_mp41 0x6d703431U
53 #define BRAND_mp42 0x6d703432U
54 #define BRAND_M4A 0x4d344120U
55 #define BRAND_jp2 0x6a703220U
56 #define BRAND_jpm 0x6a706d20U
57 #define BRAND_jpx 0x6a707820U
58 #define BRAND_mjp2 0x6d6a7032U
59 #define BRAND_mj2s 0x6d6a3273U
60 #define BRAND_qt 0x71742020U
62 #define BOX_alis 0x616c6973U
63 #define BOX_auxC 0x61757843U
64 #define BOX_co64 0x636f3634U
65 #define BOX_ctts 0x63747473U
66 #define BOX_data 0x64617461U
67 #define BOX_elst 0x656c7374U
68 #define BOX_ftyp 0x66747970U
69 #define BOX_grpl 0x6772706cU
70 #define BOX_hvcC 0x68766343U
71 #define BOX_idat 0x69646174U
72 #define BOX_iinf 0x69696e66U
73 #define BOX_iloc 0x696c6f63U
74 #define BOX_ilst 0x696c7374U
75 #define BOX_infe 0x696e6665U
76 #define BOX_iods 0x696f6473U
77 #define BOX_ipco 0x6970636fU
78 #define BOX_ipma 0x69706d61U
79 #define BOX_ipro 0x6970726fU
80 #define BOX_iprp 0x69707270U
81 #define BOX_iref 0x69726566U
82 #define BOX_ispe 0x69737065U
83 #define BOX_jP 0x6a502020U
84 #define BOX_jp2c 0x6a703263U
85 #define BOX_load 0x6c6f6164U
86 #define BOX_mdat 0x6d646174U
87 #define BOX_mdhd 0x6d646864U
88 #define BOX_mvhd 0x6d766864U
89 #define BOX_name 0x6e616d65U
90 #define BOX_pitm 0x7069746dU
91 #define BOX_pnot 0x706e6f74U
92 #define BOX_rsrc 0x72737263U
93 #define BOX_sbgp 0x73626770U
94 #define BOX_sdtp 0x73647470U
95 #define BOX_sgpd 0x73677064U
96 #define BOX_stsd 0x73747364U
97 #define BOX_tkhd 0x746b6864U
98 #define BOX_uuid 0x75756964U
99 #define BOX_wide 0x77696465U
100 #define BOX_xml 0x786d6c20U
101 #define BOX_PICT 0x50494354U
102 #define BOX_THMB 0x54484d42U
103 #define BOX_PRVW 0x50525657U
105 #define BOX_blank 0x2d2d2d2dU // "----"
106 #define BOX_cpil 0x6370696cU
107 #define BOX_gnre 0x676e7265U
108 #define BOX_tmpo 0x746d706fU
109 #define BOX_a9ART 0xa9415254U
110 #define BOX_a9cmt 0xa9636d74U
111 #define BOX_a9nam 0xa96e616dU
112 #define BOX_a9too 0xa9746f6fU
114 // JP2:
115 #define BOX_cdef 0x63646566U
116 #define BOX_colr 0x636f6c72U
117 #define BOX_jp2h 0x6a703268U
118 #define BOX_ihdr 0x69686472U
119 #define BOX_res 0x72657320U
120 #define BOX_resc 0x72657363U
121 #define BOX_resd 0x72657364U
122 #define BOX_uinf 0x75696e66U
123 #define BOX_ulst 0x756c7374U
124 #define BOX_url 0x75726c20U
125 // JPX:
126 #define BOX_jpch 0x6a706368U
127 #define BOX_jplh 0x6a706c68U
128 #define BOX_cgrp 0x63677270U
129 #define BOX_ftbl 0x6674626cU
130 #define BOX_comp 0x636f6d70U
131 #define BOX_asoc 0x61736f63U
132 #define BOX_drep 0x64726570U
133 #define BOX_dtbl 0x6474626cU
134 #define BOX_flst 0x666c7374U
135 #define BOX_lbl 0x6c626c20U
136 #define BOX_nlst 0x6e6c7374U
137 #define BOX_rreq 0x72726571U
138 // JPM:
139 #define BOX_page 0x70616765U
140 #define BOX_lobj 0x6c6f626aU
141 #define BOX_objc 0x6f626a63U
142 #define BOX_sdat 0x73646174U
143 #define BOX_mhdr 0x6d686472U
144 #define BOX_lhdr 0x6c686472U
145 #define BOX_ohdr 0x6f686472U
146 #define BOX_pagt 0x70616774U
147 #define BOX_pcol 0x70636f6cU
148 #define BOX_phdr 0x70686472U
149 #define BOX_scal 0x7363616cU
150 // BMFF, QuickTime, MP4, ...:
151 #define BOX_cinf 0x63696e66U
152 #define BOX_clip 0x636c6970U
153 #define BOX_dinf 0x64696e66U
154 #define BOX_dref 0x64726566U
155 #define BOX_edts 0x65647473U
156 //#define BOX_extr 0x65787472U // Irregular format?
157 #define BOX_fdsa 0x66647361U
158 #define BOX_fiin 0x6669696eU
159 #define BOX_free 0x66726565U
160 #define BOX_hdlr 0x68646c72U
161 #define BOX_hinf 0x68696e66U
162 #define BOX_hmhd 0x686d6864U
163 #define BOX_hnti 0x686e7469U
164 #define BOX_matt 0x6d617474U
165 #define BOX_mdia 0x6d646961U
166 #define BOX_meco 0x6d65636fU
167 #define BOX_meta 0x6d657461U
168 #define BOX_minf 0x6d696e66U
169 #define BOX_mfra 0x6d667261U
170 #define BOX_moof 0x6d6f6f66U
171 #define BOX_moov 0x6d6f6f76U
172 #define BOX_mvex 0x6d766578U
173 #define BOX_nmhd 0x6e6d6864U
174 #define BOX_paen 0x7061656eU
175 #define BOX_rinf 0x72696e66U
176 #define BOX_schi 0x73636869U
177 #define BOX_sinf 0x73696e66U
178 #define BOX_skip 0x736b6970U
179 #define BOX_smhd 0x736d6864U
180 #define BOX_stbl 0x7374626cU
181 #define BOX_stco 0x7374636fU
182 #define BOX_strd 0x73747264U
183 #define BOX_strk 0x7374726bU
184 #define BOX_stsc 0x73747363U
185 #define BOX_stss 0x73747373U
186 #define BOX_stsz 0x7374737aU
187 #define BOX_stts 0x73747473U
188 #define BOX_stz2 0x73747a32U
189 #define BOX_traf 0x74726166U
190 #define BOX_trak 0x7472616bU
191 #define BOX_tref 0x74726566U
192 #define BOX_udta 0x75647461U
193 #define BOX_vmhd 0x766d6864U
194 // JPEG XT
195 #define BOX_LCHK 0x4c43484bU
196 #define BOX_RESI 0x52455349U
197 #define BOX_SPEC 0x53504543U
199 #define CODE_Exif 0x45786966U
200 #define CODE_rICC 0x72494343U
201 #define CODE_prof 0x70726f66U
203 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";
204 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";
206 // Called for each primary or compatible brand.
207 // Brand-specific setup can be done here.
208 static void apply_brand(deark *c, lctx *d, u32 brand_id)
210 switch(brand_id) {
211 case BRAND_jp2:
212 d->is_jp2_jpx_jpm = 1;
213 break;
214 case BRAND_jpx:
215 d->is_jpx = 1;
216 d->is_jp2_jpx_jpm = 1;
217 break;
218 case BRAND_jpm:
219 d->is_jpm = 1;
220 d->is_jp2_jpx_jpm = 1;
221 break;
222 case BRAND_mjp2:
223 case BRAND_mj2s:
224 d->is_bmff = 1;
225 d->is_mj2 = 1;
226 break;
227 case BRAND_isom:
228 case BRAND_mp41:
229 case BRAND_mp42:
230 case BRAND_M4A:
231 case BRAND_qt:
232 d->is_bmff = 1;
233 break;
234 case BRAND_mif1:
235 case BRAND_heic:
236 d->is_heif = 1;
237 break;
238 default:
239 if((brand_id>>16) == 0x3367) { // "3g??"
240 d->is_bmff = 1;
245 // JPEG 2000 signature box (presumably)
246 static void do_box_jP(deark *c, lctx *d, struct de_boxesctx *bctx)
248 u32 n;
249 struct de_boxdata *curbox = bctx->curbox;
251 if(curbox->level!=0) return;
252 if(curbox->payload_len<4) return;
253 n = (u32)dbuf_getu32be(bctx->f, curbox->payload_pos);
254 if(n==0x0d0a870a) {
255 de_dbg(c, "found JPEG 2000 signature");
259 static void do_box_ftyp(deark *c, lctx *d, struct de_boxesctx *bctx)
261 i64 i;
262 i64 mver;
263 i64 num_compat_brands;
264 struct de_fourcc brand4cc;
265 struct de_boxdata *curbox = bctx->curbox;
267 if(curbox->payload_len<4) goto done;
268 dbuf_read_fourcc(bctx->f, curbox->payload_pos, &brand4cc, 4, 0x0);
269 d->major_brand = brand4cc.id;
270 de_dbg(c, "major brand: '%s'", brand4cc.id_dbgstr);
271 if(curbox->level==0)
272 apply_brand(c, d, d->major_brand);
274 if(curbox->payload_len<8) goto done;
275 mver = dbuf_getu32be(bctx->f, curbox->payload_pos+4);
276 de_dbg(c, "minor version: %u", (unsigned int)mver);
278 if(curbox->payload_len<12) goto done;
279 num_compat_brands = (curbox->payload_len - 8)/4;
281 for(i=0; i<num_compat_brands; i++) {
282 dbuf_read_fourcc(bctx->f, curbox->payload_pos + 8 + i*4, &brand4cc, 4, 0x0);
283 if(brand4cc.id==0) continue; // Placeholder. Ignore.
284 de_dbg(c, "compatible brand: '%s'", brand4cc.id_dbgstr);
285 if(curbox->level==0)
286 apply_brand(c, d, brand4cc.id);
289 done:
293 static void do_read_version_and_flags(deark *c, lctx *d, struct de_boxesctx *bctx,
294 u8 *version, u32 *flags, int dbgflag)
296 u8 version1;
297 u32 flags1;
298 u32 n;
299 struct de_boxdata *curbox = bctx->curbox;
301 n = (u32)dbuf_getu32be(bctx->f, curbox->payload_pos);
302 version1 = (u8)(n>>24);
303 flags1 = n&0x00ffffff;
304 if(dbgflag) {
305 de_dbg(c, "version=%d, flags=0x%06x", (int)version1, (unsigned int)flags1);
307 if(version) *version = version1;
308 if(flags) *flags = flags1;
311 // For any box whose entire contents are a UTF-8 text string.
312 static void do_box_justtext(deark *c, lctx *d, struct de_boxesctx *bctx)
314 struct de_boxdata *curbox = bctx->curbox;
315 de_ucstring *s = NULL;
316 const char *name;
318 name = curbox->box_name ? curbox->box_name : "value";
319 s = ucstring_create(c);
320 dbuf_read_to_ucstring_n(bctx->f, curbox->payload_pos, curbox->payload_len,
321 DE_DBG_MAX_STRLEN, s, 0, DE_ENCODING_UTF8);
322 de_dbg(c, "%s: \"%s\"", name, ucstring_getpsz_d(s));
323 ucstring_destroy(s);
326 static const char *get_ilst_type_name(unsigned int ns, unsigned int wkt)
328 const char *name = NULL;
330 if(ns!=0) goto done;
332 switch(wkt) {
333 case 0: name="binary"; break;
334 case 1: name="UTF-8"; break;
335 case 2: name="UTF-16"; break;
336 case 3: name="S/JIS"; break;
337 case 4: name="UTF-8 sort key"; break;
338 case 5: name="UTF-16 sort key"; break;
339 case 13: name="JPEG"; break;
340 case 14: name="PNG"; break;
341 case 21: name="signed int"; break;
342 case 22: name="unsigned int"; break;
343 case 23: name="float32"; break;
344 case 24: name="float64"; break;
345 case 27: name="BMP"; break;
346 case 28: name="metadata atom"; break;
348 done:
349 if(!name) name="?";
350 return name;
353 static void do_box_data(deark *c, lctx *d, struct de_boxesctx *bctx)
355 unsigned int type_field, type_namespace, wkt;
356 unsigned int cntry, lang;
357 i64 vlen;
358 struct de_boxdata *curbox = bctx->curbox;
359 struct de_boxdata *par;
360 struct de_boxdata *gpar;
361 i64 pos = curbox->payload_pos;
362 de_ucstring *s = NULL;
364 par = curbox->parent;
365 if(!par) goto done;
366 gpar = par->parent;
367 if(!gpar) goto done;
368 if(gpar->boxtype != BOX_ilst) goto done;
370 if(curbox->payload_len<8) goto done;
371 type_field = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
372 type_namespace = type_field>>24;
373 wkt = (type_field & 0x00ffffff); // well-known type (if namespace==0)
374 de_dbg(c, "type: %u, %u (%s)", type_namespace, wkt,
375 get_ilst_type_name(type_namespace, wkt));
377 cntry = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
378 lang = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
379 de_dbg(c, "locale: %u, %u", cntry, lang);
381 if(type_namespace!=0) goto done;
382 vlen = curbox->payload_pos + curbox->payload_len - pos;
384 if(wkt==1 || wkt==4) { // UTF-8
385 s = ucstring_create(c);
386 dbuf_read_to_ucstring_n(bctx->f, pos, vlen,
387 DE_DBG_MAX_STRLEN, s, 0, DE_ENCODING_UTF8);
388 de_dbg(c, "value: \"%s\"", ucstring_getpsz_d(s));
390 else if(wkt==21 && vlen==1) { // 1-byte signed int
391 int n;
392 n = (int)(signed char)dbuf_getbyte(bctx->f, pos);
393 de_dbg(c, "value: %d", n);
395 else if(wkt==21 && vlen==2) { // 2-byte BE signed int
396 int n;
397 n = (int)dbuf_geti16be(bctx->f, pos);
398 de_dbg(c, "value: %d", n);
400 else if(wkt==0) {
401 de_dbg_hexdump(c, bctx->f, pos, vlen, 256, "value", 0x1);
403 // TODO: There are lots more types
405 done:
406 ucstring_destroy(s);
409 static void do_box_hdlr(deark *c, lctx *d, struct de_boxesctx *bctx)
411 de_ucstring *s = NULL;
412 struct de_boxdata *curbox = bctx->curbox;
413 i64 pos = curbox->payload_pos;
414 struct de_fourcc tmp4cc;
416 if(curbox->payload_len<4) goto done;
417 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
418 pos += 4;
419 if(curbox->payload_len<24) goto done;
420 pos += 4; // "Predefined"
422 dbuf_read_fourcc(bctx->f, pos, &tmp4cc, 4, 0x0);
423 de_dbg(c, "handler type: '%s'", tmp4cc.id_dbgstr);
424 pos += 4;
426 pos += 12; // reserved
427 if(curbox->payload_len<25) goto done;
428 if(dbuf_getbyte(bctx->f, pos) == 0x00) goto done;
430 s = ucstring_create(c);
431 dbuf_read_to_ucstring_n(bctx->f, pos, curbox->payload_pos + curbox->payload_len - pos,
432 DE_DBG_MAX_STRLEN, s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_UTF8);
433 de_dbg(c, "metadata type name: \"%s\"", ucstring_getpsz_d(s));
435 done:
436 ucstring_destroy(s);
439 static void do_box_tkhd(deark *c, lctx *d, struct de_boxesctx *bctx)
441 u8 version;
442 u32 flags;
443 i64 pos;
444 double w, h;
445 i64 n;
446 struct de_boxdata *curbox = bctx->curbox;
448 if(curbox->payload_len<4) return;
450 pos = curbox->payload_pos;
451 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
452 pos+=4;
454 if(version==1) {
455 if(curbox->payload_len<96) return;
457 else {
458 if(curbox->payload_len<84) return;
461 // creation time, mod time
462 if(version==1)
463 pos += 8 + 8;
464 else
465 pos += 4 + 4;
467 n = dbuf_getu32be_p(bctx->f, &pos);
468 de_dbg(c, "track id: %d", (int)n);
470 pos += 4; // reserved
472 // duration
473 if(version==1)
474 pos += 8;
475 else
476 pos += 4;
478 pos += 4*2; // reserved
479 pos += 2; // layer
480 pos += 2; // alternate group
482 n = dbuf_getu16be_p(bctx->f, &pos);
483 de_dbg(c, "volume: %.3f", ((double)n)/256.0);
485 pos += 2; // reserved
486 pos += 4*9; // matrix
488 w = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
489 pos += 4;
490 h = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
491 pos += 4;
492 de_dbg(c, "dimensions: %.1f"DE_CHAR_TIMES"%.1f", w, h);
495 static void do_box_vmhd(deark *c, lctx *d, struct de_boxesctx *bctx)
497 u8 version;
498 u32 flags;
499 size_t k;
500 unsigned int clr[3];
501 unsigned int graphicsmode;
502 struct de_boxdata *curbox = bctx->curbox;
503 i64 pos = curbox->payload_pos;
505 if(curbox->payload_len<12) return;
506 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
507 pos += 4;
508 if(version!=0 || flags!=0x1) return;
510 graphicsmode = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
511 de_dbg(c, "graphicsmode: %u", graphicsmode);
513 for(k=0; k<3; k++) {
514 clr[k] = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
516 de_dbg(c, "opcolor: (%d,%d,%d)", (int)clr[0], (int)clr[1], (int)clr[2]);
519 static void do_box_PICT(deark *c, lctx *d, struct de_boxesctx *bctx)
521 struct de_boxdata *curbox = bctx->curbox;
522 dbuf *outf = NULL;
524 outf = dbuf_create_output_file(c, "pict", NULL, DE_CREATEFLAG_IS_AUX);
525 dbuf_write_zeroes(outf, 512);
526 dbuf_copy(bctx->f, curbox->payload_pos, curbox->payload_len, outf);
527 dbuf_close(outf);
530 static void do_box_smhd(deark *c, lctx *d, struct de_boxesctx *bctx)
532 u8 version;
533 u32 flags;
534 unsigned int n;
535 struct de_boxdata *curbox = bctx->curbox;
536 i64 pos = curbox->payload_pos;
538 if(curbox->payload_len<8) return;
539 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
540 pos += 4;
541 if(version!=0 || flags!=0x0) return;
543 n = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
544 de_dbg(c, "balance: %u", n);
547 static void do_box_mvhd(deark *c, lctx *d, struct de_boxesctx *bctx)
549 u8 version;
550 u32 flags;
551 i64 pos;
552 i64 n;
553 i64 timescale;
554 double nd;
555 struct de_boxdata *curbox = bctx->curbox;
557 if(curbox->payload_len<4) return;
559 pos = curbox->payload_pos;
560 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
561 pos+=4;
563 if(version==1) {
564 if(curbox->payload_len<112) return;
566 else {
567 if(curbox->payload_len<100) return;
570 // creation time, mod time
571 if(version==1)
572 pos += 8 + 8;
573 else
574 pos += 4 + 4;
576 timescale = dbuf_getu32be_p(bctx->f, &pos);
577 de_dbg(c, "timescale: %d time units per second", (int)timescale);
579 // duration
580 if(version==1) {
581 n = dbuf_geti64be(bctx->f, pos);
582 pos += 8;
584 else {
585 n = dbuf_getu32be_p(bctx->f, &pos);
587 if(timescale>0)
588 nd = (double)n / (double)timescale;
589 else
590 nd = 0.0;
591 de_dbg(c, "duration: %d time units (%.2f seconds)", (int)n, nd);
593 nd = dbuf_fmtutil_read_fixed_16_16(bctx->f, pos);
594 pos += 4; // rate
595 de_dbg(c, "rate: %.3f", nd);
597 n = dbuf_getu16be_p(bctx->f, &pos);
598 de_dbg(c, "volume: %.3f", ((double)n)/256.0);
600 pos += 2; // reserved
601 pos += 4*2; // reserved
602 pos += 4*9; // matrix
603 pos += 4*6; // pre_defined
605 n = dbuf_getu32be(bctx->f, pos);
606 de_dbg(c, "next track id: %d", (int)n);
609 static void do_box_mdhd(deark *c, lctx *d, struct de_boxesctx *bctx)
611 u8 version;
612 u32 flags;
613 i64 pos;
614 i64 n;
615 i64 timescale;
616 double nd;
617 struct de_boxdata *curbox = bctx->curbox;
619 // TODO: Share code with do_box_mvhd()?
620 if(curbox->payload_len<4) return;
622 pos = curbox->payload_pos;
623 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
624 pos+=4;
626 if(version==1) {
627 if(curbox->payload_len<36) return;
629 else {
630 if(curbox->payload_len<24) return;
633 // creation time, mod time
634 if(version==1)
635 pos += 8 + 8;
636 else
637 pos += 4 + 4;
639 timescale = dbuf_getu32be_p(bctx->f, &pos);
640 de_dbg(c, "timescale: %d time units per second", (int)timescale);
642 // duration
643 if(version==1) {
644 n = dbuf_geti64be(bctx->f, pos);
645 pos += 8;
647 else {
648 n = dbuf_getu32be_p(bctx->f, &pos);
650 if(timescale>0)
651 nd = (double)n / (double)timescale;
652 else
653 nd = 0.0;
654 de_dbg(c, "duration: %d time units (%.2f seconds)", (int)n, nd);
657 static void do_box_stsc(deark *c, lctx *d, struct de_boxesctx *bctx)
659 u8 version;
660 u32 flags;
661 struct de_boxdata *curbox = bctx->curbox;
662 i64 pos = curbox->payload_pos;
663 i64 e_count, e_to_print;
664 i64 bytesleft;
665 i64 k;
667 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
668 pos += 4;
669 if(version!=0 || flags!=0) return;
671 e_count = dbuf_getu32be_p(bctx->f, &pos);
672 de_dbg(c, "entry count: %u", (unsigned int)e_count);
674 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
675 if(bytesleft/12 < e_count) return;
677 e_to_print = de_min_int(e_count, d->max_entries_to_print);
679 for(k=0; k<e_to_print; k++) {
680 i64 first_chunk, spc, sdi;
681 first_chunk = dbuf_getu32be_p(bctx->f, &pos);
682 spc = dbuf_getu32be_p(bctx->f, &pos);
683 sdi = dbuf_getu32be_p(bctx->f, &pos);
684 de_dbg(c, "entry[%d]: first chunk=%d, samples/chunk=%d, descr. index=%d",
685 (int)k, (int)first_chunk, (int)spc, (int)sdi);
687 if(e_to_print < e_count) {
688 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
689 (int)(e_count-e_to_print), pos);
693 static void do_box_stsd(deark *c, lctx *d, struct de_boxesctx *bctx)
695 u8 version;
696 u32 flags;
697 i64 pos;
698 i64 num_entries;
699 i64 entry_size;
700 struct de_fourcc fmt4cc;
701 struct de_boxdata *curbox = bctx->curbox;
703 if(curbox->payload_len<8) return;
705 pos = curbox->payload_pos;
706 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
707 pos += 4;
708 if(version!=0) return;
710 num_entries = dbuf_getu32be_p(bctx->f, &pos);
711 de_dbg(c, "number of sample description entries: %d", (int)num_entries);
713 while(1) {
714 if(pos + 16 >= curbox->payload_pos + curbox->payload_len) break;
715 entry_size = dbuf_getu32be(bctx->f, pos);
716 de_dbg(c, "sample description entry at %d, len=%d", (int)pos, (int)entry_size);
717 if(entry_size<16) break;
719 de_dbg_indent(c, 1);
720 dbuf_read_fourcc(bctx->f, pos+4, &fmt4cc, 4, 0x0);
721 de_dbg(c, "data format: '%s'", fmt4cc.id_dbgstr);
722 de_dbg_indent(c, -1);
724 pos += entry_size;
728 // Decode a table of (4- or 8-byte) integers.
729 // Limit to d->max_entries_to_print.
730 static void do_simple_int_table(deark *c, lctx *d, struct de_boxesctx *bctx,
731 i64 pos1, i64 e_count, i64 e_size,
732 const char *s1, const char *s2)
734 i64 bytesleft;
735 i64 e_to_print;
736 i64 k;
737 struct de_boxdata *curbox = bctx->curbox;
738 i64 pos = pos1;
740 if(e_count<=0) return;
741 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
742 if(bytesleft < e_size*e_count) return;
744 e_to_print = de_min_int(e_count, d->max_entries_to_print);
746 for(k=0; k<e_to_print; k++) {
747 i64 n;
749 if(e_size==8) {
750 n = dbuf_geti64be(bctx->f, pos); pos += 8;
752 else {
753 n = dbuf_getu32be_p(bctx->f, &pos);
756 de_dbg(c, "%s[%"I64_FMT"]: %s=%"I64_FMT, s1, k, s2, n);
758 if(e_to_print < e_count) {
759 de_dbg(c, "[%"I64_FMT" more %s(s) omitted, starting at %"I64_FMT"]",
760 e_count-e_to_print, s1, pos);
764 static void do_box_stsz(deark *c, lctx *d, struct de_boxesctx *bctx)
766 u8 version;
767 u32 flags;
768 struct de_boxdata *curbox = bctx->curbox;
769 i64 pos = curbox->payload_pos;
770 i64 s_size, s_count;
772 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
773 pos += 4;
774 if(version!=0 || flags!=0) return;
776 s_size = dbuf_getu32be_p(bctx->f, &pos);
777 de_dbg(c, "sample size: %u", (unsigned int)s_size);
778 s_count = dbuf_getu32be_p(bctx->f, &pos);
779 de_dbg(c, "sample count: %u", (unsigned int)s_count);
781 if(s_size!=0) goto done;
783 do_simple_int_table(c, d, bctx, pos, s_count, 4, "sample", "entry size");
785 done:
789 // stco and co64
790 static void do_box_stco(deark *c, lctx *d, struct de_boxesctx *bctx)
792 u8 version;
793 u32 flags;
794 struct de_boxdata *curbox = bctx->curbox;
795 i64 pos = curbox->payload_pos;
796 i64 e_count;
797 i64 e_size;
799 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
800 pos += 4;
801 if(version!=0 || flags!=0) return;
803 e_size = (bctx->curbox->boxtype == BOX_co64) ? 8 : 4;
804 e_count = dbuf_getu32be_p(bctx->f, &pos);
805 de_dbg(c, "entry count: %u", (unsigned int)e_count);
807 do_simple_int_table(c, d, bctx, pos, e_count, e_size, "entry", "chunk offset");
810 static void do_box_stss(deark *c, lctx *d, struct de_boxesctx *bctx)
812 u8 version;
813 u32 flags;
814 struct de_boxdata *curbox = bctx->curbox;
815 i64 pos = curbox->payload_pos;
816 i64 e_count;
818 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
819 pos += 4;
820 if(version!=0 || flags!=0) return;
822 e_count = dbuf_getu32be_p(bctx->f, &pos);
823 de_dbg(c, "entry count: %u", (unsigned int)e_count);
825 do_simple_int_table(c, d, bctx, pos, e_count, 4, "entry", "sample number");
828 static void do_box_stts(deark *c, lctx *d, struct de_boxesctx *bctx)
830 u8 version;
831 u32 flags;
832 struct de_boxdata *curbox = bctx->curbox;
833 i64 pos = curbox->payload_pos;
834 i64 e_count, e_to_print;
835 i64 bytesleft;
836 i64 k;
838 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
839 pos += 4;
840 if(version!=0 || flags!=0) return;
842 e_count = dbuf_getu32be_p(bctx->f, &pos);
843 de_dbg(c, "entry count: %u", (unsigned int)e_count);
845 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
846 if(bytesleft/8 < e_count) return;
848 e_to_print = de_min_int(e_count, d->max_entries_to_print);
850 for(k=0; k<e_to_print; k++) {
851 i64 s_count, s_delta;
852 s_count = dbuf_getu32be_p(bctx->f, &pos);
853 s_delta = dbuf_getu32be_p(bctx->f, &pos);
854 de_dbg(c, "entry[%d]: sample count=%d, delta=%d", (int)k,
855 (int)s_count, (int)s_delta);
857 if(e_to_print < e_count) {
858 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
859 (int)(e_count-e_to_print), pos);
863 static void do_box_ctts(deark *c, lctx *d, struct de_boxesctx *bctx)
865 u8 version;
866 u32 flags;
867 struct de_boxdata *curbox = bctx->curbox;
868 i64 pos = curbox->payload_pos;
869 i64 e_count, e_to_print;
870 i64 bytesleft;
871 i64 k;
873 do_read_version_and_flags(c, d, bctx, &version, &flags, 1);
874 pos += 4;
875 if(version>1 || flags!=0) return;
877 e_count = dbuf_getu32be_p(bctx->f, &pos);
878 de_dbg(c, "entry count: %u", (unsigned int)e_count);
880 bytesleft = curbox->payload_pos + curbox->payload_len - pos;
881 if(bytesleft < e_count*8) return;
883 e_to_print = e_count;
884 if(e_to_print > d->max_entries_to_print) {
885 e_to_print = d->max_entries_to_print;
888 for(k=0; k<e_to_print; k++) {
889 i64 s_count, s_offset;
890 s_count = dbuf_getu32be_p(bctx->f, &pos);
891 if(version==0) {
892 s_offset = dbuf_getu32be_p(bctx->f, &pos);
894 else {
895 s_offset = dbuf_geti32be(bctx->f, pos); pos += 4;
897 de_dbg(c, "entry[%d]: sample count=%"I64_FMT", offset=%"I64_FMT,
898 (int)k, s_count, s_offset);
900 if(e_to_print < e_count) {
901 de_dbg(c, "[%d more entry(s) omitted, starting at %"I64_FMT"]",
902 (int)(e_count-e_to_print), pos);
906 static void do_box_full_superbox(deark *c, lctx *d, struct de_boxesctx *bctx)
908 struct de_boxdata *curbox = bctx->curbox;
910 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
911 curbox->extra_bytes_before_children = 4;
914 static void do_box_meta(deark *c, lctx *d, struct de_boxesctx *bctx)
916 if(bctx->curbox->payload_len>=8) {
917 // The QuickTime spec says 'meta' is not a full box, but in newer files
918 // it is. I don't know how you're supposed to know, but sniffing for
919 // "hdlr" should be good enough.
920 u32 n = (u32)dbuf_getu32be(bctx->f, bctx->curbox->payload_pos+4);
921 if(n==BOX_hdlr) {
922 return;
926 do_box_full_superbox(c, d, bctx);
929 static void do_box_jp2c(deark *c, lctx *d, struct de_boxesctx *bctx)
931 struct de_boxdata *curbox = bctx->curbox;
933 de_dbg(c, "JPEG 2000 codestream at %d, len=%d",
934 (int)curbox->payload_pos, (int)curbox->payload_len);
936 // I think this box is used regardless of the compression format, so make
937 // sure it seems to be in "JPEG 2000" format.
938 // This is a hack -- we could track the compression method instead.
939 if((u32)dbuf_getu32be(bctx->f, curbox->payload_pos) != 0xff4fff51U) {
940 de_dbg(c, "[non-J2C]");
941 return;
944 dbuf_create_file_from_slice(bctx->f, curbox->payload_pos, curbox->payload_len,
945 "j2c", NULL, 0);
948 static void format_jp2_res(char *buf, size_t buflen,
949 i64 num, i64 denom, int exponent)
951 // TODO: Format this better
952 de_snprintf(buf, buflen, "(%d/%d)"DE_CHAR_TIMES"10^%d points/meter",
953 (int)num, (int)denom, exponent);
956 static void do_box_resc_resd(deark *c, lctx *d, struct de_boxesctx *bctx)
958 i64 vn, vd, hn, hd;
959 int ve, he;
960 struct de_boxdata *curbox = bctx->curbox;
961 const char *name;
962 i64 pos = curbox->payload_pos;
963 char res_buf[160];
965 if(curbox->boxtype==BOX_resc)
966 name = "capture";
967 else
968 name = "display";
970 if(curbox->payload_len<10) return;
971 vn = dbuf_getu16be_p(bctx->f, &pos);
972 vd = dbuf_getu16be_p(bctx->f, &pos);
973 hn = dbuf_getu16be_p(bctx->f, &pos);
974 hd = dbuf_getu16be_p(bctx->f, &pos);
975 ve = (int)(signed char)dbuf_getbyte_p(bctx->f, &pos);
976 he = (int)(signed char)dbuf_getbyte_p(bctx->f, &pos);
977 format_jp2_res(res_buf, sizeof(res_buf), vn, vd, ve);
978 de_dbg(c, "vert. %s grid res.: %s", name, res_buf);
979 format_jp2_res(res_buf, sizeof(res_buf), hn, hd, he);
980 de_dbg(c, "horz. %s grid res.: %s", name, res_buf);
983 static const char *get_rreq_sf_name(UI n)
985 static const u8 ids[11] = {1, 2, 5, 8, 12, 18, 19, 20, 31, 45, 46};
986 static const char *names[11] = { "no extensions", "has layers",
987 "cmpr=JPEG 2000/15444-1", "no opacity", "contiguous",
988 "layers not req'd", "discrete layers", "1 codestream per layer",
989 "scaling not req'd", "sRGB", "sRGB-gray" };
990 size_t i;
992 for(i=0; i<DE_ARRAYCOUNT(ids); i++) {
993 if((UI)ids[i]==n) return names[i];
995 return "?";
998 static void do_box_rreq(deark *c, lctx *d, struct de_boxesctx *bctx)
1000 i64 pos = bctx->curbox->payload_pos;
1001 i64 endpos = pos + bctx->curbox->payload_len;
1002 UI ml;
1003 i64 nsf, nvf;
1004 u64 msk;
1005 i64 i;
1007 if(pos>=endpos) goto done;
1008 ml = (UI)dbuf_getbyte_p(bctx->f, &pos);
1009 de_dbg(c, "ml: %u bytes", ml);
1010 if(ml<1 || ml>8) goto done;
1012 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1013 pos += (i64)ml;
1014 de_dbg(c, "fuam: 0x%"U64_FMTx, msk);
1016 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1017 pos += (i64)ml;
1018 de_dbg(c, "dcm: 0x%"U64_FMTx, msk);
1020 nsf = dbuf_getu16be_p(bctx->f, &pos);
1021 de_dbg(c, "nsf: %d", (int)nsf);
1023 for(i=0; i<nsf; i++) {
1024 UI sf;
1026 if(pos>=endpos) goto done;
1027 sf = (UI)dbuf_getu16be_p(bctx->f, &pos);
1028 de_dbg(c, "sf[%d]: %u (%s)", (int)i, sf, get_rreq_sf_name(sf));
1030 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1031 pos += (i64)ml;
1032 de_dbg(c, "sm[%d]: 0x%"U64_FMTx, (int)i, msk);
1035 if(pos>=endpos) goto done;
1036 nvf = dbuf_getu16be_p(bctx->f, &pos);
1037 de_dbg(c, "nvf: %d", (int)nvf);
1039 for(i=0; i<nvf; i++) {
1040 u8 ubuf[16];
1041 char uuid_string[50];
1043 if(pos>=endpos) goto done;
1044 dbuf_read(bctx->f, ubuf, pos, 16);
1045 fmtutil_render_uuid(c, ubuf, uuid_string, sizeof(uuid_string));
1046 de_dbg(c, "vf[%d]: {%s}", (int)i, uuid_string);
1047 pos += 16;
1049 msk = (u64)dbuf_getint_ext(bctx->f, pos, ml, 0, 0);
1050 pos += (i64)ml;
1051 de_dbg(c, "vm[%d]: 0x%"U64_FMTx, (int)i, msk);
1054 done:
1058 static const char *get_jpeg2000_cmpr_name(deark *c, lctx *d, u8 ct)
1060 const char *name = NULL;
1062 if(ct==7) { name="JPEG 2000"; goto done; }
1063 if(d->is_jpx) {
1064 switch(ct) {
1065 case 0: name="uncompressed"; break;
1066 case 1: name="MH"; break;
1067 case 2: name="MR"; break;
1068 case 3: name="MMR"; break;
1069 case 4: name="JBIG bi-level"; break;
1070 case 5: name="JPEG"; break;
1071 case 6: name="JPEG-LS"; break;
1072 case 8: name="JBIG2"; break;
1073 case 9: name="JBIG"; break;
1076 // TODO: JPM
1077 done:
1078 if(!name) name="?";
1079 return name;
1082 static void do_box_ihdr(deark *c, lctx *d, struct de_boxesctx *bctx)
1084 i64 w, h, n;
1085 u8 b;
1086 struct de_boxdata *curbox = bctx->curbox;
1087 i64 pos = curbox->payload_pos;
1088 char tmps[80];
1090 if(curbox->payload_len<14) return;
1091 h = dbuf_getu32be_p(bctx->f, &pos);
1092 w = dbuf_getu32be_p(bctx->f, &pos);
1093 de_dbg_dimensions(c, w, h);
1095 n = dbuf_getu16be_p(bctx->f, &pos);
1096 de_dbg(c, "number of components: %d", (int)n);
1098 b = dbuf_getbyte_p(bctx->f, &pos);
1099 if(b==255) {
1100 de_strlcpy(tmps, "various", sizeof(tmps));
1102 else {
1103 de_snprintf(tmps, sizeof(tmps), "%u bits/comp., %ssigned",
1104 (unsigned int)(1+(b&0x7f)), (b&0x80)?"":"un");
1106 de_dbg(c, "bits-per-component code: %u (%s)", (unsigned int)b, tmps);
1108 b = dbuf_getbyte_p(bctx->f, &pos);
1109 de_dbg(c, "compression type: %u (%s)", (unsigned int)b,
1110 get_jpeg2000_cmpr_name(c, d, b));
1112 b = dbuf_getbyte_p(bctx->f, &pos);
1113 de_dbg(c, "colorspace-is-unknown flag: %d", (int)b);
1114 b = dbuf_getbyte_p(bctx->f, &pos);
1115 de_dbg(c, "has-IPR: %d", (int)b);
1118 static const char *get_channel_type_name(i64 t)
1120 const char *name;
1121 switch(t) {
1122 case 0: name = "colour image data for associated color"; break;
1123 case 1: name = "opacity"; break;
1124 case 2: name = "premultiplied opacity"; break;
1125 case 65535: name = "not specified"; break;
1126 default: name = "?";
1128 return name;
1131 static void do_box_cdef(deark *c, lctx *d, struct de_boxesctx *bctx)
1133 i64 ndescs;
1134 struct de_boxdata *curbox = bctx->curbox;
1135 i64 pos = curbox->payload_pos;
1136 i64 k;
1138 ndescs = dbuf_getu16be_p(bctx->f, &pos);
1139 de_dbg(c, "number of channel descriptions: %d", (int)ndescs);
1141 for(k=0; k<ndescs; k++) {
1142 i64 idx, typ, asoc;
1144 if(pos+6 > curbox->payload_pos + curbox->payload_len) break;
1145 de_dbg(c, "channel description[%d] at %"I64_FMT, (int)k, pos);
1146 de_dbg_indent(c, 1);
1147 idx = dbuf_getu16be_p(bctx->f, &pos);
1148 de_dbg(c, "channel index: %d", (int)idx);
1149 typ = dbuf_getu16be_p(bctx->f, &pos);
1150 de_dbg(c, "channel type: %d (%s)", (int)typ, get_channel_type_name(typ));
1151 asoc = dbuf_getu16be_p(bctx->f, &pos);
1152 de_dbg(c, "index of associated color: %d", (int)asoc);
1153 de_dbg_indent(c, -1);
1157 // BMFF-style 'colr' box
1158 static void do_box_colr_bmff(deark *c, lctx *d, struct de_boxesctx *bctx)
1160 struct de_boxdata *curbox = bctx->curbox;
1161 i64 pos = curbox->payload_pos;
1162 struct de_fourcc ct4cc; // colour_type
1164 if(curbox->payload_len<4) goto done;
1166 dbuf_read_fourcc(bctx->f, pos, &ct4cc, 4, 0x0);
1167 de_dbg(c, "colour type: '%s'", ct4cc.id_dbgstr);
1168 pos += 4;
1170 if(ct4cc.id==CODE_rICC || ct4cc.id==CODE_prof) {
1171 dbuf_create_file_from_slice(bctx->f, pos,
1172 curbox->payload_pos+curbox->payload_len-pos,
1173 "icc", NULL, DE_CREATEFLAG_IS_AUX);
1176 done:
1180 // JP2/JPX-style 'colr' box
1181 static void do_box_colr_jp2(deark *c, lctx *d, struct de_boxesctx *bctx)
1183 u8 meth;
1184 struct de_boxdata *curbox = bctx->curbox;
1185 i64 pos = curbox->payload_pos;
1186 const char *s;
1188 if(curbox->payload_len<3) goto done;
1189 meth = dbuf_getbyte_p(bctx->f, &pos);
1190 switch(meth) {
1191 case 1: s="enumerated"; break;
1192 case 2: s="ICC profile (restricted)"; break;
1193 case 3: s="ICC profile (any)"; break; // JPX only
1194 case 4: s="vendor"; break; // JPX only
1195 default: s="?";
1197 de_dbg(c, "specification method: %d (%s)", (int)meth, s);
1199 pos++; // PREC
1200 pos++; // APPROX
1202 if(meth==1) {
1203 unsigned int enumcs;
1204 if(curbox->payload_len<7) goto done;
1205 enumcs = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
1206 switch(enumcs) {
1207 // TODO: There are lots more valid values for JPX.
1208 case 16: s="sRGB"; break;
1209 case 17: s="sRGB-like grayscale"; break;
1210 case 18: s="sYCC"; break;
1211 default: s="?";
1213 de_dbg(c, "enumerated colourspace: %u (%s)", enumcs, s);
1215 else if(meth==2 || meth==3) {
1216 dbuf_create_file_from_slice(bctx->f,
1217 curbox->payload_pos+3, curbox->payload_len-3,
1218 "icc", NULL, DE_CREATEFLAG_IS_AUX);
1221 done:
1225 static void do_box_ulst(deark *c, lctx *d, struct de_boxesctx *bctx)
1227 struct de_boxdata *curbox = bctx->curbox;
1228 i64 pos = curbox->payload_pos;
1229 i64 nuuids;
1230 i64 k;
1231 u8 ubuf[16];
1232 char uuid_string[50];
1234 nuuids = dbuf_getu16be_p(bctx->f, &pos);
1235 de_dbg(c, "number of UUIDs: %d", (int)nuuids);
1237 for(k=0; k<nuuids; k++) {
1238 if(pos+16 > curbox->payload_pos + curbox->payload_len) break;
1239 dbuf_read(bctx->f, ubuf, pos, 16);
1240 fmtutil_render_uuid(c, ubuf, uuid_string, sizeof(uuid_string));
1241 de_dbg(c, "UUID[%d]: {%s}", (int)k, uuid_string);
1242 pos += 16;
1246 static void do_box_url(deark *c, lctx *d, struct de_boxesctx *bctx)
1248 de_ucstring *s = NULL;
1249 struct de_boxdata *curbox = bctx->curbox;
1250 i64 pos = curbox->payload_pos;
1251 u32 flags = 0;
1253 do_read_version_and_flags(c, d, bctx, NULL, &flags, 1);
1254 pos += 4;
1256 // "If the self-contained flag is set, [...] no string is present".
1257 // But there is no flag named "self-contained".
1258 // I assume it is flag 0x1.
1259 if(flags&0x000001) goto done;
1261 s = ucstring_create(c);
1262 dbuf_read_to_ucstring_n(bctx->f,
1263 pos, curbox->payload_pos + curbox->payload_len - pos, DE_DBG_MAX_STRLEN,
1264 s, DE_CONVFLAG_STOP_AT_NUL, DE_ENCODING_UTF8);
1265 de_dbg(c, "URL: \"%s\"", ucstring_getpsz_d(s));
1266 done:
1267 ucstring_destroy(s);
1270 static void do_box_dtbl(deark *c, lctx *d, struct de_boxesctx *bctx)
1272 i64 ndr;
1273 struct de_boxdata *curbox = bctx->curbox;
1275 ndr = dbuf_getu16be(bctx->f, curbox->payload_pos);
1276 de_dbg(c, "number of data references: %d", (int)ndr);
1278 curbox->num_children_is_known = 1;
1279 curbox->num_children = ndr;
1280 curbox->extra_bytes_before_children = 2;
1283 static void do_box_dref(deark *c, lctx *d, struct de_boxesctx *bctx)
1285 i64 nitems;
1286 u8 version;
1287 struct de_boxdata *curbox = bctx->curbox;
1288 i64 pos = curbox->payload_pos;
1290 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1291 pos += 4;
1293 nitems = dbuf_getu32be_p(bctx->f, &pos);
1294 de_dbg(c, "number of items: %u", (unsigned int)nitems);
1296 curbox->num_children_is_known = 1;
1297 curbox->num_children = nitems;
1298 curbox->extra_bytes_before_children = pos - curbox->payload_pos;
1301 static void do_box_iinf(deark *c, lctx *d, struct de_boxesctx *bctx)
1303 i64 nitems;
1304 u8 version;
1305 struct de_boxdata *curbox = bctx->curbox;
1306 i64 pos = curbox->payload_pos;
1308 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1309 pos += 4;
1311 if(version==0) {
1312 nitems = dbuf_getu16be_p(bctx->f, &pos);
1314 else {
1315 nitems = dbuf_getu32be_p(bctx->f, &pos);
1317 de_dbg(c, "number of items: %d", (int)nitems);
1319 curbox->num_children_is_known = 1;
1320 curbox->num_children = nitems;
1321 curbox->extra_bytes_before_children = pos - curbox->payload_pos;
1324 static void extract_exif_item(deark *c, lctx *d, dbuf *f)
1326 i64 dpos, dlen;
1327 u8 b0,b1;
1329 if(!d->exif_item_id_known) return;
1330 if(d->exif_item_offs<=0) return;
1331 if(d->exif_item_len<24) return;
1332 // I'm just guessing the format of this item. It seems to start with 10
1333 // bytes of header info.
1334 dpos = d->exif_item_offs+10;
1335 dlen = d->exif_item_len-10;
1336 b0 = dbuf_getbyte(f, dpos);
1337 b1 = dbuf_getbyte(f, dpos+1);
1338 if(!((b0=='M' && b1=='M') || (b0=='I' && b1=='I'))) {
1339 return;
1341 de_dbg(c, "Exif item segment at %"I64_FMT", size=%"I64_FMT, dpos, dlen);
1342 de_dbg_indent(c, 1);
1343 fmtutil_handle_exif(c, dpos, dlen);
1344 de_dbg_indent(c, -1);
1347 static void do_box_iloc(deark *c, lctx *d, struct de_boxesctx *bctx)
1349 u8 version;
1350 struct de_boxdata *curbox = bctx->curbox;
1351 i64 pos = curbox->payload_pos;
1352 unsigned int u;
1353 unsigned int offset_size, length_size, base_offset_size, index_size;
1354 i64 item_count;
1355 i64 k;
1356 int saved_indent_level;
1358 de_dbg_indent_save(c, &saved_indent_level);
1359 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1360 pos += 4;
1362 // TODO: Support more versions
1363 if(version!=1) goto done;
1365 u = (unsigned int)dbuf_getbyte_p(bctx->f, &pos);
1366 offset_size = u>>4;
1367 de_dbg(c, "offset size: %u", offset_size);
1368 if(offset_size!=0 && offset_size!=4 && offset_size!=8) goto done;
1369 length_size = u&0xf;
1370 de_dbg(c, "length size: %u", length_size);
1371 if(length_size!=0 && length_size!=4 && length_size!=8) goto done;
1373 u = (unsigned int)dbuf_getbyte_p(bctx->f, &pos);
1374 base_offset_size = u>>4;
1375 de_dbg(c, "base offset size: %u", base_offset_size);
1376 if(base_offset_size!=0 && base_offset_size!=4 && base_offset_size!=8) goto done;
1377 index_size = u&0xf;
1378 de_dbg(c, "index size: %u", index_size);
1379 if(index_size!=0 && index_size!=4 && index_size!=8) goto done;
1381 item_count = dbuf_getu16be_p(bctx->f, &pos);
1382 de_dbg(c, "item count: %d", (int)item_count);
1384 for(k=0; k<item_count; k++) {
1385 unsigned int item_id;
1386 i64 extent_count;
1387 i64 e;
1388 unsigned int cnstr_meth;
1390 if(pos >= curbox->payload_pos+curbox->payload_len) goto done;
1391 de_dbg(c, "item[%d] at %"I64_FMT, (int)k, pos);
1392 de_dbg_indent(c, 1);
1393 item_id = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1394 de_dbg(c, "item id: %u", item_id);
1396 u = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1397 cnstr_meth = u&0xf;
1398 de_dbg(c, "construction method: %u", cnstr_meth);
1400 pos += 2; // data reference index
1401 pos += base_offset_size;
1403 extent_count = dbuf_getu16be_p(bctx->f, &pos);
1404 de_dbg(c, "extent count: %d", (int)extent_count);
1406 for(e=0; e<extent_count; e++) {
1407 i64 xoffs = 0;
1408 i64 xlen = 0;
1410 if(pos >= curbox->payload_pos+curbox->payload_len) goto done;
1411 de_dbg(c, "extent[%d]", (int)e);
1412 de_dbg_indent(c, 1);
1413 pos += index_size;
1415 if(offset_size>0) {
1416 xoffs = dbuf_getint_ext(bctx->f, pos, offset_size, 0, 0);
1417 de_dbg(c, "offset: %"I64_FMT, xoffs);
1419 pos += offset_size;
1421 if(length_size>0) {
1422 xlen = dbuf_getint_ext(bctx->f, pos, length_size, 0, 0);
1423 de_dbg(c, "length: %"I64_FMT, xlen);
1425 pos += length_size;
1427 if(d->exif_item_id_known && item_id==d->exif_item_id && extent_count==1) {
1428 de_dbg(c, "[Exif item]");
1429 d->exif_item_offs = xoffs;
1430 d->exif_item_len = xlen;
1433 de_dbg_indent(c, -1);
1436 de_dbg_indent(c, -1);
1439 done:
1440 if(d->exif_item_id_known) {
1441 extract_exif_item(c, d, bctx->f);
1443 de_dbg_indent_restore(c, saved_indent_level);
1446 static void do_box_infe(deark *c, lctx *d, struct de_boxesctx *bctx)
1448 u8 version;
1449 struct de_boxdata *curbox = bctx->curbox;
1450 i64 pos = curbox->payload_pos;
1451 i64 n;
1452 unsigned int item_id;
1454 do_read_version_and_flags(c, d, bctx, &version, NULL, 1);
1455 pos += 4;
1457 if(version==2 || version==3) {
1458 struct de_fourcc itemtype4cc;
1460 if(version==2) {
1461 item_id = (unsigned int)dbuf_getu16be_p(bctx->f, &pos);
1463 else {
1464 item_id = (unsigned int)dbuf_getu32be_p(bctx->f, &pos);
1466 de_dbg(c, "item id: %u", item_id);
1468 n = dbuf_getu16be_p(bctx->f, &pos);
1469 de_dbg(c, "item protection: %u", (unsigned int)n);
1471 dbuf_read_fourcc(bctx->f, pos, &itemtype4cc, 4, 0x0);
1472 pos += 4;
1473 de_dbg(c, "item type: '%s'", itemtype4cc.id_dbgstr);
1475 if(itemtype4cc.id==CODE_Exif) {
1476 d->exif_item_id_known = 1;
1477 d->exif_item_id = item_id;
1480 // TODO: string item_name
1481 // TODO: sometimes there are additional strings after item_name
1485 static void do_box_ispe(deark *c, lctx *d, struct de_boxesctx *bctx)
1487 struct de_boxdata *curbox = bctx->curbox;
1488 i64 pos = curbox->payload_pos;
1489 i64 w, h;
1491 if(curbox->payload_len<12) return;
1492 do_read_version_and_flags(c, d, bctx, NULL, NULL, 1);
1493 pos += 4;
1494 w = dbuf_getu32be_p(bctx->f, &pos);
1495 h = dbuf_getu32be_p(bctx->f, &pos);
1496 de_dbg_dimensions(c, w, h);
1499 static void do_box_xml(deark *c, lctx *d, struct de_boxesctx *bctx)
1501 struct de_boxdata *curbox = bctx->curbox;
1503 // TODO: Detect the specific XML format, and use it to choose a better
1504 // filename.
1505 de_dbg(c, "XML data at %d, len=%d", (int)curbox->payload_pos, (int)curbox->payload_len);
1506 dbuf_create_file_from_slice(bctx->f, curbox->payload_pos, curbox->payload_len,
1507 "xml", NULL, DE_CREATEFLAG_IS_AUX);
1510 static void do_box_THMB(deark *c, lctx *d, struct de_boxesctx *bctx)
1512 struct de_boxdata *curbox = bctx->curbox;
1513 i64 img_pos;
1514 i64 img_len;
1516 if(!curbox->parent) return;
1517 if(!curbox->parent->is_uuid) return;
1518 if(de_memcmp(curbox->parent->uuid, g_uuid_cr3_85c0, 16)) return;
1519 if(curbox->payload_len<20) return;
1520 img_pos= curbox->payload_pos+16;
1521 if(dbuf_memcmp(bctx->f, img_pos, "\xff\xd8\xff", 3)) return;
1522 img_len = dbuf_getu32be(bctx->f, curbox->payload_pos+8);
1523 de_dbg(c, "image at %"I64_FMT", len=%"I64_FMT, img_pos, img_len);
1524 if(img_pos+img_len > curbox->payload_pos+curbox->payload_len) return;
1525 dbuf_create_file_from_slice(bctx->f, img_pos, img_len, "thumb.jpg", NULL,
1526 DE_CREATEFLAG_IS_AUX);
1529 static void do_box_PRVW(deark *c, lctx *d, struct de_boxesctx *bctx)
1531 struct de_boxdata *curbox = bctx->curbox;
1532 i64 img_pos;
1533 i64 img_len;
1535 if(!curbox->parent) return;
1536 if(!curbox->parent->is_uuid) return;
1537 if(de_memcmp(curbox->parent->uuid, g_uuid_cr3_eaf4, 16)) return;
1538 if(curbox->payload_len<20) return;
1539 img_pos= curbox->payload_pos+16;
1540 if(dbuf_memcmp(bctx->f, img_pos, "\xff\xd8\xff", 3)) return;
1541 img_len = dbuf_getu32be(bctx->f, curbox->payload_pos+12);
1542 de_dbg(c, "image at %"I64_FMT", len=%"I64_FMT, img_pos, img_len);
1543 if(img_pos+img_len > curbox->payload_pos+curbox->payload_len) return;
1544 dbuf_create_file_from_slice(bctx->f, img_pos, img_len, "preview.jpg", NULL,
1545 DE_CREATEFLAG_IS_AUX);
1548 // The first line that matches will be used, so items related to more-specific
1549 // formats/brands should be listed first.
1550 static const struct box_type_info box_type_info_arr[] = {
1551 {BOX_ftyp, 0x00000000, 0x00000002, "file type", do_box_ftyp},
1552 {BOX_jP , 0x00010008, 0x00000002, "JPEG 2000 signature", do_box_jP},
1553 {BOX_mdat, 0x00000008, 0x00000001, "media data", NULL},
1554 {BOX_mdat, 0x00080001, 0x00000000, "media data", NULL},
1555 {BOX_alis, 0x00000001, 0x00000000, "Macintosh file alias", NULL},
1556 {BOX_cinf, 0x00000001, 0x00000001, "complete track information", NULL},
1557 {BOX_clip, 0x00000001, 0x00000001, NULL, NULL},
1558 {BOX_co64, 0x00000001, 0x00000000, "chunk offset", do_box_stco},
1559 {BOX_colr, 0x00080001, 0x00000000, "colour information", do_box_colr_bmff},
1560 {BOX_dinf, 0x00080001, 0x00000001, "data information", NULL},
1561 {BOX_dref, 0x00080001, 0x00000001, "data reference", do_box_dref},
1562 {BOX_edts, 0x00000001, 0x00000001, "edit", NULL},
1563 {BOX_elst, 0x00000001, 0x00000000, "edit list", NULL},
1564 {BOX_fdsa, 0x00000001, 0x00000001, NULL, NULL},
1565 {BOX_fiin, 0x00000001, 0x00000001, "FD item information", NULL},
1566 {BOX_free, 0x00090001, 0x00000000, "free space", NULL},
1567 {BOX_hdlr, 0x00080001, 0x00000000, "handler reference", do_box_hdlr},
1568 {BOX_hinf, 0x00000001, 0x00000001, NULL, NULL},
1569 {BOX_hmhd, 0x00000001, 0x00000000, "hint media header", NULL},
1570 {BOX_hnti, 0x00000001, 0x00000001, NULL, NULL},
1571 {BOX_iinf, 0x00080001, 0x00000001, "item info", do_box_iinf},
1572 {BOX_iloc, 0x00080001, 0x00000000, "item location", do_box_iloc},
1573 {BOX_ilst, 0x00000001, 0x00000001, "metadata item list", NULL},
1574 {BOX_infe, 0x00080001, 0x00000000, "item info entry", do_box_infe},
1575 {BOX_iods, 0x00000001, 0x00000000, "object descriptor", NULL},
1576 {BOX_iref, 0x00080001, 0x00000001, "item reference", do_box_full_superbox},
1577 {BOX_load, 0x00000001, 0x00000000, "track load settings", NULL},
1578 {BOX_matt, 0x00000001, 0x00000001, NULL, NULL},
1579 {BOX_mdhd, 0x00000001, 0x00000000, "media header", do_box_mdhd},
1580 {BOX_mdia, 0x00000001, 0x00000001, "media", NULL},
1581 {BOX_meco, 0x00000001, 0x00000001, "additional metadata container", NULL},
1582 {BOX_meta, 0x00080001, 0x00000001, "metadata", do_box_meta},
1583 {BOX_minf, 0x00000001, 0x00000001, "media information", NULL},
1584 {BOX_mfra, 0x00000001, 0x00000001, "movie fragment random access", NULL},
1585 {BOX_moof, 0x00000001, 0x00000001, "movie fragment", NULL},
1586 {BOX_moov, 0x00000001, 0x00000001, "movie (metadata container)", NULL},
1587 {BOX_mvex, 0x00000001, 0x00000001, "movie extends", NULL},
1588 {BOX_mvhd, 0x00000001, 0x00000000, "movie header", do_box_mvhd},
1589 {BOX_nmhd, 0x00000001, 0x00000000, "null media header", NULL},
1590 {BOX_paen, 0x00000001, 0x00000001, NULL, NULL},
1591 {BOX_pnot, 0x00000001, 0x00000000, "reference to movie preview", NULL},
1592 {BOX_rinf, 0x00000001, 0x00000001, "restricted scheme information", NULL},
1593 {BOX_rsrc, 0x00000001, 0x00000000, "Macintosh resource alias", NULL},
1594 {BOX_sbgp, 0x00000001, 0x00000000, "sample-to-group", NULL},
1595 {BOX_schi, 0x00000001, 0x00000001, "scheme information", NULL},
1596 {BOX_sdtp, 0x00000001, 0x00000000, "independent and disposable samples", NULL},
1597 {BOX_sgpd, 0x00000001, 0x00000000, "sample group description", NULL},
1598 {BOX_sinf, 0x00000001, 0x00000001, "protection scheme information", NULL},
1599 {BOX_skip, 0x00080001, 0x00000000, "user-data", NULL},
1600 {BOX_smhd, 0x00000001, 0x00000000, "sound media header", do_box_smhd},
1601 {BOX_stbl, 0x00000001, 0x00000001, "sample table", NULL},
1602 {BOX_stco, 0x00000001, 0x00000000, "chunk offset", do_box_stco},
1603 {BOX_strd, 0x00000001, 0x00000001, "sub track definition", NULL},
1604 {BOX_strk, 0x00000001, 0x00000001, "sub track", NULL},
1605 {BOX_stsc, 0x00000001, 0x00000000, "sample to chunk", do_box_stsc},
1606 {BOX_stsd, 0x00000001, 0x00000000, "sample description", do_box_stsd},
1607 {BOX_stss, 0x00000001, 0x00000000, "sync sample", do_box_stss},
1608 {BOX_stsz, 0x00000001, 0x00000000, "sample sizes", do_box_stsz},
1609 {BOX_stts, 0x00000001, 0x00000000, "decoding time to sample", do_box_stts},
1610 {BOX_ctts, 0x00000001, 0x00000000, "composition time to sample", do_box_ctts},
1611 {BOX_stz2, 0x00000001, 0x00000000, "compact sample size", NULL},
1612 {BOX_tkhd, 0x00000001, 0x00000000, "track header", do_box_tkhd},
1613 {BOX_traf, 0x00000001, 0x00000001, "track fragment", NULL},
1614 {BOX_trak, 0x00000001, 0x00000001, "track", NULL},
1615 {BOX_tref, 0x00000001, 0x00000001, "track reference", NULL},
1616 {BOX_udta, 0x00000001, 0x00000001, "user data", NULL},
1617 {BOX_url , 0x00090001, 0x00000000, "URL", do_box_url},
1618 {BOX_vmhd, 0x00000001, 0x00000000, "video media header", do_box_vmhd},
1619 {BOX_wide, 0x00000001, 0x00000000, "reserved space", NULL},
1620 {BOX_PICT, 0x00000001, 0x00000000, "QuickDraw picture", do_box_PICT},
1621 {BOX_PRVW, 0x00000001, 0x00000000, "preview", do_box_PRVW},
1622 {BOX_THMB, 0x00000001, 0x00000000, "thumbnail", do_box_THMB},
1623 {BOX_asoc, 0x00010000, 0x00000001, "association", NULL},
1624 {BOX_cgrp, 0x00010000, 0x00000001, "colour group", NULL},
1625 {BOX_cdef, 0x00010000, 0x00000000, "channel definition", do_box_cdef},
1626 {BOX_colr, 0x00010000, 0x00000000, "colour specification", do_box_colr_jp2},
1627 {BOX_comp, 0x00010000, 0x00000001, NULL, NULL},
1628 {BOX_drep, 0x00010000, 0x00000001, NULL, NULL},
1629 {BOX_dtbl, 0x00010000, 0x00000001, "data reference", do_box_dtbl},
1630 {BOX_flst, 0x00010000, 0x00000000, "fragment list", NULL},
1631 {BOX_ftbl, 0x00010000, 0x00000001, "fragment table", NULL},
1632 {BOX_ihdr, 0x00010000, 0x00000000, "image header", do_box_ihdr},
1633 {BOX_jp2c, 0x00010008, 0x00000000, "contiguous codestream", do_box_jp2c},
1634 {BOX_jp2h, 0x00010000, 0x00000001, "JP2 header", NULL},
1635 {BOX_jpch, 0x00010000, 0x00000001, "codestream header", NULL},
1636 {BOX_jplh, 0x00010000, 0x00000001, "compositing layer header", NULL},
1637 {BOX_lhdr, 0x00010000, 0x00000000, "layout object header", NULL},
1638 {BOX_lbl , 0x00010000, 0x00000000, "label", do_box_justtext},
1639 {BOX_lobj, 0x00010000, 0x00000001, "layout object", NULL},
1640 {BOX_mhdr, 0x00010000, 0x00000000, "compound image header", NULL},
1641 {BOX_nlst, 0x00010000, 0x00000000, "number list", NULL},
1642 {BOX_objc, 0x00010000, 0x00000001, "object", NULL},
1643 {BOX_ohdr, 0x00010000, 0x00000000, "object header", NULL},
1644 {BOX_page, 0x00010000, 0x00000001, "page", NULL},
1645 {BOX_pagt, 0x00010000, 0x00000000, "page table", NULL},
1646 {BOX_pcol, 0x00010000, 0x00000001, "page collection", NULL},
1647 {BOX_phdr, 0x00010000, 0x00000000, "page header", NULL},
1648 {BOX_res , 0x00010000, 0x00000001, "resolution", NULL},
1649 {BOX_resc, 0x00010000, 0x00000000, "capture resolution", do_box_resc_resd},
1650 {BOX_resd, 0x00010000, 0x00000000, "default display resolution", do_box_resc_resd},
1651 {BOX_rreq, 0x00010000, 0x00000000, "reader requirements", do_box_rreq},
1652 {BOX_scal, 0x00010000, 0x00000000, "object scale", NULL},
1653 {BOX_sdat, 0x00010000, 0x00000001, NULL, NULL},
1654 {BOX_uinf, 0x00010000, 0x00000001, "UUID info", NULL},
1655 {BOX_ulst, 0x00010000, 0x00000000, "UUID list", do_box_ulst},
1656 {BOX_xml , 0x00010008, 0x00000000, "XML", do_box_xml},
1657 {BOX_LCHK, 0x00040000, 0x00000000, "checksum", NULL},
1658 {BOX_RESI, 0x00040000, 0x00000000, "residual codestream", NULL},
1659 {BOX_SPEC, 0x00040000, 0x00000001, NULL, NULL},
1660 {BOX_auxC, 0x00080000, 0x00000000, "auxiliary type property", NULL},
1661 {BOX_grpl, 0x00080000, 0x00000000, "groups list", NULL},
1662 {BOX_idat, 0x00080000, 0x00000000, "item data", NULL},
1663 {BOX_ipco, 0x00080000, 0x00000001, "item property container", NULL},
1664 {BOX_ipma, 0x00080000, 0x00000000, "item property association", NULL},
1665 {BOX_ipro, 0x00080000, 0x00000000, "item protection", NULL},
1666 {BOX_iprp, 0x00080000, 0x00000001, "item properties", NULL},
1667 {BOX_ispe, 0x00080000, 0x00000000, "image spatial extents", do_box_ispe},
1668 {BOX_hvcC, 0x00080000, 0x00000000, "HEVC configuration", NULL},
1669 {BOX_pitm, 0x00080000, 0x00000000, "primary item", NULL}
1672 // TODO: These ilst (iTunes metadata?) boxes should probably go in the above
1673 // list, but the logic for finding the right box will be complicated.
1674 // Superboxes are not flagged in this list, because that determination
1675 // is based on their location, not their type.
1676 static const struct box_type_info ilst_box_type_info_arr[] = {
1677 {BOX_data, 0x01000000, 0x00000000, "value atom", do_box_data},
1678 {BOX_name, 0x01000000, 0x00000000, "name atom", NULL},
1679 {BOX_blank, 0x01000000, 0x00000000, "custom metadata item", NULL},
1680 {BOX_cpil, 0x01000000, 0x00000000, "compilation", NULL},
1681 {BOX_gnre, 0x01000000, 0x00000000, "genre (enumerated)", NULL},
1682 {BOX_tmpo, 0x01000000, 0x00000000, "tempo", NULL},
1683 {BOX_a9ART, 0x01000000, 0x00000000, "artist", NULL},
1684 {BOX_a9cmt, 0x01000000, 0x00000000, "comment", NULL},
1685 {BOX_a9nam, 0x01000000, 0x00000000, "name / title", NULL},
1686 {BOX_a9too, 0x01000000, 0x00000000, "encoder software", NULL}
1689 static const struct box_type_info *find_box_type_info(deark *c, lctx *d,
1690 u32 boxtype, int level)
1692 size_t k;
1693 u32 mask = 0;
1695 if(d->is_bmff) mask |= 0x00000001;
1696 if(d->is_mj2) mask |= 0x000000008;
1697 if(d->is_jp2_jpx_jpm) mask |= 0x00010000;
1698 if(d->is_jpegxt) mask |= 0x00040000;
1699 if(d->is_heif) mask |= 0x00080000;
1701 for(k=0; k<DE_ARRAYCOUNT(box_type_info_arr); k++) {
1702 if(box_type_info_arr[k].boxtype != boxtype) continue;
1703 if(level==0 && (box_type_info_arr[k].flags2 & 0x2)) {
1704 // Critical box. Always match.
1705 return &box_type_info_arr[k];
1707 if((box_type_info_arr[k].flags1 & mask)==0) continue;
1708 return &box_type_info_arr[k];
1710 return NULL;
1713 static const struct box_type_info *find_ilst_box_type_info(deark *c, lctx *d,
1714 u32 boxtype)
1716 size_t k;
1718 for(k=0; k<DE_ARRAYCOUNT(ilst_box_type_info_arr); k++) {
1719 if(ilst_box_type_info_arr[k].boxtype != boxtype) continue;
1720 return &ilst_box_type_info_arr[k];
1722 return NULL;
1725 static void my_box_identify_fn(deark *c, struct de_boxesctx *bctx)
1727 const struct box_type_info *bti;
1728 lctx *d = (lctx*)bctx->userdata;
1729 struct de_boxdata *curbox = bctx->curbox;
1730 struct de_boxdata *par = curbox->parent;
1731 struct de_boxdata *gpar = NULL;
1732 int is_ilst_child = 0;
1734 if(curbox->boxtype != BOX_uuid) {
1735 curbox->box_name = "?";
1738 if(par) {
1739 gpar = par->parent;
1742 if((par && (par->boxtype==BOX_ilst)) ||
1743 (gpar && (gpar->boxtype==BOX_ilst)) )
1745 is_ilst_child = 1;
1748 if(is_ilst_child) {
1749 bti = find_ilst_box_type_info(c, d, curbox->boxtype);
1751 else {
1752 bti = find_box_type_info(c, d, curbox->boxtype, curbox->level);
1755 if(bti) {
1756 // So that we don't have to run "find" again in my_box_handler(),
1757 // record it here.
1758 curbox->box_userdata = (void*)bti;
1760 if(bti->name) {
1761 curbox->box_name = bti->name;
1764 // TODO: Do we need special handling of 'data' boxes?
1767 static int my_box_handler(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;
1773 if(curbox->is_uuid) {
1774 if(!de_memcmp(curbox->uuid, g_uuid_cr3_85c0, 16)) {
1775 curbox->is_superbox = 1;
1777 else if(!de_memcmp(curbox->uuid, g_uuid_cr3_eaf4, 16)) {
1778 curbox->is_superbox = 1;
1779 curbox->extra_bytes_before_children = 8;
1781 else {
1782 return fmtutil_default_box_handler(c, bctx);
1784 return 1;
1787 bti = (const struct box_type_info *)curbox->box_userdata;
1789 if(bti && (bti->flags2 & 0x1)) {
1790 curbox->is_superbox = 1;
1792 else if(d->is_bmff && curbox->parent && (curbox->parent->boxtype==BOX_ilst)) {
1793 curbox->is_superbox = 1;
1796 if(bti && bti->hfn) {
1797 bti->hfn(c, d, bctx);
1800 return 1;
1803 static void de_run_bmff(deark *c, de_module_params *mparams)
1805 lctx *d = NULL;
1806 struct de_boxesctx *bctx = NULL;
1807 int skip_autodetect = 0;
1808 const char *s;
1810 d = de_malloc(c, sizeof(lctx));
1811 bctx = de_malloc(c, sizeof(struct de_boxesctx));
1813 if(de_havemodcode(c, mparams, 'T')) {
1814 d->is_jpegxt = 1;
1815 skip_autodetect = 1;
1817 if(de_havemodcode(c, mparams, 'X')) {
1818 d->is_jpx = 1;
1819 d->is_jp2_jpx_jpm = 1;
1820 skip_autodetect = 1;
1822 if(de_havemodcode(c, mparams, 'B')) {
1823 d->is_bmff = 1;
1824 skip_autodetect = 1;
1827 if(!skip_autodetect) {
1828 u32 first_boxtype;
1829 // Try to detect old QuickTime files that don't have an ftyp box.
1830 first_boxtype = (u32)de_getu32be(4);
1831 if(first_boxtype==BOX_mdat || first_boxtype==BOX_moov ||
1832 first_boxtype==BOX_free || first_boxtype==BOX_wide ||
1833 first_boxtype==BOX_skip || first_boxtype==BOX_pnot)
1835 d->is_bmff = 1;
1839 s = de_get_ext_option(c, "bmff:maxentries");
1840 if(s) {
1841 d->max_entries_to_print = de_atoi64(s);
1843 else {
1844 d->max_entries_to_print = 32;
1846 if(d->max_entries_to_print<0) {
1847 d->max_entries_to_print = 0;
1850 bctx->userdata = (void*)d;
1851 bctx->f = c->infile;
1852 bctx->identify_box_fn = my_box_identify_fn;
1853 bctx->handle_box_fn = my_box_handler;
1855 fmtutil_read_boxes_format(c, bctx);
1857 de_free(c, bctx);
1858 de_free(c, d);
1861 static int de_identify_jpeg2000(deark *c)
1863 if(!dbuf_memcmp(c->infile, 0, "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a", 12))
1864 return 100;
1865 return 0;
1868 static void de_help_bmff(deark *c)
1870 de_msg(c, "-opt bmff:maxentries=<n> : Number of sample table entries to print with -d");
1873 void de_module_jpeg2000(deark *c, struct deark_module_info *mi)
1875 mi->id = "jpeg2000";
1876 mi->desc = "JPEG 2000 image";
1877 mi->desc2 = "resources only";
1878 mi->run_fn = de_run_bmff;
1879 mi->identify_fn = de_identify_jpeg2000;
1882 static int de_identify_bmff(deark *c)
1884 u32 first_boxtype;
1886 first_boxtype = (u32)de_getu32be(4);
1887 if(first_boxtype==BOX_ftyp) return 80;
1888 if(first_boxtype==BOX_mdat) return 35;
1889 if(first_boxtype==BOX_moov) return 35;
1890 if(first_boxtype==BOX_skip) return 10;
1891 if(first_boxtype==BOX_wide) return 10;
1892 if(first_boxtype==BOX_pnot) return 10;
1893 if(first_boxtype==BOX_free) return 9;
1894 return 0;
1897 void de_module_bmff(deark *c, struct deark_module_info *mi)
1899 mi->id = "bmff";
1900 mi->desc = "ISO Base Media File Format";
1901 mi->desc2 = "MP4, QuickTime, etc.";
1902 mi->id_alias[0] = "mp4";
1903 mi->run_fn = de_run_bmff;
1904 mi->identify_fn = de_identify_bmff;
1905 mi->help_fn = de_help_bmff;