lzhuf: Refactored to avoid direct array access
[deark.git] / modules / rm.c
blobbb327c565014bb9c9b47cf83af79113fbea517ff
1 // This file is part of Deark.
2 // Copyright (C) 2019 Jason Summers
3 // See the file COPYING for terms of use.
5 // RealMedia
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_rm);
11 #define CODE_CONT 0x434f4e54U
12 #define CODE_MDPR 0x4d445052U
13 #define CODE_PROP 0x50524f50U
15 struct chunkinfo {
16 struct de_fourcc chunk4cc;
17 i64 pos;
18 i64 dpos;
19 i64 dlen;
20 unsigned int version;
23 typedef struct localctx_struct {
24 int input_encoding;
25 } lctx;
27 static void read_chunk_version_p(deark *c, lctx *d, struct chunkinfo *ci, i64 *ppos)
29 ci->version = (unsigned int)de_getu16be_p(ppos);
30 de_dbg(c, "object version: %u", ci->version);
33 static void do_chunk_PROP(deark *c, lctx *d, struct chunkinfo *ci)
35 i64 pos = ci->dpos;
36 i64 n;
38 read_chunk_version_p(c, d, ci, &pos);
39 if(ci->version!=0 || ci->dlen<42) goto done;
41 pos += 7*4; // TODO: other fields
43 n = de_getu32be_p(&pos);
44 de_dbg(c, "index offset: %"I64_FMT, n);
45 n = de_getu32be_p(&pos);
46 de_dbg(c, "data offset: %"I64_FMT, n);
47 n = de_getu16be_p(&pos);
48 de_dbg(c, "num streams: %d", (int)n);
49 n = de_getu16be_p(&pos);
50 de_dbg(c, "flags: 0x%04x", (unsigned int)n);
51 done:
55 static void do_chunk_CONT(deark *c, lctx *d, struct chunkinfo *ci)
57 i64 pos = ci->dpos;
58 de_ucstring *s = NULL;
59 i64 slen;
61 read_chunk_version_p(c, d, ci, &pos);
62 if(ci->version != 0) goto done;
64 s = ucstring_create(c);
65 slen = de_getu16be_p(&pos);
66 dbuf_read_to_ucstring(c->infile, pos, slen, s, 0, d->input_encoding);
67 de_dbg(c, "title: \"%s\"", ucstring_getpsz_d(s));
68 pos += slen;
70 ucstring_empty(s);
71 slen = de_getu16be_p(&pos);
72 dbuf_read_to_ucstring(c->infile, pos, slen, s, 0, d->input_encoding);
73 de_dbg(c, "author: \"%s\"", ucstring_getpsz_d(s));
74 pos += slen;
76 ucstring_empty(s);
77 slen = de_getu16be_p(&pos);
78 dbuf_read_to_ucstring(c->infile, pos, slen, s, 0, d->input_encoding);
79 de_dbg(c, "copyright: \"%s\"", ucstring_getpsz_d(s));
80 pos += slen;
82 done:
83 ucstring_destroy(s);
86 static void do_chunk_MDPR(deark *c, lctx *d, struct chunkinfo *ci)
88 i64 pos = ci->dpos;
89 de_ucstring *s = NULL;
90 i64 slen;
91 i64 n;
93 read_chunk_version_p(c, d, ci, &pos);
94 if(ci->version != 0) goto done;
96 n = de_getu16be_p(&pos);
97 de_dbg(c, "stream number: %d", (int)n);
99 pos += 7*4; // TODO: other fields
101 slen = (i64)de_getbyte_p(&pos);
102 s = ucstring_create(c);
103 dbuf_read_to_ucstring(c->infile, pos, slen, s, 0, DE_ENCODING_ASCII);
104 de_dbg(c, "stream name: \"%s\"", ucstring_getpsz_d(s));
105 pos += slen;
107 slen = (i64)de_getbyte_p(&pos);
108 ucstring_empty(s);
109 dbuf_read_to_ucstring(c->infile, pos, slen, s, 0, DE_ENCODING_ASCII);
110 de_dbg(c, "mime type: \"%s\"", ucstring_getpsz_d(s));
111 pos += slen;
113 if(pos+4 > ci->dpos + ci->dlen) goto done;
114 n = de_getu32be_p(&pos);
115 if(n == 0) goto done;
116 de_dbg(c, "type specific data at %"I64_FMT", len=%"I64_FMT, pos, n);
117 if(pos+n > ci->dpos + ci->dlen) goto done;
118 de_dbg_indent(c, 1);
119 de_dbg_hexdump(c, c->infile, pos, n, 256, NULL, 0x1);
120 de_dbg_indent(c, -1);
122 done:
126 static int do_rm_chunk(deark *c, lctx *d, i64 pos1, i64 maxlen,
127 i64 *bytes_consumed)
129 i64 chunklen;
130 i64 pos = pos1;
131 int retval = 0;
132 int hexdump_flag = 0;
133 struct chunkinfo *ci = NULL;
135 ci = de_malloc(c, sizeof(struct chunkinfo));
136 ci->pos = pos1;
137 dbuf_read_fourcc(c->infile, pos, &ci->chunk4cc, 4, 0x0);
138 de_dbg(c, "chunk type: '%s'", ci->chunk4cc.id_dbgstr);
139 pos += 4;
140 chunklen = de_getu32be_p(&pos);
141 de_dbg(c, "chunk len: %"I64_FMT, chunklen);
142 if(chunklen < 8) goto done;
143 if(chunklen > maxlen) {
144 de_warn(c, "Chunk at %"I64_FMT" exceeds its parent's bounds", pos1);
145 chunklen = maxlen;
148 *bytes_consumed = chunklen;
149 retval = 1;
151 ci->dpos = pos;
152 ci->dlen = chunklen - 8;
153 de_dbg(c, "dpos: %"I64_FMT", dlen: %"I64_FMT, ci->dpos, ci->dlen);
155 switch(ci->chunk4cc.id) {
156 case CODE_CONT:
157 do_chunk_CONT(c, d, ci);
158 break;
159 case CODE_MDPR:
160 do_chunk_MDPR(c, d, ci);
161 break;
162 case CODE_PROP:
163 do_chunk_PROP(c, d, ci);
164 break;
165 default:
166 hexdump_flag = 1;
169 if(hexdump_flag && c->debug_level>=2) {
170 de_dbg_hexdump(c, c->infile, ci->dpos, ci->dlen, 256, NULL, 0x1);
173 done:
174 de_free(c, ci);
175 return retval;
178 static int do_rm_chunk_sequence(deark *c, lctx *d, i64 pos1, i64 len)
180 i64 pos = pos1;
182 while(1) {
183 int ret;
184 i64 bytes_consumed = 0;
186 if(pos >= pos1+len) break;
187 de_dbg(c, "chunk at %"I64_FMT, pos);
188 de_dbg_indent(c, 1);
189 ret = do_rm_chunk(c, d, pos, pos1+len-pos, &bytes_consumed);
190 de_dbg_indent(c, -1);
191 if((!ret) || (bytes_consumed<1)) goto done;
192 pos += bytes_consumed;
195 done:
196 return 1;
199 static void de_run_rm(deark *c, de_module_params *mparams)
201 lctx *d = NULL;
203 d = de_malloc(c, sizeof(lctx));
204 d->input_encoding = de_get_input_encoding(c, NULL, DE_ENCODING_WINDOWS1252);
205 do_rm_chunk_sequence(c, d, 0, c->infile->len);
206 de_free(c, d);
209 static int de_identify_rm(deark *c)
211 if(!dbuf_memcmp(c->infile, 0, ".RMF\0", 5))
212 return 100;
213 return 0;
216 void de_module_rm(deark *c, struct deark_module_info *mi)
218 mi->id = "rm";
219 mi->desc = "RealMedia";
220 mi->run_fn = de_run_rm;
221 mi->identify_fn = de_identify_rm;