aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/real_extractor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/real_extractor.c')
-rw-r--r--src/plugins/real_extractor.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/src/plugins/real_extractor.c b/src/plugins/real_extractor.c
new file mode 100644
index 0000000..c6089af
--- /dev/null
+++ b/src/plugins/real_extractor.c
@@ -0,0 +1,409 @@
1/*
2 This file is part of libextractor.
3 (C) 2002, 2003, 2009 Vidyut Samanta and Christian Grothoff
4
5 libextractor is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libextractor is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libextractor; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 */
20
21#include "platform.h"
22#include "extractor.h"
23#include <stdint.h>
24
25#define UINT32 uint32_t
26#define UINT16 uint16_t
27#define UINT8 uint8_t
28
29typedef struct
30{
31 UINT32 object_id;
32 UINT32 size;
33 UINT16 object_version; /* must be 0 */
34 UINT16 stream_number;
35 UINT32 max_bit_rate;
36 UINT32 avg_bit_rate;
37 UINT32 max_packet_size;
38 UINT32 avg_packet_size;
39 UINT32 start_time;
40 UINT32 preroll;
41 UINT32 duration;
42 UINT8 stream_name_size;
43 UINT8 data[0]; /* variable length section */
44 /*
45 UINT8[stream_name_size] stream_name;
46 UINT8 mime_type_size;
47 UINT8[mime_type_size] mime_type;
48 UINT32 type_specific_len;
49 UINT8[type_specific_len] type_specific_data;
50 */
51} Media_Properties;
52
53typedef struct
54{
55 UINT32 object_id;
56 UINT32 size;
57 UINT16 object_version; /* must be 0 */
58 UINT16 title_len;
59 UINT8 data[0]; /* variable length section */
60 /*
61 UINT8[title_len] title;
62 UINT16 author_len;
63 UINT8[author_len] author;
64 UINT16 copyright_len;
65 UINT8[copyright_len] copyright;
66 UINT16 comment_len;
67 UINT8[comment_len] comment;
68 */
69} Content_Description;
70/* author, copyright and comment are supposed to be ASCII */
71
72#define REAL_HEADER 0x2E524d46
73#define MDPR_HEADER 0x4D445052
74#define CONT_HEADER 0x434F4e54
75
76#define RAFF4_HEADER 0x2E7261FD
77
78
79static int
80processMediaProperties (const Media_Properties * prop,
81 EXTRACTOR_MetaDataProcessor proc,
82 void *proc_cls)
83{
84
85 UINT8 mime_type_size;
86 UINT32 prop_size;
87
88 prop_size = ntohl (prop->size);
89 if (prop_size <= sizeof (Media_Properties))
90 return 0;
91 if (0 != prop->object_version)
92 return 0;
93 if (prop_size <= prop->stream_name_size + sizeof (UINT8)
94 + sizeof (Media_Properties))
95 return 0;
96
97 mime_type_size = prop->data[prop->stream_name_size];
98 if (mime_type_size > 2048)
99 return 0; /* unrealistic */
100 if (prop_size > prop->stream_name_size + sizeof (UINT8) +
101 +mime_type_size + sizeof (Media_Properties))
102 {
103 char data[mime_type_size + 1];
104 memcpy (data, &prop->data[prop->stream_name_size + 1], mime_type_size);
105 data[mime_type_size] = '\0';
106
107 return proc (proc_cls,
108 "real",
109 EXTRACTOR_METATYPE_MIMETYPE,
110 EXTRACTOR_METAFORMAT_UTF8,
111 "text/plain",
112 data,
113 strlen (data));
114 }
115 return 0;
116}
117
118static int
119processContentDescription (const Content_Description * prop,
120 EXTRACTOR_MetaDataProcessor proc,
121 void *proc_cls)
122{
123 UINT16 author_len;
124 UINT16 copyright_len;
125 UINT16 comment_len;
126 UINT16 title_len;
127 char *title;
128 char *author;
129 char *copyright;
130 char *comment;
131 UINT32 prop_size;
132 int ret;
133
134 prop_size = ntohl (prop->size);
135 if (prop_size <= sizeof (Content_Description))
136 return 0;
137 if (0 != prop->object_version)
138 return 0;
139 title_len = ntohs (prop->title_len);
140 if (prop_size <= title_len + sizeof (UINT16) + sizeof (Content_Description))
141 return 0;
142 author_len = ntohs (*(UINT16 *) & prop->data[title_len]);
143 if (prop_size <= title_len + sizeof (UINT16)
144 + author_len + sizeof (Content_Description))
145 return 0;
146
147 copyright_len = ntohs (*(UINT16 *) & prop->data[title_len +
148 author_len +
149 sizeof (UINT16)]);
150
151 if (prop_size <= title_len + 2 * sizeof (UINT16)
152 + author_len + copyright_len + sizeof (Content_Description))
153 return 0;
154
155 comment_len = ntohs (*(UINT16 *) & prop->data[title_len +
156 author_len +
157 copyright_len +
158 2 * sizeof (UINT16)]);
159
160 if (prop_size < title_len + 3 * sizeof (UINT16)
161 + author_len + copyright_len + comment_len
162 + sizeof (Content_Description))
163 return 0;
164
165 title = malloc (title_len + 1);
166 memcpy (title, &prop->data[0], title_len);
167 title[title_len] = '\0';
168 ret = proc (proc_cls,
169 "real",
170 EXTRACTOR_METATYPE_TITLE,
171 EXTRACTOR_METAFORMAT_UTF8,
172 "text/plain",
173 title,
174 strlen (title)+1);
175 free (title);
176 if (ret != 0)
177 return ret;
178
179 author = malloc (author_len + 1);
180 memcpy (author, &prop->data[title_len + sizeof (UINT16)], author_len);
181 author[author_len] = '\0';
182 ret = proc (proc_cls,
183 "real",
184 EXTRACTOR_METATYPE_AUTHOR_NAME,
185 EXTRACTOR_METAFORMAT_UTF8,
186 "text/plain",
187 author,
188 strlen (author)+1);
189 free (author);
190 if (ret != 0)
191 return ret;
192
193 copyright = malloc (copyright_len + 1);
194 memcpy (copyright,
195 &prop->data[title_len + sizeof (UINT16) * 2 + author_len],
196 copyright_len);
197 copyright[copyright_len] = '\0';
198 ret = proc (proc_cls,
199 "real",
200 EXTRACTOR_METATYPE_COPYRIGHT,
201 EXTRACTOR_METAFORMAT_UTF8,
202 "text/plain",
203 copyright,
204 strlen (copyright)+1);
205 free (copyright);
206 if (ret != 0)
207 return ret;
208
209 comment = malloc (comment_len + 1);
210 memcpy (comment,
211 &prop->data[title_len + sizeof (UINT16) * 3 + author_len +
212 copyright_len], comment_len);
213 comment[comment_len] = '\0';
214 ret = proc (proc_cls,
215 "real",
216 EXTRACTOR_METATYPE_COMMENT,
217 EXTRACTOR_METAFORMAT_UTF8,
218 "text/plain",
219 comment,
220 strlen (comment)+1);
221 free (comment);
222 if (ret != 0)
223 return ret;
224 return 0;
225}
226
227typedef struct RAFF4_header
228{
229 unsigned short version;
230 unsigned short revision;
231 unsigned short header_length;
232 unsigned short compression_type;
233 unsigned int granularity;
234 unsigned int total_bytes;
235 unsigned int bytes_per_minute;
236 unsigned int bytes_per_minute2;
237 unsigned short interleave_factor;
238 unsigned short interleave_block_size;
239 unsigned int user_data;
240 float sample_rate;
241 unsigned short sample_size;
242 unsigned short channels;
243 unsigned char interleave_code[5];
244 unsigned char compression_code[5];
245 unsigned char is_interleaved;
246 unsigned char copy_byte;
247 unsigned char stream_type;
248 /*
249 unsigned char tlen;
250 unsigned char title[tlen];
251 unsigned char alen;
252 unsigned char author[alen];
253 unsigned char clen;
254 unsigned char copyright[clen];
255 unsigned char aplen;
256 unsigned char app[aplen]; */
257} RAFF4_header;
258
259#define RAFF4_HDR_SIZE 53
260
261static char *
262stndup (const char *str, size_t n)
263{
264 char *tmp;
265 tmp = malloc (n + 1);
266 tmp[n] = '\0';
267 memcpy (tmp, str, n);
268 return tmp;
269}
270
271/* audio/vnd.rn-realaudio */
272int
273EXTRACTOR_real_extract (const unsigned char *data,
274 size_t size,
275 EXTRACTOR_MetaDataProcessor proc,
276 void *proc_cls,
277 const char *options)
278{
279 const unsigned char *pos;
280 const unsigned char *end;
281 unsigned int length;
282 const RAFF4_header *hdr;
283 unsigned char tlen;
284 unsigned char alen;
285 unsigned char clen;
286 unsigned char aplen;
287 char *x;
288 int ret;
289
290 if (size <= 2 * sizeof (int))
291 return 0;
292 if (RAFF4_HEADER == ntohl (*(int *) data))
293 {
294 /* HELIX */
295 if (size <= RAFF4_HDR_SIZE + 16 + 4)
296 return 0;
297 if (0 != proc (proc_cls,
298 "real",
299 EXTRACTOR_METATYPE_MIMETYPE,
300 EXTRACTOR_METAFORMAT_UTF8,
301 "text/plain",
302 "audio/vnd.rn-realaudio",
303 strlen ("audio/vnd.rn-realaudio")+1))
304 return 1;
305 hdr = (const RAFF4_header *) &data[16];
306 if (ntohs (hdr->header_length) + 16 > size)
307 return 0;
308 tlen = data[16 + RAFF4_HDR_SIZE];
309 if (tlen + RAFF4_HDR_SIZE + 20 > size)
310 return 0;
311 alen = data[17 + tlen + RAFF4_HDR_SIZE];
312 if (tlen + alen + RAFF4_HDR_SIZE + 20 > size)
313 return 0;
314 clen = data[18 + tlen + alen + RAFF4_HDR_SIZE];
315 if (tlen + alen + clen + RAFF4_HDR_SIZE + 20 > size)
316 return 0;
317 aplen = data[19 + tlen + clen + alen + RAFF4_HDR_SIZE];
318 if (tlen + alen + clen + aplen + RAFF4_HDR_SIZE + 20 > size)
319 return 0;
320 ret = 0;
321 if ( (tlen > 0) && (ret == 0) )
322 {
323 x = stndup ((const char *) &data[17 + RAFF4_HDR_SIZE], tlen);
324 ret = proc (proc_cls,
325 "real",
326 EXTRACTOR_METATYPE_MIMETYPE,
327 EXTRACTOR_METAFORMAT_UTF8,
328 "text/plain",
329 x,
330 strlen (x)+1);
331 free (x);
332 }
333 if ( (alen > 0) && (ret == 0) )
334 {
335 x = stndup ((const char *) &data[18 + RAFF4_HDR_SIZE + tlen], alen);
336 ret = proc (proc_cls,
337 "real",
338 EXTRACTOR_METATYPE_MIMETYPE,
339 EXTRACTOR_METAFORMAT_UTF8,
340 "text/plain",
341 x,
342 strlen (x)+1);
343 free (x);
344 }
345 if ( (clen > 0) && (ret == 0) )
346 {
347 x = stndup ((const char *) &data[19 + RAFF4_HDR_SIZE + tlen + alen], clen);
348 ret = proc (proc_cls,
349 "real",
350 EXTRACTOR_METATYPE_MIMETYPE,
351 EXTRACTOR_METAFORMAT_UTF8,
352 "text/plain",
353 x,
354 strlen (x)+1);
355 free (x);
356 }
357 if ( (aplen > 0) && (ret == 0) )
358 {
359 x = stndup ((const char *) &data[20 + RAFF4_HDR_SIZE + tlen + alen + clen], aplen);
360 ret = proc (proc_cls,
361 "real",
362 EXTRACTOR_METATYPE_MIMETYPE,
363 EXTRACTOR_METAFORMAT_UTF8,
364 "text/plain",
365 x,
366 strlen (x)+1);
367 free (x);
368 }
369 return ret;
370 }
371 if (REAL_HEADER == ntohl (*(int *) data))
372 {
373 /* old real */
374 end = &data[size];
375 pos = &data[0];
376 ret = 0;
377 while (0 == ret)
378 {
379 if ((pos + 8 >= end) || (pos + 8 < pos))
380 break;
381 length = ntohl (*(((unsigned int *) pos) + 1));
382 if (length <= 0)
383 break;
384 if ((pos + length >= end) || (pos + length < pos))
385 break;
386 switch (ntohl (*((unsigned int *) pos)))
387 {
388 case MDPR_HEADER:
389 ret = processMediaProperties ((Media_Properties *) pos,
390 proc,
391 proc_cls);
392 pos += length;
393 break;
394 case CONT_HEADER:
395 ret = processContentDescription ((Content_Description *) pos,
396 proc,
397 proc_cls);
398 pos += length;
399 break;
400 case REAL_HEADER: /* treat like default */
401 default:
402 pos += length;
403 break;
404 }
405 }
406 return ret;
407 }
408 return 0;
409}