iccprofile: Decode 'dict' data type
[deark.git] / modules / afcp.c
blob8e90d4b06e95e5cd05d610fb8abaff5a70420bec
1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // AFCP metadata
6 // (AXS File Concatenation Protocol)
8 #include <deark-config.h>
9 #include <deark-private.h>
10 #include <deark-fmtutil.h>
11 DE_DECLARE_MODULE(de_module_afcp);
13 #define CODE_IPTC 0x49505443U
14 #define CODE_Nail 0x4e61696cU
15 #define CODE_PrVw 0x50725677U
17 struct afcpctx {
18 int is_le;
19 u8 endian_code;
20 i64 endpos;
21 i64 start_tag_offs;
22 i64 record_count;
25 struct afcprecord {
26 i64 dlen;
27 i64 dpos;
28 struct de_fourcc id4cc;
31 static int do_afcprec_thumbnail(deark *c, struct afcpctx *d, struct afcprecord *ar)
33 unsigned int recver;
34 i64 pos = ar->dpos;
35 i64 w, h;
36 i64 foundpos = 0;
37 struct de_fourcc imgtype;
38 const char *ext;
39 int ret;
40 int retval = 0;
42 if(ar->dlen<10) goto done;
43 recver = (unsigned int)dbuf_getu16x(c->infile, pos, d->is_le);
44 pos += 2;
45 de_dbg(c, "record version: %u", recver);
46 if(recver!=1) goto done;
48 w = dbuf_getu16x(c->infile, pos, d->is_le);
49 pos += 2;
50 h = dbuf_getu16x(c->infile, pos, d->is_le);
51 pos += 2;
52 de_dbg(c, "reported dimensions: %d"DE_CHAR_TIMES"%d", (int)w, (int)h);
53 // Nothing after this point is adequately documented in the spec.
55 dbuf_read_fourcc(c->infile, pos, &imgtype, 4, 0);
56 pos += 4;
57 de_dbg(c, "image type: '%s'", imgtype.id_dbgstr);
59 ret = dbuf_search(c->infile, (const u8*)"\xff\xd8\xff", 3, pos,
60 ar->dpos + ar->dlen - pos, &foundpos);
61 if(!ret) {
62 de_dbg(c, "[failed to find thumbnail image data]");
63 goto done;
65 if(ar->id4cc.id==CODE_PrVw) ext = "afcppreview.jpg";
66 else ext = "afcpthumb.jpg";
67 dbuf_create_file_from_slice(c->infile, foundpos, ar->dpos + ar->dlen - foundpos, ext,
68 NULL, DE_CREATEFLAG_IS_AUX);
70 retval = 1;
71 done:
72 return retval;
75 static void do_afcp_record(deark *c, struct afcpctx *d, i64 pos)
77 struct afcprecord *ar = NULL;
79 ar = de_malloc(c, sizeof(struct afcprecord));
80 dbuf_read_fourcc(c->infile, pos, &ar->id4cc, 4, 0);
81 de_dbg(c, "id: '%s'", ar->id4cc.id_dbgstr);
82 ar->dlen = dbuf_getu32x(c->infile, pos+4, d->is_le);
83 de_dbg(c, "dlen: %"I64_FMT, ar->dlen);
84 ar->dpos = dbuf_getu32x(c->infile, pos+8, d->is_le);
85 de_dbg(c, "dpos: %"I64_FMT, ar->dpos);
86 if(ar->dpos<d->start_tag_offs || ar->dpos+ar->dlen>d->endpos) goto done;
88 if(ar->id4cc.id==CODE_IPTC) {
89 de_dbg(c, "IPTC-IIM data");
90 de_dbg_indent(c, 1);
91 fmtutil_handle_iptc(c, c->infile, ar->dpos, ar->dlen, 0x0);
92 de_dbg_indent(c, -1);
94 else if(ar->id4cc.id==CODE_Nail || ar->id4cc.id==CODE_PrVw) {
95 do_afcprec_thumbnail(c, d, ar);
97 else {
98 if(c->debug_level>=2) {
99 de_dbg_hexdump(c, c->infile, ar->dpos, ar->dlen, 256, NULL, 0x1);
102 done:
103 de_free(c, ar);
106 static void do_afcp_recordlist(deark *c, struct afcpctx *d)
108 int saved_indent_level;
109 i64 pos;
110 i64 i;
112 de_dbg_indent_save(c, &saved_indent_level);
113 pos = d->start_tag_offs + 12;
114 de_dbg(c, "record list at %"I64_FMT, pos);
116 de_dbg_indent(c, 1);
117 for(i=0; i<d->record_count; i++) {
118 if(i+12 > d->endpos) goto done;
119 de_dbg(c, "record[%d] at %"I64_FMT, (int)i, pos);
120 de_dbg_indent(c, 1);
121 do_afcp_record(c, d, pos);
122 de_dbg_indent(c, -1);
123 pos += 12;
126 done:
127 de_dbg_indent_restore(c, saved_indent_level);
130 static int do_afcp_starttagrec(deark *c, struct afcpctx *d)
132 int retval = 0;
133 int saved_indent_level;
134 unsigned int version;
136 de_dbg_indent_save(c, &saved_indent_level);
137 de_dbg(c, "start tag record at %"I64_FMT, d->start_tag_offs);
138 de_dbg_indent(c, 1);
139 if(de_getbyte(d->start_tag_offs+3)!=d->endian_code) {
140 de_err(c, "AFCP start tag not found at %"I64_FMT, d->start_tag_offs);
141 goto done;
143 version = (unsigned int)dbuf_getu16x(c->infile, d->start_tag_offs+4, d->is_le);
144 de_dbg(c, "version: %u", version);
145 d->record_count = dbuf_getu16x(c->infile, d->start_tag_offs+6, d->is_le);
146 de_dbg(c, "record count: %d", (int)d->record_count);
148 if(version>1) {
149 de_warn(c, "Unexpected AFCP version number: %u", version);
152 retval = 1;
153 done:
154 de_dbg_indent_restore(c, saved_indent_level);
155 return retval;
158 static int do_afcp_eofrec(deark *c, struct afcpctx *d)
160 i64 eofrecpos;
161 int retval = 0;
162 int saved_indent_level;
164 de_dbg_indent_save(c, &saved_indent_level);
166 eofrecpos = d->endpos - 12;
167 de_dbg(c, "EOF record at %"I64_FMT, eofrecpos);
168 de_dbg_indent(c, 1);
169 d->endian_code = de_getbyte(eofrecpos+3);
170 if(d->endian_code=='*') d->is_le = 1;
171 else if(d->endian_code=='!') d->is_le = 0;
172 else {
173 de_err(c, "Invalid AFCP format");
174 goto done;
176 de_dbg(c, "is-little-endian: %d", d->is_le);
178 d->start_tag_offs = dbuf_getu32x(c->infile, eofrecpos+4, d->is_le);
179 de_dbg(c, "start tag offset: %"I64_FMT, d->start_tag_offs);
181 retval = 1;
182 done:
183 de_dbg_indent_restore(c, saved_indent_level);
184 return retval;
187 static void de_run_afcp(deark *c, de_module_params *mparams)
189 struct afcpctx *d = NULL;
190 int saved_indent_level;
192 de_dbg_indent_save(c, &saved_indent_level);
193 d = de_malloc(c, sizeof(struct afcpctx));
194 d->endpos = c->infile->len;
195 de_dbg(c, "AFCP data, ending at %"I64_FMT, d->endpos);
196 de_dbg_indent(c, 1);
198 if(!do_afcp_eofrec(c, d)) goto done;
199 if(!do_afcp_starttagrec(c, d)) goto done;
200 do_afcp_recordlist(c, d);
202 done:
203 de_free(c, d);
204 de_dbg_indent_restore(c, saved_indent_level);
207 void de_module_afcp(deark *c, struct deark_module_info *mi)
209 mi->id = "afcp";
210 mi->desc = "AXS File Concatenation Protocol";
211 mi->run_fn = de_run_afcp;
212 mi->flags |= DE_MODFLAG_HIDDEN;