New "ea_data" module
[deark.git] / modules / bpg.c
blob3c0d67e079ee6fb90e0957cc4f8c9e33dd5d369e
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // BPG
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_bpg);
12 typedef struct localctx_struct {
13 i64 width, height;
15 u8 pixel_format;
16 u8 alpha_flag;
17 i64 bit_depth;
19 u8 color_space;
20 u8 extension_present_flag;
21 u8 alpha2_flag;
22 u8 limited_range_flag;
24 i64 picture_data_len;
25 i64 extension_data_len;
27 } lctx;
29 static i64 get_ue7(deark *c, i64 *pos)
31 u8 b;
32 i64 val = 0;
33 int bytecount = 0;
35 // TODO: Better error handling
36 while(1) {
37 b = de_getbyte(*pos);
38 (*pos)++;
39 bytecount++;
41 // A quick hack to prevent 64-bit integer overflow.
42 // 5 bytes are enough for 35 bits, and none of the fields in
43 // BPG v0.9.4.1 require more than 32.
44 if(bytecount<=5)
45 val = (val<<7)|(b&0x7f);
47 if(b<0x80) {
48 break;
51 return val;
54 static void do_exif(deark *c, lctx *d, i64 pos1, i64 len1)
56 u8 buf[3];
57 i64 pos = pos1;
58 i64 len = len1;
60 if(len1<8) return;
61 de_read(buf, pos1, 3);
62 if(buf[0]==0 && (buf[1]=='M' || buf[1]=='I') && buf[2]==buf[1]) {
63 de_warn(c, "Ignoring initial NUL byte in Exif data (libbpg bug?)");
64 pos++;
65 len--;
67 fmtutil_handle_exif(c, pos, len);
70 static void do_extensions(deark *c, lctx *d, i64 pos)
72 i64 endpos;
73 i64 tag;
74 i64 payload_len;
76 endpos = pos + d->extension_data_len;
78 while(pos < endpos) {
79 tag = get_ue7(c, &pos);
80 payload_len = get_ue7(c, &pos);
81 if(pos+payload_len>endpos) break;
83 switch(tag) {
84 case 1: // Exif
85 do_exif(c, d, pos, payload_len);
86 break;
87 case 2: // ICC profile
88 dbuf_create_file_from_slice(c->infile, pos, payload_len, "icc", NULL, DE_CREATEFLAG_IS_AUX);
89 break;
90 case 3: // XMP
91 dbuf_create_file_from_slice(c->infile, pos, payload_len, "xmp", NULL, DE_CREATEFLAG_IS_AUX);
92 break;
93 case 4: // Thumbnail
94 dbuf_create_file_from_slice(c->infile, pos, payload_len, "thumb.bpg", NULL, DE_CREATEFLAG_IS_AUX);
95 break;
96 default:
97 de_dbg(c, "unrecognized extension type: %d", (int)tag);
100 pos += payload_len;
104 static void do_hevc_file(deark *c, lctx *d)
106 i64 pos;
107 u8 b;
109 pos = 4;
110 b = de_getbyte(pos);
111 pos++;
112 d->pixel_format = b>>5;
113 d->alpha_flag = (b>>4)&0x01;
114 d->bit_depth = (i64)(b&0x0f) +8;
115 de_dbg(c, "pixel format: %d", (int)d->pixel_format);
116 de_dbg(c, "alpha flag: %d", (int)d->alpha_flag);
117 de_dbg(c, "bit depth: %d", (int)d->bit_depth);
119 b = de_getbyte(pos);
120 pos++;
121 d->color_space = b>>4;
122 d->extension_present_flag = (b>>3)&0x01;
123 d->alpha2_flag = (b>>2)&0x01;
124 d->limited_range_flag = (b>>1)&0x01;
125 de_dbg(c, "color_space: %d", (int)d->color_space);
126 de_dbg(c, "extension_present_flag: %d", (int)d->extension_present_flag);
127 de_dbg(c, "alpha2_flag: %d", (int)d->alpha2_flag);
128 de_dbg(c, "limited_range_flag: %d", (int)d->limited_range_flag);
130 d->width = get_ue7(c, &pos);
131 d->height = get_ue7(c, &pos);
132 de_dbg_dimensions(c, d->width, d->height);
135 d->picture_data_len = get_ue7(c, &pos);
136 de_dbg(c, "picture_data_len: %d%s", (int)d->picture_data_len,
137 (d->picture_data_len==0)?" (= to EOF)":"");
139 if(d->extension_present_flag) {
140 d->extension_data_len = get_ue7(c, &pos);
141 de_dbg(c, "extension data len: %d", (int)d->extension_data_len);
144 if(d->extension_present_flag) {
145 do_extensions(c, d, pos);
146 pos += d->extension_data_len;
149 de_dbg(c, "hevc_header_and_data begins at %d", (int)pos);
152 static void de_run_bpg(deark *c, de_module_params *mparams)
154 lctx *d = NULL;
156 d = de_malloc(c, sizeof(lctx));
158 do_hevc_file(c, d);
160 de_free(c, d);
163 static int de_identify_bpg(deark *c)
165 if(!dbuf_memcmp(c->infile, 0, "\x42\x50\x47\xfb", 4)) {
166 return 100;
168 return 0;
171 void de_module_bpg(deark *c, struct deark_module_info *mi)
173 mi->id = "bpg";
174 mi->desc = "BPG (Better Portable Graphics)";
175 mi->desc2 = "resources only";
176 mi->run_fn = de_run_bpg;
177 mi->identify_fn = de_identify_bpg;