1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // GEM VDI Metafile (.gem)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_gemmeta
);
11 typedef struct localctx_struct
{
21 // "Function sub-ID". This is also confusingly called "sub-opcode", but
22 // "sub-opcode" means something entirely different with respect to opcode 5.
25 i64 ptsin_count
, intin_count
;
28 typedef void (*record_decoder_fn
)(deark
*c
, lctx
*d
, struct opcode_data
*op
);
36 static void do_opcode_5(deark
*c
, lctx
*d
, struct opcode_data
*op
);
37 static void do_opcode_11(deark
*c
, lctx
*d
, struct opcode_data
*op
);
39 static const struct opcode_info opcode_info_arr
[] = {
40 // This list is not intended to be complete.
41 { 5, "Escape", do_opcode_5
},
42 { 6, "Polyline", NULL
},
43 { 9, "Filled area", NULL
},
44 { 11, "GDP", do_opcode_11
},
45 { 13, "Set character baseline vector", NULL
},
46 { 15, "Set polyline linetype", NULL
},
47 { 16, "Set polyline line width", NULL
},
48 { 17, "Set polyline color index", NULL
},
49 { 18, "Set polymarker type", NULL
},
50 { 19, "Set polymarker height", NULL
},
51 { 20, "Set polymarker color index", NULL
},
52 { 21, "Set text face", NULL
},
53 { 22, "Set graphic text color index", NULL
},
54 { 23, "Set fill interior style", NULL
},
55 { 24, "Set fill style index", NULL
},
56 { 25, "Set fill color index", NULL
},
57 { 32, "Set writing mode", NULL
},
58 { 39, "Set graphic text alignment", NULL
},
59 { 104, "Set fill perimeter visibility", NULL
},
60 { 106, "Set graphic text special effects", NULL
},
61 { 107, "Set character cell height, points mode", NULL
},
62 { 108, "Set polyline end styles", NULL
},
63 { 112, "Set user defined fill pattern", NULL
},
64 { 0xffff, "EOF", NULL
},
65 { 0x0000, NULL
, NULL
}
68 static void do_opcode_5(deark
*c
, lctx
*d
, struct opcode_data
*op
)
73 if(op
->func_id
!=99) return;
74 if(op
->intin_count
<1) return;
75 sub_opcode_id
= de_getu16le(op
->intin_pos
);
77 switch(sub_opcode_id
) {
78 case 10: name
="Start Group"; break;
79 case 11: name
="End Group"; break;
80 case 49: name
="Set No Line Style"; break;
81 case 50: name
="Set Attribute Shadow On"; break;
82 case 51: name
="Set Attribute Shadow Off"; break;
83 case 80: name
="Start Draw Area Type Primitive"; break;
84 case 81: name
="End Draw Area Type Primitive"; break;
86 if(sub_opcode_id
>100) {
87 name
="for developer use";
94 de_dbg(c
, "sub-opcode id: %d (%s)", (int)sub_opcode_id
, name
);
97 static void do_opcode_11(deark
*c
, lctx
*d
, struct opcode_data
*op
)
101 switch(op
->func_id
) {
102 case 1: name
="Bar"; break;
103 case 2: name
="Arc"; break;
104 case 3: name
="Pie"; break;
105 case 4: name
="Circle"; break;
106 case 5: name
="Ellipse"; break;
107 case 6: name
="Elliptical arc"; break;
108 case 7: name
="Elliptical Pie"; break;
109 case 8: name
="Rounded rectangle"; break;
110 case 9: name
="Filled rounded rectangle"; break;
111 case 10: name
="Jutified graphic text"; break;
112 default: name
="?"; break;
115 de_dbg(c
, "function: %s", name
);
118 static const struct opcode_info
*find_opcode_info(i64 opcode
)
122 for(i
=0; opcode_info_arr
[i
].name
!=NULL
; i
++) {
123 if(opcode_info_arr
[i
].opcode
== opcode
) {
124 return &opcode_info_arr
[i
];
130 // Returns 0 if we should stop reading the file.
131 static int do_record(deark
*c
, lctx
*d
, i64 pos
, i64
*bytesused
)
134 struct opcode_data op
;
135 i64 ptsin_size_bytes
;
136 i64 intin_size_bytes
;
138 const struct opcode_info
*opinfo
;
139 const char *opcode_name
;
142 de_zeromem(&op
, sizeof(struct opcode_data
));
144 de_dbg(c
, "record at %d", (int)pos
);
147 op
.opcode
= de_getu16le(pos
);
148 op
.ptsin_count
= de_getu16le(pos
+2);
149 op
.intin_count
= de_getu16le(pos
+4);
150 op
.func_id
= de_getu16le(pos
+6);
152 ptsin_size_bytes
= 4*op
.ptsin_count
;
153 intin_size_bytes
= 2*op
.intin_count
;
154 data_size_bytes
= ptsin_size_bytes
+ intin_size_bytes
;
156 op
.ptsin_pos
= pos
+ 8;
157 op
.intin_pos
= pos
+ 8 + ptsin_size_bytes
;
159 opinfo
= find_opcode_info(op
.opcode
);
160 if(opinfo
&& opinfo
->name
)
161 opcode_name
= opinfo
->name
;
165 de_dbg(c
, "opcode=%d (%s), func_id=%d, #pts=%d, #int=%d (dlen=%d)",
166 (int)op
.opcode
, opcode_name
, (int)op
.func_id
,
167 (int)op
.ptsin_count
, (int)op
.intin_count
,
168 (int)data_size_bytes
);
170 *bytesused
= 8 + data_size_bytes
;
172 if(opinfo
&& opinfo
->fn
) {
173 opinfo
->fn(c
, d
, &op
);
176 if(op
.opcode
==65535) {
182 de_dbg_indent(c
, -1);
186 static void de_run_gemmeta(deark
*c
, de_module_params
*mparams
)
195 d
= de_malloc(c
, sizeof(lctx
));
198 hdrlen_words
= de_getu16le(pos
+2);
199 de_dbg(c
, "header length: %d words", (int)hdrlen_words
);
200 version
= de_getu16le(pos
+4);
201 de_dbg(c
, "version number: %d", (int)version
);
202 // TODO: Read more header fields.
203 imgflag
= de_getu16le(pos
+28);
204 de_dbg(c
, "image flag: %d", (int)imgflag
);
206 pos
+= hdrlen_words
*2;
209 if(pos
>= c
->infile
->len
) break;
210 if(!do_record(c
, d
, pos
, &bytesused
)) break;
211 if(bytesused
<=0) break;
217 static int de_identify_gemmeta(deark
*c
)
219 // FIXME: This will not identify all files.
220 if(!dbuf_memcmp(c
->infile
, 0, "\xff\xff\x18\x00", 4))
225 void de_module_gemmeta(deark
*c
, struct deark_module_info
*mi
)
228 mi
->desc
= "GEM VDI Metafile";
229 mi
->run_fn
= de_run_gemmeta
;
230 mi
->identify_fn
= de_identify_gemmeta
;