zip: Better parsing of Info-ZIP type 1 extra field
[deark.git] / modules / portfolio.c
blob2978d072641e3481faac25c77b73a86a6392614a
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Portfolio graphics formats:
6 // * PGF
7 // * PGC
8 // * PGX (Portfolio animation)
10 #include <deark-config.h>
11 #include <deark-private.h>
12 DE_DECLARE_MODULE(de_module_pgx);
13 DE_DECLARE_MODULE(de_module_pf_pgf);
14 DE_DECLARE_MODULE(de_module_pgc);
16 typedef struct localctx_struct {
17 u8 version;
18 } lctx;
20 static void do_pgc_in_pgx(deark *c, lctx *d, i64 pos, i64 len)
22 dbuf *f = NULL;
24 f = dbuf_create_output_file(c, "pgc", NULL, 0);
26 // Embedded PGC files don't include the 3-byte PGC header, so we have to add that.
27 dbuf_write(f, (const unsigned char*)"PG\x01", 3);
29 // Copy the rest of the PGC file.
30 dbuf_copy(c->infile, pos, len, f);
32 dbuf_close(f);
35 static int do_process_frame(deark *c, lctx *d, i64 pos1, i64 *bytes_consumed)
37 i64 pos;
38 u8 frame_type;
39 i64 frame_payload_size;
40 int retval = 1;
42 *bytes_consumed = 0;
43 pos = pos1;
45 de_dbg(c, "frame at %d", (int)pos1);
46 de_dbg_indent(c, 1);
48 // 8-byte frame header
49 frame_type = de_getbyte(pos);
50 de_dbg(c, "type: %d", (int)frame_type);
52 frame_payload_size = de_getu16le(pos+1);
53 de_dbg(c, "reported payload size: %d", (int)frame_payload_size);
55 *bytes_consumed += 8;
56 pos += 8;
57 if(pos + frame_payload_size > c->infile->len) {
58 de_err(c, "Frame goes beyond end of file");
59 retval = 0;
60 goto done;
63 switch(frame_type) {
64 case 0x00: // PGC
65 do_pgc_in_pgx(c, d, pos, frame_payload_size);
66 *bytes_consumed += frame_payload_size;
67 break;
69 case 0x01:
70 de_warn(c, "PGT frames (text screen dumps) are not supported");
72 // The spec contradicts itself about how to figure out the frame
73 // payload size of PGT frames. First it says the size field is not
74 // used. The it says it *is* used, and is expected to always be 320.
75 // In the only example file I have, it is 317, though the actual size
76 // of the frame in that file is 320.
77 *bytes_consumed += 320;
79 break;
81 case 0xfe: // APPS
82 *bytes_consumed += frame_payload_size;
83 break;
85 case 0xff: // EOF
86 retval = 0;
87 break;
89 default:
90 de_err(c, "Unknown frame type (%d)", (int)frame_type);
91 retval = 0;
92 break;
95 done:
96 de_dbg_indent(c, -1);
97 return retval;
100 static void de_run_pgx(deark *c, de_module_params *mparams)
102 lctx *d = NULL;
103 i64 pos;
104 i64 frame_size;
105 int ret;
106 int executable = 0;
108 if(dbuf_memcmp(c->infile, 0, "PGX", 3)) {
109 // Some "PGX" files are actually .COM files with an embedded PGX file.
110 // The ones I've seen always have the PGX file at offset 1248, so look
111 // for it there.
112 if(dbuf_memcmp(c->infile, 0, "PGX", 1248)) {
113 executable = 1;
117 if(executable) {
118 de_declare_fmt(c, "PGX (Portfolio Animation, executable)");
119 pos = 1248;
121 else{
122 de_declare_fmt(c, "PGX (Portfolio Animation)");
123 pos = 0;
126 d = de_malloc(c, sizeof(lctx));
128 d->version = de_getbyte(pos+3);
129 de_dbg(c, "Version: %d", (int)d->version);
131 pos += 8;
132 while(1) {
133 if(pos >= c->infile->len) break;
134 ret = do_process_frame(c, d, pos, &frame_size);
135 if(!ret || !frame_size) break;
136 pos += frame_size;
139 de_free(c, d);
142 static int de_identify_pgx(deark *c)
144 if(!dbuf_memcmp(c->infile, 0, "PGX", 3))
145 return 90;
146 return 0;
149 void de_module_pgx(deark *c, struct deark_module_info *mi)
151 mi->id = "pgx";
152 mi->desc = "Atari Portfolio animation";
153 mi->run_fn = de_run_pgx;
154 mi->identify_fn = de_identify_pgx;
157 // **************************************************************************
158 // Portfolio PGF
159 // **************************************************************************
161 static void de_run_pf_pgf(deark *c, de_module_params *mparams)
163 de_declare_fmt(c, "PGF (Portfolio graphics)");
164 de_convert_and_write_image_bilevel(c->infile, 0, 240, 64, 240/8,
165 DE_CVTF_WHITEISZERO, NULL, 0);
168 static int de_identify_pf_pgf(deark *c)
170 if(c->infile->len != 1920) return 0;
171 if(!de_input_file_has_ext(c, "pgf")) return 0;
172 return 90;
175 void de_module_pf_pgf(deark *c, struct deark_module_info *mi)
177 mi->id = "pf_pgf";
178 mi->desc = "Atari Portfolio Graphics - uncompressed";
179 mi->run_fn = de_run_pf_pgf;
180 mi->identify_fn = de_identify_pf_pgf;
183 // **************************************************************************
184 // PGC - Portfolio graphics compressed
185 // **************************************************************************
187 static void de_run_pgc(deark *c, de_module_params *mparams)
189 dbuf *unc_pixels = NULL;
190 i64 pos;
191 i64 count;
192 u8 b, b2;
194 de_declare_fmt(c, "PGC (Portfolio graphics compressed)");
195 unc_pixels = dbuf_create_membuf(c, 1920, 1);
197 pos = 3;
198 while(pos<c->infile->len) {
199 b = de_getbyte(pos);
200 pos++;
201 count = (i64)(b & 0x7f);
202 if(b & 0x80) {
203 // compressed run
204 b2 = de_getbyte(pos);
205 pos++;
206 dbuf_write_run(unc_pixels, b2, count);
208 else {
209 // uncompressed run
210 dbuf_copy(c->infile, pos, count, unc_pixels);
211 pos += count;
215 de_convert_and_write_image_bilevel(unc_pixels, 0, 240, 64, 240/8,
216 DE_CVTF_WHITEISZERO, NULL, 0);
217 dbuf_close(unc_pixels);
220 static int de_identify_pgc(deark *c)
222 if(!dbuf_memcmp(c->infile, 0, "PG\x01", 3)) {
223 return 100;
225 return 0;
228 void de_module_pgc(deark *c, struct deark_module_info *mi)
230 mi->id = "pgc";
231 mi->desc = "Atari Portfolio Graphics - compressed";
232 mi->run_fn = de_run_pgc;
233 mi->identify_fn = de_identify_pgc;