zip: Better parsing of Info-ZIP type 1 extra field
[deark.git] / modules / msp.c
blob14a6bc6d5ff88a1189c34a7fbef2cc076dfd9a15
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Microsoft Paint
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_msp);
11 typedef struct localctx_struct {
12 int ver; // 1 or 2
13 i64 width, height;
14 dbuf *rowbuf;
15 } lctx;
17 static void do_ver1(deark *c, lctx *d)
19 i64 src_rowspan;
21 // TODO: Are version-1 MSP files padded this way?
22 // (Maybe the width is always a multiple of 8, so it doesn't matter.)
23 src_rowspan = (d->width+7)/8;
25 de_convert_and_write_image_bilevel(c->infile, 32,
26 d->width, d->height, src_rowspan, 0, NULL, 0);
29 static void do_decompress_scanline(deark *c, lctx *d, de_bitmap *img,
30 i64 rownum, i64 rowoffset, i64 bytes_in_row)
32 i64 i;
33 u8 runtype;
34 i64 runcount;
35 u8 value;
37 de_dbg2(c, "decompressing row %d", (int)rownum);
39 if(!d->rowbuf) {
40 d->rowbuf = dbuf_create_membuf(c, (d->width+7)/8, 1);
43 dbuf_empty(d->rowbuf);
45 // Read the compressed data byte by byte
46 i = 0;
47 while(i<bytes_in_row) {
48 runtype = de_getbyte(rowoffset+i);
49 i++;
50 if(runtype==0x00) {
51 runcount = (i64)de_getbyte(rowoffset+i);
52 i++;
53 value = de_getbyte(rowoffset+i);
54 i++;
55 // write value runcount times
56 de_dbg2(c, "compressed, %d bytes of %d", (int)runcount, value);
57 dbuf_write_run(d->rowbuf, value, runcount);
59 else {
60 runcount = (i64)runtype;
61 de_dbg2(c, "%d bytes uncompressed", (int)runcount);
62 dbuf_copy(c->infile, rowoffset+i, runcount, d->rowbuf);
63 i+=runcount;
67 de_convert_row_bilevel(d->rowbuf, 0, img, rownum, 0);
70 static void do_ver2(deark *c, lctx *d)
72 i64 j;
73 i64 *rowoffset;
74 i64 *rowsize;
75 de_bitmap *img = NULL;
77 rowoffset = de_mallocarray(c, d->height, sizeof(i64));
78 rowsize = de_mallocarray(c, d->height, sizeof(i64));
80 // Read the scanline map, and record the row sizes.
81 for(j=0; j<d->height; j++) {
82 rowsize[j] = de_getu16le(32+2*j);
85 // Calculate the position, in the file, of each row.
86 for(j=0; j<d->height; j++) {
87 if(j==0)
88 rowoffset[j] = 32 + 2*d->height;
89 else
90 rowoffset[j] = rowoffset[j-1] + rowsize[j-1];
91 de_dbg2(c, "row %d offset=%d size=%d", (int)j, (int)rowoffset[j], (int)rowsize[j]);
94 img = de_bitmap_create(c, d->width, d->height, 1);
96 for(j=0; j<d->height; j++) {
97 do_decompress_scanline(c, d, img, j, rowoffset[j], rowsize[j]);
100 de_bitmap_write_to_file(img, NULL, 0);
102 de_free(c, rowsize);
103 de_free(c, rowoffset);
104 dbuf_close(d->rowbuf);
105 d->rowbuf = NULL;
106 de_bitmap_destroy(img);
109 static void de_run_msp(deark *c, de_module_params *mparams)
111 lctx *d;
113 d = de_malloc(c, sizeof(lctx));
115 d->ver = de_getbyte(0) == 0x4c ? 2 : 1;
116 de_dbg(c, "version: %d", d->ver);
117 de_declare_fmtf(c, "MS Paint v%d", d->ver);
119 d->width = de_getu16le(4);
120 d->height = de_getu16le(6);
121 de_dbg_dimensions(c, d->width, d->height);
123 if(d->ver==1) {
124 do_ver1(c, d);
126 else {
127 do_ver2(c, d);
130 de_free(c, d);
133 static int de_identify_msp(deark *c)
135 u8 b[4];
136 de_read(b, 0, 4);
138 if(b[0]==0x44 && b[1]==0x61 && b[2]==0x6e && b[3]==0x4d)
139 return 100;
140 if(b[0]==0x4c && b[1]==0x69 && b[2]==0x6e && b[3]==0x53)
141 return 100;
142 return 0;
145 void de_module_msp(deark *c, struct deark_module_info *mi)
147 mi->id = "msp";
148 mi->desc = "Microsoft Paint image";
149 mi->run_fn = de_run_msp;
150 mi->identify_fn = de_identify_msp;