bmp: Rewrote the RLE decompressor
[deark.git] / modules / apm.c
blob2795845c8d44dfe6fbca83d172b96daa051a81c0
1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // Apple Partition Map
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_apm);
11 struct partition_info {
12 i64 partition_startsec;
13 i64 partition_startpos;
14 i64 partition_size_in_secs;
15 i64 partition_size_in_bytes;
16 unsigned int partition_status;
17 de_ucstring *pname;
18 struct de_stringreaderdata *ptype;
21 typedef struct localctx_struct {
22 i64 secsize;
23 i64 npartitions;
24 } lctx;
26 static void destroy_partition_info(deark *c, struct partition_info *pi)
28 if(!pi) return;
29 ucstring_destroy(pi->pname);
30 de_destroy_stringreaderdata(c, pi->ptype);
31 de_free(c, pi);
34 static void do_extract_partition(deark *c, lctx *d, struct partition_info *pi)
36 de_finfo *fi = NULL;
37 const char *ext = "partition";
38 i64 len_to_extract;
39 int use_pname_in_name = 1;
40 int use_ptype_in_name = 1;
41 de_ucstring *outfname = NULL;
43 if(pi->partition_startpos >= c->infile->len) goto done;
44 len_to_extract = pi->partition_size_in_bytes;
45 if(pi->partition_startpos + len_to_extract > c->infile->len) {
46 de_warn(c, "Partition at %"I64_FMT" goes beyond end of file", pi->partition_startpos);
47 len_to_extract = c->infile->len - pi->partition_startpos;
50 fi = de_finfo_create(c);
51 outfname = ucstring_create(c);
53 if(!de_strcmp(pi->ptype->sz, "Apple_partition_map")) {
54 ext = "bin";
55 use_pname_in_name = 0;
57 else if(!de_strcmp(pi->ptype->sz, "Apple_HFS")) {
58 unsigned int sig = (unsigned int)de_getu16be(pi->partition_startpos+1024);
59 if(sig==0x4244) { // "BD"
60 ext = "hfs";
61 use_ptype_in_name = 0;
63 else if(sig==0x482b) { // "H+"
64 ext="hfs+.hfs";
65 use_ptype_in_name = 0;
67 else if(sig==0x4858) { // "HX"
68 ext="hfsx.hfs";
69 use_ptype_in_name = 0;
73 if(use_pname_in_name && ucstring_isnonempty(pi->pname)) {
74 ucstring_append_ucstring(outfname, pi->pname);
76 if(use_ptype_in_name && ucstring_isnonempty(pi->ptype->str)) {
77 if(outfname->len>1) {
78 ucstring_append_sz(outfname, ".", DE_ENCODING_LATIN1);
80 ucstring_append_ucstring(outfname, pi->ptype->str);
82 if(outfname->len>1) {
83 de_finfo_set_name_from_ucstring(c, fi, outfname, 0);
86 dbuf_create_file_from_slice(c->infile, pi->partition_startpos,
87 len_to_extract, ext, fi, 0);
89 done:
90 de_finfo_destroy(c, fi);
91 ucstring_destroy(outfname);
94 static int do_entry_at_sector(deark *c, lctx *d, i64 secnum)
96 i64 pos = secnum*d->secsize;
97 i64 npartitions;
98 int retval = 0;
99 int saved_indent_level;
100 struct partition_info *pi = NULL;
102 de_dbg_indent_save(c, &saved_indent_level);
104 if(dbuf_memcmp(c->infile, pos, "PM", 2)) {
105 de_err(c, "Partition map entry not found at %"I64_FMT, pos);
106 goto done;
109 pi = de_malloc(c, sizeof(struct partition_info));
111 de_dbg(c, "partition map entry at %"I64_FMT, pos);
112 de_dbg_indent(c, 1);
113 pos += 4;
115 npartitions = de_getu32be_p(&pos);
116 de_dbg(c, "total number of partitions: %d", (int)npartitions);
117 if(secnum==1) {
118 d->npartitions = npartitions;
120 retval = 1;
122 pi->partition_startsec = de_getu32be_p(&pos);
123 pi->partition_startpos = pi->partition_startsec * d->secsize;
124 de_dbg(c, "starting sector of partition: %"I64_FMT" (offset %"I64_FMT")",
125 pi->partition_startsec, pi->partition_startpos);
127 pi->partition_size_in_secs = de_getu32be_p(&pos);
128 pi->partition_size_in_bytes = pi->partition_size_in_secs * d->secsize;
129 de_dbg(c, "partition size: %"I64_FMT" sectors (%"I64_FMT" bytes)",
130 pi->partition_size_in_secs, pi->partition_size_in_bytes);
132 pi->pname = ucstring_create(c);
133 dbuf_read_to_ucstring(c->infile, pos, 32, pi->pname, DE_CONVFLAG_STOP_AT_NUL,
134 DE_ENCODING_ASCII);
135 de_dbg(c, "partition name: \"%s\"", ucstring_getpsz(pi->pname));
136 pos += 32;
138 pi->ptype = dbuf_read_string(c->infile, pos, 32, 32, DE_CONVFLAG_STOP_AT_NUL,
139 DE_ENCODING_ASCII);
140 de_dbg(c, "partition type: \"%s\"", ucstring_getpsz(pi->ptype->str));
141 pos += 32;
143 pi->partition_status = (unsigned int)de_getu32be_p(&pos);
144 de_dbg(c, "status: 0x%08x", (unsigned int)pi->partition_status);
146 // TODO: More fields here
148 do_extract_partition(c, d, pi);
150 done:
151 if(pi) destroy_partition_info(c, pi);
152 de_dbg_indent_restore(c, saved_indent_level);
153 return retval;
156 static void de_run_apm(deark *c, de_module_params *mparams)
158 lctx *d = NULL;
159 i64 i;
160 int ret;
162 d = de_malloc(c, sizeof(lctx));
164 d->secsize = 512;
166 // Read the first map entry (should set d->npartitions)
167 ret = do_entry_at_sector(c, d, 1);
168 if(!ret) goto done;
170 // Read the rest of the entries
171 for(i=1; i<d->npartitions; i++) {
172 ret = do_entry_at_sector(c, d, 1+i);
173 if(!ret) goto done;
176 done:
177 de_free(c, d);
180 static int de_identify_apm(deark *c)
182 i64 i;
184 for(i=0; i<2; i++) {
185 if(dbuf_memcmp(c->infile, 512+i*512, "PM\x00\x00", 4))
186 return 0;
188 return 75;
191 void de_module_apm(deark *c, struct deark_module_info *mi)
193 mi->id = "apm";
194 mi->desc = "Apple Partition Map";
195 mi->run_fn = de_run_apm;
196 mi->identify_fn = de_identify_apm;