riff: Basic support for extracting RDIB images
[deark.git] / modules / drhalo.c
blob2ee39ad354901a18e775a7540eb708f7c36bebbe
1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // Dr. Halo .CUT image
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_drhalocut);
11 typedef struct localctx_struct {
12 i64 w, h;
13 int have_pal;
14 i64 pal_entries;
15 u32 pal[256];
16 } lctx;
18 static int do_read_header(deark *c, lctx *d)
20 d->w = de_getu16le(0);
21 d->h = de_getu16le(2);
22 de_dbg_dimensions(c, d->w, d->h);
23 if(!de_good_image_dimensions(c, d->w, d->h)) return 0;
24 return 1;
27 static int do_decompress_scanline(deark *c, lctx *d, i64 line_idx,
28 i64 pos1, i64 len, dbuf *unc_pixels)
30 u8 b, b2;
31 i64 count;
32 i64 pos = pos1;
33 i64 opos1 = unc_pixels->len;
35 while(1) {
36 if((pos-pos1) >= len) break;
38 b = de_getbyte(pos++);
40 if(b==0 || b==0x80) { // end of row
41 break;
43 else if(b & 0x80) { // RLE block
44 count = (i64)(b - 0x80);
45 b2 = dbuf_getbyte(c->infile, pos++);
46 dbuf_write_run(unc_pixels, b2, count);
48 else { // uncompressed block
49 count = (i64)b;
50 dbuf_copy(c->infile, pos, count, unc_pixels);
51 pos += count;
55 de_dbg3(c, "scanline[%d]: decompressed %d bytes (expected %d) to %d bytes",
56 (int)line_idx, (int)(pos-pos1),
57 (int)len, (int)(unc_pixels->len - opos1));
58 return 1;
61 static int do_decompress(deark *c, lctx *d, i64 pos1, dbuf *unc_pixels)
63 i64 j;
64 i64 pos = pos1;
66 for(j=0; j<d->h; j++) {
67 i64 linebytecount;
69 // Make sure we're at the right place in the uncompressed pixels.
70 dbuf_truncate(unc_pixels, j*d->w);
72 if(pos > c->infile->len-2) break;
73 linebytecount = de_getu16le(pos);
74 pos += 2;
75 do_decompress_scanline(c, d, j, pos, linebytecount, unc_pixels);
76 pos += linebytecount;
79 de_dbg(c, "decompressed %d bytes to %d bytes",
80 (int)(pos-pos1), (int)unc_pixels->len);
82 return 1;
85 static void do_write_image_gray(deark *c, lctx *d, dbuf *unc_pixels)
87 de_bitmap *img = NULL;
88 i64 i, j;
89 u8 b;
90 i64 k;
91 u8 max_val;
93 max_val = 0;
94 for(k=0; k<unc_pixels->len; k++) {
95 b = dbuf_getbyte(unc_pixels, k);
96 if(b > max_val)
97 max_val = b;
99 de_dbg(c, "detected max val: %d", (int)max_val);
100 if(max_val<1) max_val=1;
102 img = de_bitmap_create(c, d->w, d->h, 1);
104 for(j=0; j<d->h; j++) {
105 for(i=0; i<d->w; i++) {
106 b = dbuf_getbyte(unc_pixels, j*d->w + i);
107 b = de_scale_n_to_255(max_val, (i64)b);
108 de_bitmap_setpixel_gray(img, i, j, b);
112 de_bitmap_write_to_file(img, NULL, 0);
113 de_bitmap_destroy(img);
116 static void do_write_image_pal(deark *c, lctx *d, dbuf *unc_pixels)
118 de_bitmap *img = NULL;
119 i64 i, j;
120 u8 b;
122 img = de_bitmap_create(c, d->w, d->h, 3);
124 for(j=0; j<d->h; j++) {
125 for(i=0; i<d->w; i++) {
126 b = dbuf_getbyte(unc_pixels, j*d->w + i);
127 de_bitmap_setpixel_rgb(img, i, j, d->pal[(unsigned int)b]);
131 de_bitmap_write_to_file(img, NULL, 0);
132 de_bitmap_destroy(img);
135 static int do_read_pal_file(deark *c, lctx *d, const char *palfn)
137 dbuf *palfile = NULL;
138 i64 pos;
139 i64 sig;
140 i64 filever;
141 i64 datasize;
142 i64 k, z;
143 i64 num_entries;
144 i64 maxidx;
145 i64 maxsamp[3];
146 unsigned int board_id;
147 unsigned int graphics_mode;
148 u8 filetype;
149 u8 filesubtype;
150 i64 osamp[3];
151 u8 samp[3];
152 int retval = 0;
153 char tmps[64];
155 de_dbg(c, "palette file");
156 de_dbg_indent(c, 1);
158 palfile = dbuf_open_input_file(c, palfn);
159 if(!palfile) {
160 goto done;
163 sig = dbuf_getu16le(palfile, 0);
164 filever = dbuf_getu16le(palfile, 2);
165 de_dbg(c, "file version: %d", (int)filever);
166 datasize = dbuf_getu16le(palfile, 4);
167 de_dbg(c, "data size: %d", (int)datasize);
168 filetype = dbuf_getbyte(palfile, 6);
169 de_dbg(c, "file type: 0x%02x", (unsigned int)filever);
170 filesubtype = dbuf_getbyte(palfile, 7);
171 de_dbg(c, "file subtype: 0x%02x", (unsigned int)filesubtype);
173 if(sig!=0x4841 /* "HA" */ || filetype!=0x0a) {
174 de_err(c, "Invalid palette file");
175 goto done;
178 board_id = (unsigned int)dbuf_getu16le(palfile, 8);
179 de_dbg(c, "board id: 0x%04x", board_id);
180 graphics_mode = (unsigned int)dbuf_getu16le(palfile, 10);
181 de_dbg(c, "graphics mode: 0x%04x", graphics_mode);
183 if(filesubtype!=0) {
184 de_warn(c, "Hardware-specific palettes are not supported");
185 retval = 1;
186 goto done;
189 maxidx = dbuf_getu16le(palfile, 0x0c);
190 de_dbg(c, "maxidx: %u", (unsigned int)maxidx);
192 for(k=0; k<3; k++) {
193 maxsamp[k] = dbuf_getu16le(palfile, 0x0e + 2*k);
194 de_dbg(c, "maxsamp[%d]: %u", (int)k, (unsigned int)maxsamp[k]);
195 if(maxsamp[k]<1) maxsamp[k]=1;
198 pos = 0x14;
200 pos += 20; // Skip palette name TODO: Display this
202 num_entries = maxidx+1;
203 if(num_entries>256) num_entries=256;
205 for(k=0; k<num_entries; k++) {
206 // As far as I can tell:
207 // If we imagine the palette file being split into 512-byte chunks, a
208 // (6-byte) palette entry is not allowed to cross a chunk boundary.
209 // If an entry would do so, it instead starts at the beginning of the
210 // next chunk.
211 while((pos%512) > 506) {
212 pos += 2;
215 for(z=0; z<3; z++) {
216 osamp[z] = dbuf_getu16le(palfile, pos);
217 pos += 2;
218 samp[z] = de_scale_n_to_255(maxsamp[z], osamp[z]);
220 d->pal[k] = DE_MAKE_RGB(samp[0], samp[1], samp[2]);
222 de_snprintf(tmps, sizeof(tmps), "(%5d,%5d,%5d) "DE_CHAR_RIGHTARROW" ",
223 (int)osamp[0], (int)osamp[1], (int)osamp[2]);
224 de_dbg_pal_entry2(c, k, d->pal[k], tmps, NULL, NULL);
227 d->have_pal = 1;
228 retval = 1;
229 done:
230 dbuf_close(palfile);
231 de_dbg_indent(c, -1);
232 return retval;
235 static void de_run_drhalocut(deark *c, de_module_params *mparams)
237 lctx *d = NULL;
238 i64 pos;
239 dbuf *unc_pixels = NULL;
240 const char *palfn;
242 d = de_malloc(c, sizeof(lctx));
244 palfn = de_get_ext_option(c, "file2");
245 if(palfn) {
246 if(!do_read_pal_file(c, d, palfn)) goto done;
249 pos = 0;
250 if(!do_read_header(c, d)) goto done;
251 pos += 6;
253 unc_pixels = dbuf_create_membuf(c, d->w*d->h, 0x1);
254 if(!do_decompress(c, d, pos, unc_pixels)) goto done;
256 if(d->have_pal)
257 do_write_image_pal(c, d, unc_pixels);
258 else
259 do_write_image_gray(c, d, unc_pixels);
261 done:
262 dbuf_close(unc_pixels);
263 de_free(c, d);
266 static int de_identify_drhalocut(deark *c)
268 if(de_input_file_has_ext(c, "cut")) return 10;
269 return 0;
272 static void de_help_drhalocut(deark *c)
274 de_msg(c, "-file2 <file.pal> : Read the palette from this file");
277 void de_module_drhalocut(deark *c, struct deark_module_info *mi)
279 mi->id = "drhalocut";
280 mi->desc = "Dr. Halo .CUT image";
281 mi->run_fn = de_run_drhalocut;
282 mi->identify_fn = de_identify_drhalocut;
283 mi->help_fn = de_help_drhalocut;